LCOV - code coverage report
Current view: top level - src/backend/commands - opclasscmds.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 535 585 91.5 %
Date: 2020-06-01 09:07:10 Functions: 24 24 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13