LCOV - code coverage report
Current view: top level - src/backend/commands - operatorcmds.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 245 264 92.8 %
Date: 2026-02-09 22:18:06 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-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        1634 : DefineOperator(List *names, List *parameters)
      68             : {
      69             :     char       *oprName;
      70             :     Oid         oprNamespace;
      71             :     AclResult   aclresult;
      72        1634 :     bool        canMerge = false;   /* operator merges */
      73        1634 :     bool        canHash = false;    /* operator hashes */
      74        1634 :     List       *functionName = NIL; /* function for operator */
      75        1634 :     TypeName   *typeName1 = NULL;   /* first type name */
      76        1634 :     TypeName   *typeName2 = NULL;   /* second type name */
      77        1634 :     Oid         typeId1 = InvalidOid;   /* types converted to OID */
      78        1634 :     Oid         typeId2 = InvalidOid;
      79             :     Oid         rettype;
      80        1634 :     List       *commutatorName = NIL;   /* optional commutator operator name */
      81        1634 :     List       *negatorName = NIL;  /* optional negator operator name */
      82        1634 :     List       *restrictionName = NIL;  /* optional restrict. sel. function */
      83        1634 :     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        1634 :     oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
      93             : 
      94             :     /* Check we have creation rights in target namespace */
      95        1634 :     aclresult = object_aclcheck(NamespaceRelationId, oprNamespace, GetUserId(), ACL_CREATE);
      96        1634 :     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       10418 :     foreach(pl, parameters)
     104             :     {
     105        8802 :         DefElem    *defel = (DefElem *) lfirst(pl);
     106             : 
     107        8802 :         if (strcmp(defel->defname, "leftarg") == 0)
     108             :         {
     109        1536 :             typeName1 = defGetTypeName(defel);
     110        1536 :             if (typeName1->setof)
     111           6 :                 ereport(ERROR,
     112             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     113             :                          errmsg("SETOF type not allowed for operator argument")));
     114             :         }
     115        7266 :         else if (strcmp(defel->defname, "rightarg") == 0)
     116             :         {
     117        1604 :             typeName2 = defGetTypeName(defel);
     118        1604 :             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        5662 :         else if (strcmp(defel->defname, "function") == 0)
     125          28 :             functionName = defGetQualifiedName(defel);
     126        5634 :         else if (strcmp(defel->defname, "procedure") == 0)
     127        1576 :             functionName = defGetQualifiedName(defel);
     128        4058 :         else if (strcmp(defel->defname, "commutator") == 0)
     129        1036 :             commutatorName = defGetQualifiedName(defel);
     130        3022 :         else if (strcmp(defel->defname, "negator") == 0)
     131         670 :             negatorName = defGetQualifiedName(defel);
     132        2352 :         else if (strcmp(defel->defname, "restrict") == 0)
     133        1028 :             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        1616 :     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        1604 :     if (typeName1)
     169        1530 :         typeId1 = typenameTypeId(NULL, typeName1);
     170        1604 :     if (typeName2)
     171        1592 :         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        1604 :     if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
     181           6 :         ereport(ERROR,
     182             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     183             :                  errmsg("operator argument types must be specified")));
     184        1598 :     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        1592 :     if (typeName1)
     191             :     {
     192        1524 :         aclresult = object_aclcheck(TypeRelationId, typeId1, GetUserId(), ACL_USAGE);
     193        1524 :         if (aclresult != ACLCHECK_OK)
     194          12 :             aclcheck_error_type(aclresult, typeId1);
     195             :     }
     196             : 
     197        1580 :     if (typeName2)
     198             :     {
     199        1580 :         aclresult = object_aclcheck(TypeRelationId, typeId2, GetUserId(), ACL_USAGE);
     200        1580 :         if (aclresult != ACLCHECK_OK)
     201           6 :             aclcheck_error_type(aclresult, typeId2);
     202             :     }
     203             : 
     204             :     /*
     205             :      * Look up the operator's underlying function.
     206             :      */
     207        1574 :     if (!OidIsValid(typeId1))
     208             :     {
     209          68 :         typeId[0] = typeId2;
     210          68 :         nargs = 1;
     211             :     }
     212        1506 :     else if (!OidIsValid(typeId2))
     213             :     {
     214           0 :         typeId[0] = typeId1;
     215           0 :         nargs = 1;
     216             :     }
     217             :     else
     218             :     {
     219        1506 :         typeId[0] = typeId1;
     220        1506 :         typeId[1] = typeId2;
     221        1506 :         nargs = 2;
     222             :     }
     223        1574 :     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        1574 :     aclresult = object_aclcheck(ProcedureRelationId, functionOid, GetUserId(), ACL_EXECUTE);
     231        1574 :     if (aclresult != ACLCHECK_OK)
     232           6 :         aclcheck_error(aclresult, OBJECT_FUNCTION,
     233           6 :                        NameListToString(functionName));
     234             : 
     235        1568 :     rettype = get_func_rettype(functionOid);
     236        1568 :     aclresult = object_aclcheck(TypeRelationId, rettype, GetUserId(), ACL_USAGE);
     237        1568 :     if (aclresult != ACLCHECK_OK)
     238           6 :         aclcheck_error_type(aclresult, rettype);
     239             : 
     240             :     /*
     241             :      * Look up restriction and join estimators if specified
     242             :      */
     243        1562 :     if (restrictionName)
     244        1028 :         restrictionOid = ValidateRestrictionEstimator(restrictionName);
     245             :     else
     246         534 :         restrictionOid = InvalidOid;
     247        1562 :     if (joinName)
     248         998 :         joinOid = ValidateJoinEstimator(joinName);
     249             :     else
     250         564 :         joinOid = InvalidOid;
     251             : 
     252             :     /*
     253             :      * now have OperatorCreate do all the work..
     254             :      */
     255             :     return
     256        1562 :         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        1482 : ValidateRestrictionEstimator(List *restrictionName)
     276             : {
     277             :     Oid         typeId[4];
     278             :     Oid         restrictionOid;
     279             : 
     280        1482 :     typeId[0] = INTERNALOID;    /* PlannerInfo */
     281        1482 :     typeId[1] = OIDOID;         /* operator OID */
     282        1482 :     typeId[2] = INTERNALOID;    /* args list */
     283        1482 :     typeId[3] = INT4OID;        /* varRelid */
     284             : 
     285        1482 :     restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
     286             : 
     287             :     /* estimators must return float8 */
     288        1476 :     if (get_func_rettype(restrictionOid) != FLOAT8OID)
     289           0 :         ereport(ERROR,
     290             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     291             :                  errmsg("restriction estimator function %s must return type %s",
     292             :                         NameListToString(restrictionName), "float8")));
     293             : 
     294             :     /*
     295             :      * If the estimator is not a built-in function, require superuser
     296             :      * privilege to install it.  This protects against using something that is
     297             :      * not a restriction estimator or has hard-wired assumptions about what
     298             :      * data types it is working with.  (Built-in estimators are required to
     299             :      * defend themselves adequately against unexpected data type choices, but
     300             :      * it seems impractical to expect that of extensions' estimators.)
     301             :      *
     302             :      * If it is built-in, only require EXECUTE rights.
     303             :      */
     304        1476 :     if (restrictionOid >= FirstGenbkiObjectId)
     305             :     {
     306          34 :         if (!superuser())
     307           0 :             ereport(ERROR,
     308             :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     309             :                      errmsg("must be superuser to specify a non-built-in restriction estimator function")));
     310             :     }
     311             :     else
     312             :     {
     313             :         AclResult   aclresult;
     314             : 
     315        1442 :         aclresult = object_aclcheck(ProcedureRelationId, restrictionOid,
     316             :                                     GetUserId(), ACL_EXECUTE);
     317        1442 :         if (aclresult != ACLCHECK_OK)
     318           0 :             aclcheck_error(aclresult, OBJECT_FUNCTION,
     319           0 :                            NameListToString(restrictionName));
     320             :     }
     321             : 
     322        1476 :     return restrictionOid;
     323             : }
     324             : 
     325             : /*
     326             :  * Look up a join estimator function by name, and verify that it has the
     327             :  * correct signature and we have the permissions to attach it to an
     328             :  * operator.
     329             :  */
     330             : static Oid
     331        1452 : ValidateJoinEstimator(List *joinName)
     332             : {
     333             :     Oid         typeId[5];
     334             :     Oid         joinOid;
     335             :     Oid         joinOid2;
     336             : 
     337        1452 :     typeId[0] = INTERNALOID;    /* PlannerInfo */
     338        1452 :     typeId[1] = OIDOID;         /* operator OID */
     339        1452 :     typeId[2] = INTERNALOID;    /* args list */
     340        1452 :     typeId[3] = INT2OID;        /* jointype */
     341        1452 :     typeId[4] = INTERNALOID;    /* SpecialJoinInfo */
     342             : 
     343             :     /*
     344             :      * As of Postgres 8.4, the preferred signature for join estimators has 5
     345             :      * arguments, but we still allow the old 4-argument form.  Whine about
     346             :      * ambiguity if both forms exist.
     347             :      */
     348        1452 :     joinOid = LookupFuncName(joinName, 5, typeId, true);
     349        1452 :     joinOid2 = LookupFuncName(joinName, 4, typeId, true);
     350        1452 :     if (OidIsValid(joinOid))
     351             :     {
     352        1446 :         if (OidIsValid(joinOid2))
     353           0 :             ereport(ERROR,
     354             :                     (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
     355             :                      errmsg("join estimator function %s has multiple matches",
     356             :                             NameListToString(joinName))));
     357             :     }
     358             :     else
     359             :     {
     360           6 :         joinOid = joinOid2;
     361             :         /* If not found, reference the 5-argument signature in error msg */
     362           6 :         if (!OidIsValid(joinOid))
     363           6 :             joinOid = LookupFuncName(joinName, 5, typeId, false);
     364             :     }
     365             : 
     366             :     /* estimators must return float8 */
     367        1446 :     if (get_func_rettype(joinOid) != FLOAT8OID)
     368           0 :         ereport(ERROR,
     369             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     370             :                  errmsg("join estimator function %s must return type %s",
     371             :                         NameListToString(joinName), "float8")));
     372             : 
     373             :     /* privilege checks are the same as in ValidateRestrictionEstimator */
     374        1446 :     if (joinOid >= FirstGenbkiObjectId)
     375             :     {
     376          10 :         if (!superuser())
     377           0 :             ereport(ERROR,
     378             :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     379             :                      errmsg("must be superuser to specify a non-built-in join estimator function")));
     380             :     }
     381             :     else
     382             :     {
     383             :         AclResult   aclresult;
     384             : 
     385        1436 :         aclresult = object_aclcheck(ProcedureRelationId, joinOid,
     386             :                                     GetUserId(), ACL_EXECUTE);
     387        1436 :         if (aclresult != ACLCHECK_OK)
     388           0 :             aclcheck_error(aclresult, OBJECT_FUNCTION,
     389           0 :                            NameListToString(joinName));
     390             :     }
     391             : 
     392        1446 :     return joinOid;
     393             : }
     394             : 
     395             : /*
     396             :  * Look up and return the OID of an operator,
     397             :  * given a possibly-qualified name and left and right type IDs.
     398             :  *
     399             :  * Verifies that the operator is defined (not a shell) and owned by
     400             :  * the current user, so that we have permission to associate it with
     401             :  * the operator being altered.  Rejecting shell operators is a policy
     402             :  * choice to help catch mistakes, rather than something essential.
     403             :  */
     404             : static Oid
     405          54 : ValidateOperatorReference(List *name,
     406             :                           Oid leftTypeId,
     407             :                           Oid rightTypeId)
     408             : {
     409             :     Oid         oid;
     410             :     bool        defined;
     411             : 
     412          54 :     oid = OperatorLookup(name,
     413             :                          leftTypeId,
     414             :                          rightTypeId,
     415             :                          &defined);
     416             : 
     417             :     /* These message strings are chosen to match parse_oper.c */
     418          54 :     if (!OidIsValid(oid))
     419           0 :         ereport(ERROR,
     420             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     421             :                  errmsg("operator does not exist: %s",
     422             :                         op_signature_string(name,
     423             :                                             leftTypeId,
     424             :                                             rightTypeId))));
     425             : 
     426          54 :     if (!defined)
     427           0 :         ereport(ERROR,
     428             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     429             :                  errmsg("operator is only a shell: %s",
     430             :                         op_signature_string(name,
     431             :                                             leftTypeId,
     432             :                                             rightTypeId))));
     433             : 
     434          54 :     if (!object_ownercheck(OperatorRelationId, oid, GetUserId()))
     435           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
     436           0 :                        NameListToString(name));
     437             : 
     438          54 :     return oid;
     439             : }
     440             : 
     441             : 
     442             : /*
     443             :  * Guts of operator deletion.
     444             :  */
     445             : void
     446         788 : RemoveOperatorById(Oid operOid)
     447             : {
     448             :     Relation    relation;
     449             :     HeapTuple   tup;
     450             :     Form_pg_operator op;
     451             : 
     452         788 :     relation = table_open(OperatorRelationId, RowExclusiveLock);
     453             : 
     454         788 :     tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     455         788 :     if (!HeapTupleIsValid(tup)) /* should not happen */
     456           0 :         elog(ERROR, "cache lookup failed for operator %u", operOid);
     457         788 :     op = (Form_pg_operator) GETSTRUCT(tup);
     458             : 
     459             :     /*
     460             :      * Reset links from commutator and negator, if any.  In case of a
     461             :      * self-commutator or self-negator, this means we have to re-fetch the
     462             :      * updated tuple.  (We could optimize away updates on the tuple we're
     463             :      * about to drop, but it doesn't seem worth convoluting the logic for.)
     464             :      */
     465         788 :     if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
     466             :     {
     467         378 :         OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
     468         378 :         if (operOid == op->oprcom || operOid == op->oprnegate)
     469             :         {
     470         148 :             ReleaseSysCache(tup);
     471         148 :             tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     472         148 :             if (!HeapTupleIsValid(tup)) /* should not happen */
     473           0 :                 elog(ERROR, "cache lookup failed for operator %u", operOid);
     474             :         }
     475             :     }
     476             : 
     477         788 :     CatalogTupleDelete(relation, &tup->t_self);
     478             : 
     479         788 :     ReleaseSysCache(tup);
     480             : 
     481         788 :     table_close(relation, RowExclusiveLock);
     482         788 : }
     483             : 
     484             : /*
     485             :  * AlterOperator
     486             :  *      routine implementing ALTER OPERATOR <operator> SET (option = ...).
     487             :  *
     488             :  * Currently, only RESTRICT and JOIN estimator functions can be changed.
     489             :  * COMMUTATOR, NEGATOR, MERGES, and HASHES attributes can be set if they
     490             :  * have not been set previously.  (Changing or removing one of these
     491             :  * attributes could invalidate existing plans, which seems more trouble
     492             :  * than it's worth.)
     493             :  */
     494             : ObjectAddress
     495         608 : AlterOperator(AlterOperatorStmt *stmt)
     496             : {
     497             :     ObjectAddress address;
     498             :     Oid         oprId;
     499             :     Relation    catalog;
     500             :     HeapTuple   tup;
     501             :     Form_pg_operator oprForm;
     502             :     int         i;
     503             :     ListCell   *pl;
     504             :     Datum       values[Natts_pg_operator];
     505             :     bool        nulls[Natts_pg_operator];
     506             :     bool        replaces[Natts_pg_operator];
     507         608 :     List       *restrictionName = NIL;  /* optional restrict. sel. function */
     508         608 :     bool        updateRestriction = false;
     509             :     Oid         restrictionOid;
     510         608 :     List       *joinName = NIL; /* optional join sel. function */
     511         608 :     bool        updateJoin = false;
     512             :     Oid         joinOid;
     513         608 :     List       *commutatorName = NIL;   /* optional commutator operator name */
     514             :     Oid         commutatorOid;
     515         608 :     List       *negatorName = NIL;  /* optional negator operator name */
     516             :     Oid         negatorOid;
     517         608 :     bool        canMerge = false;
     518         608 :     bool        updateMerges = false;
     519         608 :     bool        canHash = false;
     520         608 :     bool        updateHashes = false;
     521             : 
     522             :     /* Look up the operator */
     523         608 :     oprId = LookupOperWithArgs(stmt->opername, false);
     524         608 :     catalog = table_open(OperatorRelationId, RowExclusiveLock);
     525         608 :     tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(oprId));
     526         608 :     if (!HeapTupleIsValid(tup))
     527           0 :         elog(ERROR, "cache lookup failed for operator %u", oprId);
     528         608 :     oprForm = (Form_pg_operator) GETSTRUCT(tup);
     529             : 
     530             :     /* Process options */
     531        1658 :     foreach(pl, stmt->options)
     532             :     {
     533        1056 :         DefElem    *defel = (DefElem *) lfirst(pl);
     534             :         List       *param;
     535             : 
     536        1056 :         if (defel->arg == NULL)
     537          64 :             param = NIL;        /* NONE, removes the function */
     538             :         else
     539         992 :             param = defGetQualifiedName(defel);
     540             : 
     541        1056 :         if (strcmp(defel->defname, "restrict") == 0)
     542             :         {
     543         472 :             restrictionName = param;
     544         472 :             updateRestriction = true;
     545             :         }
     546         584 :         else if (strcmp(defel->defname, "join") == 0)
     547             :         {
     548         466 :             joinName = param;
     549         466 :             updateJoin = true;
     550             :         }
     551         118 :         else if (strcmp(defel->defname, "commutator") == 0)
     552             :         {
     553          24 :             commutatorName = defGetQualifiedName(defel);
     554             :         }
     555          94 :         else if (strcmp(defel->defname, "negator") == 0)
     556             :         {
     557          30 :             negatorName = defGetQualifiedName(defel);
     558             :         }
     559          64 :         else if (strcmp(defel->defname, "merges") == 0)
     560             :         {
     561          24 :             canMerge = defGetBoolean(defel);
     562          24 :             updateMerges = true;
     563             :         }
     564          40 :         else if (strcmp(defel->defname, "hashes") == 0)
     565             :         {
     566          34 :             canHash = defGetBoolean(defel);
     567          34 :             updateHashes = true;
     568             :         }
     569             : 
     570             :         /*
     571             :          * The rest of the options that CREATE accepts cannot be changed.
     572             :          * Check for them so that we can give a meaningful error message.
     573             :          */
     574           6 :         else if (strcmp(defel->defname, "leftarg") == 0 ||
     575           6 :                  strcmp(defel->defname, "rightarg") == 0 ||
     576           6 :                  strcmp(defel->defname, "function") == 0 ||
     577           6 :                  strcmp(defel->defname, "procedure") == 0)
     578             :         {
     579           0 :             ereport(ERROR,
     580             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     581             :                      errmsg("operator attribute \"%s\" cannot be changed",
     582             :                             defel->defname)));
     583             :         }
     584             :         else
     585           6 :             ereport(ERROR,
     586             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     587             :                      errmsg("operator attribute \"%s\" not recognized",
     588             :                             defel->defname)));
     589             :     }
     590             : 
     591             :     /* Check permissions. Must be owner. */
     592         602 :     if (!object_ownercheck(OperatorRelationId, oprId, GetUserId()))
     593           6 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
     594           6 :                        NameStr(oprForm->oprname));
     595             : 
     596             :     /*
     597             :      * Look up OIDs for any parameters specified
     598             :      */
     599         596 :     if (restrictionName)
     600         454 :         restrictionOid = ValidateRestrictionEstimator(restrictionName);
     601             :     else
     602         142 :         restrictionOid = InvalidOid;
     603         590 :     if (joinName)
     604         454 :         joinOid = ValidateJoinEstimator(joinName);
     605             :     else
     606         136 :         joinOid = InvalidOid;
     607             : 
     608         584 :     if (commutatorName)
     609             :     {
     610             :         /* commutator has reversed arg types */
     611          24 :         commutatorOid = ValidateOperatorReference(commutatorName,
     612             :                                                   oprForm->oprright,
     613             :                                                   oprForm->oprleft);
     614             : 
     615             :         /*
     616             :          * We don't need to do anything extra for a self commutator as in
     617             :          * OperatorCreate, since the operator surely exists already.
     618             :          */
     619             :     }
     620             :     else
     621         560 :         commutatorOid = InvalidOid;
     622             : 
     623         584 :     if (negatorName)
     624             :     {
     625          30 :         negatorOid = ValidateOperatorReference(negatorName,
     626             :                                                oprForm->oprleft,
     627             :                                                oprForm->oprright);
     628             : 
     629             :         /* Must reject self-negation */
     630          30 :         if (negatorOid == oprForm->oid)
     631           6 :             ereport(ERROR,
     632             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     633             :                      errmsg("operator cannot be its own negator")));
     634             :     }
     635             :     else
     636             :     {
     637         554 :         negatorOid = InvalidOid;
     638             :     }
     639             : 
     640             :     /*
     641             :      * Check that we're not changing any attributes that might be depended on
     642             :      * by plans, while allowing no-op updates.
     643             :      */
     644         578 :     if (OidIsValid(commutatorOid) && OidIsValid(oprForm->oprcom) &&
     645          12 :         commutatorOid != oprForm->oprcom)
     646           6 :         ereport(ERROR,
     647             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     648             :                  errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
     649             :                         "commutator")));
     650             : 
     651         572 :     if (OidIsValid(negatorOid) && OidIsValid(oprForm->oprnegate) &&
     652          12 :         negatorOid != oprForm->oprnegate)
     653           6 :         ereport(ERROR,
     654             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     655             :                  errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
     656             :                         "negator")));
     657             : 
     658         566 :     if (updateMerges && oprForm->oprcanmerge && !canMerge)
     659           6 :         ereport(ERROR,
     660             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     661             :                  errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
     662             :                         "merges")));
     663             : 
     664         560 :     if (updateHashes && oprForm->oprcanhash && !canHash)
     665           6 :         ereport(ERROR,
     666             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     667             :                  errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
     668             :                         "hashes")));
     669             : 
     670             :     /* Perform additional checks, like OperatorCreate does */
     671         554 :     OperatorValidateParams(oprForm->oprleft,
     672             :                            oprForm->oprright,
     673             :                            oprForm->oprresult,
     674             :                            OidIsValid(commutatorOid),
     675             :                            OidIsValid(negatorOid),
     676             :                            OidIsValid(restrictionOid),
     677             :                            OidIsValid(joinOid),
     678             :                            canMerge,
     679             :                            canHash);
     680             : 
     681             :     /* Update the tuple */
     682        8864 :     for (i = 0; i < Natts_pg_operator; ++i)
     683             :     {
     684        8310 :         values[i] = (Datum) 0;
     685        8310 :         replaces[i] = false;
     686        8310 :         nulls[i] = false;
     687             :     }
     688         554 :     if (updateRestriction)
     689             :     {
     690         460 :         replaces[Anum_pg_operator_oprrest - 1] = true;
     691         460 :         values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionOid);
     692             :     }
     693         554 :     if (updateJoin)
     694             :     {
     695         460 :         replaces[Anum_pg_operator_oprjoin - 1] = true;
     696         460 :         values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
     697             :     }
     698         554 :     if (OidIsValid(commutatorOid))
     699             :     {
     700          18 :         replaces[Anum_pg_operator_oprcom - 1] = true;
     701          18 :         values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorOid);
     702             :     }
     703         554 :     if (OidIsValid(negatorOid))
     704             :     {
     705          18 :         replaces[Anum_pg_operator_oprnegate - 1] = true;
     706          18 :         values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorOid);
     707             :     }
     708         554 :     if (updateMerges)
     709             :     {
     710          18 :         replaces[Anum_pg_operator_oprcanmerge - 1] = true;
     711          18 :         values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
     712             :     }
     713         554 :     if (updateHashes)
     714             :     {
     715          28 :         replaces[Anum_pg_operator_oprcanhash - 1] = true;
     716          28 :         values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
     717             :     }
     718             : 
     719         554 :     tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
     720             :                             values, nulls, replaces);
     721             : 
     722         554 :     CatalogTupleUpdate(catalog, &tup->t_self, tup);
     723             : 
     724         554 :     address = makeOperatorDependencies(tup, false, true);
     725             : 
     726         554 :     if (OidIsValid(commutatorOid) || OidIsValid(negatorOid))
     727          36 :         OperatorUpd(oprId, commutatorOid, negatorOid, false);
     728             : 
     729         542 :     InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
     730             : 
     731         542 :     table_close(catalog, NoLock);
     732             : 
     733         542 :     return address;
     734             : }

Generated by: LCOV version 1.16