LCOV - differential code coverage report
Current view: top level - src/backend/commands - operatorcmds.c (source / functions) Coverage Total Hit LBC UIC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 91.5 % 211 193 9 9 2 83 8 100 16 82 2
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 5 5 5 5
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * operatorcmds.c
       4                 :  *
       5                 :  *    Routines for operator manipulation commands
       6                 :  *
       7                 :  * Portions Copyright (c) 1996-2023, 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 "FooDefine" routines (in src/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/dependency.h"
      37                 : #include "catalog/indexing.h"
      38                 : #include "catalog/objectaccess.h"
      39                 : #include "catalog/pg_namespace.h"
      40                 : #include "catalog/pg_operator.h"
      41                 : #include "catalog/pg_proc.h"
      42                 : #include "catalog/pg_type.h"
      43                 : #include "commands/alter.h"
      44                 : #include "commands/defrem.h"
      45                 : #include "miscadmin.h"
      46                 : #include "parser/parse_func.h"
      47                 : #include "parser/parse_oper.h"
      48                 : #include "parser/parse_type.h"
      49                 : #include "utils/acl.h"
      50                 : #include "utils/builtins.h"
      51                 : #include "utils/lsyscache.h"
      52                 : #include "utils/rel.h"
      53                 : #include "utils/syscache.h"
      54                 : 
      55                 : static Oid  ValidateRestrictionEstimator(List *restrictionName);
      56                 : static Oid  ValidateJoinEstimator(List *joinName);
      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 GIC         742 : DefineOperator(List *names, List *parameters)
      68                 : {
      69 ECB             :     char       *oprName;
      70                 :     Oid         oprNamespace;
      71                 :     AclResult   aclresult;
      72 GIC         742 :     bool        canMerge = false;   /* operator merges */
      73             742 :     bool        canHash = false;    /* operator hashes */
      74 CBC         742 :     List       *functionName = NIL; /* function for operator */
      75             742 :     TypeName   *typeName1 = NULL;   /* first type name */
      76             742 :     TypeName   *typeName2 = NULL;   /* second type name */
      77             742 :     Oid         typeId1 = InvalidOid;   /* types converted to OID */
      78             742 :     Oid         typeId2 = InvalidOid;
      79 ECB             :     Oid         rettype;
      80 CBC         742 :     List       *commutatorName = NIL;   /* optional commutator operator name */
      81 GIC         742 :     List       *negatorName = NIL;  /* optional negator operator name */
      82 CBC         742 :     List       *restrictionName = NIL;  /* optional restrict. sel. function */
      83             742 :     List       *joinName = NIL; /* optional join sel. function */
      84 ECB             :     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 GIC         742 :     oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
      93                 : 
      94 ECB             :     /* Check we have creation rights in target namespace */
      95 GNC         742 :     aclresult = object_aclcheck(NamespaceRelationId, oprNamespace, GetUserId(), ACL_CREATE);
      96 GIC         742 :     if (aclresult != ACLCHECK_OK)
      97 CBC           3 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
      98               3 :                        get_namespace_name(oprNamespace));
      99 ECB             : 
     100                 :     /*
     101                 :      * loop over the definition list and extract the information we need.
     102                 :      */
     103 GIC        4816 :     foreach(pl, parameters)
     104                 :     {
     105 CBC        4083 :         DefElem    *defel = (DefElem *) lfirst(pl);
     106                 : 
     107            4083 :         if (strcmp(defel->defname, "leftarg") == 0)
     108                 :         {
     109             693 :             typeName1 = defGetTypeName(defel);
     110 GIC         693 :             if (typeName1->setof)
     111 CBC           3 :                 ereport(ERROR,
     112 ECB             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     113                 :                          errmsg("SETOF type not allowed for operator argument")));
     114                 :         }
     115 GIC        3390 :         else if (strcmp(defel->defname, "rightarg") == 0)
     116                 :         {
     117 CBC         727 :             typeName2 = defGetTypeName(defel);
     118 GIC         727 :             if (typeName2->setof)
     119 CBC           3 :                 ereport(ERROR,
     120 ECB             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     121                 :                          errmsg("SETOF type not allowed for operator argument")));
     122                 :         }
     123                 :         /* "function" and "procedure" are equivalent here */
     124 GIC        2663 :         else if (strcmp(defel->defname, "function") == 0)
     125              14 :             functionName = defGetQualifiedName(defel);
     126 CBC        2649 :         else if (strcmp(defel->defname, "procedure") == 0)
     127             713 :             functionName = defGetQualifiedName(defel);
     128            1936 :         else if (strcmp(defel->defname, "commutator") == 0)
     129             474 :             commutatorName = defGetQualifiedName(defel);
     130            1462 :         else if (strcmp(defel->defname, "negator") == 0)
     131             320 :             negatorName = defGetQualifiedName(defel);
     132            1142 :         else if (strcmp(defel->defname, "restrict") == 0)
     133             496 :             restrictionName = defGetQualifiedName(defel);
     134             646 :         else if (strcmp(defel->defname, "join") == 0)
     135             484 :             joinName = defGetQualifiedName(defel);
     136             162 :         else if (strcmp(defel->defname, "hashes") == 0)
     137              46 :             canHash = defGetBoolean(defel);
     138             116 :         else if (strcmp(defel->defname, "merges") == 0)
     139              70 :             canMerge = defGetBoolean(defel);
     140 ECB             :         /* These obsolete options are taken as meaning canMerge */
     141 CBC          46 :         else if (strcmp(defel->defname, "sort1") == 0)
     142 GIC           5 :             canMerge = true;
     143 CBC          41 :         else if (strcmp(defel->defname, "sort2") == 0)
     144               5 :             canMerge = true;
     145              36 :         else if (strcmp(defel->defname, "ltcmp") == 0)
     146               3 :             canMerge = true;
     147              33 :         else if (strcmp(defel->defname, "gtcmp") == 0)
     148               3 :             canMerge = true;
     149 ECB             :         else
     150                 :         {
     151                 :             /* WARNING, not ERROR, for historical backwards-compatibility */
     152 GIC          30 :             ereport(WARNING,
     153                 :                     (errcode(ERRCODE_SYNTAX_ERROR),
     154 ECB             :                      errmsg("operator attribute \"%s\" not recognized",
     155                 :                             defel->defname)));
     156                 :         }
     157                 :     }
     158                 : 
     159                 :     /*
     160                 :      * make sure we have our required definitions
     161                 :      */
     162 GIC         733 :     if (functionName == NIL)
     163               6 :         ereport(ERROR,
     164 ECB             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     165                 :                  errmsg("operator function must be specified")));
     166                 : 
     167                 :     /* Transform type names to type OIDs */
     168 GIC         727 :     if (typeName1)
     169             690 :         typeId1 = typenameTypeId(NULL, typeName1);
     170 CBC         727 :     if (typeName2)
     171             721 :         typeId2 = typenameTypeId(NULL, typeName2);
     172 ECB             : 
     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 GIC         727 :     if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
     181               3 :         ereport(ERROR,
     182 ECB             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     183                 :                  errmsg("operator argument types must be specified")));
     184 GIC         724 :     if (!OidIsValid(typeId2))
     185               3 :         ereport(ERROR,
     186 ECB             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     187                 :                  errmsg("operator right argument type must be specified"),
     188                 :                  errdetail("Postfix operators are not supported.")));
     189                 : 
     190 GIC         721 :     if (typeName1)
     191                 :     {
     192 GNC         687 :         aclresult = object_aclcheck(TypeRelationId, typeId1, GetUserId(), ACL_USAGE);
     193 GIC         687 :         if (aclresult != ACLCHECK_OK)
     194 CBC           6 :             aclcheck_error_type(aclresult, typeId1);
     195 ECB             :     }
     196                 : 
     197 GIC         715 :     if (typeName2)
     198                 :     {
     199 GNC         715 :         aclresult = object_aclcheck(TypeRelationId, typeId2, GetUserId(), ACL_USAGE);
     200 GIC         715 :         if (aclresult != ACLCHECK_OK)
     201 CBC           3 :             aclcheck_error_type(aclresult, typeId2);
     202 ECB             :     }
     203                 : 
     204                 :     /*
     205                 :      * Look up the operator's underlying function.
     206                 :      */
     207 GIC         712 :     if (!OidIsValid(typeId1))
     208                 :     {
     209 CBC          34 :         typeId[0] = typeId2;
     210 GIC          34 :         nargs = 1;
     211 ECB             :     }
     212 CBC         678 :     else if (!OidIsValid(typeId2))
     213                 :     {
     214 LBC           0 :         typeId[0] = typeId1;
     215 UIC           0 :         nargs = 1;
     216 EUB             :     }
     217                 :     else
     218                 :     {
     219 GIC         678 :         typeId[0] = typeId1;
     220             678 :         typeId[1] = typeId2;
     221 CBC         678 :         nargs = 2;
     222 ECB             :     }
     223 CBC         712 :     functionOid = LookupFuncName(functionName, nargs, typeId, false);
     224                 : 
     225 ECB             :     /*
     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 GNC         712 :     aclresult = object_aclcheck(ProcedureRelationId, functionOid, GetUserId(), ACL_EXECUTE);
     231 GIC         712 :     if (aclresult != ACLCHECK_OK)
     232 CBC           3 :         aclcheck_error(aclresult, OBJECT_FUNCTION,
     233               3 :                        NameListToString(functionName));
     234 ECB             : 
     235 CBC         709 :     rettype = get_func_rettype(functionOid);
     236 GNC         709 :     aclresult = object_aclcheck(TypeRelationId, rettype, GetUserId(), ACL_USAGE);
     237 CBC         709 :     if (aclresult != ACLCHECK_OK)
     238               3 :         aclcheck_error_type(aclresult, rettype);
     239 ECB             : 
     240                 :     /*
     241                 :      * Look up restriction and join estimators if specified
     242                 :      */
     243 GIC         706 :     if (restrictionName)
     244             496 :         restrictionOid = ValidateRestrictionEstimator(restrictionName);
     245 ECB             :     else
     246 CBC         210 :         restrictionOid = InvalidOid;
     247 GIC         706 :     if (joinName)
     248 CBC         484 :         joinOid = ValidateJoinEstimator(joinName);
     249 ECB             :     else
     250 CBC         222 :         joinOid = InvalidOid;
     251                 : 
     252 ECB             :     /*
     253                 :      * now have OperatorCreate do all the work..
     254                 :      */
     255                 :     return
     256 GIC         706 :         OperatorCreate(oprName, /* operator name */
     257                 :                        oprNamespace,    /* namespace */
     258 ECB             :                        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 GIC         721 : ValidateRestrictionEstimator(List *restrictionName)
     276                 : {
     277 ECB             :     Oid         typeId[4];
     278                 :     Oid         restrictionOid;
     279                 :     AclResult   aclresult;
     280                 : 
     281 GIC         721 :     typeId[0] = INTERNALOID;    /* PlannerInfo */
     282             721 :     typeId[1] = OIDOID;         /* operator OID */
     283 CBC         721 :     typeId[2] = INTERNALOID;    /* args list */
     284             721 :     typeId[3] = INT4OID;        /* varRelid */
     285 ECB             : 
     286 CBC         721 :     restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
     287                 : 
     288 ECB             :     /* estimators must return float8 */
     289 GIC         718 :     if (get_func_rettype(restrictionOid) != FLOAT8OID)
     290 UIC           0 :         ereport(ERROR,
     291 ECB             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     292 EUB             :                  errmsg("restriction estimator function %s must return type %s",
     293                 :                         NameListToString(restrictionName), "float8")));
     294                 : 
     295                 :     /* Require EXECUTE rights for the estimator */
     296 GNC         718 :     aclresult = object_aclcheck(ProcedureRelationId, restrictionOid, GetUserId(), ACL_EXECUTE);
     297 GIC         718 :     if (aclresult != ACLCHECK_OK)
     298 LBC           0 :         aclcheck_error(aclresult, OBJECT_FUNCTION,
     299               0 :                        NameListToString(restrictionName));
     300 EUB             : 
     301 GBC         718 :     return restrictionOid;
     302                 : }
     303 ECB             : 
     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 GIC         709 : ValidateJoinEstimator(List *joinName)
     311                 : {
     312 ECB             :     Oid         typeId[5];
     313                 :     Oid         joinOid;
     314                 :     Oid         joinOid2;
     315                 :     AclResult   aclresult;
     316                 : 
     317 GIC         709 :     typeId[0] = INTERNALOID;    /* PlannerInfo */
     318             709 :     typeId[1] = OIDOID;         /* operator OID */
     319 CBC         709 :     typeId[2] = INTERNALOID;    /* args list */
     320             709 :     typeId[3] = INT2OID;        /* jointype */
     321             709 :     typeId[4] = INTERNALOID;    /* SpecialJoinInfo */
     322 ECB             : 
     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 GIC         709 :     joinOid = LookupFuncName(joinName, 5, typeId, true);
     329             709 :     joinOid2 = LookupFuncName(joinName, 4, typeId, true);
     330 CBC         709 :     if (OidIsValid(joinOid))
     331 ECB             :     {
     332 CBC         706 :         if (OidIsValid(joinOid2))
     333 UIC           0 :             ereport(ERROR,
     334 ECB             :                     (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
     335 EUB             :                      errmsg("join estimator function %s has multiple matches",
     336                 :                             NameListToString(joinName))));
     337                 :     }
     338                 :     else
     339                 :     {
     340 GIC           3 :         joinOid = joinOid2;
     341                 :         /* If not found, reference the 5-argument signature in error msg */
     342 CBC           3 :         if (!OidIsValid(joinOid))
     343 GIC           3 :             joinOid = LookupFuncName(joinName, 5, typeId, false);
     344 ECB             :     }
     345                 : 
     346                 :     /* estimators must return float8 */
     347 GIC         706 :     if (get_func_rettype(joinOid) != FLOAT8OID)
     348 UIC           0 :         ereport(ERROR,
     349 ECB             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     350 EUB             :                  errmsg("join estimator function %s must return type %s",
     351                 :                         NameListToString(joinName), "float8")));
     352                 : 
     353                 :     /* Require EXECUTE rights for the estimator */
     354 GNC         706 :     aclresult = object_aclcheck(ProcedureRelationId, joinOid, GetUserId(), ACL_EXECUTE);
     355 GIC         706 :     if (aclresult != ACLCHECK_OK)
     356 LBC           0 :         aclcheck_error(aclresult, OBJECT_FUNCTION,
     357               0 :                        NameListToString(joinName));
     358 EUB             : 
     359 GBC         706 :     return joinOid;
     360                 : }
     361 ECB             : 
     362                 : /*
     363                 :  * Guts of operator deletion.
     364                 :  */
     365                 : void
     366 GIC         336 : RemoveOperatorById(Oid operOid)
     367                 : {
     368 ECB             :     Relation    relation;
     369                 :     HeapTuple   tup;
     370                 :     Form_pg_operator op;
     371                 : 
     372 GIC         336 :     relation = table_open(OperatorRelationId, RowExclusiveLock);
     373                 : 
     374 CBC         336 :     tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     375 GIC         336 :     if (!HeapTupleIsValid(tup)) /* should not happen */
     376 LBC           0 :         elog(ERROR, "cache lookup failed for operator %u", operOid);
     377 CBC         336 :     op = (Form_pg_operator) GETSTRUCT(tup);
     378 EUB             : 
     379 ECB             :     /*
     380                 :      * Reset links from commutator and negator, if any.  In case of a
     381                 :      * self-commutator or self-negator, this means we have to re-fetch the
     382                 :      * updated tuple.  (We could optimize away updates on the tuple we're
     383                 :      * about to drop, but it doesn't seem worth convoluting the logic for.)
     384                 :      */
     385 GIC         336 :     if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
     386                 :     {
     387 CBC         154 :         OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
     388 GIC         154 :         if (operOid == op->oprcom || operOid == op->oprnegate)
     389 ECB             :         {
     390 CBC          47 :             ReleaseSysCache(tup);
     391 GIC          47 :             tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     392 CBC          47 :             if (!HeapTupleIsValid(tup)) /* should not happen */
     393 LBC           0 :                 elog(ERROR, "cache lookup failed for operator %u", operOid);
     394 ECB             :         }
     395 EUB             :     }
     396                 : 
     397 GIC         336 :     CatalogTupleDelete(relation, &tup->t_self);
     398                 : 
     399 CBC         336 :     ReleaseSysCache(tup);
     400                 : 
     401             336 :     table_close(relation, RowExclusiveLock);
     402 GIC         336 : }
     403 ECB             : 
     404                 : /*
     405                 :  * AlterOperator
     406                 :  *      routine implementing ALTER OPERATOR <operator> SET (option = ...).
     407                 :  *
     408                 :  * Currently, only RESTRICT and JOIN estimator functions can be changed.
     409                 :  */
     410                 : ObjectAddress
     411 GIC         258 : AlterOperator(AlterOperatorStmt *stmt)
     412                 : {
     413 ECB             :     ObjectAddress address;
     414                 :     Oid         oprId;
     415                 :     Relation    catalog;
     416                 :     HeapTuple   tup;
     417                 :     Form_pg_operator oprForm;
     418                 :     int         i;
     419                 :     ListCell   *pl;
     420                 :     Datum       values[Natts_pg_operator];
     421                 :     bool        nulls[Natts_pg_operator];
     422                 :     bool        replaces[Natts_pg_operator];
     423 GIC         258 :     List       *restrictionName = NIL;  /* optional restrict. sel. function */
     424             258 :     bool        updateRestriction = false;
     425 ECB             :     Oid         restrictionOid;
     426 CBC         258 :     List       *joinName = NIL; /* optional join sel. function */
     427 GIC         258 :     bool        updateJoin = false;
     428 ECB             :     Oid         joinOid;
     429                 : 
     430                 :     /* Look up the operator */
     431 GIC         258 :     oprId = LookupOperWithArgs(stmt->opername, false);
     432             258 :     catalog = table_open(OperatorRelationId, RowExclusiveLock);
     433 CBC         258 :     tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(oprId));
     434             258 :     if (!HeapTupleIsValid(tup))
     435 LBC           0 :         elog(ERROR, "cache lookup failed for operator %u", oprId);
     436 CBC         258 :     oprForm = (Form_pg_operator) GETSTRUCT(tup);
     437 EUB             : 
     438 ECB             :     /* Process options */
     439 GIC         723 :     foreach(pl, stmt->options)
     440                 :     {
     441 CBC         480 :         DefElem    *defel = (DefElem *) lfirst(pl);
     442                 :         List       *param;
     443 ECB             : 
     444 GIC         480 :         if (defel->arg == NULL)
     445              15 :             param = NIL;        /* NONE, removes the function */
     446 ECB             :         else
     447 CBC         465 :             param = defGetQualifiedName(defel);
     448                 : 
     449             480 :         if (strcmp(defel->defname, "restrict") == 0)
     450                 :         {
     451             234 :             restrictionName = param;
     452 GIC         234 :             updateRestriction = true;
     453 ECB             :         }
     454 CBC         246 :         else if (strcmp(defel->defname, "join") == 0)
     455                 :         {
     456             231 :             joinName = param;
     457 GIC         231 :             updateJoin = true;
     458 ECB             :         }
     459                 : 
     460                 :         /*
     461                 :          * The rest of the options that CREATE accepts cannot be changed.
     462                 :          * Check for them so that we can give a meaningful error message.
     463                 :          */
     464 GIC          15 :         else if (strcmp(defel->defname, "leftarg") == 0 ||
     465              15 :                  strcmp(defel->defname, "rightarg") == 0 ||
     466 CBC          15 :                  strcmp(defel->defname, "function") == 0 ||
     467              15 :                  strcmp(defel->defname, "procedure") == 0 ||
     468              15 :                  strcmp(defel->defname, "commutator") == 0 ||
     469               9 :                  strcmp(defel->defname, "negator") == 0 ||
     470               3 :                  strcmp(defel->defname, "hashes") == 0 ||
     471               3 :                  strcmp(defel->defname, "merges") == 0)
     472 ECB             :         {
     473 CBC          12 :             ereport(ERROR,
     474                 :                     (errcode(ERRCODE_SYNTAX_ERROR),
     475 ECB             :                      errmsg("operator attribute \"%s\" cannot be changed",
     476                 :                             defel->defname)));
     477                 :         }
     478                 :         else
     479 GIC           3 :             ereport(ERROR,
     480                 :                     (errcode(ERRCODE_SYNTAX_ERROR),
     481 ECB             :                      errmsg("operator attribute \"%s\" not recognized",
     482                 :                             defel->defname)));
     483                 :     }
     484                 : 
     485                 :     /* Check permissions. Must be owner. */
     486 GNC         243 :     if (!object_ownercheck(OperatorRelationId, oprId, GetUserId()))
     487 GIC           3 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
     488 CBC           3 :                        NameStr(oprForm->oprname));
     489 ECB             : 
     490                 :     /*
     491                 :      * Look up restriction and join estimators if specified
     492                 :      */
     493 GIC         240 :     if (restrictionName)
     494             225 :         restrictionOid = ValidateRestrictionEstimator(restrictionName);
     495 ECB             :     else
     496 CBC          15 :         restrictionOid = InvalidOid;
     497 GIC         237 :     if (joinName)
     498 CBC         225 :         joinOid = ValidateJoinEstimator(joinName);
     499 ECB             :     else
     500 CBC          12 :         joinOid = InvalidOid;
     501                 : 
     502 ECB             :     /* Perform additional checks, like OperatorCreate does */
     503 GIC         234 :     if (!(OidIsValid(oprForm->oprleft) && OidIsValid(oprForm->oprright)))
     504                 :     {
     505 ECB             :         /* If it's not a binary op, these things mustn't be set: */
     506 UIC           0 :         if (OidIsValid(joinOid))
     507               0 :             ereport(ERROR,
     508 EUB             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     509                 :                      errmsg("only binary operators can have join selectivity")));
     510                 :     }
     511                 : 
     512 GIC         234 :     if (oprForm->oprresult != BOOLOID)
     513                 :     {
     514 LBC           0 :         if (OidIsValid(restrictionOid))
     515 UIC           0 :             ereport(ERROR,
     516 EUB             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     517                 :                      errmsg("only boolean operators can have restriction selectivity")));
     518 UIC           0 :         if (OidIsValid(joinOid))
     519               0 :             ereport(ERROR,
     520 EUB             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     521                 :                      errmsg("only boolean operators can have join selectivity")));
     522                 :     }
     523                 : 
     524                 :     /* Update the tuple */
     525 GIC        3744 :     for (i = 0; i < Natts_pg_operator; ++i)
     526                 :     {
     527 CBC        3510 :         values[i] = (Datum) 0;
     528 GIC        3510 :         replaces[i] = false;
     529 CBC        3510 :         nulls[i] = false;
     530 ECB             :     }
     531 CBC         234 :     if (updateRestriction)
     532                 :     {
     533             228 :         replaces[Anum_pg_operator_oprrest - 1] = true;
     534 GIC         228 :         values[Anum_pg_operator_oprrest - 1] = restrictionOid;
     535 ECB             :     }
     536 CBC         234 :     if (updateJoin)
     537                 :     {
     538             228 :         replaces[Anum_pg_operator_oprjoin - 1] = true;
     539 GIC         228 :         values[Anum_pg_operator_oprjoin - 1] = joinOid;
     540 ECB             :     }
     541                 : 
     542 GIC         234 :     tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
     543                 :                             values, nulls, replaces);
     544 ECB             : 
     545 GIC         234 :     CatalogTupleUpdate(catalog, &tup->t_self, tup);
     546                 : 
     547 CBC         234 :     address = makeOperatorDependencies(tup, false, true);
     548                 : 
     549             234 :     InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
     550                 : 
     551             234 :     table_close(catalog, NoLock);
     552                 : 
     553             234 :     return address;
     554                 : }
        

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