LCOV - code coverage report
Current view: top level - src/backend/commands - opclasscmds.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 479 534 89.7 %
Date: 2017-09-29 15:12:54 Functions: 24 24 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11