LCOV - code coverage report
Current view: top level - src/backend/commands - operatorcmds.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 191 206 92.7 %
Date: 2020-06-01 09:07:10 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-2020, 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_operator.h"
      40             : #include "catalog/pg_type.h"
      41             : #include "commands/alter.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/builtins.h"
      49             : #include "utils/lsyscache.h"
      50             : #include "utils/rel.h"
      51             : #include "utils/syscache.h"
      52             : 
      53             : static Oid  ValidateRestrictionEstimator(List *restrictionName);
      54             : static Oid  ValidateJoinEstimator(List *joinName);
      55             : 
      56             : /*
      57             :  * DefineOperator
      58             :  *      this function extracts all the information from the
      59             :  *      parameter list generated by the parser and then has
      60             :  *      OperatorCreate() do all the actual work.
      61             :  *
      62             :  * 'parameters' is a list of DefElem
      63             :  */
      64             : ObjectAddress
      65        1320 : DefineOperator(List *names, List *parameters)
      66             : {
      67             :     char       *oprName;
      68             :     Oid         oprNamespace;
      69             :     AclResult   aclresult;
      70        1320 :     bool        canMerge = false;   /* operator merges */
      71        1320 :     bool        canHash = false;    /* operator hashes */
      72        1320 :     List       *functionName = NIL; /* function for operator */
      73        1320 :     TypeName   *typeName1 = NULL;   /* first type name */
      74        1320 :     TypeName   *typeName2 = NULL;   /* second type name */
      75        1320 :     Oid         typeId1 = InvalidOid;   /* types converted to OID */
      76        1320 :     Oid         typeId2 = InvalidOid;
      77             :     Oid         rettype;
      78        1320 :     List       *commutatorName = NIL;   /* optional commutator operator name */
      79        1320 :     List       *negatorName = NIL;  /* optional negator operator name */
      80        1320 :     List       *restrictionName = NIL;  /* optional restrict. sel. function */
      81        1320 :     List       *joinName = NIL; /* optional join sel. function */
      82             :     Oid         functionOid;    /* functions converted to OID */
      83             :     Oid         restrictionOid;
      84             :     Oid         joinOid;
      85             :     Oid         typeId[2];      /* to hold left and right arg */
      86             :     int         nargs;
      87             :     ListCell   *pl;
      88             : 
      89             :     /* Convert list of names to a name and namespace */
      90        1320 :     oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
      91             : 
      92             :     /* Check we have creation rights in target namespace */
      93        1320 :     aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE);
      94        1320 :     if (aclresult != ACLCHECK_OK)
      95           4 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
      96           4 :                        get_namespace_name(oprNamespace));
      97             : 
      98             :     /*
      99             :      * loop over the definition list and extract the information we need.
     100             :      */
     101        8656 :     foreach(pl, parameters)
     102             :     {
     103        7348 :         DefElem    *defel = (DefElem *) lfirst(pl);
     104             : 
     105        7348 :         if (strcmp(defel->defname, "leftarg") == 0)
     106             :         {
     107        1258 :             typeName1 = defGetTypeName(defel);
     108        1258 :             if (typeName1->setof)
     109           4 :                 ereport(ERROR,
     110             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     111             :                          errmsg("SETOF type not allowed for operator argument")));
     112             :         }
     113        6090 :         else if (strcmp(defel->defname, "rightarg") == 0)
     114             :         {
     115        1276 :             typeName2 = defGetTypeName(defel);
     116        1276 :             if (typeName2->setof)
     117           4 :                 ereport(ERROR,
     118             :                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     119             :                          errmsg("SETOF type not allowed for operator argument")));
     120             :         }
     121             :         /* "function" and "procedure" are equivalent here */
     122        4814 :         else if (strcmp(defel->defname, "function") == 0)
     123          30 :             functionName = defGetQualifiedName(defel);
     124        4784 :         else if (strcmp(defel->defname, "procedure") == 0)
     125        1270 :             functionName = defGetQualifiedName(defel);
     126        3514 :         else if (strcmp(defel->defname, "commutator") == 0)
     127         890 :             commutatorName = defGetQualifiedName(defel);
     128        2624 :         else if (strcmp(defel->defname, "negator") == 0)
     129         566 :             negatorName = defGetQualifiedName(defel);
     130        2058 :         else if (strcmp(defel->defname, "restrict") == 0)
     131         908 :             restrictionName = defGetQualifiedName(defel);
     132        1150 :         else if (strcmp(defel->defname, "join") == 0)
     133         892 :             joinName = defGetQualifiedName(defel);
     134         258 :         else if (strcmp(defel->defname, "hashes") == 0)
     135          80 :             canHash = defGetBoolean(defel);
     136         178 :         else if (strcmp(defel->defname, "merges") == 0)
     137         114 :             canMerge = defGetBoolean(defel);
     138             :         /* These obsolete options are taken as meaning canMerge */
     139          64 :         else if (strcmp(defel->defname, "sort1") == 0)
     140           8 :             canMerge = true;
     141          56 :         else if (strcmp(defel->defname, "sort2") == 0)
     142           8 :             canMerge = true;
     143          48 :         else if (strcmp(defel->defname, "ltcmp") == 0)
     144           4 :             canMerge = true;
     145          44 :         else if (strcmp(defel->defname, "gtcmp") == 0)
     146           4 :             canMerge = true;
     147             :         else
     148             :         {
     149             :             /* WARNING, not ERROR, for historical backwards-compatibility */
     150          40 :             ereport(WARNING,
     151             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     152             :                      errmsg("operator attribute \"%s\" not recognized",
     153             :                             defel->defname)));
     154             :         }
     155             :     }
     156             : 
     157             :     /*
     158             :      * make sure we have our required definitions
     159             :      */
     160        1308 :     if (functionName == NIL)
     161           8 :         ereport(ERROR,
     162             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     163             :                  errmsg("operator function must be specified")));
     164             : 
     165             :     /* Transform type names to type OIDs */
     166        1300 :     if (typeName1)
     167        1250 :         typeId1 = typenameTypeId(NULL, typeName1);
     168        1300 :     if (typeName2)
     169        1272 :         typeId2 = typenameTypeId(NULL, typeName2);
     170             : 
     171        1300 :     if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
     172           4 :         ereport(ERROR,
     173             :                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     174             :                  errmsg("at least one of leftarg or rightarg must be specified")));
     175             : 
     176        1296 :     if (typeName1)
     177             :     {
     178        1250 :         aclresult = pg_type_aclcheck(typeId1, GetUserId(), ACL_USAGE);
     179        1250 :         if (aclresult != ACLCHECK_OK)
     180           8 :             aclcheck_error_type(aclresult, typeId1);
     181             :     }
     182             : 
     183        1288 :     if (typeName2)
     184             :     {
     185        1264 :         aclresult = pg_type_aclcheck(typeId2, GetUserId(), ACL_USAGE);
     186        1264 :         if (aclresult != ACLCHECK_OK)
     187           4 :             aclcheck_error_type(aclresult, typeId2);
     188             :     }
     189             : 
     190             :     /*
     191             :      * Look up the operator's underlying function.
     192             :      */
     193        1284 :     if (!OidIsValid(typeId1))
     194             :     {
     195          46 :         typeId[0] = typeId2;
     196          46 :         nargs = 1;
     197             :     }
     198        1238 :     else if (!OidIsValid(typeId2))
     199             :     {
     200          24 :         typeId[0] = typeId1;
     201          24 :         nargs = 1;
     202             :     }
     203             :     else
     204             :     {
     205        1214 :         typeId[0] = typeId1;
     206        1214 :         typeId[1] = typeId2;
     207        1214 :         nargs = 2;
     208             :     }
     209        1284 :     functionOid = LookupFuncName(functionName, nargs, typeId, false);
     210             : 
     211             :     /*
     212             :      * We require EXECUTE rights for the function.  This isn't strictly
     213             :      * necessary, since EXECUTE will be checked at any attempted use of the
     214             :      * operator, but it seems like a good idea anyway.
     215             :      */
     216        1284 :     aclresult = pg_proc_aclcheck(functionOid, GetUserId(), ACL_EXECUTE);
     217        1284 :     if (aclresult != ACLCHECK_OK)
     218           4 :         aclcheck_error(aclresult, OBJECT_FUNCTION,
     219           4 :                        NameListToString(functionName));
     220             : 
     221        1280 :     rettype = get_func_rettype(functionOid);
     222        1280 :     aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
     223        1280 :     if (aclresult != ACLCHECK_OK)
     224           4 :         aclcheck_error_type(aclresult, rettype);
     225             : 
     226             :     /*
     227             :      * Look up restriction and join estimators if specified
     228             :      */
     229        1276 :     if (restrictionName)
     230         908 :         restrictionOid = ValidateRestrictionEstimator(restrictionName);
     231             :     else
     232         368 :         restrictionOid = InvalidOid;
     233        1276 :     if (joinName)
     234         892 :         joinOid = ValidateJoinEstimator(joinName);
     235             :     else
     236         384 :         joinOid = InvalidOid;
     237             : 
     238             :     /*
     239             :      * now have OperatorCreate do all the work..
     240             :      */
     241             :     return
     242        1276 :         OperatorCreate(oprName, /* operator name */
     243             :                        oprNamespace,    /* namespace */
     244             :                        typeId1, /* left type id */
     245             :                        typeId2, /* right type id */
     246             :                        functionOid, /* function for operator */
     247             :                        commutatorName,  /* optional commutator operator name */
     248             :                        negatorName, /* optional negator operator name */
     249             :                        restrictionOid,  /* optional restrict. sel. function */
     250             :                        joinOid, /* optional join sel. function name */
     251             :                        canMerge,    /* operator merges */
     252             :                        canHash);    /* operator hashes */
     253             : }
     254             : 
     255             : /*
     256             :  * Look up a restriction estimator function ny name, and verify that it has
     257             :  * the correct signature and we have the permissions to attach it to an
     258             :  * operator.
     259             :  */
     260             : static Oid
     261        1348 : ValidateRestrictionEstimator(List *restrictionName)
     262             : {
     263             :     Oid         typeId[4];
     264             :     Oid         restrictionOid;
     265             :     AclResult   aclresult;
     266             : 
     267        1348 :     typeId[0] = INTERNALOID;    /* PlannerInfo */
     268        1348 :     typeId[1] = OIDOID;         /* operator OID */
     269        1348 :     typeId[2] = INTERNALOID;    /* args list */
     270        1348 :     typeId[3] = INT4OID;        /* varRelid */
     271             : 
     272        1348 :     restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
     273             : 
     274             :     /* estimators must return float8 */
     275        1344 :     if (get_func_rettype(restrictionOid) != FLOAT8OID)
     276           0 :         ereport(ERROR,
     277             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     278             :                  errmsg("restriction estimator function %s must return type %s",
     279             :                         NameListToString(restrictionName), "float8")));
     280             : 
     281             :     /* Require EXECUTE rights for the estimator */
     282        1344 :     aclresult = pg_proc_aclcheck(restrictionOid, GetUserId(), ACL_EXECUTE);
     283        1344 :     if (aclresult != ACLCHECK_OK)
     284           0 :         aclcheck_error(aclresult, OBJECT_FUNCTION,
     285           0 :                        NameListToString(restrictionName));
     286             : 
     287        1344 :     return restrictionOid;
     288             : }
     289             : 
     290             : /*
     291             :  * Look up a join estimator function ny name, and verify that it has the
     292             :  * correct signature and we have the permissions to attach it to an
     293             :  * operator.
     294             :  */
     295             : static Oid
     296        1332 : ValidateJoinEstimator(List *joinName)
     297             : {
     298             :     Oid         typeId[5];
     299             :     Oid         joinOid;
     300             :     AclResult   aclresult;
     301             : 
     302        1332 :     typeId[0] = INTERNALOID;    /* PlannerInfo */
     303        1332 :     typeId[1] = OIDOID;         /* operator OID */
     304        1332 :     typeId[2] = INTERNALOID;    /* args list */
     305        1332 :     typeId[3] = INT2OID;        /* jointype */
     306        1332 :     typeId[4] = INTERNALOID;    /* SpecialJoinInfo */
     307             : 
     308             :     /*
     309             :      * As of Postgres 8.4, the preferred signature for join estimators has 5
     310             :      * arguments, but we still allow the old 4-argument form. Try the
     311             :      * preferred form first.
     312             :      */
     313        1332 :     joinOid = LookupFuncName(joinName, 5, typeId, true);
     314        1332 :     if (!OidIsValid(joinOid))
     315           4 :         joinOid = LookupFuncName(joinName, 4, typeId, true);
     316             :     /* If not found, reference the 5-argument signature in error msg */
     317        1332 :     if (!OidIsValid(joinOid))
     318           4 :         joinOid = LookupFuncName(joinName, 5, typeId, false);
     319             : 
     320             :     /* estimators must return float8 */
     321        1328 :     if (get_func_rettype(joinOid) != FLOAT8OID)
     322           0 :         ereport(ERROR,
     323             :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     324             :                  errmsg("join estimator function %s must return type %s",
     325             :                         NameListToString(joinName), "float8")));
     326             : 
     327             :     /* Require EXECUTE rights for the estimator */
     328        1328 :     aclresult = pg_proc_aclcheck(joinOid, GetUserId(), ACL_EXECUTE);
     329        1328 :     if (aclresult != ACLCHECK_OK)
     330           0 :         aclcheck_error(aclresult, OBJECT_FUNCTION,
     331           0 :                        NameListToString(joinName));
     332             : 
     333        1328 :     return joinOid;
     334             : }
     335             : 
     336             : /*
     337             :  * Guts of operator deletion.
     338             :  */
     339             : void
     340         600 : RemoveOperatorById(Oid operOid)
     341             : {
     342             :     Relation    relation;
     343             :     HeapTuple   tup;
     344             :     Form_pg_operator op;
     345             : 
     346         600 :     relation = table_open(OperatorRelationId, RowExclusiveLock);
     347             : 
     348         600 :     tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     349         600 :     if (!HeapTupleIsValid(tup)) /* should not happen */
     350           0 :         elog(ERROR, "cache lookup failed for operator %u", operOid);
     351         600 :     op = (Form_pg_operator) GETSTRUCT(tup);
     352             : 
     353             :     /*
     354             :      * Reset links from commutator and negator, if any.  In case of a
     355             :      * self-commutator or self-negator, this means we have to re-fetch the
     356             :      * updated tuple.  (We could optimize away updates on the tuple we're
     357             :      * about to drop, but it doesn't seem worth convoluting the logic for.)
     358             :      */
     359         600 :     if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
     360             :     {
     361         278 :         OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
     362         278 :         if (operOid == op->oprcom || operOid == op->oprnegate)
     363             :         {
     364          82 :             ReleaseSysCache(tup);
     365          82 :             tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
     366          82 :             if (!HeapTupleIsValid(tup)) /* should not happen */
     367           0 :                 elog(ERROR, "cache lookup failed for operator %u", operOid);
     368             :         }
     369             :     }
     370             : 
     371         600 :     CatalogTupleDelete(relation, &tup->t_self);
     372             : 
     373         600 :     ReleaseSysCache(tup);
     374             : 
     375         600 :     table_close(relation, RowExclusiveLock);
     376         600 : }
     377             : 
     378             : /*
     379             :  * AlterOperator
     380             :  *      routine implementing ALTER OPERATOR <operator> SET (option = ...).
     381             :  *
     382             :  * Currently, only RESTRICT and JOIN estimator functions can be changed.
     383             :  */
     384             : ObjectAddress
     385         484 : AlterOperator(AlterOperatorStmt *stmt)
     386             : {
     387             :     ObjectAddress address;
     388             :     Oid         oprId;
     389             :     Relation    catalog;
     390             :     HeapTuple   tup;
     391             :     Form_pg_operator oprForm;
     392             :     int         i;
     393             :     ListCell   *pl;
     394             :     Datum       values[Natts_pg_operator];
     395             :     bool        nulls[Natts_pg_operator];
     396             :     bool        replaces[Natts_pg_operator];
     397         484 :     List       *restrictionName = NIL;  /* optional restrict. sel. function */
     398         484 :     bool        updateRestriction = false;
     399             :     Oid         restrictionOid;
     400         484 :     List       *joinName = NIL; /* optional join sel. function */
     401         484 :     bool        updateJoin = false;
     402             :     Oid         joinOid;
     403             : 
     404             :     /* Look up the operator */
     405         484 :     oprId = LookupOperWithArgs(stmt->opername, false);
     406         484 :     catalog = table_open(OperatorRelationId, RowExclusiveLock);
     407         484 :     tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(oprId));
     408         484 :     if (!HeapTupleIsValid(tup))
     409           0 :         elog(ERROR, "cache lookup failed for operator %u", oprId);
     410         484 :     oprForm = (Form_pg_operator) GETSTRUCT(tup);
     411             : 
     412             :     /* Process options */
     413        1384 :     foreach(pl, stmt->options)
     414             :     {
     415         920 :         DefElem    *defel = (DefElem *) lfirst(pl);
     416             :         List       *param;
     417             : 
     418         920 :         if (defel->arg == NULL)
     419          20 :             param = NIL;        /* NONE, removes the function */
     420             :         else
     421         900 :             param = defGetQualifiedName(defel);
     422             : 
     423         920 :         if (strcmp(defel->defname, "restrict") == 0)
     424             :         {
     425         452 :             restrictionName = param;
     426         452 :             updateRestriction = true;
     427             :         }
     428         468 :         else if (strcmp(defel->defname, "join") == 0)
     429             :         {
     430         448 :             joinName = param;
     431         448 :             updateJoin = true;
     432             :         }
     433             : 
     434             :         /*
     435             :          * The rest of the options that CREATE accepts cannot be changed.
     436             :          * Check for them so that we can give a meaningful error message.
     437             :          */
     438          20 :         else if (strcmp(defel->defname, "leftarg") == 0 ||
     439          20 :                  strcmp(defel->defname, "rightarg") == 0 ||
     440          20 :                  strcmp(defel->defname, "function") == 0 ||
     441          20 :                  strcmp(defel->defname, "procedure") == 0 ||
     442          20 :                  strcmp(defel->defname, "commutator") == 0 ||
     443          12 :                  strcmp(defel->defname, "negator") == 0 ||
     444           4 :                  strcmp(defel->defname, "hashes") == 0 ||
     445           4 :                  strcmp(defel->defname, "merges") == 0)
     446             :         {
     447          16 :             ereport(ERROR,
     448             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     449             :                      errmsg("operator attribute \"%s\" cannot be changed",
     450             :                             defel->defname)));
     451             :         }
     452             :         else
     453           4 :             ereport(ERROR,
     454             :                     (errcode(ERRCODE_SYNTAX_ERROR),
     455             :                      errmsg("operator attribute \"%s\" not recognized",
     456             :                             defel->defname)));
     457             :     }
     458             : 
     459             :     /* Check permissions. Must be owner. */
     460         464 :     if (!pg_oper_ownercheck(oprId, GetUserId()))
     461           4 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
     462           4 :                        NameStr(oprForm->oprname));
     463             : 
     464             :     /*
     465             :      * Look up restriction and join estimators if specified
     466             :      */
     467         460 :     if (restrictionName)
     468         440 :         restrictionOid = ValidateRestrictionEstimator(restrictionName);
     469             :     else
     470          20 :         restrictionOid = InvalidOid;
     471         456 :     if (joinName)
     472         440 :         joinOid = ValidateJoinEstimator(joinName);
     473             :     else
     474          16 :         joinOid = InvalidOid;
     475             : 
     476             :     /* Perform additional checks, like OperatorCreate does */
     477         452 :     if (!(OidIsValid(oprForm->oprleft) && OidIsValid(oprForm->oprright)))
     478             :     {
     479             :         /* If it's not a binary op, these things mustn't be set: */
     480           0 :         if (OidIsValid(joinOid))
     481           0 :             ereport(ERROR,
     482             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     483             :                      errmsg("only binary operators can have join selectivity")));
     484             :     }
     485             : 
     486         452 :     if (oprForm->oprresult != BOOLOID)
     487             :     {
     488           0 :         if (OidIsValid(restrictionOid))
     489           0 :             ereport(ERROR,
     490             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     491             :                      errmsg("only boolean operators can have restriction selectivity")));
     492           0 :         if (OidIsValid(joinOid))
     493           0 :             ereport(ERROR,
     494             :                     (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
     495             :                      errmsg("only boolean operators can have join selectivity")));
     496             :     }
     497             : 
     498             :     /* Update the tuple */
     499        7232 :     for (i = 0; i < Natts_pg_operator; ++i)
     500             :     {
     501        6780 :         values[i] = (Datum) 0;
     502        6780 :         replaces[i] = false;
     503        6780 :         nulls[i] = false;
     504             :     }
     505         452 :     if (updateRestriction)
     506             :     {
     507         444 :         replaces[Anum_pg_operator_oprrest - 1] = true;
     508         444 :         values[Anum_pg_operator_oprrest - 1] = restrictionOid;
     509             :     }
     510         452 :     if (updateJoin)
     511             :     {
     512         444 :         replaces[Anum_pg_operator_oprjoin - 1] = true;
     513         444 :         values[Anum_pg_operator_oprjoin - 1] = joinOid;
     514             :     }
     515             : 
     516         452 :     tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
     517             :                             values, nulls, replaces);
     518             : 
     519         452 :     CatalogTupleUpdate(catalog, &tup->t_self, tup);
     520             : 
     521         452 :     address = makeOperatorDependencies(tup, true);
     522             : 
     523         452 :     InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
     524             : 
     525         452 :     table_close(catalog, NoLock);
     526             : 
     527         452 :     return address;
     528             : }

Generated by: LCOV version 1.13