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

Generated by: LCOV version 1.14