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

Generated by: LCOV version 1.14