LCOV - code coverage report
Current view: top level - src/backend/commands - operatorcmds.c (source / functions) Hit Total Coverage
Test: PostgreSQL 16beta1 Lines: 193 211 91.5 %
Date: 2023-05-30 17:15:13 Functions: 5 5 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-2023, PostgreSQL Global Development Group
       8             :  * Portions Copyright (c) 1994, Regents of the University of California
       9             :  *
      10             :  *
      11             :  * IDENTIFICATION
      12             :  *    src/backend/commands/operatorcmds.c
      13             :  *
      14             :  * DESCRIPTION
      15             :  *    The "DefineFoo" routines take the parse tree and pick out the
      16             :  *    appropriate arguments/flags, passing the results to the
      17             :  *    corresponding "FooDefine" routines (in src/catalog) that do
      18             :  *    the actual catalog-munging.  These routines also verify permission
      19             :  *    of the user to execute the command.
      20             :  *
      21             :  * NOTES
      22             :  *    These things must be defined and committed in the following order:
      23             :  *      "create function":
      24             :  *              input/output, recv/send functions
      25             :  *      "create type":
      26             :  *              type
      27             :  *      "create operator":
      28             :  *              operators
      29             :  *
      30             :  *-------------------------------------------------------------------------
      31             :  */
      32             : #include "postgres.h"
      33             : 
      34             : #include "access/htup_details.h"
      35             : #include "access/table.h"
      36             : #include "catalog/dependency.h"
      37             : #include "catalog/indexing.h"
      38             : #include "catalog/objectaccess.h"
      39             : #include "catalog/pg_namespace.h"
      40             : #include "catalog/pg_operator.h"
      41             : #include "catalog/pg_proc.h"
      42             : #include "catalog/pg_type.h"
      43             : #include "commands/alter.h"
      44             : #include "commands/defrem.h"
      45             : #include "miscadmin.h"
      46             : #include "parser/parse_func.h"
      47             : #include "parser/parse_oper.h"
      48             : #include "parser/parse_type.h"
      49             : #include "utils/acl.h"
      50             : #include "utils/builtins.h"
      51             : #include "utils/lsyscache.h"
      52             : #include "utils/rel.h"
      53             : #include "utils/syscache.h"
      54             : 
      55             : static Oid  ValidateRestrictionEstimator(List *restrictionName);
      56             : static Oid  ValidateJoinEstimator(List *joinName);
      57             : 
      58             : /*
      59             :  * DefineOperator
      60             :  *      this function extracts all the information from the
      61             :  *      parameter list generated by the parser and then has
      62             :  *      OperatorCreate() do all the actual work.
      63             :  *
      64             :  * 'parameters' is a list of DefElem
      65             :  */
      66             : ObjectAddress
      67        1516 : DefineOperator(List *names, List *parameters)
      68             : {
      69             :     char       *oprName;
      70             :     Oid         oprNamespace;
      71             :     AclResult   aclresult;
      72        1516 :     bool        canMerge = false;   /* operator merges */
      73        1516 :     bool        canHash = false;    /* operator hashes */
      74        1516 :     List       *functionName = NIL; /* function for operator */
      75        1516 :     TypeName   *typeName1 = NULL;   /* first type name */
      76        1516 :     TypeName   *typeName2 = NULL;   /* second type name */
      77        1516 :     Oid         typeId1 = InvalidOid;   /* types converted to OID */
      78        1516 :     Oid         typeId2 = InvalidOid;
      79             :     Oid         rettype;
      80        1516 :     List       *commutatorName = NIL;   /* optional commutator operator name */
      81        1516 :     List       *negatorName = NIL;  /* optional negator operator name */
      82        1516 :     List       *restrictionName = NIL;  /* optional restrict. sel. function */
      83        1516 :     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        1516 :     oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
      93             : 
      94             :     /* Check we have creation rights in target namespace */
      95        1516 :     aclresult = object_aclcheck(NamespaceRelationId, oprNamespace, GetUserId(), ACL_CREATE);
      96        1516 :     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        9860 :     foreach(pl, parameters)
     104             :     {
     105        8362 :         DefElem    *defel = (DefElem *) lfirst(pl);
     106             : 
     107        8362 :         if (strcmp(defel->defname, "leftarg") == 0)
     108             :         {
     109        1418 :             typeName1 = defGetTypeName(defel);
     110        1418 :             if (typeName1->setof)
     111           6 :                 ereport(ERROR,
     112             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     113             :                          errmsg("SETOF type not allowed for operator argument")));
     114             :         }
     115        6944 :         else if (strcmp(defel->defname, "rightarg") == 0)
     116             :         {
     117        1486 :             typeName2 = defGetTypeName(defel);
     118        1486 :             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        5458 :         else if (strcmp(defel->defname, "function") == 0)
     125          28 :             functionName = defGetQualifiedName(defel);
     126        5430 :         else if (strcmp(defel->defname, "procedure") == 0)
     127        1458 :             functionName = defGetQualifiedName(defel);
     128        3972 :         else if (strcmp(defel->defname, "commutator") == 0)
     129         974 :             commutatorName = defGetQualifiedName(defel);
     130        2998 :         else if (strcmp(defel->defname, "negator") == 0)
     131         652 :             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        1498 :     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        1486 :     if (typeName1)
     169        1412 :         typeId1 = typenameTypeId(NULL, typeName1);
     170        1486 :     if (typeName2)
     171        1474 :         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        1486 :     if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
     181           6 :         ereport(ERROR,
     182             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     183             :                  errmsg("operator argument types must be specified")));
     184        1480 :     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        1474 :     if (typeName1)
     191             :     {
     192        1406 :         aclresult = object_aclcheck(TypeRelationId, typeId1, GetUserId(), ACL_USAGE);
     193        1406 :         if (aclresult != ACLCHECK_OK)
     194          12 :             aclcheck_error_type(aclresult, typeId1);
     195             :     }
     196             : 
     197        1462 :     if (typeName2)
     198             :     {
     199        1462 :         aclresult = object_aclcheck(TypeRelationId, typeId2, GetUserId(), ACL_USAGE);
     200        1462 :         if (aclresult != ACLCHECK_OK)
     201           6 :             aclcheck_error_type(aclresult, typeId2);
     202             :     }
     203             : 
     204             :     /*
     205             :      * Look up the operator's underlying function.
     206             :      */
     207        1456 :     if (!OidIsValid(typeId1))
     208             :     {
     209          68 :         typeId[0] = typeId2;
     210          68 :         nargs = 1;
     211             :     }
     212        1388 :     else if (!OidIsValid(typeId2))
     213             :     {
     214           0 :         typeId[0] = typeId1;
     215           0 :         nargs = 1;
     216             :     }
     217             :     else
     218             :     {
     219        1388 :         typeId[0] = typeId1;
     220        1388 :         typeId[1] = typeId2;
     221        1388 :         nargs = 2;
     222             :     }
     223        1456 :     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        1456 :     aclresult = object_aclcheck(ProcedureRelationId, functionOid, GetUserId(), ACL_EXECUTE);
     231        1456 :     if (aclresult != ACLCHECK_OK)
     232           6 :         aclcheck_error(aclresult, OBJECT_FUNCTION,
     233           6 :                        NameListToString(functionName));
     234             : 
     235        1450 :     rettype = get_func_rettype(functionOid);
     236        1450 :     aclresult = object_aclcheck(TypeRelationId, rettype, GetUserId(), ACL_USAGE);
     237        1450 :     if (aclresult != ACLCHECK_OK)
     238           6 :         aclcheck_error_type(aclresult, rettype);
     239             : 
     240             :     /*
     241             :      * Look up restriction and join estimators if specified
     242             :      */
     243        1444 :     if (restrictionName)
     244        1022 :         restrictionOid = ValidateRestrictionEstimator(restrictionName);
     245             :     else
     246         422 :         restrictionOid = InvalidOid;
     247        1444 :     if (joinName)
     248         998 :         joinOid = ValidateJoinEstimator(joinName);
     249             :     else
     250         446 :         joinOid = InvalidOid;
     251             : 
     252             :     /*
     253             :      * now have OperatorCreate do all the work..
     254             :      */
     255             :     return
     256        1444 :         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             :  * Guts of operator deletion.
     364             :  */
     365             : void
     366         704 : RemoveOperatorById(Oid operOid)
     367             : {
     368             :     Relation    relation;
     369             :     HeapTuple   tup;
     370             :     Form_pg_operator op;
     371             : 
     372         704 :     relation = table_open(OperatorRelationId, RowExclusiveLock);
     373             : 
     374         704 :     tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     375         704 :     if (!HeapTupleIsValid(tup)) /* should not happen */
     376           0 :         elog(ERROR, "cache lookup failed for operator %u", operOid);
     377         704 :     op = (Form_pg_operator) GETSTRUCT(tup);
     378             : 
     379             :     /*
     380             :      * Reset links from commutator and negator, if any.  In case of a
     381             :      * self-commutator or self-negator, this means we have to re-fetch the
     382             :      * updated tuple.  (We could optimize away updates on the tuple we're
     383             :      * about to drop, but it doesn't seem worth convoluting the logic for.)
     384             :      */
     385         704 :     if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
     386             :     {
     387         324 :         OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
     388         324 :         if (operOid == op->oprcom || operOid == op->oprnegate)
     389             :         {
     390         100 :             ReleaseSysCache(tup);
     391         100 :             tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     392         100 :             if (!HeapTupleIsValid(tup)) /* should not happen */
     393           0 :                 elog(ERROR, "cache lookup failed for operator %u", operOid);
     394             :         }
     395             :     }
     396             : 
     397         704 :     CatalogTupleDelete(relation, &tup->t_self);
     398             : 
     399         704 :     ReleaseSysCache(tup);
     400             : 
     401         704 :     table_close(relation, RowExclusiveLock);
     402         704 : }
     403             : 
     404             : /*
     405             :  * AlterOperator
     406             :  *      routine implementing ALTER OPERATOR <operator> SET (option = ...).
     407             :  *
     408             :  * Currently, only RESTRICT and JOIN estimator functions can be changed.
     409             :  */
     410             : ObjectAddress
     411         520 : AlterOperator(AlterOperatorStmt *stmt)
     412             : {
     413             :     ObjectAddress address;
     414             :     Oid         oprId;
     415             :     Relation    catalog;
     416             :     HeapTuple   tup;
     417             :     Form_pg_operator oprForm;
     418             :     int         i;
     419             :     ListCell   *pl;
     420             :     Datum       values[Natts_pg_operator];
     421             :     bool        nulls[Natts_pg_operator];
     422             :     bool        replaces[Natts_pg_operator];
     423         520 :     List       *restrictionName = NIL;  /* optional restrict. sel. function */
     424         520 :     bool        updateRestriction = false;
     425             :     Oid         restrictionOid;
     426         520 :     List       *joinName = NIL; /* optional join sel. function */
     427         520 :     bool        updateJoin = false;
     428             :     Oid         joinOid;
     429             : 
     430             :     /* Look up the operator */
     431         520 :     oprId = LookupOperWithArgs(stmt->opername, false);
     432         520 :     catalog = table_open(OperatorRelationId, RowExclusiveLock);
     433         520 :     tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(oprId));
     434         520 :     if (!HeapTupleIsValid(tup))
     435           0 :         elog(ERROR, "cache lookup failed for operator %u", oprId);
     436         520 :     oprForm = (Form_pg_operator) GETSTRUCT(tup);
     437             : 
     438             :     /* Process options */
     439        1458 :     foreach(pl, stmt->options)
     440             :     {
     441         968 :         DefElem    *defel = (DefElem *) lfirst(pl);
     442             :         List       *param;
     443             : 
     444         968 :         if (defel->arg == NULL)
     445          30 :             param = NIL;        /* NONE, removes the function */
     446             :         else
     447         938 :             param = defGetQualifiedName(defel);
     448             : 
     449         968 :         if (strcmp(defel->defname, "restrict") == 0)
     450             :         {
     451         472 :             restrictionName = param;
     452         472 :             updateRestriction = true;
     453             :         }
     454         496 :         else if (strcmp(defel->defname, "join") == 0)
     455             :         {
     456         466 :             joinName = param;
     457         466 :             updateJoin = true;
     458             :         }
     459             : 
     460             :         /*
     461             :          * The rest of the options that CREATE accepts cannot be changed.
     462             :          * Check for them so that we can give a meaningful error message.
     463             :          */
     464          30 :         else if (strcmp(defel->defname, "leftarg") == 0 ||
     465          30 :                  strcmp(defel->defname, "rightarg") == 0 ||
     466          30 :                  strcmp(defel->defname, "function") == 0 ||
     467          30 :                  strcmp(defel->defname, "procedure") == 0 ||
     468          30 :                  strcmp(defel->defname, "commutator") == 0 ||
     469          18 :                  strcmp(defel->defname, "negator") == 0 ||
     470           6 :                  strcmp(defel->defname, "hashes") == 0 ||
     471           6 :                  strcmp(defel->defname, "merges") == 0)
     472             :         {
     473          24 :             ereport(ERROR,
     474             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     475             :                      errmsg("operator attribute \"%s\" cannot be changed",
     476             :                             defel->defname)));
     477             :         }
     478             :         else
     479           6 :             ereport(ERROR,
     480             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     481             :                      errmsg("operator attribute \"%s\" not recognized",
     482             :                             defel->defname)));
     483             :     }
     484             : 
     485             :     /* Check permissions. Must be owner. */
     486         490 :     if (!object_ownercheck(OperatorRelationId, oprId, GetUserId()))
     487           6 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
     488           6 :                        NameStr(oprForm->oprname));
     489             : 
     490             :     /*
     491             :      * Look up restriction and join estimators if specified
     492             :      */
     493         484 :     if (restrictionName)
     494         454 :         restrictionOid = ValidateRestrictionEstimator(restrictionName);
     495             :     else
     496          30 :         restrictionOid = InvalidOid;
     497         478 :     if (joinName)
     498         454 :         joinOid = ValidateJoinEstimator(joinName);
     499             :     else
     500          24 :         joinOid = InvalidOid;
     501             : 
     502             :     /* Perform additional checks, like OperatorCreate does */
     503         472 :     if (!(OidIsValid(oprForm->oprleft) && OidIsValid(oprForm->oprright)))
     504             :     {
     505             :         /* If it's not a binary op, these things mustn't be set: */
     506           0 :         if (OidIsValid(joinOid))
     507           0 :             ereport(ERROR,
     508             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     509             :                      errmsg("only binary operators can have join selectivity")));
     510             :     }
     511             : 
     512         472 :     if (oprForm->oprresult != BOOLOID)
     513             :     {
     514           0 :         if (OidIsValid(restrictionOid))
     515           0 :             ereport(ERROR,
     516             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     517             :                      errmsg("only boolean operators can have restriction selectivity")));
     518           0 :         if (OidIsValid(joinOid))
     519           0 :             ereport(ERROR,
     520             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     521             :                      errmsg("only boolean operators can have join selectivity")));
     522             :     }
     523             : 
     524             :     /* Update the tuple */
     525        7552 :     for (i = 0; i < Natts_pg_operator; ++i)
     526             :     {
     527        7080 :         values[i] = (Datum) 0;
     528        7080 :         replaces[i] = false;
     529        7080 :         nulls[i] = false;
     530             :     }
     531         472 :     if (updateRestriction)
     532             :     {
     533         460 :         replaces[Anum_pg_operator_oprrest - 1] = true;
     534         460 :         values[Anum_pg_operator_oprrest - 1] = restrictionOid;
     535             :     }
     536         472 :     if (updateJoin)
     537             :     {
     538         460 :         replaces[Anum_pg_operator_oprjoin - 1] = true;
     539         460 :         values[Anum_pg_operator_oprjoin - 1] = joinOid;
     540             :     }
     541             : 
     542         472 :     tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
     543             :                             values, nulls, replaces);
     544             : 
     545         472 :     CatalogTupleUpdate(catalog, &tup->t_self, tup);
     546             : 
     547         472 :     address = makeOperatorDependencies(tup, false, true);
     548             : 
     549         472 :     InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
     550             : 
     551         472 :     table_close(catalog, NoLock);
     552             : 
     553         472 :     return address;
     554             : }

Generated by: LCOV version 1.14