LCOV - code coverage report
Current view: top level - src/backend/commands - operatorcmds.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 92.8 % 264 245
Test Date: 2026-03-12 19:14:48 Functions: 100.0 % 6 6
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          826 : DefineOperator(List *names, List *parameters)
      68              : {
      69              :     char       *oprName;
      70              :     Oid         oprNamespace;
      71              :     AclResult   aclresult;
      72          826 :     bool        canMerge = false;   /* operator merges */
      73          826 :     bool        canHash = false;    /* operator hashes */
      74          826 :     List       *functionName = NIL; /* function for operator */
      75          826 :     TypeName   *typeName1 = NULL;   /* first type name */
      76          826 :     TypeName   *typeName2 = NULL;   /* second type name */
      77          826 :     Oid         typeId1 = InvalidOid;   /* types converted to OID */
      78          826 :     Oid         typeId2 = InvalidOid;
      79              :     Oid         rettype;
      80          826 :     List       *commutatorName = NIL;   /* optional commutator operator name */
      81          826 :     List       *negatorName = NIL;  /* optional negator operator name */
      82          826 :     List       *restrictionName = NIL;  /* optional restrict. sel. function */
      83          826 :     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          826 :     oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
      93              : 
      94              :     /* Check we have creation rights in target namespace */
      95          826 :     aclresult = object_aclcheck(NamespaceRelationId, oprNamespace, GetUserId(), ACL_CREATE);
      96          826 :     if (aclresult != ACLCHECK_OK)
      97            3 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
      98            3 :                        get_namespace_name(oprNamespace));
      99              : 
     100              :     /*
     101              :      * loop over the definition list and extract the information we need.
     102              :      */
     103         5271 :     foreach(pl, parameters)
     104              :     {
     105         4454 :         DefElem    *defel = (DefElem *) lfirst(pl);
     106              : 
     107         4454 :         if (strcmp(defel->defname, "leftarg") == 0)
     108              :         {
     109          777 :             typeName1 = defGetTypeName(defel);
     110          777 :             if (typeName1->setof)
     111            3 :                 ereport(ERROR,
     112              :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     113              :                          errmsg("SETOF type not allowed for operator argument")));
     114              :         }
     115         3677 :         else if (strcmp(defel->defname, "rightarg") == 0)
     116              :         {
     117          811 :             typeName2 = defGetTypeName(defel);
     118          811 :             if (typeName2->setof)
     119            3 :                 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         2866 :         else if (strcmp(defel->defname, "function") == 0)
     125           20 :             functionName = defGetQualifiedName(defel);
     126         2846 :         else if (strcmp(defel->defname, "procedure") == 0)
     127          791 :             functionName = defGetQualifiedName(defel);
     128         2055 :         else if (strcmp(defel->defname, "commutator") == 0)
     129          524 :             commutatorName = defGetQualifiedName(defel);
     130         1531 :         else if (strcmp(defel->defname, "negator") == 0)
     131          341 :             negatorName = defGetQualifiedName(defel);
     132         1190 :         else if (strcmp(defel->defname, "restrict") == 0)
     133          520 :             restrictionName = defGetQualifiedName(defel);
     134          670 :         else if (strcmp(defel->defname, "join") == 0)
     135          505 :             joinName = defGetQualifiedName(defel);
     136          165 :         else if (strcmp(defel->defname, "hashes") == 0)
     137           47 :             canHash = defGetBoolean(defel);
     138          118 :         else if (strcmp(defel->defname, "merges") == 0)
     139           72 :             canMerge = defGetBoolean(defel);
     140              :         /* These obsolete options are taken as meaning canMerge */
     141           46 :         else if (strcmp(defel->defname, "sort1") == 0)
     142            5 :             canMerge = true;
     143           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              :         else
     150              :         {
     151              :             /* WARNING, not ERROR, for historical backwards-compatibility */
     152           30 :             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          817 :     if (functionName == NIL)
     163            6 :         ereport(ERROR,
     164              :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     165              :                  errmsg("operator function must be specified")));
     166              : 
     167              :     /* Transform type names to type OIDs */
     168          811 :     if (typeName1)
     169          774 :         typeId1 = typenameTypeId(NULL, typeName1);
     170          811 :     if (typeName2)
     171          805 :         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          811 :     if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
     181            3 :         ereport(ERROR,
     182              :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     183              :                  errmsg("operator argument types must be specified")));
     184          808 :     if (!OidIsValid(typeId2))
     185            3 :         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          805 :     if (typeName1)
     191              :     {
     192          771 :         aclresult = object_aclcheck(TypeRelationId, typeId1, GetUserId(), ACL_USAGE);
     193          771 :         if (aclresult != ACLCHECK_OK)
     194            6 :             aclcheck_error_type(aclresult, typeId1);
     195              :     }
     196              : 
     197          799 :     if (typeName2)
     198              :     {
     199          799 :         aclresult = object_aclcheck(TypeRelationId, typeId2, GetUserId(), ACL_USAGE);
     200          799 :         if (aclresult != ACLCHECK_OK)
     201            3 :             aclcheck_error_type(aclresult, typeId2);
     202              :     }
     203              : 
     204              :     /*
     205              :      * Look up the operator's underlying function.
     206              :      */
     207          796 :     if (!OidIsValid(typeId1))
     208              :     {
     209           34 :         typeId[0] = typeId2;
     210           34 :         nargs = 1;
     211              :     }
     212          762 :     else if (!OidIsValid(typeId2))
     213              :     {
     214            0 :         typeId[0] = typeId1;
     215            0 :         nargs = 1;
     216              :     }
     217              :     else
     218              :     {
     219          762 :         typeId[0] = typeId1;
     220          762 :         typeId[1] = typeId2;
     221          762 :         nargs = 2;
     222              :     }
     223          796 :     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          796 :     aclresult = object_aclcheck(ProcedureRelationId, functionOid, GetUserId(), ACL_EXECUTE);
     231          796 :     if (aclresult != ACLCHECK_OK)
     232            3 :         aclcheck_error(aclresult, OBJECT_FUNCTION,
     233            3 :                        NameListToString(functionName));
     234              : 
     235          793 :     rettype = get_func_rettype(functionOid);
     236          793 :     aclresult = object_aclcheck(TypeRelationId, rettype, GetUserId(), ACL_USAGE);
     237          793 :     if (aclresult != ACLCHECK_OK)
     238            3 :         aclcheck_error_type(aclresult, rettype);
     239              : 
     240              :     /*
     241              :      * Look up restriction and join estimators if specified
     242              :      */
     243          790 :     if (restrictionName)
     244          520 :         restrictionOid = ValidateRestrictionEstimator(restrictionName);
     245              :     else
     246          270 :         restrictionOid = InvalidOid;
     247          790 :     if (joinName)
     248          505 :         joinOid = ValidateJoinEstimator(joinName);
     249              :     else
     250          285 :         joinOid = InvalidOid;
     251              : 
     252              :     /*
     253              :      * now have OperatorCreate do all the work..
     254              :      */
     255              :     return
     256          790 :         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          747 : ValidateRestrictionEstimator(List *restrictionName)
     276              : {
     277              :     Oid         typeId[4];
     278              :     Oid         restrictionOid;
     279              : 
     280          747 :     typeId[0] = INTERNALOID;    /* PlannerInfo */
     281          747 :     typeId[1] = OIDOID;         /* operator OID */
     282          747 :     typeId[2] = INTERNALOID;    /* args list */
     283          747 :     typeId[3] = INT4OID;        /* varRelid */
     284              : 
     285          747 :     restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
     286              : 
     287              :     /* estimators must return float8 */
     288          744 :     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          744 :     if (restrictionOid >= FirstGenbkiObjectId)
     305              :     {
     306           17 :         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          727 :         aclresult = object_aclcheck(ProcedureRelationId, restrictionOid,
     316              :                                     GetUserId(), ACL_EXECUTE);
     317          727 :         if (aclresult != ACLCHECK_OK)
     318            0 :             aclcheck_error(aclresult, OBJECT_FUNCTION,
     319            0 :                            NameListToString(restrictionName));
     320              :     }
     321              : 
     322          744 :     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          732 : ValidateJoinEstimator(List *joinName)
     332              : {
     333              :     Oid         typeId[5];
     334              :     Oid         joinOid;
     335              :     Oid         joinOid2;
     336              : 
     337          732 :     typeId[0] = INTERNALOID;    /* PlannerInfo */
     338          732 :     typeId[1] = OIDOID;         /* operator OID */
     339          732 :     typeId[2] = INTERNALOID;    /* args list */
     340          732 :     typeId[3] = INT2OID;        /* jointype */
     341          732 :     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          732 :     joinOid = LookupFuncName(joinName, 5, typeId, true);
     349          732 :     joinOid2 = LookupFuncName(joinName, 4, typeId, true);
     350          732 :     if (OidIsValid(joinOid))
     351              :     {
     352          729 :         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            3 :         joinOid = joinOid2;
     361              :         /* If not found, reference the 5-argument signature in error msg */
     362            3 :         if (!OidIsValid(joinOid))
     363            3 :             joinOid = LookupFuncName(joinName, 5, typeId, false);
     364              :     }
     365              : 
     366              :     /* estimators must return float8 */
     367          729 :     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          729 :     if (joinOid >= FirstGenbkiObjectId)
     375              :     {
     376            5 :         if (!superuser())
     377            0 :             ereport(ERROR,
     378              :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     379              :                      errmsg("must be superuser to specify a non-built-in join estimator function")));
     380              :     }
     381              :     else
     382              :     {
     383              :         AclResult   aclresult;
     384              : 
     385          724 :         aclresult = object_aclcheck(ProcedureRelationId, joinOid,
     386              :                                     GetUserId(), ACL_EXECUTE);
     387          724 :         if (aclresult != ACLCHECK_OK)
     388            0 :             aclcheck_error(aclresult, OBJECT_FUNCTION,
     389            0 :                            NameListToString(joinName));
     390              :     }
     391              : 
     392          729 :     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           27 : ValidateOperatorReference(List *name,
     406              :                           Oid leftTypeId,
     407              :                           Oid rightTypeId)
     408              : {
     409              :     Oid         oid;
     410              :     bool        defined;
     411              : 
     412           27 :     oid = OperatorLookup(name,
     413              :                          leftTypeId,
     414              :                          rightTypeId,
     415              :                          &defined);
     416              : 
     417              :     /* These message strings are chosen to match parse_oper.c */
     418           27 :     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           27 :     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           27 :     if (!object_ownercheck(OperatorRelationId, oid, GetUserId()))
     435            0 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
     436            0 :                        NameListToString(name));
     437              : 
     438           27 :     return oid;
     439              : }
     440              : 
     441              : 
     442              : /*
     443              :  * Guts of operator deletion.
     444              :  */
     445              : void
     446          400 : RemoveOperatorById(Oid operOid)
     447              : {
     448              :     Relation    relation;
     449              :     HeapTuple   tup;
     450              :     Form_pg_operator op;
     451              : 
     452          400 :     relation = table_open(OperatorRelationId, RowExclusiveLock);
     453              : 
     454          400 :     tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     455          400 :     if (!HeapTupleIsValid(tup)) /* should not happen */
     456            0 :         elog(ERROR, "cache lookup failed for operator %u", operOid);
     457          400 :     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          400 :     if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
     466              :     {
     467          193 :         OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
     468          193 :         if (operOid == op->oprcom || operOid == op->oprnegate)
     469              :         {
     470           76 :             ReleaseSysCache(tup);
     471           76 :             tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     472           76 :             if (!HeapTupleIsValid(tup)) /* should not happen */
     473            0 :                 elog(ERROR, "cache lookup failed for operator %u", operOid);
     474              :         }
     475              :     }
     476              : 
     477          400 :     CatalogTupleDelete(relation, &tup->t_self);
     478              : 
     479          400 :     ReleaseSysCache(tup);
     480              : 
     481          400 :     table_close(relation, RowExclusiveLock);
     482          400 : }
     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          304 : 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          304 :     List       *restrictionName = NIL;  /* optional restrict. sel. function */
     508          304 :     bool        updateRestriction = false;
     509              :     Oid         restrictionOid;
     510          304 :     List       *joinName = NIL; /* optional join sel. function */
     511          304 :     bool        updateJoin = false;
     512              :     Oid         joinOid;
     513          304 :     List       *commutatorName = NIL;   /* optional commutator operator name */
     514              :     Oid         commutatorOid;
     515          304 :     List       *negatorName = NIL;  /* optional negator operator name */
     516              :     Oid         negatorOid;
     517          304 :     bool        canMerge = false;
     518          304 :     bool        updateMerges = false;
     519          304 :     bool        canHash = false;
     520          304 :     bool        updateHashes = false;
     521              : 
     522              :     /* Look up the operator */
     523          304 :     oprId = LookupOperWithArgs(stmt->opername, false);
     524          304 :     catalog = table_open(OperatorRelationId, RowExclusiveLock);
     525          304 :     tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(oprId));
     526          304 :     if (!HeapTupleIsValid(tup))
     527            0 :         elog(ERROR, "cache lookup failed for operator %u", oprId);
     528          304 :     oprForm = (Form_pg_operator) GETSTRUCT(tup);
     529              : 
     530              :     /* Process options */
     531          829 :     foreach(pl, stmt->options)
     532              :     {
     533          528 :         DefElem    *defel = (DefElem *) lfirst(pl);
     534              :         List       *param;
     535              : 
     536          528 :         if (defel->arg == NULL)
     537           32 :             param = NIL;        /* NONE, removes the function */
     538              :         else
     539          496 :             param = defGetQualifiedName(defel);
     540              : 
     541          528 :         if (strcmp(defel->defname, "restrict") == 0)
     542              :         {
     543          236 :             restrictionName = param;
     544          236 :             updateRestriction = true;
     545              :         }
     546          292 :         else if (strcmp(defel->defname, "join") == 0)
     547              :         {
     548          233 :             joinName = param;
     549          233 :             updateJoin = true;
     550              :         }
     551           59 :         else if (strcmp(defel->defname, "commutator") == 0)
     552              :         {
     553           12 :             commutatorName = defGetQualifiedName(defel);
     554              :         }
     555           47 :         else if (strcmp(defel->defname, "negator") == 0)
     556              :         {
     557           15 :             negatorName = defGetQualifiedName(defel);
     558              :         }
     559           32 :         else if (strcmp(defel->defname, "merges") == 0)
     560              :         {
     561           12 :             canMerge = defGetBoolean(defel);
     562           12 :             updateMerges = true;
     563              :         }
     564           20 :         else if (strcmp(defel->defname, "hashes") == 0)
     565              :         {
     566           17 :             canHash = defGetBoolean(defel);
     567           17 :             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            3 :         else if (strcmp(defel->defname, "leftarg") == 0 ||
     575            3 :                  strcmp(defel->defname, "rightarg") == 0 ||
     576            3 :                  strcmp(defel->defname, "function") == 0 ||
     577            3 :                  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            3 :             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          301 :     if (!object_ownercheck(OperatorRelationId, oprId, GetUserId()))
     593            3 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
     594            3 :                        NameStr(oprForm->oprname));
     595              : 
     596              :     /*
     597              :      * Look up OIDs for any parameters specified
     598              :      */
     599          298 :     if (restrictionName)
     600          227 :         restrictionOid = ValidateRestrictionEstimator(restrictionName);
     601              :     else
     602           71 :         restrictionOid = InvalidOid;
     603          295 :     if (joinName)
     604          227 :         joinOid = ValidateJoinEstimator(joinName);
     605              :     else
     606           68 :         joinOid = InvalidOid;
     607              : 
     608          292 :     if (commutatorName)
     609              :     {
     610              :         /* commutator has reversed arg types */
     611           12 :         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          280 :         commutatorOid = InvalidOid;
     622              : 
     623          292 :     if (negatorName)
     624              :     {
     625           15 :         negatorOid = ValidateOperatorReference(negatorName,
     626              :                                                oprForm->oprleft,
     627              :                                                oprForm->oprright);
     628              : 
     629              :         /* Must reject self-negation */
     630           15 :         if (negatorOid == oprForm->oid)
     631            3 :             ereport(ERROR,
     632              :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     633              :                      errmsg("operator cannot be its own negator")));
     634              :     }
     635              :     else
     636              :     {
     637          277 :         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          289 :     if (OidIsValid(commutatorOid) && OidIsValid(oprForm->oprcom) &&
     645            6 :         commutatorOid != oprForm->oprcom)
     646            3 :         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          286 :     if (OidIsValid(negatorOid) && OidIsValid(oprForm->oprnegate) &&
     652            6 :         negatorOid != oprForm->oprnegate)
     653            3 :         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          283 :     if (updateMerges && oprForm->oprcanmerge && !canMerge)
     659            3 :         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          280 :     if (updateHashes && oprForm->oprcanhash && !canHash)
     665            3 :         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          277 :     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         4432 :     for (i = 0; i < Natts_pg_operator; ++i)
     683              :     {
     684         4155 :         values[i] = (Datum) 0;
     685         4155 :         replaces[i] = false;
     686         4155 :         nulls[i] = false;
     687              :     }
     688          277 :     if (updateRestriction)
     689              :     {
     690          230 :         replaces[Anum_pg_operator_oprrest - 1] = true;
     691          230 :         values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionOid);
     692              :     }
     693          277 :     if (updateJoin)
     694              :     {
     695          230 :         replaces[Anum_pg_operator_oprjoin - 1] = true;
     696          230 :         values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
     697              :     }
     698          277 :     if (OidIsValid(commutatorOid))
     699              :     {
     700            9 :         replaces[Anum_pg_operator_oprcom - 1] = true;
     701            9 :         values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorOid);
     702              :     }
     703          277 :     if (OidIsValid(negatorOid))
     704              :     {
     705            9 :         replaces[Anum_pg_operator_oprnegate - 1] = true;
     706            9 :         values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorOid);
     707              :     }
     708          277 :     if (updateMerges)
     709              :     {
     710            9 :         replaces[Anum_pg_operator_oprcanmerge - 1] = true;
     711            9 :         values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
     712              :     }
     713          277 :     if (updateHashes)
     714              :     {
     715           14 :         replaces[Anum_pg_operator_oprcanhash - 1] = true;
     716           14 :         values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
     717              :     }
     718              : 
     719          277 :     tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
     720              :                             values, nulls, replaces);
     721              : 
     722          277 :     CatalogTupleUpdate(catalog, &tup->t_self, tup);
     723              : 
     724          277 :     address = makeOperatorDependencies(tup, false, true);
     725              : 
     726          277 :     if (OidIsValid(commutatorOid) || OidIsValid(negatorOid))
     727           18 :         OperatorUpd(oprId, commutatorOid, negatorOid, false);
     728              : 
     729          271 :     InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
     730              : 
     731          271 :     table_close(catalog, NoLock);
     732              : 
     733          271 :     return address;
     734              : }
        

Generated by: LCOV version 2.0-1