LCOV - code coverage report
Current view: top level - src/backend/commands - operatorcmds.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 241 258 93.4 %
Date: 2024-04-26 03:10:58 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * operatorcmds.c
       4             :  *
       5             :  *    Routines for operator manipulation commands
       6             :  *
       7             :  * Portions Copyright (c) 1996-2024, 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/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        1578 : DefineOperator(List *names, List *parameters)
      68             : {
      69             :     char       *oprName;
      70             :     Oid         oprNamespace;
      71             :     AclResult   aclresult;
      72        1578 :     bool        canMerge = false;   /* operator merges */
      73        1578 :     bool        canHash = false;    /* operator hashes */
      74        1578 :     List       *functionName = NIL; /* function for operator */
      75        1578 :     TypeName   *typeName1 = NULL;   /* first type name */
      76        1578 :     TypeName   *typeName2 = NULL;   /* second type name */
      77        1578 :     Oid         typeId1 = InvalidOid;   /* types converted to OID */
      78        1578 :     Oid         typeId2 = InvalidOid;
      79             :     Oid         rettype;
      80        1578 :     List       *commutatorName = NIL;   /* optional commutator operator name */
      81        1578 :     List       *negatorName = NIL;  /* optional negator operator name */
      82        1578 :     List       *restrictionName = NIL;  /* optional restrict. sel. function */
      83        1578 :     List       *joinName = NIL; /* optional join sel. function */
      84             :     Oid         functionOid;    /* functions converted to OID */
      85             :     Oid         restrictionOid;
      86             :     Oid         joinOid;
      87             :     Oid         typeId[2];      /* to hold left and right arg */
      88             :     int         nargs;
      89             :     ListCell   *pl;
      90             : 
      91             :     /* Convert list of names to a name and namespace */
      92        1578 :     oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
      93             : 
      94             :     /* Check we have creation rights in target namespace */
      95        1578 :     aclresult = object_aclcheck(NamespaceRelationId, oprNamespace, GetUserId(), ACL_CREATE);
      96        1578 :     if (aclresult != ACLCHECK_OK)
      97           6 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
      98           6 :                        get_namespace_name(oprNamespace));
      99             : 
     100             :     /*
     101             :      * loop over the definition list and extract the information we need.
     102             :      */
     103       10138 :     foreach(pl, parameters)
     104             :     {
     105        8578 :         DefElem    *defel = (DefElem *) lfirst(pl);
     106             : 
     107        8578 :         if (strcmp(defel->defname, "leftarg") == 0)
     108             :         {
     109        1480 :             typeName1 = defGetTypeName(defel);
     110        1480 :             if (typeName1->setof)
     111           6 :                 ereport(ERROR,
     112             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     113             :                          errmsg("SETOF type not allowed for operator argument")));
     114             :         }
     115        7098 :         else if (strcmp(defel->defname, "rightarg") == 0)
     116             :         {
     117        1548 :             typeName2 = defGetTypeName(defel);
     118        1548 :             if (typeName2->setof)
     119           6 :                 ereport(ERROR,
     120             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     121             :                          errmsg("SETOF type not allowed for operator argument")));
     122             :         }
     123             :         /* "function" and "procedure" are equivalent here */
     124        5550 :         else if (strcmp(defel->defname, "function") == 0)
     125          28 :             functionName = defGetQualifiedName(defel);
     126        5522 :         else if (strcmp(defel->defname, "procedure") == 0)
     127        1520 :             functionName = defGetQualifiedName(defel);
     128        4002 :         else if (strcmp(defel->defname, "commutator") == 0)
     129         986 :             commutatorName = defGetQualifiedName(defel);
     130        3016 :         else if (strcmp(defel->defname, "negator") == 0)
     131         670 :             negatorName = defGetQualifiedName(defel);
     132        2346 :         else if (strcmp(defel->defname, "restrict") == 0)
     133        1022 :             restrictionName = defGetQualifiedName(defel);
     134        1324 :         else if (strcmp(defel->defname, "join") == 0)
     135         998 :             joinName = defGetQualifiedName(defel);
     136         326 :         else if (strcmp(defel->defname, "hashes") == 0)
     137          92 :             canHash = defGetBoolean(defel);
     138         234 :         else if (strcmp(defel->defname, "merges") == 0)
     139         142 :             canMerge = defGetBoolean(defel);
     140             :         /* These obsolete options are taken as meaning canMerge */
     141          92 :         else if (strcmp(defel->defname, "sort1") == 0)
     142          10 :             canMerge = true;
     143          82 :         else if (strcmp(defel->defname, "sort2") == 0)
     144          10 :             canMerge = true;
     145          72 :         else if (strcmp(defel->defname, "ltcmp") == 0)
     146           6 :             canMerge = true;
     147          66 :         else if (strcmp(defel->defname, "gtcmp") == 0)
     148           6 :             canMerge = true;
     149             :         else
     150             :         {
     151             :             /* WARNING, not ERROR, for historical backwards-compatibility */
     152          60 :             ereport(WARNING,
     153             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     154             :                      errmsg("operator attribute \"%s\" not recognized",
     155             :                             defel->defname)));
     156             :         }
     157             :     }
     158             : 
     159             :     /*
     160             :      * make sure we have our required definitions
     161             :      */
     162        1560 :     if (functionName == NIL)
     163          12 :         ereport(ERROR,
     164             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     165             :                  errmsg("operator function must be specified")));
     166             : 
     167             :     /* Transform type names to type OIDs */
     168        1548 :     if (typeName1)
     169        1474 :         typeId1 = typenameTypeId(NULL, typeName1);
     170        1548 :     if (typeName2)
     171        1536 :         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        1548 :     if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
     181           6 :         ereport(ERROR,
     182             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     183             :                  errmsg("operator argument types must be specified")));
     184        1542 :     if (!OidIsValid(typeId2))
     185           6 :         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        1536 :     if (typeName1)
     191             :     {
     192        1468 :         aclresult = object_aclcheck(TypeRelationId, typeId1, GetUserId(), ACL_USAGE);
     193        1468 :         if (aclresult != ACLCHECK_OK)
     194          12 :             aclcheck_error_type(aclresult, typeId1);
     195             :     }
     196             : 
     197        1524 :     if (typeName2)
     198             :     {
     199        1524 :         aclresult = object_aclcheck(TypeRelationId, typeId2, GetUserId(), ACL_USAGE);
     200        1524 :         if (aclresult != ACLCHECK_OK)
     201           6 :             aclcheck_error_type(aclresult, typeId2);
     202             :     }
     203             : 
     204             :     /*
     205             :      * Look up the operator's underlying function.
     206             :      */
     207        1518 :     if (!OidIsValid(typeId1))
     208             :     {
     209          68 :         typeId[0] = typeId2;
     210          68 :         nargs = 1;
     211             :     }
     212        1450 :     else if (!OidIsValid(typeId2))
     213             :     {
     214           0 :         typeId[0] = typeId1;
     215           0 :         nargs = 1;
     216             :     }
     217             :     else
     218             :     {
     219        1450 :         typeId[0] = typeId1;
     220        1450 :         typeId[1] = typeId2;
     221        1450 :         nargs = 2;
     222             :     }
     223        1518 :     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        1518 :     aclresult = object_aclcheck(ProcedureRelationId, functionOid, GetUserId(), ACL_EXECUTE);
     231        1518 :     if (aclresult != ACLCHECK_OK)
     232           6 :         aclcheck_error(aclresult, OBJECT_FUNCTION,
     233           6 :                        NameListToString(functionName));
     234             : 
     235        1512 :     rettype = get_func_rettype(functionOid);
     236        1512 :     aclresult = object_aclcheck(TypeRelationId, rettype, GetUserId(), ACL_USAGE);
     237        1512 :     if (aclresult != ACLCHECK_OK)
     238           6 :         aclcheck_error_type(aclresult, rettype);
     239             : 
     240             :     /*
     241             :      * Look up restriction and join estimators if specified
     242             :      */
     243        1506 :     if (restrictionName)
     244        1022 :         restrictionOid = ValidateRestrictionEstimator(restrictionName);
     245             :     else
     246         484 :         restrictionOid = InvalidOid;
     247        1506 :     if (joinName)
     248         998 :         joinOid = ValidateJoinEstimator(joinName);
     249             :     else
     250         508 :         joinOid = InvalidOid;
     251             : 
     252             :     /*
     253             :      * now have OperatorCreate do all the work..
     254             :      */
     255             :     return
     256        1506 :         OperatorCreate(oprName, /* operator name */
     257             :                        oprNamespace,    /* namespace */
     258             :                        typeId1, /* left type id */
     259             :                        typeId2, /* right type id */
     260             :                        functionOid, /* function for operator */
     261             :                        commutatorName,  /* optional commutator operator name */
     262             :                        negatorName, /* optional negator operator name */
     263             :                        restrictionOid,  /* optional restrict. sel. function */
     264             :                        joinOid, /* optional join sel. function name */
     265             :                        canMerge,    /* operator merges */
     266             :                        canHash);    /* operator hashes */
     267             : }
     268             : 
     269             : /*
     270             :  * Look up a restriction estimator function by name, and verify that it has
     271             :  * the correct signature and we have the permissions to attach it to an
     272             :  * operator.
     273             :  */
     274             : static Oid
     275        1476 : ValidateRestrictionEstimator(List *restrictionName)
     276             : {
     277             :     Oid         typeId[4];
     278             :     Oid         restrictionOid;
     279             :     AclResult   aclresult;
     280             : 
     281        1476 :     typeId[0] = INTERNALOID;    /* PlannerInfo */
     282        1476 :     typeId[1] = OIDOID;         /* operator OID */
     283        1476 :     typeId[2] = INTERNALOID;    /* args list */
     284        1476 :     typeId[3] = INT4OID;        /* varRelid */
     285             : 
     286        1476 :     restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
     287             : 
     288             :     /* estimators must return float8 */
     289        1470 :     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        1470 :     aclresult = object_aclcheck(ProcedureRelationId, restrictionOid, GetUserId(), ACL_EXECUTE);
     297        1470 :     if (aclresult != ACLCHECK_OK)
     298           0 :         aclcheck_error(aclresult, OBJECT_FUNCTION,
     299           0 :                        NameListToString(restrictionName));
     300             : 
     301        1470 :     return restrictionOid;
     302             : }
     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        1452 : ValidateJoinEstimator(List *joinName)
     311             : {
     312             :     Oid         typeId[5];
     313             :     Oid         joinOid;
     314             :     Oid         joinOid2;
     315             :     AclResult   aclresult;
     316             : 
     317        1452 :     typeId[0] = INTERNALOID;    /* PlannerInfo */
     318        1452 :     typeId[1] = OIDOID;         /* operator OID */
     319        1452 :     typeId[2] = INTERNALOID;    /* args list */
     320        1452 :     typeId[3] = INT2OID;        /* jointype */
     321        1452 :     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        1452 :     joinOid = LookupFuncName(joinName, 5, typeId, true);
     329        1452 :     joinOid2 = LookupFuncName(joinName, 4, typeId, true);
     330        1452 :     if (OidIsValid(joinOid))
     331             :     {
     332        1446 :         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             :     }
     338             :     else
     339             :     {
     340           6 :         joinOid = joinOid2;
     341             :         /* If not found, reference the 5-argument signature in error msg */
     342           6 :         if (!OidIsValid(joinOid))
     343           6 :             joinOid = LookupFuncName(joinName, 5, typeId, false);
     344             :     }
     345             : 
     346             :     /* estimators must return float8 */
     347        1446 :     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        1446 :     aclresult = object_aclcheck(ProcedureRelationId, joinOid, GetUserId(), ACL_EXECUTE);
     355        1446 :     if (aclresult != ACLCHECK_OK)
     356           0 :         aclcheck_error(aclresult, OBJECT_FUNCTION,
     357           0 :                        NameListToString(joinName));
     358             : 
     359        1446 :     return joinOid;
     360             : }
     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          54 : ValidateOperatorReference(List *name,
     373             :                           Oid leftTypeId,
     374             :                           Oid rightTypeId)
     375             : {
     376             :     Oid         oid;
     377             :     bool        defined;
     378             : 
     379          54 :     oid = OperatorLookup(name,
     380             :                          leftTypeId,
     381             :                          rightTypeId,
     382             :                          &defined);
     383             : 
     384             :     /* These message strings are chosen to match parse_oper.c */
     385          54 :     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          54 :     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          54 :     if (!object_ownercheck(OperatorRelationId, oid, GetUserId()))
     402           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
     403           0 :                        NameListToString(name));
     404             : 
     405          54 :     return oid;
     406             : }
     407             : 
     408             : 
     409             : /*
     410             :  * Guts of operator deletion.
     411             :  */
     412             : void
     413         734 : RemoveOperatorById(Oid operOid)
     414             : {
     415             :     Relation    relation;
     416             :     HeapTuple   tup;
     417             :     Form_pg_operator op;
     418             : 
     419         734 :     relation = table_open(OperatorRelationId, RowExclusiveLock);
     420             : 
     421         734 :     tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     422         734 :     if (!HeapTupleIsValid(tup)) /* should not happen */
     423           0 :         elog(ERROR, "cache lookup failed for operator %u", operOid);
     424         734 :     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         734 :     if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
     433             :     {
     434         330 :         OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
     435         330 :         if (operOid == op->oprcom || operOid == op->oprnegate)
     436             :         {
     437         100 :             ReleaseSysCache(tup);
     438         100 :             tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     439         100 :             if (!HeapTupleIsValid(tup)) /* should not happen */
     440           0 :                 elog(ERROR, "cache lookup failed for operator %u", operOid);
     441             :         }
     442             :     }
     443             : 
     444         734 :     CatalogTupleDelete(relation, &tup->t_self);
     445             : 
     446         734 :     ReleaseSysCache(tup);
     447             : 
     448         734 :     table_close(relation, RowExclusiveLock);
     449         734 : }
     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         602 : AlterOperator(AlterOperatorStmt *stmt)
     463             : {
     464             :     ObjectAddress address;
     465             :     Oid         oprId;
     466             :     Relation    catalog;
     467             :     HeapTuple   tup;
     468             :     Form_pg_operator oprForm;
     469             :     int         i;
     470             :     ListCell   *pl;
     471             :     Datum       values[Natts_pg_operator];
     472             :     bool        nulls[Natts_pg_operator];
     473             :     bool        replaces[Natts_pg_operator];
     474         602 :     List       *restrictionName = NIL;  /* optional restrict. sel. function */
     475         602 :     bool        updateRestriction = false;
     476             :     Oid         restrictionOid;
     477         602 :     List       *joinName = NIL; /* optional join sel. function */
     478         602 :     bool        updateJoin = false;
     479             :     Oid         joinOid;
     480         602 :     List       *commutatorName = NIL;   /* optional commutator operator name */
     481             :     Oid         commutatorOid;
     482         602 :     List       *negatorName = NIL;  /* optional negator operator name */
     483             :     Oid         negatorOid;
     484         602 :     bool        canMerge = false;
     485         602 :     bool        updateMerges = false;
     486         602 :     bool        canHash = false;
     487         602 :     bool        updateHashes = false;
     488             : 
     489             :     /* Look up the operator */
     490         602 :     oprId = LookupOperWithArgs(stmt->opername, false);
     491         602 :     catalog = table_open(OperatorRelationId, RowExclusiveLock);
     492         602 :     tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(oprId));
     493         602 :     if (!HeapTupleIsValid(tup))
     494           0 :         elog(ERROR, "cache lookup failed for operator %u", oprId);
     495         602 :     oprForm = (Form_pg_operator) GETSTRUCT(tup);
     496             : 
     497             :     /* Process options */
     498        1646 :     foreach(pl, stmt->options)
     499             :     {
     500        1050 :         DefElem    *defel = (DefElem *) lfirst(pl);
     501             :         List       *param;
     502             : 
     503        1050 :         if (defel->arg == NULL)
     504          58 :             param = NIL;        /* NONE, removes the function */
     505             :         else
     506         992 :             param = defGetQualifiedName(defel);
     507             : 
     508        1050 :         if (strcmp(defel->defname, "restrict") == 0)
     509             :         {
     510         472 :             restrictionName = param;
     511         472 :             updateRestriction = true;
     512             :         }
     513         578 :         else if (strcmp(defel->defname, "join") == 0)
     514             :         {
     515         466 :             joinName = param;
     516         466 :             updateJoin = true;
     517             :         }
     518         112 :         else if (strcmp(defel->defname, "commutator") == 0)
     519             :         {
     520          24 :             commutatorName = defGetQualifiedName(defel);
     521             :         }
     522          88 :         else if (strcmp(defel->defname, "negator") == 0)
     523             :         {
     524          30 :             negatorName = defGetQualifiedName(defel);
     525             :         }
     526          58 :         else if (strcmp(defel->defname, "merges") == 0)
     527             :         {
     528          24 :             canMerge = defGetBoolean(defel);
     529          24 :             updateMerges = true;
     530             :         }
     531          34 :         else if (strcmp(defel->defname, "hashes") == 0)
     532             :         {
     533          28 :             canHash = defGetBoolean(defel);
     534          28 :             updateHashes = true;
     535             :         }
     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           6 :         else if (strcmp(defel->defname, "leftarg") == 0 ||
     542           6 :                  strcmp(defel->defname, "rightarg") == 0 ||
     543           6 :                  strcmp(defel->defname, "function") == 0 ||
     544           6 :                  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             :         }
     551             :         else
     552           6 :             ereport(ERROR,
     553             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     554             :                      errmsg("operator attribute \"%s\" not recognized",
     555             :                             defel->defname)));
     556             :     }
     557             : 
     558             :     /* Check permissions. Must be owner. */
     559         596 :     if (!object_ownercheck(OperatorRelationId, oprId, GetUserId()))
     560           6 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
     561           6 :                        NameStr(oprForm->oprname));
     562             : 
     563             :     /*
     564             :      * Look up OIDs for any parameters specified
     565             :      */
     566         590 :     if (restrictionName)
     567         454 :         restrictionOid = ValidateRestrictionEstimator(restrictionName);
     568             :     else
     569         136 :         restrictionOid = InvalidOid;
     570         584 :     if (joinName)
     571         454 :         joinOid = ValidateJoinEstimator(joinName);
     572             :     else
     573         130 :         joinOid = InvalidOid;
     574             : 
     575         578 :     if (commutatorName)
     576             :     {
     577             :         /* commutator has reversed arg types */
     578          24 :         commutatorOid = ValidateOperatorReference(commutatorName,
     579             :                                                   oprForm->oprright,
     580             :                                                   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             :     }
     587             :     else
     588         554 :         commutatorOid = InvalidOid;
     589             : 
     590         578 :     if (negatorName)
     591             :     {
     592          30 :         negatorOid = ValidateOperatorReference(negatorName,
     593             :                                                oprForm->oprleft,
     594             :                                                oprForm->oprright);
     595             : 
     596             :         /* Must reject self-negation */
     597          30 :         if (negatorOid == oprForm->oid)
     598           6 :             ereport(ERROR,
     599             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     600             :                      errmsg("operator cannot be its own negator")));
     601             :     }
     602             :     else
     603             :     {
     604         548 :         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         572 :     if (OidIsValid(commutatorOid) && OidIsValid(oprForm->oprcom) &&
     612          12 :         commutatorOid != oprForm->oprcom)
     613           6 :         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         566 :     if (OidIsValid(negatorOid) && OidIsValid(oprForm->oprnegate) &&
     619          12 :         negatorOid != oprForm->oprnegate)
     620           6 :         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         560 :     if (updateMerges && oprForm->oprcanmerge && !canMerge)
     626           6 :         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         554 :     if (updateHashes && oprForm->oprcanhash && !canHash)
     632           6 :         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         548 :     OperatorValidateParams(oprForm->oprleft,
     639             :                            oprForm->oprright,
     640             :                            oprForm->oprresult,
     641             :                            OidIsValid(commutatorOid),
     642             :                            OidIsValid(negatorOid),
     643             :                            OidIsValid(restrictionOid),
     644             :                            OidIsValid(joinOid),
     645             :                            canMerge,
     646             :                            canHash);
     647             : 
     648             :     /* Update the tuple */
     649        8768 :     for (i = 0; i < Natts_pg_operator; ++i)
     650             :     {
     651        8220 :         values[i] = (Datum) 0;
     652        8220 :         replaces[i] = false;
     653        8220 :         nulls[i] = false;
     654             :     }
     655         548 :     if (updateRestriction)
     656             :     {
     657         460 :         replaces[Anum_pg_operator_oprrest - 1] = true;
     658         460 :         values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionOid);
     659             :     }
     660         548 :     if (updateJoin)
     661             :     {
     662         460 :         replaces[Anum_pg_operator_oprjoin - 1] = true;
     663         460 :         values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
     664             :     }
     665         548 :     if (OidIsValid(commutatorOid))
     666             :     {
     667          18 :         replaces[Anum_pg_operator_oprcom - 1] = true;
     668          18 :         values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorOid);
     669             :     }
     670         548 :     if (OidIsValid(negatorOid))
     671             :     {
     672          18 :         replaces[Anum_pg_operator_oprnegate - 1] = true;
     673          18 :         values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorOid);
     674             :     }
     675         548 :     if (updateMerges)
     676             :     {
     677          18 :         replaces[Anum_pg_operator_oprcanmerge - 1] = true;
     678          18 :         values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
     679             :     }
     680         548 :     if (updateHashes)
     681             :     {
     682          22 :         replaces[Anum_pg_operator_oprcanhash - 1] = true;
     683          22 :         values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
     684             :     }
     685             : 
     686         548 :     tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
     687             :                             values, nulls, replaces);
     688             : 
     689         548 :     CatalogTupleUpdate(catalog, &tup->t_self, tup);
     690             : 
     691         548 :     address = makeOperatorDependencies(tup, false, true);
     692             : 
     693         548 :     if (OidIsValid(commutatorOid) || OidIsValid(negatorOid))
     694          36 :         OperatorUpd(oprId, commutatorOid, negatorOid, false);
     695             : 
     696         536 :     InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
     697             : 
     698         536 :     table_close(catalog, NoLock);
     699             : 
     700         536 :     return address;
     701             : }

Generated by: LCOV version 1.14