LCOV - code coverage report
Current view: top level - src/backend/commands - opclasscmds.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 87.1 % 800 697
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 21 21
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 52.2 % 584 305

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * opclasscmds.c
       4                 :             :  *
       5                 :             :  *        Routines for opclass (and opfamily) 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/opclasscmds.c
      13                 :             :  *
      14                 :             :  *-------------------------------------------------------------------------
      15                 :             :  */
      16                 :             : #include "postgres.h"
      17                 :             : 
      18                 :             : #include <limits.h>
      19                 :             : 
      20                 :             : #include "access/genam.h"
      21                 :             : #include "access/hash.h"
      22                 :             : #include "access/htup_details.h"
      23                 :             : #include "access/nbtree.h"
      24                 :             : #include "access/table.h"
      25                 :             : #include "catalog/catalog.h"
      26                 :             : #include "catalog/dependency.h"
      27                 :             : #include "catalog/indexing.h"
      28                 :             : #include "catalog/objectaccess.h"
      29                 :             : #include "catalog/pg_am.h"
      30                 :             : #include "catalog/pg_amop.h"
      31                 :             : #include "catalog/pg_amproc.h"
      32                 :             : #include "catalog/pg_namespace.h"
      33                 :             : #include "catalog/pg_opclass.h"
      34                 :             : #include "catalog/pg_operator.h"
      35                 :             : #include "catalog/pg_opfamily.h"
      36                 :             : #include "catalog/pg_proc.h"
      37                 :             : #include "catalog/pg_type.h"
      38                 :             : #include "commands/defrem.h"
      39                 :             : #include "commands/event_trigger.h"
      40                 :             : #include "miscadmin.h"
      41                 :             : #include "parser/parse_func.h"
      42                 :             : #include "parser/parse_oper.h"
      43                 :             : #include "parser/parse_type.h"
      44                 :             : #include "utils/acl.h"
      45                 :             : #include "utils/builtins.h"
      46                 :             : #include "utils/fmgroids.h"
      47                 :             : #include "utils/lsyscache.h"
      48                 :             : #include "utils/rel.h"
      49                 :             : #include "utils/syscache.h"
      50                 :             : 
      51                 :             : static void AlterOpFamilyAdd(AlterOpFamilyStmt *stmt,
      52                 :             :                                                          Oid amoid, Oid opfamilyoid,
      53                 :             :                                                          int maxOpNumber, int maxProcNumber,
      54                 :             :                                                          int optsProcNumber, List *items);
      55                 :             : static void AlterOpFamilyDrop(AlterOpFamilyStmt *stmt,
      56                 :             :                                                           Oid amoid, Oid opfamilyoid,
      57                 :             :                                                           int maxOpNumber, int maxProcNumber,
      58                 :             :                                                           List *items);
      59                 :             : static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype);
      60                 :             : static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
      61                 :             : static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid,
      62                 :             :                                                         int opclassOptsProcNum);
      63                 :             : static void addFamilyMember(List **list, OpFamilyMember *member);
      64                 :             : static void storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
      65                 :             :                                                    List *operators, bool isAdd);
      66                 :             : static void storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
      67                 :             :                                                         List *procedures, bool isAdd);
      68                 :             : static bool typeDepNeeded(Oid typid, OpFamilyMember *member);
      69                 :             : static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
      70                 :             :                                                   List *operators);
      71                 :             : static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
      72                 :             :                                                    List *procedures);
      73                 :             : 
      74                 :             : /*
      75                 :             :  * OpFamilyCacheLookup
      76                 :             :  *              Look up an existing opfamily by name.
      77                 :             :  *
      78                 :             :  * Returns a syscache tuple reference, or NULL if not found.
      79                 :             :  */
      80                 :             : static HeapTuple
      81                 :          90 : OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok)
      82                 :             : {
      83                 :          90 :         char       *schemaname;
      84                 :          90 :         char       *opfname;
      85                 :          90 :         HeapTuple       htup;
      86                 :             : 
      87                 :             :         /* deconstruct the name list */
      88                 :          90 :         DeconstructQualifiedName(opfamilyname, &schemaname, &opfname);
      89                 :             : 
      90         [ +  + ]:          90 :         if (schemaname)
      91                 :             :         {
      92                 :             :                 /* Look in specific schema only */
      93                 :           6 :                 Oid                     namespaceId;
      94                 :             : 
      95                 :           6 :                 namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
      96         [ +  + ]:           6 :                 if (!OidIsValid(namespaceId))
      97                 :           1 :                         htup = NULL;
      98                 :             :                 else
      99                 :           5 :                         htup = SearchSysCache3(OPFAMILYAMNAMENSP,
     100                 :           5 :                                                                    ObjectIdGetDatum(amID),
     101                 :           5 :                                                                    PointerGetDatum(opfname),
     102                 :           5 :                                                                    ObjectIdGetDatum(namespaceId));
     103                 :           6 :         }
     104                 :             :         else
     105                 :             :         {
     106                 :             :                 /* Unqualified opfamily name, so search the search path */
     107                 :          84 :                 Oid                     opfID = OpfamilynameGetOpfid(amID, opfname);
     108                 :             : 
     109         [ +  + ]:          84 :                 if (!OidIsValid(opfID))
     110                 :           2 :                         htup = NULL;
     111                 :             :                 else
     112                 :          82 :                         htup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfID));
     113                 :          84 :         }
     114                 :             : 
     115   [ +  +  +  + ]:          90 :         if (!HeapTupleIsValid(htup) && !missing_ok)
     116                 :             :         {
     117                 :           1 :                 HeapTuple       amtup;
     118                 :             : 
     119                 :           1 :                 amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
     120         [ +  - ]:           1 :                 if (!HeapTupleIsValid(amtup))
     121   [ #  #  #  # ]:           0 :                         elog(ERROR, "cache lookup failed for access method %u", amID);
     122   [ +  -  +  - ]:           1 :                 ereport(ERROR,
     123                 :             :                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     124                 :             :                                  errmsg("operator family \"%s\" does not exist for access method \"%s\"",
     125                 :             :                                                 NameListToString(opfamilyname),
     126                 :             :                                                 NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname))));
     127                 :           0 :         }
     128                 :             : 
     129                 :         178 :         return htup;
     130                 :          89 : }
     131                 :             : 
     132                 :             : /*
     133                 :             :  * get_opfamily_oid
     134                 :             :  *        find an opfamily OID by possibly qualified name
     135                 :             :  *
     136                 :             :  * If not found, returns InvalidOid if missing_ok, else throws error.
     137                 :             :  */
     138                 :             : Oid
     139                 :          89 : get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
     140                 :             : {
     141                 :          89 :         HeapTuple       htup;
     142                 :          89 :         Form_pg_opfamily opfamform;
     143                 :          89 :         Oid                     opfID;
     144                 :             : 
     145                 :          89 :         htup = OpFamilyCacheLookup(amID, opfamilyname, missing_ok);
     146         [ +  + ]:          89 :         if (!HeapTupleIsValid(htup))
     147                 :           2 :                 return InvalidOid;
     148                 :          87 :         opfamform = (Form_pg_opfamily) GETSTRUCT(htup);
     149                 :          87 :         opfID = opfamform->oid;
     150                 :          87 :         ReleaseSysCache(htup);
     151                 :             : 
     152                 :          87 :         return opfID;
     153                 :          89 : }
     154                 :             : 
     155                 :             : /*
     156                 :             :  * OpClassCacheLookup
     157                 :             :  *              Look up an existing opclass by name.
     158                 :             :  *
     159                 :             :  * Returns a syscache tuple reference, or NULL if not found.
     160                 :             :  */
     161                 :             : static HeapTuple
     162                 :          36 : OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
     163                 :             : {
     164                 :          36 :         char       *schemaname;
     165                 :          36 :         char       *opcname;
     166                 :          36 :         HeapTuple       htup;
     167                 :             : 
     168                 :             :         /* deconstruct the name list */
     169                 :          36 :         DeconstructQualifiedName(opclassname, &schemaname, &opcname);
     170                 :             : 
     171         [ +  + ]:          36 :         if (schemaname)
     172                 :             :         {
     173                 :             :                 /* Look in specific schema only */
     174                 :           3 :                 Oid                     namespaceId;
     175                 :             : 
     176                 :           3 :                 namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
     177         [ +  + ]:           3 :                 if (!OidIsValid(namespaceId))
     178                 :           1 :                         htup = NULL;
     179                 :             :                 else
     180                 :           2 :                         htup = SearchSysCache3(CLAAMNAMENSP,
     181                 :           2 :                                                                    ObjectIdGetDatum(amID),
     182                 :           2 :                                                                    PointerGetDatum(opcname),
     183                 :           2 :                                                                    ObjectIdGetDatum(namespaceId));
     184                 :           3 :         }
     185                 :             :         else
     186                 :             :         {
     187                 :             :                 /* Unqualified opclass name, so search the search path */
     188                 :          33 :                 Oid                     opcID = OpclassnameGetOpcid(amID, opcname);
     189                 :             : 
     190         [ +  + ]:          33 :                 if (!OidIsValid(opcID))
     191                 :           2 :                         htup = NULL;
     192                 :             :                 else
     193                 :          31 :                         htup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcID));
     194                 :          33 :         }
     195                 :             : 
     196   [ +  +  +  + ]:          36 :         if (!HeapTupleIsValid(htup) && !missing_ok)
     197                 :             :         {
     198                 :           1 :                 HeapTuple       amtup;
     199                 :             : 
     200                 :           1 :                 amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
     201         [ +  - ]:           1 :                 if (!HeapTupleIsValid(amtup))
     202   [ #  #  #  # ]:           0 :                         elog(ERROR, "cache lookup failed for access method %u", amID);
     203   [ +  -  +  - ]:           1 :                 ereport(ERROR,
     204                 :             :                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     205                 :             :                                  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
     206                 :             :                                                 NameListToString(opclassname),
     207                 :             :                                                 NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname))));
     208                 :           0 :         }
     209                 :             : 
     210                 :          70 :         return htup;
     211                 :          35 : }
     212                 :             : 
     213                 :             : /*
     214                 :             :  * get_opclass_oid
     215                 :             :  *        find an opclass OID by possibly qualified name
     216                 :             :  *
     217                 :             :  * If not found, returns InvalidOid if missing_ok, else throws error.
     218                 :             :  */
     219                 :             : Oid
     220                 :          35 : get_opclass_oid(Oid amID, List *opclassname, bool missing_ok)
     221                 :             : {
     222                 :          35 :         HeapTuple       htup;
     223                 :          35 :         Form_pg_opclass opcform;
     224                 :          35 :         Oid                     opcID;
     225                 :             : 
     226                 :          35 :         htup = OpClassCacheLookup(amID, opclassname, missing_ok);
     227         [ +  + ]:          35 :         if (!HeapTupleIsValid(htup))
     228                 :           2 :                 return InvalidOid;
     229                 :          33 :         opcform = (Form_pg_opclass) GETSTRUCT(htup);
     230                 :          33 :         opcID = opcform->oid;
     231                 :          33 :         ReleaseSysCache(htup);
     232                 :             : 
     233                 :          33 :         return opcID;
     234                 :          35 : }
     235                 :             : 
     236                 :             : /*
     237                 :             :  * CreateOpFamily
     238                 :             :  *              Internal routine to make the catalog entry for a new operator family.
     239                 :             :  *
     240                 :             :  * Caller must have done permissions checks etc. already.
     241                 :             :  */
     242                 :             : static ObjectAddress
     243                 :          35 : CreateOpFamily(CreateOpFamilyStmt *stmt, const char *opfname,
     244                 :             :                            Oid namespaceoid, Oid amoid)
     245                 :             : {
     246                 :          35 :         Oid                     opfamilyoid;
     247                 :          35 :         Relation        rel;
     248                 :          35 :         HeapTuple       tup;
     249                 :          35 :         Datum           values[Natts_pg_opfamily];
     250                 :          35 :         bool            nulls[Natts_pg_opfamily];
     251                 :          35 :         NameData        opfName;
     252                 :          35 :         ObjectAddress myself,
     253                 :             :                                 referenced;
     254                 :             : 
     255                 :          35 :         rel = table_open(OperatorFamilyRelationId, RowExclusiveLock);
     256                 :             : 
     257                 :             :         /*
     258                 :             :          * Make sure there is no existing opfamily of this name (this is just to
     259                 :             :          * give a more friendly error message than "duplicate key").
     260                 :             :          */
     261         [ +  - ]:          35 :         if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
     262                 :             :                                                           ObjectIdGetDatum(amoid),
     263                 :             :                                                           CStringGetDatum(opfname),
     264                 :             :                                                           ObjectIdGetDatum(namespaceoid)))
     265   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     266                 :             :                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
     267                 :             :                                  errmsg("operator family \"%s\" for access method \"%s\" already exists",
     268                 :             :                                                 opfname, stmt->amname)));
     269                 :             : 
     270                 :             :         /*
     271                 :             :          * Okay, let's create the pg_opfamily entry.
     272                 :             :          */
     273                 :          35 :         memset(values, 0, sizeof(values));
     274                 :          35 :         memset(nulls, false, sizeof(nulls));
     275                 :             : 
     276                 :          35 :         opfamilyoid = GetNewOidWithIndex(rel, OpfamilyOidIndexId,
     277                 :             :                                                                          Anum_pg_opfamily_oid);
     278                 :          35 :         values[Anum_pg_opfamily_oid - 1] = ObjectIdGetDatum(opfamilyoid);
     279                 :          35 :         values[Anum_pg_opfamily_opfmethod - 1] = ObjectIdGetDatum(amoid);
     280                 :          35 :         namestrcpy(&opfName, opfname);
     281                 :          35 :         values[Anum_pg_opfamily_opfname - 1] = NameGetDatum(&opfName);
     282                 :          35 :         values[Anum_pg_opfamily_opfnamespace - 1] = ObjectIdGetDatum(namespaceoid);
     283                 :          35 :         values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId());
     284                 :             : 
     285                 :          35 :         tup = heap_form_tuple(rel->rd_att, values, nulls);
     286                 :             : 
     287                 :          35 :         CatalogTupleInsert(rel, tup);
     288                 :             : 
     289                 :          35 :         heap_freetuple(tup);
     290                 :             : 
     291                 :             :         /*
     292                 :             :          * Create dependencies for the opfamily proper.
     293                 :             :          */
     294                 :          35 :         myself.classId = OperatorFamilyRelationId;
     295                 :          35 :         myself.objectId = opfamilyoid;
     296                 :          35 :         myself.objectSubId = 0;
     297                 :             : 
     298                 :             :         /* dependency on access method */
     299                 :          35 :         referenced.classId = AccessMethodRelationId;
     300                 :          35 :         referenced.objectId = amoid;
     301                 :          35 :         referenced.objectSubId = 0;
     302                 :          35 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
     303                 :             : 
     304                 :             :         /* dependency on namespace */
     305                 :          35 :         referenced.classId = NamespaceRelationId;
     306                 :          35 :         referenced.objectId = namespaceoid;
     307                 :          35 :         referenced.objectSubId = 0;
     308                 :          35 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     309                 :             : 
     310                 :             :         /* dependency on owner */
     311                 :          35 :         recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
     312                 :             : 
     313                 :             :         /* dependency on extension */
     314                 :          35 :         recordDependencyOnCurrentExtension(&myself, false);
     315                 :             : 
     316                 :             :         /* Report the new operator family to possibly interested event triggers */
     317                 :          35 :         EventTriggerCollectSimpleCommand(myself, InvalidObjectAddress,
     318                 :          35 :                                                                          (Node *) stmt);
     319                 :             : 
     320                 :             :         /* Post creation hook for new operator family */
     321         [ +  - ]:          35 :         InvokeObjectPostCreateHook(OperatorFamilyRelationId, opfamilyoid, 0);
     322                 :             : 
     323                 :          35 :         table_close(rel, RowExclusiveLock);
     324                 :             : 
     325                 :             :         return myself;
     326                 :          35 : }
     327                 :             : 
     328                 :             : /*
     329                 :             :  * DefineOpClass
     330                 :             :  *              Define a new index operator class.
     331                 :             :  */
     332                 :             : ObjectAddress
     333                 :          16 : DefineOpClass(CreateOpClassStmt *stmt)
     334                 :             : {
     335                 :          16 :         char       *opcname;            /* name of opclass we're creating */
     336                 :          16 :         Oid                     amoid,                  /* our AM's oid */
     337                 :             :                                 typeoid,                /* indexable datatype oid */
     338                 :             :                                 storageoid,             /* storage datatype oid, if any */
     339                 :             :                                 namespaceoid,   /* namespace to create opclass in */
     340                 :             :                                 opfamilyoid,    /* oid of containing opfamily */
     341                 :             :                                 opclassoid;             /* oid of opclass we create */
     342                 :          16 :         int                     maxOpNumber,    /* amstrategies value */
     343                 :             :                                 optsProcNumber, /* amoptsprocnum value */
     344                 :             :                                 maxProcNumber;  /* amsupport value */
     345                 :          16 :         bool            amstorage;              /* amstorage flag */
     346                 :          16 :         bool            isDefault = stmt->isDefault;
     347                 :          16 :         List       *operators;          /* OpFamilyMember list for operators */
     348                 :          16 :         List       *procedures;         /* OpFamilyMember list for support procs */
     349                 :          16 :         ListCell   *l;
     350                 :          16 :         Relation        rel;
     351                 :          16 :         HeapTuple       tup;
     352                 :          16 :         Form_pg_am      amform;
     353                 :          16 :         const IndexAmRoutine *amroutine;
     354                 :          16 :         Datum           values[Natts_pg_opclass];
     355                 :          16 :         bool            nulls[Natts_pg_opclass];
     356                 :          16 :         AclResult       aclresult;
     357                 :          16 :         NameData        opcName;
     358                 :          16 :         ObjectAddress myself,
     359                 :             :                                 referenced;
     360                 :             : 
     361                 :             :         /* Convert list of names to a name and namespace */
     362                 :          16 :         namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
     363                 :             :                                                                                                          &opcname);
     364                 :             : 
     365                 :             :         /* Check we have creation rights in target namespace */
     366                 :          16 :         aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE);
     367         [ +  - ]:          16 :         if (aclresult != ACLCHECK_OK)
     368                 :           0 :                 aclcheck_error(aclresult, OBJECT_SCHEMA,
     369                 :           0 :                                            get_namespace_name(namespaceoid));
     370                 :             : 
     371                 :             :         /* Get necessary info about access method */
     372                 :          16 :         tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
     373         [ +  - ]:          16 :         if (!HeapTupleIsValid(tup))
     374   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     375                 :             :                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     376                 :             :                                  errmsg("access method \"%s\" does not exist",
     377                 :             :                                                 stmt->amname)));
     378                 :             : 
     379                 :          16 :         amform = (Form_pg_am) GETSTRUCT(tup);
     380                 :          16 :         amoid = amform->oid;
     381                 :          16 :         amroutine = GetIndexAmRoutineByAmId(amoid, false);
     382                 :          16 :         ReleaseSysCache(tup);
     383                 :             : 
     384                 :          16 :         maxOpNumber = amroutine->amstrategies;
     385                 :             :         /* if amstrategies is zero, just enforce that op numbers fit in int16 */
     386         [ +  + ]:          16 :         if (maxOpNumber <= 0)
     387                 :           1 :                 maxOpNumber = SHRT_MAX;
     388                 :          16 :         maxProcNumber = amroutine->amsupport;
     389                 :          16 :         optsProcNumber = amroutine->amoptsprocnum;
     390                 :          16 :         amstorage = amroutine->amstorage;
     391                 :             : 
     392                 :             :         /* XXX Should we make any privilege check against the AM? */
     393                 :             : 
     394                 :             :         /*
     395                 :             :          * The question of appropriate permissions for CREATE OPERATOR CLASS is
     396                 :             :          * interesting.  Creating an opclass is tantamount to granting public
     397                 :             :          * execute access on the functions involved, since the index machinery
     398                 :             :          * generally does not check access permission before using the functions.
     399                 :             :          * A minimum expectation therefore is that the caller have execute
     400                 :             :          * privilege with grant option.  Since we don't have a way to make the
     401                 :             :          * opclass go away if the grant option is revoked, we choose instead to
     402                 :             :          * require ownership of the functions.  It's also not entirely clear what
     403                 :             :          * permissions should be required on the datatype, but ownership seems
     404                 :             :          * like a safe choice.
     405                 :             :          *
     406                 :             :          * Currently, we require superuser privileges to create an opclass. This
     407                 :             :          * seems necessary because we have no way to validate that the offered set
     408                 :             :          * of operators and functions are consistent with the AM's expectations.
     409                 :             :          * It would be nice to provide such a check someday, if it can be done
     410                 :             :          * without solving the halting problem :-(
     411                 :             :          *
     412                 :             :          * XXX re-enable NOT_USED code sections below if you remove this test.
     413                 :             :          */
     414         [ +  - ]:          16 :         if (!superuser())
     415   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     416                 :             :                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     417                 :             :                                  errmsg("must be superuser to create an operator class")));
     418                 :             : 
     419                 :             :         /* Look up the datatype */
     420                 :          16 :         typeoid = typenameTypeId(NULL, stmt->datatype);
     421                 :             : 
     422                 :             : #ifdef NOT_USED
     423                 :             :         /* XXX this is unnecessary given the superuser check above */
     424                 :             :         /* Check we have ownership of the datatype */
     425                 :             :         if (!object_ownercheck(TypeRelationId, typeoid, GetUserId()))
     426                 :             :                 aclcheck_error_type(ACLCHECK_NOT_OWNER, typeoid);
     427                 :             : #endif
     428                 :             : 
     429                 :             :         /*
     430                 :             :          * Look up the containing operator family, or create one if FAMILY option
     431                 :             :          * was omitted and there's not a match already.
     432                 :             :          */
     433         [ -  + ]:          16 :         if (stmt->opfamilyname)
     434                 :             :         {
     435                 :           0 :                 opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
     436                 :           0 :         }
     437                 :             :         else
     438                 :             :         {
     439                 :             :                 /* Lookup existing family of same name and namespace */
     440                 :          16 :                 tup = SearchSysCache3(OPFAMILYAMNAMENSP,
     441                 :          16 :                                                           ObjectIdGetDatum(amoid),
     442                 :          16 :                                                           PointerGetDatum(opcname),
     443                 :          16 :                                                           ObjectIdGetDatum(namespaceoid));
     444         [ +  + ]:          16 :                 if (HeapTupleIsValid(tup))
     445                 :             :                 {
     446                 :           2 :                         opfamilyoid = ((Form_pg_opfamily) GETSTRUCT(tup))->oid;
     447                 :             : 
     448                 :             :                         /*
     449                 :             :                          * XXX given the superuser check above, there's no need for an
     450                 :             :                          * ownership check here
     451                 :             :                          */
     452                 :           2 :                         ReleaseSysCache(tup);
     453                 :           2 :                 }
     454                 :             :                 else
     455                 :             :                 {
     456                 :          14 :                         CreateOpFamilyStmt *opfstmt;
     457                 :          14 :                         ObjectAddress tmpAddr;
     458                 :             : 
     459                 :          14 :                         opfstmt = makeNode(CreateOpFamilyStmt);
     460                 :          14 :                         opfstmt->opfamilyname = stmt->opclassname;
     461                 :          14 :                         opfstmt->amname = stmt->amname;
     462                 :             : 
     463                 :             :                         /*
     464                 :             :                          * Create it ... again no need for more permissions ...
     465                 :             :                          */
     466                 :          14 :                         tmpAddr = CreateOpFamily(opfstmt, opcname, namespaceoid, amoid);
     467                 :          14 :                         opfamilyoid = tmpAddr.objectId;
     468                 :          14 :                 }
     469                 :             :         }
     470                 :             : 
     471                 :          16 :         operators = NIL;
     472                 :          16 :         procedures = NIL;
     473                 :             : 
     474                 :             :         /* Storage datatype is optional */
     475                 :          16 :         storageoid = InvalidOid;
     476                 :             : 
     477                 :             :         /*
     478                 :             :          * Scan the "items" list to obtain additional info.
     479                 :             :          */
     480   [ +  -  +  +  :          68 :         foreach(l, stmt->items)
                   +  + ]
     481                 :             :         {
     482                 :          52 :                 CreateOpClassItem *item = lfirst_node(CreateOpClassItem, l);
     483                 :          52 :                 Oid                     operOid;
     484                 :          52 :                 Oid                     funcOid;
     485                 :          52 :                 Oid                     sortfamilyOid;
     486                 :          52 :                 OpFamilyMember *member;
     487                 :             : 
     488   [ -  +  +  + ]:          52 :                 switch (item->itemtype)
     489                 :             :                 {
     490                 :             :                         case OPCLASS_ITEM_OPERATOR:
     491         [ +  - ]:          33 :                                 if (item->number <= 0 || item->number > maxOpNumber)
     492   [ #  #  #  # ]:           0 :                                         ereport(ERROR,
     493                 :             :                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     494                 :             :                                                          errmsg("invalid operator number %d,"
     495                 :             :                                                                         " must be between 1 and %d",
     496                 :             :                                                                         item->number, maxOpNumber)));
     497         [ +  + ]:          33 :                                 if (item->name->objargs != NIL)
     498                 :          17 :                                         operOid = LookupOperWithArgs(item->name, false);
     499                 :             :                                 else
     500                 :             :                                 {
     501                 :             :                                         /* Default to binary op on input datatype */
     502                 :          32 :                                         operOid = LookupOperName(NULL, item->name->objname,
     503                 :          16 :                                                                                          typeoid, typeoid,
     504                 :             :                                                                                          false, -1);
     505                 :             :                                 }
     506                 :             : 
     507         [ +  - ]:          33 :                                 if (item->order_family)
     508                 :           0 :                                         sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
     509                 :           0 :                                                                                                          item->order_family,
     510                 :             :                                                                                                          false);
     511                 :             :                                 else
     512                 :          33 :                                         sortfamilyOid = InvalidOid;
     513                 :             : 
     514                 :             : #ifdef NOT_USED
     515                 :             :                                 /* XXX this is unnecessary given the superuser check above */
     516                 :             :                                 /* Caller must own operator and its underlying function */
     517                 :             :                                 if (!object_ownercheck(OperatorRelationId, operOid, GetUserId()))
     518                 :             :                                         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
     519                 :             :                                                                    get_opname(operOid));
     520                 :             :                                 funcOid = get_opcode(operOid);
     521                 :             :                                 if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
     522                 :             :                                         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
     523                 :             :                                                                    get_func_name(funcOid));
     524                 :             : #endif
     525                 :             : 
     526                 :             :                                 /* Save the info */
     527                 :          33 :                                 member = palloc0_object(OpFamilyMember);
     528                 :          33 :                                 member->is_func = false;
     529                 :          33 :                                 member->object = operOid;
     530                 :          33 :                                 member->number = item->number;
     531                 :          33 :                                 member->sortfamily = sortfamilyOid;
     532                 :          33 :                                 assignOperTypes(member, amoid, typeoid);
     533                 :          33 :                                 addFamilyMember(&operators, member);
     534                 :          33 :                                 break;
     535                 :             :                         case OPCLASS_ITEM_FUNCTION:
     536         [ +  - ]:          14 :                                 if (item->number <= 0 || item->number > maxProcNumber)
     537   [ #  #  #  # ]:           0 :                                         ereport(ERROR,
     538                 :             :                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     539                 :             :                                                          errmsg("invalid function number %d,"
     540                 :             :                                                                         " must be between 1 and %d",
     541                 :             :                                                                         item->number, maxProcNumber)));
     542                 :          14 :                                 funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
     543                 :             : #ifdef NOT_USED
     544                 :             :                                 /* XXX this is unnecessary given the superuser check above */
     545                 :             :                                 /* Caller must own function */
     546                 :             :                                 if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
     547                 :             :                                         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
     548                 :             :                                                                    get_func_name(funcOid));
     549                 :             : #endif
     550                 :             :                                 /* Save the info */
     551                 :          14 :                                 member = palloc0_object(OpFamilyMember);
     552                 :          14 :                                 member->is_func = true;
     553                 :          14 :                                 member->object = funcOid;
     554                 :          14 :                                 member->number = item->number;
     555                 :             : 
     556                 :             :                                 /* allow overriding of the function's actual arg types */
     557         [ +  - ]:          14 :                                 if (item->class_args)
     558                 :           0 :                                         processTypesSpec(item->class_args,
     559                 :           0 :                                                                          &member->lefttype, &member->righttype);
     560                 :             : 
     561                 :          14 :                                 assignProcTypes(member, amoid, typeoid, optsProcNumber);
     562                 :          14 :                                 addFamilyMember(&procedures, member);
     563                 :          14 :                                 break;
     564                 :             :                         case OPCLASS_ITEM_STORAGETYPE:
     565         [ +  - ]:           5 :                                 if (OidIsValid(storageoid))
     566   [ #  #  #  # ]:           0 :                                         ereport(ERROR,
     567                 :             :                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     568                 :             :                                                          errmsg("storage type specified more than once")));
     569                 :           5 :                                 storageoid = typenameTypeId(NULL, item->storedtype);
     570                 :             : 
     571                 :             : #ifdef NOT_USED
     572                 :             :                                 /* XXX this is unnecessary given the superuser check above */
     573                 :             :                                 /* Check we have ownership of the datatype */
     574                 :             :                                 if (!object_ownercheck(TypeRelationId, storageoid, GetUserId()))
     575                 :             :                                         aclcheck_error_type(ACLCHECK_NOT_OWNER, storageoid);
     576                 :             : #endif
     577                 :           5 :                                 break;
     578                 :             :                         default:
     579   [ #  #  #  # ]:           0 :                                 elog(ERROR, "unrecognized item type: %d", item->itemtype);
     580                 :           0 :                                 break;
     581                 :             :                 }
     582                 :          52 :         }
     583                 :             : 
     584                 :             :         /*
     585                 :             :          * If storagetype is specified, make sure it's legal.
     586                 :             :          */
     587         [ +  + ]:          16 :         if (OidIsValid(storageoid))
     588                 :             :         {
     589                 :             :                 /* Just drop the spec if same as column datatype */
     590         [ +  - ]:           5 :                 if (storageoid == typeoid)
     591                 :           5 :                         storageoid = InvalidOid;
     592         [ #  # ]:           0 :                 else if (!amstorage)
     593   [ #  #  #  # ]:           0 :                         ereport(ERROR,
     594                 :             :                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     595                 :             :                                          errmsg("storage type cannot be different from data type for access method \"%s\"",
     596                 :             :                                                         stmt->amname)));
     597                 :           5 :         }
     598                 :             : 
     599                 :          16 :         rel = table_open(OperatorClassRelationId, RowExclusiveLock);
     600                 :             : 
     601                 :             :         /*
     602                 :             :          * Make sure there is no existing opclass of this name (this is just to
     603                 :             :          * give a more friendly error message than "duplicate key").
     604                 :             :          */
     605         [ +  - ]:          16 :         if (SearchSysCacheExists3(CLAAMNAMENSP,
     606                 :             :                                                           ObjectIdGetDatum(amoid),
     607                 :             :                                                           CStringGetDatum(opcname),
     608                 :             :                                                           ObjectIdGetDatum(namespaceoid)))
     609   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     610                 :             :                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
     611                 :             :                                  errmsg("operator class \"%s\" for access method \"%s\" already exists",
     612                 :             :                                                 opcname, stmt->amname)));
     613                 :             : 
     614                 :             :         /*
     615                 :             :          * HACK: if we're trying to create btree_gist's gist_inet_ops or
     616                 :             :          * gist_cidr_ops during a binary upgrade, avoid failure in the next stanza
     617                 :             :          * by silently making the new opclass non-default.  Without this kluge, we
     618                 :             :          * would fail to upgrade databases containing pre-1.9 versions of
     619                 :             :          * contrib/btree_gist.  We can remove it sometime in the far future when
     620                 :             :          * we don't expect any such databases to exist.  (The result of this hack
     621                 :             :          * is that the installed version of btree_gist will approximate btree_gist
     622                 :             :          * 1.9, how closely depending on whether it's 1.8 or something older.
     623                 :             :          * ALTER EXTENSION UPDATE can be used to bring it up to real 1.9.)
     624                 :             :          */
     625   [ +  +  +  - ]:          16 :         if (isDefault && IsBinaryUpgrade)
     626                 :             :         {
     627         [ #  # ]:           0 :                 if (amoid == GIST_AM_OID &&
     628   [ #  #  #  # ]:           0 :                         ((typeoid == INETOID && strcmp(opcname, "gist_inet_ops") == 0) ||
     629         [ #  # ]:           0 :                          (typeoid == CIDROID && strcmp(opcname, "gist_cidr_ops") == 0)))
     630                 :           0 :                         isDefault = false;
     631                 :           0 :         }
     632                 :             : 
     633                 :             :         /*
     634                 :             :          * If we are creating a default opclass, check there isn't one already.
     635                 :             :          * (Note we do not restrict this test to visible opclasses; this ensures
     636                 :             :          * that typcache.c can find unique solutions to its questions.)
     637                 :             :          */
     638         [ +  + ]:          16 :         if (isDefault)
     639                 :             :         {
     640                 :           3 :                 ScanKeyData skey[1];
     641                 :           3 :                 SysScanDesc scan;
     642                 :             : 
     643                 :           6 :                 ScanKeyInit(&skey[0],
     644                 :             :                                         Anum_pg_opclass_opcmethod,
     645                 :             :                                         BTEqualStrategyNumber, F_OIDEQ,
     646                 :           3 :                                         ObjectIdGetDatum(amoid));
     647                 :             : 
     648                 :           6 :                 scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
     649                 :           3 :                                                                   NULL, 1, skey);
     650                 :             : 
     651         [ +  + ]:          91 :                 while (HeapTupleIsValid(tup = systable_getnext(scan)))
     652                 :             :                 {
     653                 :          88 :                         Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
     654                 :             : 
     655   [ -  +  #  # ]:          88 :                         if (opclass->opcintype == typeoid && opclass->opcdefault)
     656   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
     657                 :             :                                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
     658                 :             :                                                  errmsg("could not make operator class \"%s\" be default for type %s",
     659                 :             :                                                                 opcname,
     660                 :             :                                                                 TypeNameToString(stmt->datatype)),
     661                 :             :                                                  errdetail("Operator class \"%s\" already is the default.",
     662                 :             :                                                                    NameStr(opclass->opcname))));
     663                 :          88 :                 }
     664                 :             : 
     665                 :           3 :                 systable_endscan(scan);
     666                 :           3 :         }
     667                 :             : 
     668                 :             :         /*
     669                 :             :          * Okay, let's create the pg_opclass entry.
     670                 :             :          */
     671                 :          16 :         memset(values, 0, sizeof(values));
     672                 :          16 :         memset(nulls, false, sizeof(nulls));
     673                 :             : 
     674                 :          16 :         opclassoid = GetNewOidWithIndex(rel, OpclassOidIndexId,
     675                 :             :                                                                         Anum_pg_opclass_oid);
     676                 :          16 :         values[Anum_pg_opclass_oid - 1] = ObjectIdGetDatum(opclassoid);
     677                 :          16 :         values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid);
     678                 :          16 :         namestrcpy(&opcName, opcname);
     679                 :          16 :         values[Anum_pg_opclass_opcname - 1] = NameGetDatum(&opcName);
     680                 :          16 :         values[Anum_pg_opclass_opcnamespace - 1] = ObjectIdGetDatum(namespaceoid);
     681                 :          16 :         values[Anum_pg_opclass_opcowner - 1] = ObjectIdGetDatum(GetUserId());
     682                 :          16 :         values[Anum_pg_opclass_opcfamily - 1] = ObjectIdGetDatum(opfamilyoid);
     683                 :          16 :         values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid);
     684                 :          16 :         values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(isDefault);
     685                 :          16 :         values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid);
     686                 :             : 
     687                 :          16 :         tup = heap_form_tuple(rel->rd_att, values, nulls);
     688                 :             : 
     689                 :          16 :         CatalogTupleInsert(rel, tup);
     690                 :             : 
     691                 :          16 :         heap_freetuple(tup);
     692                 :             : 
     693                 :             :         /*
     694                 :             :          * Now that we have the opclass OID, set up default dependency info for
     695                 :             :          * the pg_amop and pg_amproc entries.  Historically, CREATE OPERATOR CLASS
     696                 :             :          * has created hard dependencies on the opclass, so that's what we use.
     697                 :             :          */
     698   [ +  +  +  +  :          49 :         foreach(l, operators)
                   +  + ]
     699                 :             :         {
     700                 :          33 :                 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
     701                 :             : 
     702                 :          33 :                 op->ref_is_hard = true;
     703                 :          33 :                 op->ref_is_family = false;
     704                 :          33 :                 op->refobjid = opclassoid;
     705                 :          33 :         }
     706   [ +  +  +  +  :          30 :         foreach(l, procedures)
                   +  + ]
     707                 :             :         {
     708                 :          14 :                 OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
     709                 :             : 
     710                 :          14 :                 proc->ref_is_hard = true;
     711                 :          14 :                 proc->ref_is_family = false;
     712                 :          14 :                 proc->refobjid = opclassoid;
     713                 :          14 :         }
     714                 :             : 
     715                 :             :         /*
     716                 :             :          * Let the index AM editorialize on the dependency choices.  It could also
     717                 :             :          * do further validation on the operators and functions, if it likes.
     718                 :             :          */
     719         [ -  + ]:          16 :         if (amroutine->amadjustmembers)
     720                 :          32 :                 amroutine->amadjustmembers(opfamilyoid,
     721                 :          16 :                                                                    opclassoid,
     722                 :          16 :                                                                    operators,
     723                 :          16 :                                                                    procedures);
     724                 :             : 
     725                 :             :         /*
     726                 :             :          * Now add tuples to pg_amop and pg_amproc tying in the operators and
     727                 :             :          * functions.  Dependencies on them are inserted, too.
     728                 :             :          */
     729                 :          32 :         storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
     730                 :          16 :                                    operators, false);
     731                 :          32 :         storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
     732                 :          16 :                                         procedures, false);
     733                 :             : 
     734                 :             :         /* let event triggers know what happened */
     735                 :          16 :         EventTriggerCollectCreateOpClass(stmt, opclassoid, operators, procedures);
     736                 :             : 
     737                 :             :         /*
     738                 :             :          * Create dependencies for the opclass proper.  Note: we do not need a
     739                 :             :          * dependency link to the AM, because that exists through the opfamily.
     740                 :             :          */
     741                 :          16 :         myself.classId = OperatorClassRelationId;
     742                 :          16 :         myself.objectId = opclassoid;
     743                 :          16 :         myself.objectSubId = 0;
     744                 :             : 
     745                 :             :         /* dependency on namespace */
     746                 :          16 :         referenced.classId = NamespaceRelationId;
     747                 :          16 :         referenced.objectId = namespaceoid;
     748                 :          16 :         referenced.objectSubId = 0;
     749                 :          16 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     750                 :             : 
     751                 :             :         /* dependency on opfamily */
     752                 :          16 :         referenced.classId = OperatorFamilyRelationId;
     753                 :          16 :         referenced.objectId = opfamilyoid;
     754                 :          16 :         referenced.objectSubId = 0;
     755                 :          16 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
     756                 :             : 
     757                 :             :         /* dependency on indexed datatype */
     758                 :          16 :         referenced.classId = TypeRelationId;
     759                 :          16 :         referenced.objectId = typeoid;
     760                 :          16 :         referenced.objectSubId = 0;
     761                 :          16 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     762                 :             : 
     763                 :             :         /* dependency on storage datatype */
     764         [ +  - ]:          16 :         if (OidIsValid(storageoid))
     765                 :             :         {
     766                 :           0 :                 referenced.classId = TypeRelationId;
     767                 :           0 :                 referenced.objectId = storageoid;
     768                 :           0 :                 referenced.objectSubId = 0;
     769                 :           0 :                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     770                 :           0 :         }
     771                 :             : 
     772                 :             :         /* dependency on owner */
     773                 :          16 :         recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
     774                 :             : 
     775                 :             :         /* dependency on extension */
     776                 :          16 :         recordDependencyOnCurrentExtension(&myself, false);
     777                 :             : 
     778                 :             :         /* Post creation hook for new operator class */
     779         [ +  - ]:          16 :         InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
     780                 :             : 
     781                 :          16 :         table_close(rel, RowExclusiveLock);
     782                 :             : 
     783                 :             :         return myself;
     784                 :          16 : }
     785                 :             : 
     786                 :             : 
     787                 :             : /*
     788                 :             :  * DefineOpFamily
     789                 :             :  *              Define a new index operator family.
     790                 :             :  */
     791                 :             : ObjectAddress
     792                 :          21 : DefineOpFamily(CreateOpFamilyStmt *stmt)
     793                 :             : {
     794                 :          21 :         char       *opfname;            /* name of opfamily we're creating */
     795                 :          21 :         Oid                     amoid,                  /* our AM's oid */
     796                 :             :                                 namespaceoid;   /* namespace to create opfamily in */
     797                 :          21 :         AclResult       aclresult;
     798                 :             : 
     799                 :             :         /* Convert list of names to a name and namespace */
     800                 :          21 :         namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
     801                 :             :                                                                                                          &opfname);
     802                 :             : 
     803                 :             :         /* Check we have creation rights in target namespace */
     804                 :          21 :         aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE);
     805         [ +  - ]:          21 :         if (aclresult != ACLCHECK_OK)
     806                 :           0 :                 aclcheck_error(aclresult, OBJECT_SCHEMA,
     807                 :           0 :                                            get_namespace_name(namespaceoid));
     808                 :             : 
     809                 :             :         /* Get access method OID, throwing an error if it doesn't exist. */
     810                 :          21 :         amoid = get_index_am_oid(stmt->amname, false);
     811                 :             : 
     812                 :             :         /* XXX Should we make any privilege check against the AM? */
     813                 :             : 
     814                 :             :         /*
     815                 :             :          * Currently, we require superuser privileges to create an opfamily. See
     816                 :             :          * comments in DefineOpClass.
     817                 :             :          */
     818         [ +  - ]:          21 :         if (!superuser())
     819   [ #  #  #  # ]:           0 :                 ereport(ERROR,
     820                 :             :                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     821                 :             :                                  errmsg("must be superuser to create an operator family")));
     822                 :             : 
     823                 :             :         /* Insert pg_opfamily catalog entry */
     824                 :          21 :         return CreateOpFamily(stmt, opfname, namespaceoid, amoid);
     825                 :          21 : }
     826                 :             : 
     827                 :             : 
     828                 :             : /*
     829                 :             :  * AlterOpFamily
     830                 :             :  *              Add or remove operators/procedures within an existing operator family.
     831                 :             :  *
     832                 :             :  * Note: this implements only ALTER OPERATOR FAMILY ... ADD/DROP.  Some
     833                 :             :  * other commands called ALTER OPERATOR FAMILY exist, but go through
     834                 :             :  * different code paths.
     835                 :             :  */
     836                 :             : Oid
     837                 :          46 : AlterOpFamily(AlterOpFamilyStmt *stmt)
     838                 :             : {
     839                 :          46 :         Oid                     amoid,                  /* our AM's oid */
     840                 :             :                                 opfamilyoid;    /* oid of opfamily */
     841                 :          46 :         int                     maxOpNumber,    /* amstrategies value */
     842                 :             :                                 optsProcNumber, /* amoptsprocnum value */
     843                 :             :                                 maxProcNumber;  /* amsupport value */
     844                 :          46 :         HeapTuple       tup;
     845                 :          46 :         Form_pg_am      amform;
     846                 :          46 :         const IndexAmRoutine *amroutine;
     847                 :             : 
     848                 :             :         /* Get necessary info about access method */
     849                 :          46 :         tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
     850         [ +  + ]:          46 :         if (!HeapTupleIsValid(tup))
     851   [ +  -  +  - ]:           1 :                 ereport(ERROR,
     852                 :             :                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     853                 :             :                                  errmsg("access method \"%s\" does not exist",
     854                 :             :                                                 stmt->amname)));
     855                 :             : 
     856                 :          45 :         amform = (Form_pg_am) GETSTRUCT(tup);
     857                 :          45 :         amoid = amform->oid;
     858                 :          45 :         amroutine = GetIndexAmRoutineByAmId(amoid, false);
     859                 :          45 :         ReleaseSysCache(tup);
     860                 :             : 
     861                 :          45 :         maxOpNumber = amroutine->amstrategies;
     862                 :             :         /* if amstrategies is zero, just enforce that op numbers fit in int16 */
     863         [ +  + ]:          45 :         if (maxOpNumber <= 0)
     864                 :           4 :                 maxOpNumber = SHRT_MAX;
     865                 :          45 :         maxProcNumber = amroutine->amsupport;
     866                 :          45 :         optsProcNumber = amroutine->amoptsprocnum;
     867                 :             : 
     868                 :             :         /* XXX Should we make any privilege check against the AM? */
     869                 :             : 
     870                 :             :         /* Look up the opfamily */
     871                 :          45 :         opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
     872                 :             : 
     873                 :             :         /*
     874                 :             :          * Currently, we require superuser privileges to alter an opfamily.
     875                 :             :          *
     876                 :             :          * XXX re-enable NOT_USED code sections below if you remove this test.
     877                 :             :          */
     878         [ +  + ]:          45 :         if (!superuser())
     879   [ +  -  +  - ]:           1 :                 ereport(ERROR,
     880                 :             :                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
     881                 :             :                                  errmsg("must be superuser to alter an operator family")));
     882                 :             : 
     883                 :             :         /*
     884                 :             :          * ADD and DROP cases need separate code from here on down.
     885                 :             :          */
     886         [ +  + ]:          44 :         if (stmt->isDrop)
     887                 :          12 :                 AlterOpFamilyDrop(stmt, amoid, opfamilyoid,
     888                 :           6 :                                                   maxOpNumber, maxProcNumber, stmt->items);
     889                 :             :         else
     890                 :          76 :                 AlterOpFamilyAdd(stmt, amoid, opfamilyoid,
     891                 :          38 :                                                  maxOpNumber, maxProcNumber, optsProcNumber,
     892                 :          38 :                                                  stmt->items);
     893                 :             : 
     894                 :          88 :         return opfamilyoid;
     895                 :          44 : }
     896                 :             : 
     897                 :             : /*
     898                 :             :  * ADD part of ALTER OP FAMILY
     899                 :             :  */
     900                 :             : static void
     901                 :          27 : AlterOpFamilyAdd(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid,
     902                 :             :                                  int maxOpNumber, int maxProcNumber, int optsProcNumber,
     903                 :             :                                  List *items)
     904                 :             : {
     905                 :          27 :         const IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
     906                 :          27 :         List       *operators;          /* OpFamilyMember list for operators */
     907                 :          27 :         List       *procedures;         /* OpFamilyMember list for support procs */
     908                 :          27 :         ListCell   *l;
     909                 :             : 
     910                 :          27 :         operators = NIL;
     911                 :          27 :         procedures = NIL;
     912                 :             : 
     913                 :             :         /*
     914                 :             :          * Scan the "items" list to obtain additional info.
     915                 :             :          */
     916   [ +  +  +  +  :          85 :         foreach(l, items)
                   +  + ]
     917                 :             :         {
     918                 :          64 :                 CreateOpClassItem *item = lfirst_node(CreateOpClassItem, l);
     919                 :          64 :                 Oid                     operOid;
     920                 :          64 :                 Oid                     funcOid;
     921                 :          64 :                 Oid                     sortfamilyOid;
     922                 :          64 :                 OpFamilyMember *member;
     923                 :             : 
     924   [ +  +  -  + ]:          64 :                 switch (item->itemtype)
     925                 :             :                 {
     926                 :             :                         case OPCLASS_ITEM_OPERATOR:
     927         [ +  + ]:          43 :                                 if (item->number <= 0 || item->number > maxOpNumber)
     928   [ +  -  +  - ]:           2 :                                         ereport(ERROR,
     929                 :             :                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     930                 :             :                                                          errmsg("invalid operator number %d,"
     931                 :             :                                                                         " must be between 1 and %d",
     932                 :             :                                                                         item->number, maxOpNumber)));
     933         [ +  + ]:          41 :                                 if (item->name->objargs != NIL)
     934                 :          40 :                                         operOid = LookupOperWithArgs(item->name, false);
     935                 :             :                                 else
     936                 :             :                                 {
     937   [ +  -  +  - ]:           1 :                                         ereport(ERROR,
     938                 :             :                                                         (errcode(ERRCODE_SYNTAX_ERROR),
     939                 :             :                                                          errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
     940                 :           0 :                                         operOid = InvalidOid;   /* keep compiler quiet */
     941                 :             :                                 }
     942                 :             : 
     943         [ +  + ]:          40 :                                 if (item->order_family)
     944                 :           3 :                                         sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
     945                 :           3 :                                                                                                          item->order_family,
     946                 :             :                                                                                                          false);
     947                 :             :                                 else
     948                 :          37 :                                         sortfamilyOid = InvalidOid;
     949                 :             : 
     950                 :             : #ifdef NOT_USED
     951                 :             :                                 /* XXX this is unnecessary given the superuser check above */
     952                 :             :                                 /* Caller must own operator and its underlying function */
     953                 :             :                                 if (!object_ownercheck(OperatorRelationId, operOid, GetUserId()))
     954                 :             :                                         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
     955                 :             :                                                                    get_opname(operOid));
     956                 :             :                                 funcOid = get_opcode(operOid);
     957                 :             :                                 if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
     958                 :             :                                         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
     959                 :             :                                                                    get_func_name(funcOid));
     960                 :             : #endif
     961                 :             : 
     962                 :             :                                 /* Save the info */
     963                 :          40 :                                 member = palloc0_object(OpFamilyMember);
     964                 :          40 :                                 member->is_func = false;
     965                 :          40 :                                 member->object = operOid;
     966                 :          40 :                                 member->number = item->number;
     967                 :          40 :                                 member->sortfamily = sortfamilyOid;
     968                 :             :                                 /* We can set up dependency fields immediately */
     969                 :             :                                 /* Historically, ALTER ADD has created soft dependencies */
     970                 :          40 :                                 member->ref_is_hard = false;
     971                 :          40 :                                 member->ref_is_family = true;
     972                 :          40 :                                 member->refobjid = opfamilyoid;
     973                 :          40 :                                 assignOperTypes(member, amoid, InvalidOid);
     974                 :          40 :                                 addFamilyMember(&operators, member);
     975                 :          40 :                                 break;
     976                 :             :                         case OPCLASS_ITEM_FUNCTION:
     977         [ +  + ]:          20 :                                 if (item->number <= 0 || item->number > maxProcNumber)
     978   [ +  -  +  - ]:           2 :                                         ereport(ERROR,
     979                 :             :                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     980                 :             :                                                          errmsg("invalid function number %d,"
     981                 :             :                                                                         " must be between 1 and %d",
     982                 :             :                                                                         item->number, maxProcNumber)));
     983                 :          18 :                                 funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
     984                 :             : #ifdef NOT_USED
     985                 :             :                                 /* XXX this is unnecessary given the superuser check above */
     986                 :             :                                 /* Caller must own function */
     987                 :             :                                 if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
     988                 :             :                                         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
     989                 :             :                                                                    get_func_name(funcOid));
     990                 :             : #endif
     991                 :             : 
     992                 :             :                                 /* Save the info */
     993                 :          18 :                                 member = palloc0_object(OpFamilyMember);
     994                 :          18 :                                 member->is_func = true;
     995                 :          18 :                                 member->object = funcOid;
     996                 :          18 :                                 member->number = item->number;
     997                 :             :                                 /* We can set up dependency fields immediately */
     998                 :             :                                 /* Historically, ALTER ADD has created soft dependencies */
     999                 :          18 :                                 member->ref_is_hard = false;
    1000                 :          18 :                                 member->ref_is_family = true;
    1001                 :          18 :                                 member->refobjid = opfamilyoid;
    1002                 :             : 
    1003                 :             :                                 /* allow overriding of the function's actual arg types */
    1004         [ +  + ]:          18 :                                 if (item->class_args)
    1005                 :          10 :                                         processTypesSpec(item->class_args,
    1006                 :           5 :                                                                          &member->lefttype, &member->righttype);
    1007                 :             : 
    1008                 :          18 :                                 assignProcTypes(member, amoid, InvalidOid, optsProcNumber);
    1009                 :          18 :                                 addFamilyMember(&procedures, member);
    1010                 :          18 :                                 break;
    1011                 :             :                         case OPCLASS_ITEM_STORAGETYPE:
    1012   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    1013                 :             :                                                 (errcode(ERRCODE_SYNTAX_ERROR),
    1014                 :             :                                                  errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
    1015                 :           0 :                                 break;
    1016                 :             :                         default:
    1017   [ #  #  #  # ]:           0 :                                 elog(ERROR, "unrecognized item type: %d", item->itemtype);
    1018                 :           0 :                                 break;
    1019                 :             :                 }
    1020                 :          58 :         }
    1021                 :             : 
    1022                 :             :         /*
    1023                 :             :          * Let the index AM editorialize on the dependency choices.  It could also
    1024                 :             :          * do further validation on the operators and functions, if it likes.
    1025                 :             :          */
    1026         [ -  + ]:          19 :         if (amroutine->amadjustmembers)
    1027                 :          38 :                 amroutine->amadjustmembers(opfamilyoid,
    1028                 :             :                                                                    InvalidOid,  /* no specific opclass */
    1029                 :          19 :                                                                    operators,
    1030                 :          19 :                                                                    procedures);
    1031                 :             : 
    1032                 :             :         /*
    1033                 :             :          * Add tuples to pg_amop and pg_amproc tying in the operators and
    1034                 :             :          * functions.  Dependencies on them are inserted, too.
    1035                 :             :          */
    1036                 :          38 :         storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
    1037                 :          19 :                                    operators, true);
    1038                 :          38 :         storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
    1039                 :          19 :                                         procedures, true);
    1040                 :             : 
    1041                 :             :         /* make information available to event triggers */
    1042                 :          38 :         EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
    1043                 :          19 :                                                                   operators, procedures);
    1044                 :          19 : }
    1045                 :             : 
    1046                 :             : /*
    1047                 :             :  * DROP part of ALTER OP FAMILY
    1048                 :             :  */
    1049                 :             : static void
    1050                 :           6 : AlterOpFamilyDrop(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid,
    1051                 :             :                                   int maxOpNumber, int maxProcNumber, List *items)
    1052                 :             : {
    1053                 :           6 :         List       *operators;          /* OpFamilyMember list for operators */
    1054                 :           6 :         List       *procedures;         /* OpFamilyMember list for support procs */
    1055                 :           6 :         ListCell   *l;
    1056                 :             : 
    1057                 :           6 :         operators = NIL;
    1058                 :           6 :         procedures = NIL;
    1059                 :             : 
    1060                 :             :         /*
    1061                 :             :          * Scan the "items" list to obtain additional info.
    1062                 :             :          */
    1063   [ +  +  +  +  :          17 :         foreach(l, items)
                   +  + ]
    1064                 :             :         {
    1065                 :          11 :                 CreateOpClassItem *item = lfirst_node(CreateOpClassItem, l);
    1066                 :          11 :                 Oid                     lefttype,
    1067                 :             :                                         righttype;
    1068                 :          11 :                 OpFamilyMember *member;
    1069                 :             : 
    1070   [ +  +  -  - ]:          11 :                 switch (item->itemtype)
    1071                 :             :                 {
    1072                 :             :                         case OPCLASS_ITEM_OPERATOR:
    1073         [ +  - ]:           8 :                                 if (item->number <= 0 || item->number > maxOpNumber)
    1074   [ #  #  #  # ]:           0 :                                         ereport(ERROR,
    1075                 :             :                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1076                 :             :                                                          errmsg("invalid operator number %d,"
    1077                 :             :                                                                         " must be between 1 and %d",
    1078                 :             :                                                                         item->number, maxOpNumber)));
    1079                 :           8 :                                 processTypesSpec(item->class_args, &lefttype, &righttype);
    1080                 :             :                                 /* Save the info */
    1081                 :           8 :                                 member = palloc0_object(OpFamilyMember);
    1082                 :           8 :                                 member->is_func = false;
    1083                 :           8 :                                 member->number = item->number;
    1084                 :           8 :                                 member->lefttype = lefttype;
    1085                 :           8 :                                 member->righttype = righttype;
    1086                 :           8 :                                 addFamilyMember(&operators, member);
    1087                 :           8 :                                 break;
    1088                 :             :                         case OPCLASS_ITEM_FUNCTION:
    1089         [ +  - ]:           3 :                                 if (item->number <= 0 || item->number > maxProcNumber)
    1090   [ #  #  #  # ]:           0 :                                         ereport(ERROR,
    1091                 :             :                                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1092                 :             :                                                          errmsg("invalid function number %d,"
    1093                 :             :                                                                         " must be between 1 and %d",
    1094                 :             :                                                                         item->number, maxProcNumber)));
    1095                 :           3 :                                 processTypesSpec(item->class_args, &lefttype, &righttype);
    1096                 :             :                                 /* Save the info */
    1097                 :           3 :                                 member = palloc0_object(OpFamilyMember);
    1098                 :           3 :                                 member->is_func = true;
    1099                 :           3 :                                 member->number = item->number;
    1100                 :           3 :                                 member->lefttype = lefttype;
    1101                 :           3 :                                 member->righttype = righttype;
    1102                 :           3 :                                 addFamilyMember(&procedures, member);
    1103                 :           3 :                                 break;
    1104                 :           0 :                         case OPCLASS_ITEM_STORAGETYPE:
    1105                 :             :                                 /* grammar prevents this from appearing */
    1106                 :             :                         default:
    1107   [ #  #  #  # ]:           0 :                                 elog(ERROR, "unrecognized item type: %d", item->itemtype);
    1108                 :           0 :                                 break;
    1109                 :             :                 }
    1110                 :          11 :         }
    1111                 :             : 
    1112                 :             :         /*
    1113                 :             :          * Remove tuples from pg_amop and pg_amproc.
    1114                 :             :          */
    1115                 :           6 :         dropOperators(stmt->opfamilyname, amoid, opfamilyoid, operators);
    1116                 :           6 :         dropProcedures(stmt->opfamilyname, amoid, opfamilyoid, procedures);
    1117                 :             : 
    1118                 :             :         /* make information available to event triggers */
    1119                 :          12 :         EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
    1120                 :           6 :                                                                   operators, procedures);
    1121                 :           6 : }
    1122                 :             : 
    1123                 :             : 
    1124                 :             : /*
    1125                 :             :  * Deal with explicit arg types used in ALTER ADD/DROP
    1126                 :             :  */
    1127                 :             : static void
    1128                 :          16 : processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
    1129                 :             : {
    1130                 :          16 :         TypeName   *typeName;
    1131                 :             : 
    1132         [ +  - ]:          16 :         Assert(args != NIL);
    1133                 :             : 
    1134                 :          16 :         typeName = (TypeName *) linitial(args);
    1135                 :          16 :         *lefttype = typenameTypeId(NULL, typeName);
    1136                 :             : 
    1137         [ +  + ]:          16 :         if (list_length(args) > 1)
    1138                 :             :         {
    1139                 :          14 :                 typeName = (TypeName *) lsecond(args);
    1140                 :          14 :                 *righttype = typenameTypeId(NULL, typeName);
    1141                 :          14 :         }
    1142                 :             :         else
    1143                 :           2 :                 *righttype = *lefttype;
    1144                 :             : 
    1145         [ +  + ]:          16 :         if (list_length(args) > 2)
    1146   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    1147                 :             :                                 (errcode(ERRCODE_SYNTAX_ERROR),
    1148                 :             :                                  errmsg("one or two argument types must be specified")));
    1149                 :          15 : }
    1150                 :             : 
    1151                 :             : 
    1152                 :             : /*
    1153                 :             :  * Determine the lefttype/righttype to assign to an operator,
    1154                 :             :  * and do any validity checking we can manage.
    1155                 :             :  */
    1156                 :             : static void
    1157                 :          73 : assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
    1158                 :             : {
    1159                 :          73 :         Operator        optup;
    1160                 :          73 :         Form_pg_operator opform;
    1161                 :             : 
    1162                 :             :         /* Fetch the operator definition */
    1163                 :          73 :         optup = SearchSysCache1(OPEROID, ObjectIdGetDatum(member->object));
    1164         [ +  - ]:          73 :         if (!HeapTupleIsValid(optup))
    1165   [ #  #  #  # ]:           0 :                 elog(ERROR, "cache lookup failed for operator %u", member->object);
    1166                 :          73 :         opform = (Form_pg_operator) GETSTRUCT(optup);
    1167                 :             : 
    1168                 :             :         /*
    1169                 :             :          * Opfamily operators must be binary.
    1170                 :             :          */
    1171         [ +  - ]:          73 :         if (opform->oprkind != 'b')
    1172   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1173                 :             :                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1174                 :             :                                  errmsg("index operators must be binary")));
    1175                 :             : 
    1176         [ +  + ]:          73 :         if (OidIsValid(member->sortfamily))
    1177                 :             :         {
    1178                 :             :                 /*
    1179                 :             :                  * Ordering op, check index supports that.  (We could perhaps also
    1180                 :             :                  * check that the operator returns a type supported by the sortfamily,
    1181                 :             :                  * but that seems more trouble than it's worth here.  If it does not,
    1182                 :             :                  * the operator will never be matchable to any ORDER BY clause, but no
    1183                 :             :                  * worse consequences can ensue.  Also, trying to check that would
    1184                 :             :                  * create an ordering hazard during dump/reload: it's possible that
    1185                 :             :                  * the family has been created but not yet populated with the required
    1186                 :             :                  * operators.)
    1187                 :             :                  */
    1188         [ +  + ]:           3 :                 if (!GetIndexAmRoutineByAmId(amoid, false)->amcanorderbyop)
    1189   [ +  -  +  - ]:           1 :                         ereport(ERROR,
    1190                 :             :                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1191                 :             :                                          errmsg("access method \"%s\" does not support ordering operators",
    1192                 :             :                                                         get_am_name(amoid))));
    1193                 :           2 :         }
    1194                 :             :         else
    1195                 :             :         {
    1196                 :             :                 /*
    1197                 :             :                  * Search operators must return boolean.
    1198                 :             :                  */
    1199         [ +  - ]:          70 :                 if (opform->oprresult != BOOLOID)
    1200   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    1201                 :             :                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1202                 :             :                                          errmsg("index search operators must return boolean")));
    1203                 :             :         }
    1204                 :             : 
    1205                 :             :         /*
    1206                 :             :          * If lefttype/righttype isn't specified, use the operator's input types
    1207                 :             :          */
    1208         [ -  + ]:          72 :         if (!OidIsValid(member->lefttype))
    1209                 :          72 :                 member->lefttype = opform->oprleft;
    1210         [ -  + ]:          72 :         if (!OidIsValid(member->righttype))
    1211                 :          72 :                 member->righttype = opform->oprright;
    1212                 :             : 
    1213                 :          72 :         ReleaseSysCache(optup);
    1214                 :          72 : }
    1215                 :             : 
    1216                 :             : /*
    1217                 :             :  * Determine the lefttype/righttype to assign to a support procedure,
    1218                 :             :  * and do any validity checking we can manage.
    1219                 :             :  */
    1220                 :             : static void
    1221                 :          32 : assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid,
    1222                 :             :                                 int opclassOptsProcNum)
    1223                 :             : {
    1224                 :          32 :         HeapTuple       proctup;
    1225                 :          32 :         Form_pg_proc procform;
    1226                 :             : 
    1227                 :             :         /* Fetch the procedure definition */
    1228                 :          32 :         proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(member->object));
    1229         [ +  - ]:          32 :         if (!HeapTupleIsValid(proctup))
    1230   [ #  #  #  # ]:           0 :                 elog(ERROR, "cache lookup failed for function %u", member->object);
    1231                 :          32 :         procform = (Form_pg_proc) GETSTRUCT(proctup);
    1232                 :             : 
    1233                 :             :         /* Check the signature of the opclass options parsing function */
    1234         [ +  + ]:          32 :         if (member->number == opclassOptsProcNum)
    1235                 :             :         {
    1236         [ -  + ]:           3 :                 if (OidIsValid(typeoid))
    1237                 :             :                 {
    1238   [ #  #  #  # ]:           0 :                         if ((OidIsValid(member->lefttype) && member->lefttype != typeoid) ||
    1239         [ #  # ]:           0 :                                 (OidIsValid(member->righttype) && member->righttype != typeoid))
    1240   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1241                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1242                 :             :                                                  errmsg("associated data types for operator class options parsing functions must match opclass input type")));
    1243                 :           0 :                 }
    1244                 :             :                 else
    1245                 :             :                 {
    1246         [ +  + ]:           3 :                         if (member->lefttype != member->righttype)
    1247   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    1248                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1249                 :             :                                                  errmsg("left and right associated data types for operator class options parsing functions must match")));
    1250                 :             :                 }
    1251                 :             : 
    1252         [ +  + ]:           2 :                 if (procform->prorettype != VOIDOID ||
    1253                 :           1 :                         procform->pronargs != 1 ||
    1254                 :           1 :                         procform->proargtypes.values[0] != INTERNALOID)
    1255   [ +  -  +  - ]:           1 :                         ereport(ERROR,
    1256                 :             :                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1257                 :             :                                          errmsg("invalid operator class options parsing function"),
    1258                 :             :                                          errhint("Valid signature of operator class options parsing function is %s.",
    1259                 :             :                                                          "(internal) RETURNS void")));
    1260                 :           1 :         }
    1261                 :             : 
    1262                 :             :         /*
    1263                 :             :          * Ordering comparison procs must be 2-arg procs returning int4.  Ordering
    1264                 :             :          * sortsupport procs must take internal and return void.  Ordering
    1265                 :             :          * in_range procs must be 5-arg procs returning bool.  Ordering equalimage
    1266                 :             :          * procs must take 1 arg and return bool.  Hashing support proc 1 must be
    1267                 :             :          * a 1-arg proc returning int4, while proc 2 must be a 2-arg proc
    1268                 :             :          * returning int8. Otherwise we don't know.
    1269                 :             :          */
    1270         [ +  + ]:          29 :         else if (GetIndexAmRoutineByAmId(amoid, false)->amcanorder)
    1271                 :             :         {
    1272         [ +  + ]:          14 :                 if (member->number == BTORDER_PROC)
    1273                 :             :                 {
    1274         [ +  + ]:          12 :                         if (procform->pronargs != 2)
    1275   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    1276                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1277                 :             :                                                  errmsg("ordering comparison functions must have two arguments")));
    1278         [ +  + ]:          11 :                         if (procform->prorettype != INT4OID)
    1279   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    1280                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1281                 :             :                                                  errmsg("ordering comparison functions must return integer")));
    1282                 :             : 
    1283                 :             :                         /*
    1284                 :             :                          * If lefttype/righttype isn't specified, use the proc's input
    1285                 :             :                          * types
    1286                 :             :                          */
    1287         [ +  - ]:          10 :                         if (!OidIsValid(member->lefttype))
    1288                 :          10 :                                 member->lefttype = procform->proargtypes.values[0];
    1289         [ +  - ]:          10 :                         if (!OidIsValid(member->righttype))
    1290                 :          10 :                                 member->righttype = procform->proargtypes.values[1];
    1291                 :          10 :                 }
    1292         [ -  + ]:           2 :                 else if (member->number == BTSORTSUPPORT_PROC)
    1293                 :             :                 {
    1294         [ #  # ]:           0 :                         if (procform->pronargs != 1 ||
    1295                 :           0 :                                 procform->proargtypes.values[0] != INTERNALOID)
    1296   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1297                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1298                 :             :                                                  errmsg("ordering sort support functions must accept type \"internal\"")));
    1299         [ #  # ]:           0 :                         if (procform->prorettype != VOIDOID)
    1300   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1301                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1302                 :             :                                                  errmsg("ordering sort support functions must return void")));
    1303                 :             : 
    1304                 :             :                         /*
    1305                 :             :                          * Can't infer lefttype/righttype from proc, so use default rule
    1306                 :             :                          */
    1307                 :           0 :                 }
    1308         [ -  + ]:           2 :                 else if (member->number == BTINRANGE_PROC)
    1309                 :             :                 {
    1310         [ #  # ]:           0 :                         if (procform->pronargs != 5)
    1311   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1312                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1313                 :             :                                                  errmsg("ordering in_range functions must have five arguments")));
    1314         [ #  # ]:           0 :                         if (procform->prorettype != BOOLOID)
    1315   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1316                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1317                 :             :                                                  errmsg("ordering in_range functions must return boolean")));
    1318                 :             : 
    1319                 :             :                         /*
    1320                 :             :                          * If lefttype/righttype isn't specified, use the proc's input
    1321                 :             :                          * types (we look at the test-value and offset arguments)
    1322                 :             :                          */
    1323         [ #  # ]:           0 :                         if (!OidIsValid(member->lefttype))
    1324                 :           0 :                                 member->lefttype = procform->proargtypes.values[0];
    1325         [ #  # ]:           0 :                         if (!OidIsValid(member->righttype))
    1326                 :           0 :                                 member->righttype = procform->proargtypes.values[2];
    1327                 :           0 :                 }
    1328         [ +  + ]:           2 :                 else if (member->number == BTEQUALIMAGE_PROC)
    1329                 :             :                 {
    1330         [ +  - ]:           1 :                         if (procform->pronargs != 1)
    1331   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1332                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1333                 :             :                                                  errmsg("ordering equal image functions must have one argument")));
    1334         [ +  - ]:           1 :                         if (procform->prorettype != BOOLOID)
    1335   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1336                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1337                 :             :                                                  errmsg("ordering equal image functions must return boolean")));
    1338                 :             : 
    1339                 :             :                         /*
    1340                 :             :                          * pg_amproc functions are indexed by (lefttype, righttype), but
    1341                 :             :                          * an equalimage function can only be called at CREATE INDEX time.
    1342                 :             :                          * The same opclass opcintype OID is always used for lefttype and
    1343                 :             :                          * righttype.  Providing a cross-type routine isn't sensible.
    1344                 :             :                          * Reject cross-type ALTER OPERATOR FAMILY ...  ADD FUNCTION 4
    1345                 :             :                          * statements here.
    1346                 :             :                          */
    1347         [ -  + ]:           1 :                         if (member->lefttype != member->righttype)
    1348   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    1349                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1350                 :             :                                                  errmsg("ordering equal image functions must not be cross-type")));
    1351                 :           0 :                 }
    1352         [ -  + ]:           1 :                 else if (member->number == BTSKIPSUPPORT_PROC)
    1353                 :             :                 {
    1354         [ +  - ]:           1 :                         if (procform->pronargs != 1 ||
    1355                 :           1 :                                 procform->proargtypes.values[0] != INTERNALOID)
    1356   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1357                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1358                 :             :                                                  errmsg("btree skip support functions must accept type \"internal\"")));
    1359         [ +  - ]:           1 :                         if (procform->prorettype != VOIDOID)
    1360   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1361                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1362                 :             :                                                  errmsg("btree skip support functions must return void")));
    1363                 :             : 
    1364                 :             :                         /*
    1365                 :             :                          * pg_amproc functions are indexed by (lefttype, righttype), but a
    1366                 :             :                          * skip support function doesn't make sense in cross-type
    1367                 :             :                          * scenarios.  The same opclass opcintype OID is always used for
    1368                 :             :                          * lefttype and righttype.  Providing a cross-type routine isn't
    1369                 :             :                          * sensible.  Reject cross-type ALTER OPERATOR FAMILY ...  ADD
    1370                 :             :                          * FUNCTION 6 statements here.
    1371                 :             :                          */
    1372         [ -  + ]:           1 :                         if (member->lefttype != member->righttype)
    1373   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    1374                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1375                 :             :                                                  errmsg("btree skip support functions must not be cross-type")));
    1376                 :           0 :                 }
    1377                 :          10 :         }
    1378         [ +  + ]:          15 :         else if (GetIndexAmRoutineByAmId(amoid, false)->amcanhash)
    1379                 :             :         {
    1380         [ +  + ]:           9 :                 if (member->number == HASHSTANDARD_PROC)
    1381                 :             :                 {
    1382         [ +  + ]:           4 :                         if (procform->pronargs != 1)
    1383   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    1384                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1385                 :             :                                                  errmsg("hash function 1 must have one argument")));
    1386         [ +  + ]:           3 :                         if (procform->prorettype != INT4OID)
    1387   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    1388                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1389                 :             :                                                  errmsg("hash function 1 must return integer")));
    1390                 :           2 :                 }
    1391         [ -  + ]:           5 :                 else if (member->number == HASHEXTENDED_PROC)
    1392                 :             :                 {
    1393         [ +  - ]:           5 :                         if (procform->pronargs != 2)
    1394   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1395                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1396                 :             :                                                  errmsg("hash function 2 must have two arguments")));
    1397         [ +  - ]:           5 :                         if (procform->prorettype != INT8OID)
    1398   [ #  #  #  # ]:           0 :                                 ereport(ERROR,
    1399                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1400                 :             :                                                  errmsg("hash function 2 must return bigint")));
    1401                 :           5 :                 }
    1402                 :             : 
    1403                 :             :                 /*
    1404                 :             :                  * If lefttype/righttype isn't specified, use the proc's input type
    1405                 :             :                  */
    1406         [ +  - ]:           7 :                 if (!OidIsValid(member->lefttype))
    1407                 :           7 :                         member->lefttype = procform->proargtypes.values[0];
    1408         [ +  - ]:           7 :                 if (!OidIsValid(member->righttype))
    1409                 :           7 :                         member->righttype = procform->proargtypes.values[0];
    1410                 :           7 :         }
    1411                 :             : 
    1412                 :             :         /*
    1413                 :             :          * The default in CREATE OPERATOR CLASS is to use the class' opcintype as
    1414                 :             :          * lefttype and righttype.  In CREATE or ALTER OPERATOR FAMILY, opcintype
    1415                 :             :          * isn't available, so make the user specify the types.
    1416                 :             :          */
    1417         [ +  + ]:          24 :         if (!OidIsValid(member->lefttype))
    1418                 :           6 :                 member->lefttype = typeoid;
    1419         [ +  + ]:          24 :         if (!OidIsValid(member->righttype))
    1420                 :           6 :                 member->righttype = typeoid;
    1421                 :             : 
    1422         [ +  + ]:          24 :         if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
    1423   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    1424                 :             :                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1425                 :             :                                  errmsg("associated data types must be specified for index support function")));
    1426                 :             : 
    1427                 :          23 :         ReleaseSysCache(proctup);
    1428                 :          23 : }
    1429                 :             : 
    1430                 :             : /*
    1431                 :             :  * Add a new family member to the appropriate list, after checking for
    1432                 :             :  * duplicated strategy or proc number.
    1433                 :             :  */
    1434                 :             : static void
    1435                 :         105 : addFamilyMember(List **list, OpFamilyMember *member)
    1436                 :             : {
    1437                 :         105 :         ListCell   *l;
    1438                 :             : 
    1439   [ +  +  +  +  :         271 :         foreach(l, *list)
                   +  + ]
    1440                 :             :         {
    1441                 :         168 :                 OpFamilyMember *old = (OpFamilyMember *) lfirst(l);
    1442                 :             : 
    1443         [ +  + ]:         168 :                 if (old->number == member->number &&
    1444   [ +  -  -  + ]:           2 :                         old->lefttype == member->lefttype &&
    1445                 :           2 :                         old->righttype == member->righttype)
    1446                 :             :                 {
    1447         [ +  + ]:           2 :                         if (member->is_func)
    1448   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    1449                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1450                 :             :                                                  errmsg("function number %d for (%s,%s) appears more than once",
    1451                 :             :                                                                 member->number,
    1452                 :             :                                                                 format_type_be(member->lefttype),
    1453                 :             :                                                                 format_type_be(member->righttype))));
    1454                 :             :                         else
    1455   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    1456                 :             :                                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1457                 :             :                                                  errmsg("operator number %d for (%s,%s) appears more than once",
    1458                 :             :                                                                 member->number,
    1459                 :             :                                                                 format_type_be(member->lefttype),
    1460                 :             :                                                                 format_type_be(member->righttype))));
    1461                 :           0 :                 }
    1462                 :         166 :         }
    1463                 :         103 :         *list = lappend(*list, member);
    1464                 :         103 : }
    1465                 :             : 
    1466                 :             : /*
    1467                 :             :  * Dump the operators to pg_amop
    1468                 :             :  *
    1469                 :             :  * We also make dependency entries in pg_depend for the pg_amop entries.
    1470                 :             :  */
    1471                 :             : static void
    1472                 :          35 : storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
    1473                 :             :                            List *operators, bool isAdd)
    1474                 :             : {
    1475                 :          35 :         Relation        rel;
    1476                 :          35 :         Datum           values[Natts_pg_amop];
    1477                 :          35 :         bool            nulls[Natts_pg_amop];
    1478                 :          35 :         HeapTuple       tup;
    1479                 :          35 :         Oid                     entryoid;
    1480                 :          35 :         ObjectAddress myself,
    1481                 :             :                                 referenced;
    1482                 :          35 :         ListCell   *l;
    1483                 :             : 
    1484                 :          35 :         rel = table_open(AccessMethodOperatorRelationId, RowExclusiveLock);
    1485                 :             : 
    1486   [ +  +  +  +  :          94 :         foreach(l, operators)
                   +  + ]
    1487                 :             :         {
    1488                 :          61 :                 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
    1489                 :          61 :                 char            oppurpose;
    1490                 :             : 
    1491                 :             :                 /*
    1492                 :             :                  * If adding to an existing family, check for conflict with an
    1493                 :             :                  * existing pg_amop entry (just to give a nicer error message)
    1494                 :             :                  */
    1495   [ +  +  +  + ]:          61 :                 if (isAdd &&
    1496                 :          28 :                         SearchSysCacheExists4(AMOPSTRATEGY,
    1497                 :             :                                                                   ObjectIdGetDatum(opfamilyoid),
    1498                 :             :                                                                   ObjectIdGetDatum(op->lefttype),
    1499                 :             :                                                                   ObjectIdGetDatum(op->righttype),
    1500                 :             :                                                                   Int16GetDatum(op->number)))
    1501   [ +  -  +  - ]:           2 :                         ereport(ERROR,
    1502                 :             :                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
    1503                 :             :                                          errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
    1504                 :             :                                                         op->number,
    1505                 :             :                                                         format_type_be(op->lefttype),
    1506                 :             :                                                         format_type_be(op->righttype),
    1507                 :             :                                                         NameListToString(opfamilyname))));
    1508                 :             : 
    1509                 :          59 :                 oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;
    1510                 :             : 
    1511                 :             :                 /* Create the pg_amop entry */
    1512                 :          59 :                 memset(values, 0, sizeof(values));
    1513                 :          59 :                 memset(nulls, false, sizeof(nulls));
    1514                 :             : 
    1515                 :          59 :                 entryoid = GetNewOidWithIndex(rel, AccessMethodOperatorOidIndexId,
    1516                 :             :                                                                           Anum_pg_amop_oid);
    1517                 :          59 :                 values[Anum_pg_amop_oid - 1] = ObjectIdGetDatum(entryoid);
    1518                 :          59 :                 values[Anum_pg_amop_amopfamily - 1] = ObjectIdGetDatum(opfamilyoid);
    1519                 :          59 :                 values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype);
    1520                 :          59 :                 values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype);
    1521                 :          59 :                 values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
    1522                 :          59 :                 values[Anum_pg_amop_amoppurpose - 1] = CharGetDatum(oppurpose);
    1523                 :          59 :                 values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
    1524                 :          59 :                 values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
    1525                 :          59 :                 values[Anum_pg_amop_amopsortfamily - 1] = ObjectIdGetDatum(op->sortfamily);
    1526                 :             : 
    1527                 :          59 :                 tup = heap_form_tuple(rel->rd_att, values, nulls);
    1528                 :             : 
    1529                 :          59 :                 CatalogTupleInsert(rel, tup);
    1530                 :             : 
    1531                 :          59 :                 heap_freetuple(tup);
    1532                 :             : 
    1533                 :             :                 /* Make its dependencies */
    1534                 :          59 :                 myself.classId = AccessMethodOperatorRelationId;
    1535                 :          59 :                 myself.objectId = entryoid;
    1536                 :          59 :                 myself.objectSubId = 0;
    1537                 :             : 
    1538                 :          59 :                 referenced.classId = OperatorRelationId;
    1539                 :          59 :                 referenced.objectId = op->object;
    1540                 :          59 :                 referenced.objectSubId = 0;
    1541                 :             : 
    1542                 :             :                 /* see comments in amapi.h about dependency strength */
    1543                 :          59 :                 recordDependencyOn(&myself, &referenced,
    1544                 :          59 :                                                    op->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
    1545                 :             : 
    1546                 :          59 :                 referenced.classId = op->ref_is_family ? OperatorFamilyRelationId :
    1547                 :             :                         OperatorClassRelationId;
    1548                 :          59 :                 referenced.objectId = op->refobjid;
    1549                 :          59 :                 referenced.objectSubId = 0;
    1550                 :             : 
    1551                 :          59 :                 recordDependencyOn(&myself, &referenced,
    1552                 :          59 :                                                    op->ref_is_hard ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
    1553                 :             : 
    1554         [ +  - ]:          59 :                 if (typeDepNeeded(op->lefttype, op))
    1555                 :             :                 {
    1556                 :           0 :                         referenced.classId = TypeRelationId;
    1557                 :           0 :                         referenced.objectId = op->lefttype;
    1558                 :           0 :                         referenced.objectSubId = 0;
    1559                 :             : 
    1560                 :             :                         /* see comments in amapi.h about dependency strength */
    1561                 :           0 :                         recordDependencyOn(&myself, &referenced,
    1562                 :           0 :                                                            op->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
    1563                 :           0 :                 }
    1564                 :             : 
    1565   [ +  +  +  - ]:          59 :                 if (op->lefttype != op->righttype &&
    1566                 :          19 :                         typeDepNeeded(op->righttype, op))
    1567                 :             :                 {
    1568                 :           0 :                         referenced.classId = TypeRelationId;
    1569                 :           0 :                         referenced.objectId = op->righttype;
    1570                 :           0 :                         referenced.objectSubId = 0;
    1571                 :             : 
    1572                 :             :                         /* see comments in amapi.h about dependency strength */
    1573                 :           0 :                         recordDependencyOn(&myself, &referenced,
    1574                 :           0 :                                                            op->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
    1575                 :           0 :                 }
    1576                 :             : 
    1577                 :             :                 /* A search operator also needs a dep on the referenced opfamily */
    1578         [ +  + ]:          59 :                 if (OidIsValid(op->sortfamily))
    1579                 :             :                 {
    1580                 :           2 :                         referenced.classId = OperatorFamilyRelationId;
    1581                 :           2 :                         referenced.objectId = op->sortfamily;
    1582                 :           2 :                         referenced.objectSubId = 0;
    1583                 :             : 
    1584                 :           2 :                         recordDependencyOn(&myself, &referenced,
    1585                 :           2 :                                                            op->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
    1586                 :           2 :                 }
    1587                 :             : 
    1588                 :             :                 /* Post create hook of this access method operator */
    1589         [ +  - ]:          59 :                 InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
    1590                 :             :                                                                    entryoid, 0);
    1591                 :          59 :         }
    1592                 :             : 
    1593                 :          33 :         table_close(rel, RowExclusiveLock);
    1594                 :          33 : }
    1595                 :             : 
    1596                 :             : /*
    1597                 :             :  * Dump the procedures (support routines) to pg_amproc
    1598                 :             :  *
    1599                 :             :  * We also make dependency entries in pg_depend for the pg_amproc entries.
    1600                 :             :  */
    1601                 :             : static void
    1602                 :          33 : storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
    1603                 :             :                                 List *procedures, bool isAdd)
    1604                 :             : {
    1605                 :          33 :         Relation        rel;
    1606                 :          33 :         Datum           values[Natts_pg_amproc];
    1607                 :          33 :         bool            nulls[Natts_pg_amproc];
    1608                 :          33 :         HeapTuple       tup;
    1609                 :          33 :         Oid                     entryoid;
    1610                 :          33 :         ObjectAddress myself,
    1611                 :             :                                 referenced;
    1612                 :          33 :         ListCell   *l;
    1613                 :             : 
    1614                 :          33 :         rel = table_open(AccessMethodProcedureRelationId, RowExclusiveLock);
    1615                 :             : 
    1616   [ +  +  +  +  :          53 :         foreach(l, procedures)
                   +  + ]
    1617                 :             :         {
    1618                 :          20 :                 OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
    1619                 :             : 
    1620                 :             :                 /*
    1621                 :             :                  * If adding to an existing family, check for conflict with an
    1622                 :             :                  * existing pg_amproc entry (just to give a nicer error message)
    1623                 :             :                  */
    1624   [ +  +  +  - ]:          20 :                 if (isAdd &&
    1625                 :           6 :                         SearchSysCacheExists4(AMPROCNUM,
    1626                 :             :                                                                   ObjectIdGetDatum(opfamilyoid),
    1627                 :             :                                                                   ObjectIdGetDatum(proc->lefttype),
    1628                 :             :                                                                   ObjectIdGetDatum(proc->righttype),
    1629                 :             :                                                                   Int16GetDatum(proc->number)))
    1630   [ #  #  #  # ]:           0 :                         ereport(ERROR,
    1631                 :             :                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
    1632                 :             :                                          errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
    1633                 :             :                                                         proc->number,
    1634                 :             :                                                         format_type_be(proc->lefttype),
    1635                 :             :                                                         format_type_be(proc->righttype),
    1636                 :             :                                                         NameListToString(opfamilyname))));
    1637                 :             : 
    1638                 :             :                 /* Create the pg_amproc entry */
    1639                 :          20 :                 memset(values, 0, sizeof(values));
    1640                 :          20 :                 memset(nulls, false, sizeof(nulls));
    1641                 :             : 
    1642                 :          20 :                 entryoid = GetNewOidWithIndex(rel, AccessMethodProcedureOidIndexId,
    1643                 :             :                                                                           Anum_pg_amproc_oid);
    1644                 :          20 :                 values[Anum_pg_amproc_oid - 1] = ObjectIdGetDatum(entryoid);
    1645                 :          20 :                 values[Anum_pg_amproc_amprocfamily - 1] = ObjectIdGetDatum(opfamilyoid);
    1646                 :          20 :                 values[Anum_pg_amproc_amproclefttype - 1] = ObjectIdGetDatum(proc->lefttype);
    1647                 :          20 :                 values[Anum_pg_amproc_amprocrighttype - 1] = ObjectIdGetDatum(proc->righttype);
    1648                 :          20 :                 values[Anum_pg_amproc_amprocnum - 1] = Int16GetDatum(proc->number);
    1649                 :          20 :                 values[Anum_pg_amproc_amproc - 1] = ObjectIdGetDatum(proc->object);
    1650                 :             : 
    1651                 :          20 :                 tup = heap_form_tuple(rel->rd_att, values, nulls);
    1652                 :             : 
    1653                 :          20 :                 CatalogTupleInsert(rel, tup);
    1654                 :             : 
    1655                 :          20 :                 heap_freetuple(tup);
    1656                 :             : 
    1657                 :             :                 /* Make its dependencies */
    1658                 :          20 :                 myself.classId = AccessMethodProcedureRelationId;
    1659                 :          20 :                 myself.objectId = entryoid;
    1660                 :          20 :                 myself.objectSubId = 0;
    1661                 :             : 
    1662                 :          20 :                 referenced.classId = ProcedureRelationId;
    1663                 :          20 :                 referenced.objectId = proc->object;
    1664                 :          20 :                 referenced.objectSubId = 0;
    1665                 :             : 
    1666                 :             :                 /* see comments in amapi.h about dependency strength */
    1667                 :          20 :                 recordDependencyOn(&myself, &referenced,
    1668                 :          20 :                                                    proc->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
    1669                 :             : 
    1670                 :          20 :                 referenced.classId = proc->ref_is_family ? OperatorFamilyRelationId :
    1671                 :             :                         OperatorClassRelationId;
    1672                 :          20 :                 referenced.objectId = proc->refobjid;
    1673                 :          20 :                 referenced.objectSubId = 0;
    1674                 :             : 
    1675                 :          20 :                 recordDependencyOn(&myself, &referenced,
    1676                 :          20 :                                                    proc->ref_is_hard ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
    1677                 :             : 
    1678         [ +  - ]:          20 :                 if (typeDepNeeded(proc->lefttype, proc))
    1679                 :             :                 {
    1680                 :           0 :                         referenced.classId = TypeRelationId;
    1681                 :           0 :                         referenced.objectId = proc->lefttype;
    1682                 :           0 :                         referenced.objectSubId = 0;
    1683                 :             : 
    1684                 :             :                         /* see comments in amapi.h about dependency strength */
    1685                 :           0 :                         recordDependencyOn(&myself, &referenced,
    1686                 :           0 :                                                            proc->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
    1687                 :           0 :                 }
    1688                 :             : 
    1689   [ +  +  +  - ]:          20 :                 if (proc->lefttype != proc->righttype &&
    1690                 :           4 :                         typeDepNeeded(proc->righttype, proc))
    1691                 :             :                 {
    1692                 :           0 :                         referenced.classId = TypeRelationId;
    1693                 :           0 :                         referenced.objectId = proc->righttype;
    1694                 :           0 :                         referenced.objectSubId = 0;
    1695                 :             : 
    1696                 :             :                         /* see comments in amapi.h about dependency strength */
    1697                 :           0 :                         recordDependencyOn(&myself, &referenced,
    1698                 :           0 :                                                            proc->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
    1699                 :           0 :                 }
    1700                 :             : 
    1701                 :             :                 /* Post create hook of access method procedure */
    1702         [ +  - ]:          20 :                 InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
    1703                 :             :                                                                    entryoid, 0);
    1704                 :          20 :         }
    1705                 :             : 
    1706                 :          33 :         table_close(rel, RowExclusiveLock);
    1707                 :          33 : }
    1708                 :             : 
    1709                 :             : /*
    1710                 :             :  * Detect whether a pg_amop or pg_amproc entry needs an explicit dependency
    1711                 :             :  * on its lefttype or righttype.
    1712                 :             :  *
    1713                 :             :  * We make such a dependency unless the entry has an indirect dependency
    1714                 :             :  * via its referenced operator or function.  That's nearly always true
    1715                 :             :  * for operators, but might well not be true for support functions.
    1716                 :             :  */
    1717                 :             : static bool
    1718                 :         102 : typeDepNeeded(Oid typid, OpFamilyMember *member)
    1719                 :             : {
    1720                 :         102 :         bool            result = true;
    1721                 :             : 
    1722                 :             :         /*
    1723                 :             :          * If the type is pinned, we don't need a dependency.  This is a bit of a
    1724                 :             :          * layering violation perhaps (recordDependencyOn would ignore the request
    1725                 :             :          * anyway), but it's a cheap test and will frequently save a syscache
    1726                 :             :          * lookup here.
    1727                 :             :          */
    1728         [ +  + ]:         102 :         if (IsPinnedObject(TypeRelationId, typid))
    1729                 :          90 :                 return false;
    1730                 :             : 
    1731                 :             :         /* Nope, so check the input types of the function or operator. */
    1732         [ +  + ]:          12 :         if (member->is_func)
    1733                 :             :         {
    1734                 :           3 :                 Oid                *argtypes;
    1735                 :           3 :                 int                     nargs;
    1736                 :             : 
    1737                 :           3 :                 (void) get_func_signature(member->object, &argtypes, &nargs);
    1738         [ +  - ]:           7 :                 for (int i = 0; i < nargs; i++)
    1739                 :             :                 {
    1740         [ +  + ]:           4 :                         if (typid == argtypes[i])
    1741                 :             :                         {
    1742                 :           3 :                                 result = false; /* match, no dependency needed */
    1743                 :           3 :                                 break;
    1744                 :             :                         }
    1745                 :           1 :                 }
    1746                 :           3 :                 pfree(argtypes);
    1747                 :           3 :         }
    1748                 :             :         else
    1749                 :             :         {
    1750                 :           9 :                 Oid                     lefttype,
    1751                 :             :                                         righttype;
    1752                 :             : 
    1753                 :           9 :                 op_input_types(member->object, &lefttype, &righttype);
    1754   [ +  +  +  - ]:           9 :                 if (typid == lefttype || typid == righttype)
    1755                 :           9 :                         result = false;         /* match, no dependency needed */
    1756                 :           9 :         }
    1757                 :          12 :         return result;
    1758                 :         102 : }
    1759                 :             : 
    1760                 :             : 
    1761                 :             : /*
    1762                 :             :  * Remove operator entries from an opfamily.
    1763                 :             :  *
    1764                 :             :  * Note: this is only allowed for "loose" members of an opfamily, hence
    1765                 :             :  * behavior is always RESTRICT.
    1766                 :             :  */
    1767                 :             : static void
    1768                 :           5 : dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
    1769                 :             :                           List *operators)
    1770                 :             : {
    1771                 :           5 :         ListCell   *l;
    1772                 :             : 
    1773   [ +  +  +  +  :          11 :         foreach(l, operators)
                   +  + ]
    1774                 :             :         {
    1775                 :           7 :                 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
    1776                 :           7 :                 Oid                     amopid;
    1777                 :           7 :                 ObjectAddress object;
    1778                 :             : 
    1779                 :           7 :                 amopid = GetSysCacheOid4(AMOPSTRATEGY, Anum_pg_amop_oid,
    1780                 :             :                                                                  ObjectIdGetDatum(opfamilyoid),
    1781                 :             :                                                                  ObjectIdGetDatum(op->lefttype),
    1782                 :             :                                                                  ObjectIdGetDatum(op->righttype),
    1783                 :             :                                                                  Int16GetDatum(op->number));
    1784         [ +  + ]:           7 :                 if (!OidIsValid(amopid))
    1785   [ +  -  +  - ]:           1 :                         ereport(ERROR,
    1786                 :             :                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
    1787                 :             :                                          errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
    1788                 :             :                                                         op->number,
    1789                 :             :                                                         format_type_be(op->lefttype),
    1790                 :             :                                                         format_type_be(op->righttype),
    1791                 :             :                                                         NameListToString(opfamilyname))));
    1792                 :             : 
    1793                 :           6 :                 object.classId = AccessMethodOperatorRelationId;
    1794                 :           6 :                 object.objectId = amopid;
    1795                 :           6 :                 object.objectSubId = 0;
    1796                 :             : 
    1797                 :           6 :                 performDeletion(&object, DROP_RESTRICT, 0);
    1798                 :           6 :         }
    1799                 :           4 : }
    1800                 :             : 
    1801                 :             : /*
    1802                 :             :  * Remove procedure entries from an opfamily.
    1803                 :             :  *
    1804                 :             :  * Note: this is only allowed for "loose" members of an opfamily, hence
    1805                 :             :  * behavior is always RESTRICT.
    1806                 :             :  */
    1807                 :             : static void
    1808                 :           4 : dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
    1809                 :             :                            List *procedures)
    1810                 :             : {
    1811                 :           4 :         ListCell   *l;
    1812                 :             : 
    1813   [ +  +  +  +  :           6 :         foreach(l, procedures)
                   +  + ]
    1814                 :             :         {
    1815                 :           3 :                 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
    1816                 :           3 :                 Oid                     amprocid;
    1817                 :           3 :                 ObjectAddress object;
    1818                 :             : 
    1819                 :           3 :                 amprocid = GetSysCacheOid4(AMPROCNUM, Anum_pg_amproc_oid,
    1820                 :             :                                                                    ObjectIdGetDatum(opfamilyoid),
    1821                 :             :                                                                    ObjectIdGetDatum(op->lefttype),
    1822                 :             :                                                                    ObjectIdGetDatum(op->righttype),
    1823                 :             :                                                                    Int16GetDatum(op->number));
    1824         [ +  + ]:           3 :                 if (!OidIsValid(amprocid))
    1825   [ +  -  +  - ]:           1 :                         ereport(ERROR,
    1826                 :             :                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
    1827                 :             :                                          errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
    1828                 :             :                                                         op->number,
    1829                 :             :                                                         format_type_be(op->lefttype),
    1830                 :             :                                                         format_type_be(op->righttype),
    1831                 :             :                                                         NameListToString(opfamilyname))));
    1832                 :             : 
    1833                 :           2 :                 object.classId = AccessMethodProcedureRelationId;
    1834                 :           2 :                 object.objectId = amprocid;
    1835                 :           2 :                 object.objectSubId = 0;
    1836                 :             : 
    1837                 :           2 :                 performDeletion(&object, DROP_RESTRICT, 0);
    1838                 :           2 :         }
    1839                 :           3 : }
    1840                 :             : 
    1841                 :             : /*
    1842                 :             :  * Subroutine for ALTER OPERATOR CLASS SET SCHEMA/RENAME
    1843                 :             :  *
    1844                 :             :  * Is there an operator class with the given name and signature already
    1845                 :             :  * in the given namespace?      If so, raise an appropriate error message.
    1846                 :             :  */
    1847                 :             : void
    1848                 :           6 : IsThereOpClassInNamespace(const char *opcname, Oid opcmethod,
    1849                 :             :                                                   Oid opcnamespace)
    1850                 :             : {
    1851                 :             :         /* make sure the new name doesn't exist */
    1852         [ +  + ]:           6 :         if (SearchSysCacheExists3(CLAAMNAMENSP,
    1853                 :             :                                                           ObjectIdGetDatum(opcmethod),
    1854                 :             :                                                           CStringGetDatum(opcname),
    1855                 :             :                                                           ObjectIdGetDatum(opcnamespace)))
    1856   [ +  -  +  - ]:           2 :                 ereport(ERROR,
    1857                 :             :                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
    1858                 :             :                                  errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
    1859                 :             :                                                 opcname,
    1860                 :             :                                                 get_am_name(opcmethod),
    1861                 :             :                                                 get_namespace_name(opcnamespace))));
    1862                 :           4 : }
    1863                 :             : 
    1864                 :             : /*
    1865                 :             :  * Subroutine for ALTER OPERATOR FAMILY SET SCHEMA/RENAME
    1866                 :             :  *
    1867                 :             :  * Is there an operator family with the given name and signature already
    1868                 :             :  * in the given namespace?      If so, raise an appropriate error message.
    1869                 :             :  */
    1870                 :             : void
    1871                 :           6 : IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod,
    1872                 :             :                                                    Oid opfnamespace)
    1873                 :             : {
    1874                 :             :         /* make sure the new name doesn't exist */
    1875         [ +  + ]:           6 :         if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
    1876                 :             :                                                           ObjectIdGetDatum(opfmethod),
    1877                 :             :                                                           CStringGetDatum(opfname),
    1878                 :             :                                                           ObjectIdGetDatum(opfnamespace)))
    1879   [ +  -  +  - ]:           2 :                 ereport(ERROR,
    1880                 :             :                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
    1881                 :             :                                  errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
    1882                 :             :                                                 opfname,
    1883                 :             :                                                 get_am_name(opfmethod),
    1884                 :             :                                                 get_namespace_name(opfnamespace))));
    1885                 :           4 : }
        

Generated by: LCOV version 2.3.2-1