LCOV - differential code coverage report
Current view: top level - src/backend/commands - opclasscmds.c (source / functions) Coverage Total Hit UBC GNC CBC DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 91.8 % 570 523 47 2 521 2
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 20 20 2 18
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * opclasscmds.c
       4                 :  *
       5                 :  *    Routines for opclass (and opfamily) manipulation commands
       6                 :  *
       7                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
       8                 :  * Portions Copyright (c) 1994, Regents of the University of California
       9                 :  *
      10                 :  *
      11                 :  * IDENTIFICATION
      12                 :  *    src/backend/commands/opclasscmds.c
      13                 :  *
      14                 :  *-------------------------------------------------------------------------
      15                 :  */
      16                 : #include "postgres.h"
      17                 : 
      18                 : #include <limits.h>
      19                 : 
      20                 : #include "access/genam.h"
      21                 : #include "access/hash.h"
      22                 : #include "access/htup_details.h"
      23                 : #include "access/nbtree.h"
      24                 : #include "access/sysattr.h"
      25                 : #include "access/table.h"
      26                 : #include "catalog/catalog.h"
      27                 : #include "catalog/dependency.h"
      28                 : #include "catalog/indexing.h"
      29                 : #include "catalog/objectaccess.h"
      30                 : #include "catalog/pg_am.h"
      31                 : #include "catalog/pg_amop.h"
      32                 : #include "catalog/pg_amproc.h"
      33                 : #include "catalog/pg_namespace.h"
      34                 : #include "catalog/pg_opclass.h"
      35                 : #include "catalog/pg_operator.h"
      36                 : #include "catalog/pg_opfamily.h"
      37                 : #include "catalog/pg_proc.h"
      38                 : #include "catalog/pg_type.h"
      39                 : #include "commands/alter.h"
      40                 : #include "commands/defrem.h"
      41                 : #include "commands/event_trigger.h"
      42                 : #include "miscadmin.h"
      43                 : #include "parser/parse_func.h"
      44                 : #include "parser/parse_oper.h"
      45                 : #include "parser/parse_type.h"
      46                 : #include "utils/builtins.h"
      47                 : #include "utils/fmgroids.h"
      48                 : #include "utils/lsyscache.h"
      49                 : #include "utils/rel.h"
      50                 : #include "utils/syscache.h"
      51                 : 
      52                 : static void AlterOpFamilyAdd(AlterOpFamilyStmt *stmt,
      53                 :                              Oid amoid, Oid opfamilyoid,
      54                 :                              int maxOpNumber, int maxProcNumber,
      55                 :                              int optsProcNumber, List *items);
      56                 : static void AlterOpFamilyDrop(AlterOpFamilyStmt *stmt,
      57                 :                               Oid amoid, Oid opfamilyoid,
      58                 :                               int maxOpNumber, int maxProcNumber,
      59                 :                               List *items);
      60                 : static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype);
      61                 : static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
      62                 : static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid,
      63                 :                             int opclassOptsProcNum);
      64                 : static void addFamilyMember(List **list, OpFamilyMember *member);
      65                 : static void storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
      66                 :                            List *operators, bool isAdd);
      67                 : static void storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
      68                 :                             List *procedures, bool isAdd);
      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 CBC         410 : 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             410 :     DeconstructQualifiedName(opfamilyname, &schemaname, &opfname);
      89                 : 
      90             410 :     if (schemaname)
      91                 :     {
      92                 :         /* Look in specific schema only */
      93                 :         Oid         namespaceId;
      94                 : 
      95              49 :         namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
      96              46 :         if (!OidIsValid(namespaceId))
      97               3 :             htup = NULL;
      98                 :         else
      99              43 :             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             361 :         Oid         opfID = OpfamilynameGetOpfid(amID, opfname);
     108                 : 
     109             361 :         if (!OidIsValid(opfID))
     110               6 :             htup = NULL;
     111                 :         else
     112             355 :             htup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfID));
     113                 :     }
     114                 : 
     115             407 :     if (!HeapTupleIsValid(htup) && !missing_ok)
     116                 :     {
     117                 :         HeapTuple   amtup;
     118                 : 
     119               3 :         amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
     120               3 :         if (!HeapTupleIsValid(amtup))
     121 UBC           0 :             elog(ERROR, "cache lookup failed for access method %u", amID);
     122 CBC           3 :         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             404 :     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             410 : get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
     140                 : {
     141                 :     HeapTuple   htup;
     142                 :     Form_pg_opfamily opfamform;
     143                 :     Oid         opfID;
     144                 : 
     145             410 :     htup = OpFamilyCacheLookup(amID, opfamilyname, missing_ok);
     146             404 :     if (!HeapTupleIsValid(htup))
     147               6 :         return InvalidOid;
     148             398 :     opfamform = (Form_pg_opfamily) GETSTRUCT(htup);
     149             398 :     opfID = opfamform->oid;
     150             398 :     ReleaseSysCache(htup);
     151                 : 
     152             398 :     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             107 : 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             107 :     DeconstructQualifiedName(opclassname, &schemaname, &opcname);
     170                 : 
     171             107 :     if (schemaname)
     172                 :     {
     173                 :         /* Look in specific schema only */
     174                 :         Oid         namespaceId;
     175                 : 
     176              13 :         namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
     177              13 :         if (!OidIsValid(namespaceId))
     178               3 :             htup = NULL;
     179                 :         else
     180              10 :             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              94 :         Oid         opcID = OpclassnameGetOpcid(amID, opcname);
     189                 : 
     190              94 :         if (!OidIsValid(opcID))
     191               6 :             htup = NULL;
     192                 :         else
     193              88 :             htup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcID));
     194                 :     }
     195                 : 
     196             107 :     if (!HeapTupleIsValid(htup) && !missing_ok)
     197                 :     {
     198                 :         HeapTuple   amtup;
     199                 : 
     200               3 :         amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
     201               3 :         if (!HeapTupleIsValid(amtup))
     202 UBC           0 :             elog(ERROR, "cache lookup failed for access method %u", amID);
     203 CBC           3 :         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             104 :     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             107 : get_opclass_oid(Oid amID, List *opclassname, bool missing_ok)
     221                 : {
     222                 :     HeapTuple   htup;
     223                 :     Form_pg_opclass opcform;
     224                 :     Oid         opcID;
     225                 : 
     226             107 :     htup = OpClassCacheLookup(amID, opclassname, missing_ok);
     227             104 :     if (!HeapTupleIsValid(htup))
     228               6 :         return InvalidOid;
     229              98 :     opcform = (Form_pg_opclass) GETSTRUCT(htup);
     230              98 :     opcID = opcform->oid;
     231              98 :     ReleaseSysCache(htup);
     232                 : 
     233              98 :     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             229 : 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             229 :     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             229 :     if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
     262                 :                               ObjectIdGetDatum(amoid),
     263                 :                               CStringGetDatum(opfname),
     264                 :                               ObjectIdGetDatum(namespaceoid)))
     265 UBC           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 CBC         229 :     memset(values, 0, sizeof(values));
     274             229 :     memset(nulls, false, sizeof(nulls));
     275                 : 
     276             229 :     opfamilyoid = GetNewOidWithIndex(rel, OpfamilyOidIndexId,
     277                 :                                      Anum_pg_opfamily_oid);
     278             229 :     values[Anum_pg_opfamily_oid - 1] = ObjectIdGetDatum(opfamilyoid);
     279             229 :     values[Anum_pg_opfamily_opfmethod - 1] = ObjectIdGetDatum(amoid);
     280             229 :     namestrcpy(&opfName, opfname);
     281             229 :     values[Anum_pg_opfamily_opfname - 1] = NameGetDatum(&opfName);
     282             229 :     values[Anum_pg_opfamily_opfnamespace - 1] = ObjectIdGetDatum(namespaceoid);
     283             229 :     values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId());
     284                 : 
     285             229 :     tup = heap_form_tuple(rel->rd_att, values, nulls);
     286                 : 
     287             229 :     CatalogTupleInsert(rel, tup);
     288                 : 
     289             229 :     heap_freetuple(tup);
     290                 : 
     291                 :     /*
     292                 :      * Create dependencies for the opfamily proper.
     293                 :      */
     294             229 :     myself.classId = OperatorFamilyRelationId;
     295             229 :     myself.objectId = opfamilyoid;
     296             229 :     myself.objectSubId = 0;
     297                 : 
     298                 :     /* dependency on access method */
     299             229 :     referenced.classId = AccessMethodRelationId;
     300             229 :     referenced.objectId = amoid;
     301             229 :     referenced.objectSubId = 0;
     302             229 :     recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
     303                 : 
     304                 :     /* dependency on namespace */
     305             229 :     referenced.classId = NamespaceRelationId;
     306             229 :     referenced.objectId = namespaceoid;
     307             229 :     referenced.objectSubId = 0;
     308             229 :     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     309                 : 
     310                 :     /* dependency on owner */
     311             229 :     recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
     312                 : 
     313                 :     /* dependency on extension */
     314             229 :     recordDependencyOnCurrentExtension(&myself, false);
     315                 : 
     316                 :     /* Report the new operator family to possibly interested event triggers */
     317             229 :     EventTriggerCollectSimpleCommand(myself, InvalidObjectAddress,
     318                 :                                      (Node *) stmt);
     319                 : 
     320                 :     /* Post creation hook for new operator family */
     321             229 :     InvokeObjectPostCreateHook(OperatorFamilyRelationId, opfamilyoid, 0);
     322                 : 
     323             229 :     table_close(rel, RowExclusiveLock);
     324                 : 
     325             229 :     return myself;
     326                 : }
     327                 : 
     328                 : /*
     329                 :  * DefineOpClass
     330                 :  *      Define a new index operator class.
     331                 :  */
     332                 : ObjectAddress
     333             183 : 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             183 :     namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
     362                 :                                                      &opcname);
     363                 : 
     364                 :     /* Check we have creation rights in target namespace */
     365 GNC         183 :     aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE);
     366 CBC         183 :     if (aclresult != ACLCHECK_OK)
     367 UBC           0 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
     368               0 :                        get_namespace_name(namespaceoid));
     369                 : 
     370                 :     /* Get necessary info about access method */
     371 CBC         183 :     tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
     372             183 :     if (!HeapTupleIsValid(tup))
     373 UBC           0 :         ereport(ERROR,
     374                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     375                 :                  errmsg("access method \"%s\" does not exist",
     376                 :                         stmt->amname)));
     377                 : 
     378 CBC         183 :     amform = (Form_pg_am) GETSTRUCT(tup);
     379             183 :     amoid = amform->oid;
     380             183 :     amroutine = GetIndexAmRoutineByAmId(amoid, false);
     381             183 :     ReleaseSysCache(tup);
     382                 : 
     383             183 :     maxOpNumber = amroutine->amstrategies;
     384                 :     /* if amstrategies is zero, just enforce that op numbers fit in int16 */
     385             183 :     if (maxOpNumber <= 0)
     386              88 :         maxOpNumber = SHRT_MAX;
     387             183 :     maxProcNumber = amroutine->amsupport;
     388             183 :     optsProcNumber = amroutine->amoptsprocnum;
     389             183 :     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             183 :     if (!superuser())
     414 UBC           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 CBC         183 :     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             183 :     if (stmt->opfamilyname)
     433                 :     {
     434              22 :         opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
     435                 :     }
     436                 :     else
     437                 :     {
     438                 :         /* Lookup existing family of same name and namespace */
     439             161 :         tup = SearchSysCache3(OPFAMILYAMNAMENSP,
     440                 :                               ObjectIdGetDatum(amoid),
     441                 :                               PointerGetDatum(opcname),
     442                 :                               ObjectIdGetDatum(namespaceoid));
     443             161 :         if (HeapTupleIsValid(tup))
     444                 :         {
     445               6 :             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               6 :             ReleaseSysCache(tup);
     452                 :         }
     453                 :         else
     454                 :         {
     455                 :             CreateOpFamilyStmt *opfstmt;
     456                 :             ObjectAddress tmpAddr;
     457                 : 
     458             155 :             opfstmt = makeNode(CreateOpFamilyStmt);
     459             155 :             opfstmt->opfamilyname = stmt->opclassname;
     460             155 :             opfstmt->amname = stmt->amname;
     461                 : 
     462                 :             /*
     463                 :              * Create it ... again no need for more permissions ...
     464                 :              */
     465             155 :             tmpAddr = CreateOpFamily(opfstmt, opcname, namespaceoid, amoid);
     466             155 :             opfamilyoid = tmpAddr.objectId;
     467                 :         }
     468                 :     }
     469                 : 
     470             183 :     operators = NIL;
     471             183 :     procedures = NIL;
     472                 : 
     473                 :     /* Storage datatype is optional */
     474             183 :     storageoid = InvalidOid;
     475                 : 
     476                 :     /*
     477                 :      * Scan the "items" list to obtain additional info.
     478                 :      */
     479            1580 :     foreach(l, stmt->items)
     480                 :     {
     481            1397 :         CreateOpClassItem *item = lfirst_node(CreateOpClassItem, l);
     482                 :         Oid         operOid;
     483                 :         Oid         funcOid;
     484                 :         Oid         sortfamilyOid;
     485                 :         OpFamilyMember *member;
     486                 : 
     487            1397 :         switch (item->itemtype)
     488                 :         {
     489             707 :             case OPCLASS_ITEM_OPERATOR:
     490             707 :                 if (item->number <= 0 || item->number > maxOpNumber)
     491 UBC           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 CBC         707 :                 if (item->name->objargs != NIL)
     497             181 :                     operOid = LookupOperWithArgs(item->name, false);
     498                 :                 else
     499                 :                 {
     500                 :                     /* Default to binary op on input datatype */
     501             526 :                     operOid = LookupOperName(NULL, item->name->objname,
     502                 :                                              typeoid, typeoid,
     503                 :                                              false, -1);
     504                 :                 }
     505                 : 
     506             707 :                 if (item->order_family)
     507              12 :                     sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
     508                 :                                                      item->order_family,
     509                 :                                                      false);
     510                 :                 else
     511             695 :                     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             707 :                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
     527             707 :                 member->is_func = false;
     528             707 :                 member->object = operOid;
     529             707 :                 member->number = item->number;
     530             707 :                 member->sortfamily = sortfamilyOid;
     531             707 :                 assignOperTypes(member, amoid, typeoid);
     532             707 :                 addFamilyMember(&operators, member);
     533             707 :                 break;
     534             594 :             case OPCLASS_ITEM_FUNCTION:
     535             594 :                 if (item->number <= 0 || item->number > maxProcNumber)
     536 UBC           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 CBC         594 :                 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             594 :                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
     551             594 :                 member->is_func = true;
     552             594 :                 member->object = funcOid;
     553             594 :                 member->number = item->number;
     554                 : 
     555                 :                 /* allow overriding of the function's actual arg types */
     556             594 :                 if (item->class_args)
     557 UBC           0 :                     processTypesSpec(item->class_args,
     558                 :                                      &member->lefttype, &member->righttype);
     559                 : 
     560 CBC         594 :                 assignProcTypes(member, amoid, typeoid, optsProcNumber);
     561             594 :                 addFamilyMember(&procedures, member);
     562             594 :                 break;
     563              96 :             case OPCLASS_ITEM_STORAGETYPE:
     564              96 :                 if (OidIsValid(storageoid))
     565 UBC           0 :                     ereport(ERROR,
     566                 :                             (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
     567                 :                              errmsg("storage type specified more than once")));
     568 CBC          96 :                 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              96 :                 break;
     577 UBC           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 CBC         183 :     if (OidIsValid(storageoid))
     587                 :     {
     588                 :         /* Just drop the spec if same as column datatype */
     589              96 :         if (storageoid == typeoid)
     590              47 :             storageoid = InvalidOid;
     591              49 :         else if (!amstorage)
     592 UBC           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 CBC         183 :     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             183 :     if (SearchSysCacheExists3(CLAAMNAMENSP,
     605                 :                               ObjectIdGetDatum(amoid),
     606                 :                               CStringGetDatum(opcname),
     607                 :                               ObjectIdGetDatum(namespaceoid)))
     608 UBC           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 CBC         183 :     if (stmt->isDefault)
     619                 :     {
     620                 :         ScanKeyData skey[1];
     621                 :         SysScanDesc scan;
     622                 : 
     623             134 :         ScanKeyInit(&skey[0],
     624                 :                     Anum_pg_opclass_opcmethod,
     625                 :                     BTEqualStrategyNumber, F_OIDEQ,
     626                 :                     ObjectIdGetDatum(amoid));
     627                 : 
     628             134 :         scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
     629                 :                                   NULL, 1, skey);
     630                 : 
     631            3462 :         while (HeapTupleIsValid(tup = systable_getnext(scan)))
     632                 :         {
     633            3328 :             Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
     634                 : 
     635            3328 :             if (opclass->opcintype == typeoid && opclass->opcdefault)
     636 UBC           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 CBC         134 :         systable_endscan(scan);
     646                 :     }
     647                 : 
     648                 :     /*
     649                 :      * Okay, let's create the pg_opclass entry.
     650                 :      */
     651             183 :     memset(values, 0, sizeof(values));
     652             183 :     memset(nulls, false, sizeof(nulls));
     653                 : 
     654             183 :     opclassoid = GetNewOidWithIndex(rel, OpclassOidIndexId,
     655                 :                                     Anum_pg_opclass_oid);
     656             183 :     values[Anum_pg_opclass_oid - 1] = ObjectIdGetDatum(opclassoid);
     657             183 :     values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid);
     658             183 :     namestrcpy(&opcName, opcname);
     659             183 :     values[Anum_pg_opclass_opcname - 1] = NameGetDatum(&opcName);
     660             183 :     values[Anum_pg_opclass_opcnamespace - 1] = ObjectIdGetDatum(namespaceoid);
     661             183 :     values[Anum_pg_opclass_opcowner - 1] = ObjectIdGetDatum(GetUserId());
     662             183 :     values[Anum_pg_opclass_opcfamily - 1] = ObjectIdGetDatum(opfamilyoid);
     663             183 :     values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid);
     664             183 :     values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(stmt->isDefault);
     665             183 :     values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid);
     666                 : 
     667             183 :     tup = heap_form_tuple(rel->rd_att, values, nulls);
     668                 : 
     669             183 :     CatalogTupleInsert(rel, tup);
     670                 : 
     671             183 :     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             890 :     foreach(l, operators)
     679                 :     {
     680             707 :         OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
     681                 : 
     682             707 :         op->ref_is_hard = true;
     683             707 :         op->ref_is_family = false;
     684             707 :         op->refobjid = opclassoid;
     685                 :     }
     686             777 :     foreach(l, procedures)
     687                 :     {
     688             594 :         OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
     689                 : 
     690             594 :         proc->ref_is_hard = true;
     691             594 :         proc->ref_is_family = false;
     692             594 :         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             183 :     if (amroutine->amadjustmembers)
     700             178 :         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             183 :     storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
     710                 :                    operators, false);
     711             183 :     storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
     712                 :                     procedures, false);
     713                 : 
     714                 :     /* let event triggers know what happened */
     715             183 :     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             183 :     myself.classId = OperatorClassRelationId;
     722             183 :     myself.objectId = opclassoid;
     723             183 :     myself.objectSubId = 0;
     724                 : 
     725                 :     /* dependency on namespace */
     726             183 :     referenced.classId = NamespaceRelationId;
     727             183 :     referenced.objectId = namespaceoid;
     728             183 :     referenced.objectSubId = 0;
     729             183 :     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     730                 : 
     731                 :     /* dependency on opfamily */
     732             183 :     referenced.classId = OperatorFamilyRelationId;
     733             183 :     referenced.objectId = opfamilyoid;
     734             183 :     referenced.objectSubId = 0;
     735             183 :     recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
     736                 : 
     737                 :     /* dependency on indexed datatype */
     738             183 :     referenced.classId = TypeRelationId;
     739             183 :     referenced.objectId = typeoid;
     740             183 :     referenced.objectSubId = 0;
     741             183 :     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     742                 : 
     743                 :     /* dependency on storage datatype */
     744             183 :     if (OidIsValid(storageoid))
     745                 :     {
     746              49 :         referenced.classId = TypeRelationId;
     747              49 :         referenced.objectId = storageoid;
     748              49 :         referenced.objectSubId = 0;
     749              49 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
     750                 :     }
     751                 : 
     752                 :     /* dependency on owner */
     753             183 :     recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
     754                 : 
     755                 :     /* dependency on extension */
     756             183 :     recordDependencyOnCurrentExtension(&myself, false);
     757                 : 
     758                 :     /* Post creation hook for new operator class */
     759             183 :     InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
     760                 : 
     761             183 :     table_close(rel, RowExclusiveLock);
     762                 : 
     763             183 :     return myself;
     764                 : }
     765                 : 
     766                 : 
     767                 : /*
     768                 :  * DefineOpFamily
     769                 :  *      Define a new index operator family.
     770                 :  */
     771                 : ObjectAddress
     772              74 : 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              74 :     namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
     781                 :                                                      &opfname);
     782                 : 
     783                 :     /* Check we have creation rights in target namespace */
     784 GNC          74 :     aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE);
     785 CBC          74 :     if (aclresult != ACLCHECK_OK)
     786 UBC           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 CBC          74 :     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              74 :     if (!superuser())
     799 UBC           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 CBC          74 :     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             223 : AlterOpFamily(AlterOpFamilyStmt *stmt)
     818                 : {
     819                 :     Oid         amoid,          /* our AM's oid */
     820                 :                 opfamilyoid;    /* oid of opfamily */
     821                 :     int         maxOpNumber,    /* amstrategies value */
     822                 :                 optsProcNumber, /* amopclassopts 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             223 :     tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
     830             223 :     if (!HeapTupleIsValid(tup))
     831               3 :         ereport(ERROR,
     832                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     833                 :                  errmsg("access method \"%s\" does not exist",
     834                 :                         stmt->amname)));
     835                 : 
     836             220 :     amform = (Form_pg_am) GETSTRUCT(tup);
     837             220 :     amoid = amform->oid;
     838             220 :     amroutine = GetIndexAmRoutineByAmId(amoid, false);
     839             220 :     ReleaseSysCache(tup);
     840                 : 
     841             220 :     maxOpNumber = amroutine->amstrategies;
     842                 :     /* if amstrategies is zero, just enforce that op numbers fit in int16 */
     843             220 :     if (maxOpNumber <= 0)
     844              73 :         maxOpNumber = SHRT_MAX;
     845             220 :     maxProcNumber = amroutine->amsupport;
     846             220 :     optsProcNumber = amroutine->amoptsprocnum;
     847                 : 
     848                 :     /* XXX Should we make any privilege check against the AM? */
     849                 : 
     850                 :     /* Look up the opfamily */
     851             220 :     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             217 :     if (!superuser())
     859               3 :         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             214 :     if (stmt->isDrop)
     867              30 :         AlterOpFamilyDrop(stmt, amoid, opfamilyoid,
     868                 :                           maxOpNumber, maxProcNumber, stmt->items);
     869                 :     else
     870             184 :         AlterOpFamilyAdd(stmt, amoid, opfamilyoid,
     871                 :                          maxOpNumber, maxProcNumber, optsProcNumber,
     872                 :                          stmt->items);
     873                 : 
     874             145 :     return opfamilyoid;
     875                 : }
     876                 : 
     877                 : /*
     878                 :  * ADD part of ALTER OP FAMILY
     879                 :  */
     880                 : static void
     881             184 : AlterOpFamilyAdd(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid,
     882                 :                  int maxOpNumber, int maxProcNumber, int optsProcNumber,
     883                 :                  List *items)
     884                 : {
     885             184 :     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             184 :     operators = NIL;
     891             184 :     procedures = NIL;
     892                 : 
     893                 :     /*
     894                 :      * Scan the "items" list to obtain additional info.
     895                 :      */
     896             581 :     foreach(l, items)
     897                 :     {
     898             451 :         CreateOpClassItem *item = lfirst_node(CreateOpClassItem, l);
     899                 :         Oid         operOid;
     900                 :         Oid         funcOid;
     901                 :         Oid         sortfamilyOid;
     902                 :         OpFamilyMember *member;
     903                 : 
     904             451 :         switch (item->itemtype)
     905                 :         {
     906             306 :             case OPCLASS_ITEM_OPERATOR:
     907             306 :                 if (item->number <= 0 || item->number > maxOpNumber)
     908               6 :                     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             300 :                 if (item->name->objargs != NIL)
     914             297 :                     operOid = LookupOperWithArgs(item->name, false);
     915                 :                 else
     916                 :                 {
     917               3 :                     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             297 :                 if (item->order_family)
     924              24 :                     sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
     925                 :                                                      item->order_family,
     926                 :                                                      false);
     927                 :                 else
     928             273 :                     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             297 :                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
     944             297 :                 member->is_func = false;
     945             297 :                 member->object = operOid;
     946             297 :                 member->number = item->number;
     947             297 :                 member->sortfamily = sortfamilyOid;
     948                 :                 /* We can set up dependency fields immediately */
     949                 :                 /* Historically, ALTER ADD has created soft dependencies */
     950             297 :                 member->ref_is_hard = false;
     951             297 :                 member->ref_is_family = true;
     952             297 :                 member->refobjid = opfamilyoid;
     953             297 :                 assignOperTypes(member, amoid, InvalidOid);
     954             294 :                 addFamilyMember(&operators, member);
     955             291 :                 break;
     956             142 :             case OPCLASS_ITEM_FUNCTION:
     957             142 :                 if (item->number <= 0 || item->number > maxProcNumber)
     958               6 :                     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             136 :                 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             133 :                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
     974             133 :                 member->is_func = true;
     975             133 :                 member->object = funcOid;
     976             133 :                 member->number = item->number;
     977                 :                 /* We can set up dependency fields immediately */
     978                 :                 /* Historically, ALTER ADD has created soft dependencies */
     979             133 :                 member->ref_is_hard = false;
     980             133 :                 member->ref_is_family = true;
     981             133 :                 member->refobjid = opfamilyoid;
     982                 : 
     983                 :                 /* allow overriding of the function's actual arg types */
     984             133 :                 if (item->class_args)
     985              68 :                     processTypesSpec(item->class_args,
     986                 :                                      &member->lefttype, &member->righttype);
     987                 : 
     988             133 :                 assignProcTypes(member, amoid, InvalidOid, optsProcNumber);
     989             109 :                 addFamilyMember(&procedures, member);
     990             106 :                 break;
     991               3 :             case OPCLASS_ITEM_STORAGETYPE:
     992               3 :                 ereport(ERROR,
     993                 :                         (errcode(ERRCODE_SYNTAX_ERROR),
     994                 :                          errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
     995                 :                 break;
     996 UBC           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 CBC         130 :     if (amroutine->amadjustmembers)
    1007             130 :         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             130 :     storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
    1017                 :                    operators, true);
    1018             124 :     storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
    1019                 :                     procedures, true);
    1020                 : 
    1021                 :     /* make information available to event triggers */
    1022             124 :     EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
    1023                 :                                   operators, procedures);
    1024             124 : }
    1025                 : 
    1026                 : /*
    1027                 :  * DROP part of ALTER OP FAMILY
    1028                 :  */
    1029                 : static void
    1030              30 : 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              30 :     operators = NIL;
    1038              30 :     procedures = NIL;
    1039                 : 
    1040                 :     /*
    1041                 :      * Scan the "items" list to obtain additional info.
    1042                 :      */
    1043              72 :     foreach(l, items)
    1044                 :     {
    1045              45 :         CreateOpClassItem *item = lfirst_node(CreateOpClassItem, l);
    1046                 :         Oid         lefttype,
    1047                 :                     righttype;
    1048                 :         OpFamilyMember *member;
    1049                 : 
    1050              45 :         switch (item->itemtype)
    1051                 :         {
    1052              28 :             case OPCLASS_ITEM_OPERATOR:
    1053              28 :                 if (item->number <= 0 || item->number > maxOpNumber)
    1054 UBC           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 CBC          28 :                 processTypesSpec(item->class_args, &lefttype, &righttype);
    1060                 :                 /* Save the info */
    1061              25 :                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
    1062              25 :                 member->is_func = false;
    1063              25 :                 member->number = item->number;
    1064              25 :                 member->lefttype = lefttype;
    1065              25 :                 member->righttype = righttype;
    1066              25 :                 addFamilyMember(&operators, member);
    1067              25 :                 break;
    1068              17 :             case OPCLASS_ITEM_FUNCTION:
    1069              17 :                 if (item->number <= 0 || item->number > maxProcNumber)
    1070 UBC           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 CBC          17 :                 processTypesSpec(item->class_args, &lefttype, &righttype);
    1076                 :                 /* Save the info */
    1077              17 :                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
    1078              17 :                 member->is_func = true;
    1079              17 :                 member->number = item->number;
    1080              17 :                 member->lefttype = lefttype;
    1081              17 :                 member->righttype = righttype;
    1082              17 :                 addFamilyMember(&procedures, member);
    1083              17 :                 break;
    1084 UBC           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 CBC          27 :     dropOperators(stmt->opfamilyname, amoid, opfamilyoid, operators);
    1096              24 :     dropProcedures(stmt->opfamilyname, amoid, opfamilyoid, procedures);
    1097                 : 
    1098                 :     /* make information available to event triggers */
    1099              21 :     EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
    1100                 :                                   operators, procedures);
    1101              21 : }
    1102                 : 
    1103                 : 
    1104                 : /*
    1105                 :  * Deal with explicit arg types used in ALTER ADD/DROP
    1106                 :  */
    1107                 : static void
    1108             113 : processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
    1109                 : {
    1110                 :     TypeName   *typeName;
    1111                 : 
    1112             113 :     Assert(args != NIL);
    1113                 : 
    1114             113 :     typeName = (TypeName *) linitial(args);
    1115             113 :     *lefttype = typenameTypeId(NULL, typeName);
    1116                 : 
    1117             113 :     if (list_length(args) > 1)
    1118                 :     {
    1119              85 :         typeName = (TypeName *) lsecond(args);
    1120              85 :         *righttype = typenameTypeId(NULL, typeName);
    1121                 :     }
    1122                 :     else
    1123              28 :         *righttype = *lefttype;
    1124                 : 
    1125             113 :     if (list_length(args) > 2)
    1126               3 :         ereport(ERROR,
    1127                 :                 (errcode(ERRCODE_SYNTAX_ERROR),
    1128                 :                  errmsg("one or two argument types must be specified")));
    1129             110 : }
    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            1004 : assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
    1138                 : {
    1139                 :     Operator    optup;
    1140                 :     Form_pg_operator opform;
    1141                 : 
    1142                 :     /* Fetch the operator definition */
    1143            1004 :     optup = SearchSysCache1(OPEROID, ObjectIdGetDatum(member->object));
    1144            1004 :     if (!HeapTupleIsValid(optup))
    1145 UBC           0 :         elog(ERROR, "cache lookup failed for operator %u", member->object);
    1146 CBC        1004 :     opform = (Form_pg_operator) GETSTRUCT(optup);
    1147                 : 
    1148                 :     /*
    1149                 :      * Opfamily operators must be binary.
    1150                 :      */
    1151            1004 :     if (opform->oprkind != 'b')
    1152 UBC           0 :         ereport(ERROR,
    1153                 :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1154                 :                  errmsg("index operators must be binary")));
    1155                 : 
    1156 CBC        1004 :     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              36 :         IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
    1169                 : 
    1170              36 :         if (!amroutine->amcanorderbyop)
    1171               3 :             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             968 :         if (opform->oprresult != BOOLOID)
    1182 UBC           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 CBC        1001 :     if (!OidIsValid(member->lefttype))
    1191            1001 :         member->lefttype = opform->oprleft;
    1192            1001 :     if (!OidIsValid(member->righttype))
    1193            1001 :         member->righttype = opform->oprright;
    1194                 : 
    1195            1001 :     ReleaseSysCache(optup);
    1196            1001 : }
    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             727 : 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             727 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(member->object));
    1211             727 :     if (!HeapTupleIsValid(proctup))
    1212 UBC           0 :         elog(ERROR, "cache lookup failed for function %u", member->object);
    1213 CBC         727 :     procform = (Form_pg_proc) GETSTRUCT(proctup);
    1214                 : 
    1215                 :     /* Check the signature of the opclass options parsing function */
    1216             727 :     if (member->number == opclassOptsProcNum)
    1217                 :     {
    1218              23 :         if (OidIsValid(typeoid))
    1219                 :         {
    1220 UBC           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 CBC          23 :             if (member->lefttype != member->righttype)
    1229               3 :                 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              20 :         if (procform->prorettype != VOIDOID ||
    1235              17 :             procform->pronargs != 1 ||
    1236              17 :             procform->proargtypes.values[0] != INTERNALOID)
    1237               3 :             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             704 :     else if (amoid == BTREE_AM_OID)
    1253                 :     {
    1254              90 :         if (member->number == BTORDER_PROC)
    1255                 :         {
    1256              83 :             if (procform->pronargs != 2)
    1257               3 :                 ereport(ERROR,
    1258                 :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1259                 :                          errmsg("btree comparison functions must have two arguments")));
    1260              80 :             if (procform->prorettype != INT4OID)
    1261               3 :                 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              77 :             if (!OidIsValid(member->lefttype))
    1270              76 :                 member->lefttype = procform->proargtypes.values[0];
    1271              77 :             if (!OidIsValid(member->righttype))
    1272              76 :                 member->righttype = procform->proargtypes.values[1];
    1273                 :         }
    1274               7 :         else if (member->number == BTSORTSUPPORT_PROC)
    1275                 :         {
    1276               2 :             if (procform->pronargs != 1 ||
    1277               2 :                 procform->proargtypes.values[0] != INTERNALOID)
    1278 UBC           0 :                 ereport(ERROR,
    1279                 :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1280                 :                          errmsg("btree sort support functions must accept type \"internal\"")));
    1281 CBC           2 :             if (procform->prorettype != VOIDOID)
    1282 UBC           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 CBC           5 :         else if (member->number == BTINRANGE_PROC)
    1291                 :         {
    1292 UBC           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 CBC           5 :         else if (member->number == BTEQUALIMAGE_PROC)
    1311                 :         {
    1312               5 :             if (procform->pronargs != 1)
    1313 UBC           0 :                 ereport(ERROR,
    1314                 :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1315                 :                          errmsg("btree equal image functions must have one argument")));
    1316 CBC           5 :             if (procform->prorettype != BOOLOID)
    1317 UBC           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 leftype 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 CBC           5 :             if (member->lefttype != member->righttype)
    1330               3 :                 ereport(ERROR,
    1331                 :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1332                 :                          errmsg("btree equal image functions must not be cross-type")));
    1333                 :         }
    1334                 :     }
    1335             614 :     else if (amoid == HASH_AM_OID)
    1336                 :     {
    1337              50 :         if (member->number == HASHSTANDARD_PROC)
    1338                 :         {
    1339              26 :             if (procform->pronargs != 1)
    1340               3 :                 ereport(ERROR,
    1341                 :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1342                 :                          errmsg("hash function 1 must have one argument")));
    1343              23 :             if (procform->prorettype != INT4OID)
    1344               3 :                 ereport(ERROR,
    1345                 :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1346                 :                          errmsg("hash function 1 must return integer")));
    1347                 :         }
    1348              24 :         else if (member->number == HASHEXTENDED_PROC)
    1349                 :         {
    1350              24 :             if (procform->pronargs != 2)
    1351 UBC           0 :                 ereport(ERROR,
    1352                 :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1353                 :                          errmsg("hash function 2 must have two arguments")));
    1354 CBC          24 :             if (procform->prorettype != INT8OID)
    1355 UBC           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 CBC          44 :         if (!OidIsValid(member->lefttype))
    1364              41 :             member->lefttype = procform->proargtypes.values[0];
    1365              44 :         if (!OidIsValid(member->righttype))
    1366              41 :             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             706 :     if (!OidIsValid(member->lefttype))
    1375             530 :         member->lefttype = typeoid;
    1376             706 :     if (!OidIsValid(member->righttype))
    1377             530 :         member->righttype = typeoid;
    1378                 : 
    1379             706 :     if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
    1380               3 :         ereport(ERROR,
    1381                 :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
    1382                 :                  errmsg("associated data types must be specified for index support function")));
    1383                 : 
    1384             703 :     ReleaseSysCache(proctup);
    1385             703 : }
    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            1746 : addFamilyMember(List **list, OpFamilyMember *member)
    1393                 : {
    1394                 :     ListCell   *l;
    1395                 : 
    1396            5942 :     foreach(l, *list)
    1397                 :     {
    1398            4202 :         OpFamilyMember *old = (OpFamilyMember *) lfirst(l);
    1399                 : 
    1400            4202 :         if (old->number == member->number &&
    1401             195 :             old->lefttype == member->lefttype &&
    1402             195 :             old->righttype == member->righttype)
    1403                 :         {
    1404               6 :             if (member->is_func)
    1405               3 :                 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               3 :                 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            1740 :     *list = lappend(*list, member);
    1421            1740 : }
    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             313 : 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             313 :     rel = table_open(AccessMethodOperatorRelationId, RowExclusiveLock);
    1442                 : 
    1443            1275 :     foreach(l, operators)
    1444                 :     {
    1445             968 :         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            1229 :         if (isAdd &&
    1453             261 :             SearchSysCacheExists4(AMOPSTRATEGY,
    1454                 :                                   ObjectIdGetDatum(opfamilyoid),
    1455                 :                                   ObjectIdGetDatum(op->lefttype),
    1456                 :                                   ObjectIdGetDatum(op->righttype),
    1457                 :                                   Int16GetDatum(op->number)))
    1458               6 :             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             962 :         oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;
    1467                 : 
    1468                 :         /* Create the pg_amop entry */
    1469             962 :         memset(values, 0, sizeof(values));
    1470             962 :         memset(nulls, false, sizeof(nulls));
    1471                 : 
    1472             962 :         entryoid = GetNewOidWithIndex(rel, AccessMethodOperatorOidIndexId,
    1473                 :                                       Anum_pg_amop_oid);
    1474             962 :         values[Anum_pg_amop_oid - 1] = ObjectIdGetDatum(entryoid);
    1475             962 :         values[Anum_pg_amop_amopfamily - 1] = ObjectIdGetDatum(opfamilyoid);
    1476             962 :         values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype);
    1477             962 :         values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype);
    1478             962 :         values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
    1479             962 :         values[Anum_pg_amop_amoppurpose - 1] = CharGetDatum(oppurpose);
    1480             962 :         values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
    1481             962 :         values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
    1482             962 :         values[Anum_pg_amop_amopsortfamily - 1] = ObjectIdGetDatum(op->sortfamily);
    1483                 : 
    1484             962 :         tup = heap_form_tuple(rel->rd_att, values, nulls);
    1485                 : 
    1486             962 :         CatalogTupleInsert(rel, tup);
    1487                 : 
    1488             962 :         heap_freetuple(tup);
    1489                 : 
    1490                 :         /* Make its dependencies */
    1491             962 :         myself.classId = AccessMethodOperatorRelationId;
    1492             962 :         myself.objectId = entryoid;
    1493             962 :         myself.objectSubId = 0;
    1494                 : 
    1495             962 :         referenced.classId = OperatorRelationId;
    1496             962 :         referenced.objectId = op->object;
    1497             962 :         referenced.objectSubId = 0;
    1498                 : 
    1499                 :         /* see comments in amapi.h about dependency strength */
    1500             962 :         recordDependencyOn(&myself, &referenced,
    1501             962 :                            op->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
    1502                 : 
    1503             962 :         referenced.classId = op->ref_is_family ? OperatorFamilyRelationId :
    1504                 :             OperatorClassRelationId;
    1505             962 :         referenced.objectId = op->refobjid;
    1506             962 :         referenced.objectSubId = 0;
    1507                 : 
    1508             962 :         recordDependencyOn(&myself, &referenced,
    1509             962 :                            op->ref_is_hard ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
    1510                 : 
    1511                 :         /* A search operator also needs a dep on the referenced opfamily */
    1512             962 :         if (OidIsValid(op->sortfamily))
    1513                 :         {
    1514              33 :             referenced.classId = OperatorFamilyRelationId;
    1515              33 :             referenced.objectId = op->sortfamily;
    1516              33 :             referenced.objectSubId = 0;
    1517                 : 
    1518              33 :             recordDependencyOn(&myself, &referenced,
    1519              33 :                                op->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
    1520                 :         }
    1521                 : 
    1522                 :         /* Post create hook of this access method operator */
    1523             962 :         InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
    1524                 :                                    entryoid, 0);
    1525                 :     }
    1526                 : 
    1527             307 :     table_close(rel, RowExclusiveLock);
    1528             307 : }
    1529                 : 
    1530                 : /*
    1531                 :  * Dump the procedures (support routines) to pg_amproc
    1532                 :  *
    1533                 :  * We also make dependency entries in pg_depend for the pg_amproc entries.
    1534                 :  */
    1535                 : static void
    1536             307 : storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
    1537                 :                 List *procedures, bool isAdd)
    1538                 : {
    1539                 :     Relation    rel;
    1540                 :     Datum       values[Natts_pg_amproc];
    1541                 :     bool        nulls[Natts_pg_amproc];
    1542                 :     HeapTuple   tup;
    1543                 :     Oid         entryoid;
    1544                 :     ObjectAddress myself,
    1545                 :                 referenced;
    1546                 :     ListCell   *l;
    1547                 : 
    1548             307 :     rel = table_open(AccessMethodProcedureRelationId, RowExclusiveLock);
    1549                 : 
    1550            1001 :     foreach(l, procedures)
    1551                 :     {
    1552             694 :         OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
    1553                 : 
    1554                 :         /*
    1555                 :          * If adding to an existing family, check for conflict with an
    1556                 :          * existing pg_amproc entry (just to give a nicer error message)
    1557                 :          */
    1558             794 :         if (isAdd &&
    1559             100 :             SearchSysCacheExists4(AMPROCNUM,
    1560                 :                                   ObjectIdGetDatum(opfamilyoid),
    1561                 :                                   ObjectIdGetDatum(proc->lefttype),
    1562                 :                                   ObjectIdGetDatum(proc->righttype),
    1563                 :                                   Int16GetDatum(proc->number)))
    1564 UBC           0 :             ereport(ERROR,
    1565                 :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
    1566                 :                      errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
    1567                 :                             proc->number,
    1568                 :                             format_type_be(proc->lefttype),
    1569                 :                             format_type_be(proc->righttype),
    1570                 :                             NameListToString(opfamilyname))));
    1571                 : 
    1572                 :         /* Create the pg_amproc entry */
    1573 CBC         694 :         memset(values, 0, sizeof(values));
    1574             694 :         memset(nulls, false, sizeof(nulls));
    1575                 : 
    1576             694 :         entryoid = GetNewOidWithIndex(rel, AccessMethodProcedureOidIndexId,
    1577                 :                                       Anum_pg_amproc_oid);
    1578             694 :         values[Anum_pg_amproc_oid - 1] = ObjectIdGetDatum(entryoid);
    1579             694 :         values[Anum_pg_amproc_amprocfamily - 1] = ObjectIdGetDatum(opfamilyoid);
    1580             694 :         values[Anum_pg_amproc_amproclefttype - 1] = ObjectIdGetDatum(proc->lefttype);
    1581             694 :         values[Anum_pg_amproc_amprocrighttype - 1] = ObjectIdGetDatum(proc->righttype);
    1582             694 :         values[Anum_pg_amproc_amprocnum - 1] = Int16GetDatum(proc->number);
    1583             694 :         values[Anum_pg_amproc_amproc - 1] = ObjectIdGetDatum(proc->object);
    1584                 : 
    1585             694 :         tup = heap_form_tuple(rel->rd_att, values, nulls);
    1586                 : 
    1587             694 :         CatalogTupleInsert(rel, tup);
    1588                 : 
    1589             694 :         heap_freetuple(tup);
    1590                 : 
    1591                 :         /* Make its dependencies */
    1592             694 :         myself.classId = AccessMethodProcedureRelationId;
    1593             694 :         myself.objectId = entryoid;
    1594             694 :         myself.objectSubId = 0;
    1595                 : 
    1596             694 :         referenced.classId = ProcedureRelationId;
    1597             694 :         referenced.objectId = proc->object;
    1598             694 :         referenced.objectSubId = 0;
    1599                 : 
    1600                 :         /* see comments in amapi.h about dependency strength */
    1601             694 :         recordDependencyOn(&myself, &referenced,
    1602             694 :                            proc->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
    1603                 : 
    1604             694 :         referenced.classId = proc->ref_is_family ? OperatorFamilyRelationId :
    1605                 :             OperatorClassRelationId;
    1606             694 :         referenced.objectId = proc->refobjid;
    1607             694 :         referenced.objectSubId = 0;
    1608                 : 
    1609             694 :         recordDependencyOn(&myself, &referenced,
    1610             694 :                            proc->ref_is_hard ? DEPENDENCY_INTERNAL : DEPENDENCY_AUTO);
    1611                 : 
    1612                 :         /* Post create hook of access method procedure */
    1613             694 :         InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
    1614                 :                                    entryoid, 0);
    1615                 :     }
    1616                 : 
    1617             307 :     table_close(rel, RowExclusiveLock);
    1618             307 : }
    1619                 : 
    1620                 : 
    1621                 : /*
    1622                 :  * Remove operator entries from an opfamily.
    1623                 :  *
    1624                 :  * Note: this is only allowed for "loose" members of an opfamily, hence
    1625                 :  * behavior is always RESTRICT.
    1626                 :  */
    1627                 : static void
    1628              27 : dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
    1629                 :               List *operators)
    1630                 : {
    1631                 :     ListCell   *l;
    1632                 : 
    1633              49 :     foreach(l, operators)
    1634                 :     {
    1635              25 :         OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
    1636                 :         Oid         amopid;
    1637                 :         ObjectAddress object;
    1638                 : 
    1639              25 :         amopid = GetSysCacheOid4(AMOPSTRATEGY, Anum_pg_amop_oid,
    1640                 :                                  ObjectIdGetDatum(opfamilyoid),
    1641                 :                                  ObjectIdGetDatum(op->lefttype),
    1642                 :                                  ObjectIdGetDatum(op->righttype),
    1643                 :                                  Int16GetDatum(op->number));
    1644              25 :         if (!OidIsValid(amopid))
    1645               3 :             ereport(ERROR,
    1646                 :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    1647                 :                      errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
    1648                 :                             op->number,
    1649                 :                             format_type_be(op->lefttype),
    1650                 :                             format_type_be(op->righttype),
    1651                 :                             NameListToString(opfamilyname))));
    1652                 : 
    1653              22 :         object.classId = AccessMethodOperatorRelationId;
    1654              22 :         object.objectId = amopid;
    1655              22 :         object.objectSubId = 0;
    1656                 : 
    1657              22 :         performDeletion(&object, DROP_RESTRICT, 0);
    1658                 :     }
    1659              24 : }
    1660                 : 
    1661                 : /*
    1662                 :  * Remove procedure entries from an opfamily.
    1663                 :  *
    1664                 :  * Note: this is only allowed for "loose" members of an opfamily, hence
    1665                 :  * behavior is always RESTRICT.
    1666                 :  */
    1667                 : static void
    1668              24 : dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
    1669                 :                List *procedures)
    1670                 : {
    1671                 :     ListCell   *l;
    1672                 : 
    1673              38 :     foreach(l, procedures)
    1674                 :     {
    1675              17 :         OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
    1676                 :         Oid         amprocid;
    1677                 :         ObjectAddress object;
    1678                 : 
    1679              17 :         amprocid = GetSysCacheOid4(AMPROCNUM, Anum_pg_amproc_oid,
    1680                 :                                    ObjectIdGetDatum(opfamilyoid),
    1681                 :                                    ObjectIdGetDatum(op->lefttype),
    1682                 :                                    ObjectIdGetDatum(op->righttype),
    1683                 :                                    Int16GetDatum(op->number));
    1684              17 :         if (!OidIsValid(amprocid))
    1685               3 :             ereport(ERROR,
    1686                 :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
    1687                 :                      errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
    1688                 :                             op->number,
    1689                 :                             format_type_be(op->lefttype),
    1690                 :                             format_type_be(op->righttype),
    1691                 :                             NameListToString(opfamilyname))));
    1692                 : 
    1693              14 :         object.classId = AccessMethodProcedureRelationId;
    1694              14 :         object.objectId = amprocid;
    1695              14 :         object.objectSubId = 0;
    1696                 : 
    1697              14 :         performDeletion(&object, DROP_RESTRICT, 0);
    1698                 :     }
    1699              21 : }
    1700                 : 
    1701                 : /*
    1702                 :  * Subroutine for ALTER OPERATOR CLASS SET SCHEMA/RENAME
    1703                 :  *
    1704                 :  * Is there an operator class with the given name and signature already
    1705                 :  * in the given namespace?  If so, raise an appropriate error message.
    1706                 :  */
    1707                 : void
    1708              18 : IsThereOpClassInNamespace(const char *opcname, Oid opcmethod,
    1709                 :                           Oid opcnamespace)
    1710                 : {
    1711                 :     /* make sure the new name doesn't exist */
    1712              18 :     if (SearchSysCacheExists3(CLAAMNAMENSP,
    1713                 :                               ObjectIdGetDatum(opcmethod),
    1714                 :                               CStringGetDatum(opcname),
    1715                 :                               ObjectIdGetDatum(opcnamespace)))
    1716               6 :         ereport(ERROR,
    1717                 :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
    1718                 :                  errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
    1719                 :                         opcname,
    1720                 :                         get_am_name(opcmethod),
    1721                 :                         get_namespace_name(opcnamespace))));
    1722              12 : }
    1723                 : 
    1724                 : /*
    1725                 :  * Subroutine for ALTER OPERATOR FAMILY SET SCHEMA/RENAME
    1726                 :  *
    1727                 :  * Is there an operator family with the given name and signature already
    1728                 :  * in the given namespace?  If so, raise an appropriate error message.
    1729                 :  */
    1730                 : void
    1731              18 : IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod,
    1732                 :                            Oid opfnamespace)
    1733                 : {
    1734                 :     /* make sure the new name doesn't exist */
    1735              18 :     if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
    1736                 :                               ObjectIdGetDatum(opfmethod),
    1737                 :                               CStringGetDatum(opfname),
    1738                 :                               ObjectIdGetDatum(opfnamespace)))
    1739               6 :         ereport(ERROR,
    1740                 :                 (errcode(ERRCODE_DUPLICATE_OBJECT),
    1741                 :                  errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
    1742                 :                         opfname,
    1743                 :                         get_am_name(opfmethod),
    1744                 :                         get_namespace_name(opfnamespace))));
    1745              12 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a