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 17:13:01 Functions: 100.0 % 20 20 2 18
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (120,180] days: 100.0 % 2 2 2
Legend: Lines: hit not hit (240..) days: 91.7 % 568 521 47 521
Function coverage date bins:
(240..) days: 100.0 % 20 20 2 18

 Age         Owner                  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
 4630 rhaas                      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 */
 5951 tgl                        88             410 :     DeconstructQualifiedName(opfamilyname, &schemaname, &opfname);
                                 89                 : 
                                 90             410 :     if (schemaname)
                                 91                 :     {
                                 92                 :         /* Look in specific schema only */
                                 93                 :         Oid         namespaceId;
                                 94                 : 
 3363 alvherre                   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 */
 5624 bruce                     107             361 :         Oid         opfID = OpfamilynameGetOpfid(amID, opfname);
                                108                 : 
 5951 tgl                       109             361 :         if (!OidIsValid(opfID))
 4630 rhaas                     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))
 4630 rhaas                     121 UBC           0 :             elog(ERROR, "cache lookup failed for access method %u", amID);
 4630 rhaas                     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;
 1601 andres                    148             398 :     opfamform = (Form_pg_opfamily) GETSTRUCT(htup);
                                149             398 :     opfID = opfamform->oid;
 4630 rhaas                     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 */
 5951 tgl                       169             107 :     DeconstructQualifiedName(opclassname, &schemaname, &opcname);
                                170                 : 
                                171             107 :     if (schemaname)
                                172                 :     {
                                173                 :         /* Look in specific schema only */
                                174                 :         Oid         namespaceId;
                                175                 : 
 3363 alvherre                  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 */
 5624 bruce                     188              94 :         Oid         opcID = OpclassnameGetOpcid(amID, opcname);
                                189                 : 
 5951 tgl                       190              94 :         if (!OidIsValid(opcID))
 4630 rhaas                     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))
 4630 rhaas                     202 UBC           0 :             elog(ERROR, "cache lookup failed for access method %u", amID);
 4630 rhaas                     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;
 1601 andres                    229              98 :     opcform = (Form_pg_opclass) GETSTRUCT(htup);
                                230              98 :     opcID = opcform->oid;
 4630 rhaas                     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
  324 alvherre                  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                 : 
 1539 andres                    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                 :      */
 4802 rhaas                     261             229 :     if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
                                262                 :                               ObjectIdGetDatum(amoid),
                                263                 :                               CStringGetDatum(opfname),
                                264                 :                               ObjectIdGetDatum(namespaceoid)))
 5951 tgl                       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                 :      */
 5951 tgl                       273 CBC         229 :     memset(values, 0, sizeof(values));
 5271                           274             229 :     memset(nulls, false, sizeof(nulls));
                                275                 : 
 1601 andres                    276             229 :     opfamilyoid = GetNewOidWithIndex(rel, OpfamilyOidIndexId,
                                277                 :                                      Anum_pg_opfamily_oid);
                                278             229 :     values[Anum_pg_opfamily_oid - 1] = ObjectIdGetDatum(opfamilyoid);
 5951 tgl                       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                 : 
 5271                           285             229 :     tup = heap_form_tuple(rel->rd_att, values, nulls);
                                286                 : 
 1601 andres                    287             229 :     CatalogTupleInsert(rel, tup);
                                288                 : 
 5951 tgl                       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 */
 2552                           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 */
 5951                           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 */
 4278                           314             229 :     recordDependencyOnCurrentExtension(&myself, false);
                                315                 : 
                                316                 :     /* Report the new operator family to possibly interested event triggers */
  324 alvherre                  317             229 :     EventTriggerCollectSimpleCommand(myself, InvalidObjectAddress,
                                318                 :                                      (Node *) stmt);
                                319                 : 
                                320                 :     /* Post creation hook for new operator family */
 3686 rhaas                     321             229 :     InvokeObjectPostCreateHook(OperatorFamilyRelationId, opfamilyoid, 0);
                                322                 : 
 1539 andres                    323             229 :     table_close(rel, RowExclusiveLock);
                                324                 : 
 2959 alvherre                  325             229 :     return myself;
                                326                 : }
                                327                 : 
                                328                 : /*
                                329                 :  * DefineOpClass
                                330                 :  *      Define a new index operator class.
                                331                 :  */
                                332                 : ObjectAddress
 7559 tgl                       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 */
  147 peter                     365 GNC         183 :     aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE);
 7559 tgl                       366 CBC         183 :     if (aclresult != ACLCHECK_OK)
 1954 peter_e                   367 UBC           0 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
 7191 tgl                       368               0 :                        get_namespace_name(namespaceoid));
                                369                 : 
                                370                 :     /* Get necessary info about access method */
 4802 rhaas                     371 CBC         183 :     tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
 7559 tgl                       372             183 :     if (!HeapTupleIsValid(tup))
 7205 tgl                       373 UBC           0 :         ereport(ERROR,
                                374                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                                375                 :                  errmsg("access method \"%s\" does not exist",
                                376                 :                         stmt->amname)));
                                377                 : 
 1601 andres                    378 CBC         183 :     amform = (Form_pg_am) GETSTRUCT(tup);
                                379             183 :     amoid = amform->oid;
 2430 tgl                       380             183 :     amroutine = GetIndexAmRoutineByAmId(amoid, false);
 2639                           381             183 :     ReleaseSysCache(tup);
                                382                 : 
                                383             183 :     maxOpNumber = amroutine->amstrategies;
                                384                 :     /* if amstrategies is zero, just enforce that op numbers fit in int16 */
 5956                           385             183 :     if (maxOpNumber <= 0)
                                386              88 :         maxOpNumber = SHRT_MAX;
 2639                           387             183 :     maxProcNumber = amroutine->amsupport;
 1105 akorotkov                 388             183 :     optsProcNumber = amroutine->amoptsprocnum;
 2639 tgl                       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                 :      */
 7492                           413             183 :     if (!superuser())
 7205 tgl                       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 */
 4549 peter_e                   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                 :      */
 5951 tgl                       432             183 :     if (stmt->opfamilyname)
                                433                 :     {
 4630 rhaas                     434              22 :         opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
                                435                 :     }
                                436                 :     else
                                437                 :     {
                                438                 :         /* Lookup existing family of same name and namespace */
 4802                           439             161 :         tup = SearchSysCache3(OPFAMILYAMNAMENSP,
                                440                 :                               ObjectIdGetDatum(amoid),
                                441                 :                               PointerGetDatum(opcname),
                                442                 :                               ObjectIdGetDatum(namespaceoid));
 5951 tgl                       443             161 :         if (HeapTupleIsValid(tup))
                                444                 :         {
 1601 andres                    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                 :              */
 5951 tgl                       451               6 :             ReleaseSysCache(tup);
                                452                 :         }
                                453                 :         else
                                454                 :         {
                                455                 :             CreateOpFamilyStmt *opfstmt;
                                456                 :             ObjectAddress tmpAddr;
                                457                 : 
  324 alvherre                  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);
 2959                           466             155 :             opfamilyoid = tmpAddr.objectId;
                                467                 :         }
                                468                 :     }
                                469                 : 
 7088 tgl                       470             183 :     operators = NIL;
                                471             183 :     procedures = NIL;
                                472                 : 
                                473                 :     /* Storage datatype is optional */
 7559                           474             183 :     storageoid = InvalidOid;
                                475                 : 
                                476                 :     /*
                                477                 :      * Scan the "items" list to obtain additional info.
                                478                 :      */
 7088                           479            1580 :     foreach(l, stmt->items)
                                480                 :     {
 2190                           481            1397 :         CreateOpClassItem *item = lfirst_node(CreateOpClassItem, l);
                                482                 :         Oid         operOid;
                                483                 :         Oid         funcOid;
                                484                 :         Oid         sortfamilyOid;
                                485                 :         OpFamilyMember *member;
                                486                 : 
 7559                           487            1397 :         switch (item->itemtype)
                                488                 :         {
                                489             707 :             case OPCLASS_ITEM_OPERATOR:
 5956                           490             707 :                 if (item->number <= 0 || item->number > maxOpNumber)
 7205 tgl                       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)));
 2293 peter_e                   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                 : 
 4519 tgl                       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 */
 5951                           526             707 :                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
  981                           527             707 :                 member->is_func = false;
 7088                           528             707 :                 member->object = operOid;
                                529             707 :                 member->number = item->number;
 4519                           530             707 :                 member->sortfamily = sortfamilyOid;
 5951                           531             707 :                 assignOperTypes(member, amoid, typeoid);
  981                           532             707 :                 addFamilyMember(&operators, member);
 7559                           533             707 :                 break;
                                534             594 :             case OPCLASS_ITEM_FUNCTION:
 5956                           535             594 :                 if (item->number <= 0 || item->number > maxProcNumber)
 7205 tgl                       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)));
 1956 peter_e                   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 */
 5951 tgl                       550             594 :                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
  981                           551             594 :                 member->is_func = true;
 7088                           552             594 :                 member->object = funcOid;
                                553             594 :                 member->number = item->number;
                                554                 : 
                                555                 :                 /* allow overriding of the function's actual arg types */
 5920                           556             594 :                 if (item->class_args)
 5920 tgl                       557 UBC           0 :                     processTypesSpec(item->class_args,
                                558                 :                                      &member->lefttype, &member->righttype);
                                559                 : 
 1105 akorotkov                 560 CBC         594 :                 assignProcTypes(member, amoid, typeoid, optsProcNumber);
  981 tgl                       561             594 :                 addFamilyMember(&procedures, member);
 7559                           562             594 :                 break;
                                563              96 :             case OPCLASS_ITEM_STORAGETYPE:
                                564              96 :                 if (OidIsValid(storageoid))
 7205 tgl                       565 UBC           0 :                     ereport(ERROR,
                                566                 :                             (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                567                 :                              errmsg("storage type specified more than once")));
 4549 peter_e                   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
 7559 tgl                       576              96 :                 break;
 7559 tgl                       577 UBC           0 :             default:
 7205                           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                 :      */
 7559 tgl                       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;
 6186                           591              49 :         else if (!amstorage)
 6186 tgl                       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                 : 
 1539 andres                    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                 :      */
 4802 rhaas                     604             183 :     if (SearchSysCacheExists3(CLAAMNAMENSP,
                                605                 :                               ObjectIdGetDatum(amoid),
                                606                 :                               CStringGetDatum(opcname),
                                607                 :                               ObjectIdGetDatum(namespaceoid)))
 7205 tgl                       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                 :      */
 7559 tgl                       618 CBC         183 :     if (stmt->isDefault)
                                619                 :     {
                                620                 :         ScanKeyData skey[1];
                                621                 :         SysScanDesc scan;
                                622                 : 
 7088                           623             134 :         ScanKeyInit(&skey[0],
                                624                 :                     Anum_pg_opclass_opcmethod,
                                625                 :                     BTEqualStrategyNumber, F_OIDEQ,
                                626                 :                     ObjectIdGetDatum(amoid));
                                627                 : 
 6569                           628             134 :         scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
                                629                 :                                   NULL, 1, skey);
                                630                 : 
 7559                           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)
 7205 tgl                       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                 : 
 7559 tgl                       645 CBC         134 :         systable_endscan(scan);
                                646                 :     }
                                647                 : 
                                648                 :     /*
                                649                 :      * Okay, let's create the pg_opclass entry.
                                650                 :      */
 5951                           651             183 :     memset(values, 0, sizeof(values));
 5271                           652             183 :     memset(nulls, false, sizeof(nulls));
                                653                 : 
 1601 andres                    654             183 :     opclassoid = GetNewOidWithIndex(rel, OpclassOidIndexId,
                                655                 :                                     Anum_pg_opclass_oid);
                                656             183 :     values[Anum_pg_opclass_oid - 1] = ObjectIdGetDatum(opclassoid);
 5951 tgl                       657             183 :     values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid);
 7559                           658             183 :     namestrcpy(&opcName, opcname);
 5951                           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                 : 
 5271                           667             183 :     tup = heap_form_tuple(rel->rd_att, values, nulls);
                                668                 : 
 1601 andres                    669             183 :     CatalogTupleInsert(rel, tup);
                                670                 : 
 7559 tgl                       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                 :      */
  981                           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                 :      */
 5920                           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 */
 2890 alvherre                  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                 :      */
 6569 tgl                       721             183 :     myself.classId = OperatorClassRelationId;
 7559                           722             183 :     myself.objectId = opclassoid;
                                723             183 :     myself.objectSubId = 0;
                                724                 : 
                                725                 :     /* dependency on namespace */
 6569                           726             183 :     referenced.classId = NamespaceRelationId;
 7559                           727             183 :     referenced.objectId = namespaceoid;
                                728             183 :     referenced.objectSubId = 0;
                                729             183 :     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
                                730                 : 
                                731                 :     /* dependency on opfamily */
 5951                           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 */
 6569                           738             183 :     referenced.classId = TypeRelationId;
 7559                           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                 :     {
 6569                           746              49 :         referenced.classId = TypeRelationId;
 7559                           747              49 :         referenced.objectId = storageoid;
                                748              49 :         referenced.objectSubId = 0;
                                749              49 :         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
                                750                 :     }
                                751                 : 
                                752                 :     /* dependency on owner */
 6485                           753             183 :     recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
                                754                 : 
                                755                 :     /* dependency on extension */
 4278                           756             183 :     recordDependencyOnCurrentExtension(&myself, false);
                                757                 : 
                                758                 :     /* Post creation hook for new operator class */
 3686 rhaas                     759             183 :     InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
                                760                 : 
 1539 andres                    761             183 :     table_close(rel, RowExclusiveLock);
                                762                 : 
 2959 alvherre                  763             183 :     return myself;
                                764                 : }
                                765                 : 
                                766                 : 
                                767                 : /*
                                768                 :  * DefineOpFamily
                                769                 :  *      Define a new index operator family.
                                770                 :  */
                                771                 : ObjectAddress
 5624 bruce                     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 */
 5920 tgl                       780              74 :     namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
                                781                 :                                                      &opfname);
                                782                 : 
                                783                 :     /* Check we have creation rights in target namespace */
  147 peter                     784 GNC          74 :     aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE);
 5920 tgl                       785 CBC          74 :     if (aclresult != ACLCHECK_OK)
 1954 peter_e                   786 UBC           0 :         aclcheck_error(aclresult, OBJECT_SCHEMA,
 5920 tgl                       787               0 :                        get_namespace_name(namespaceoid));
                                788                 : 
                                789                 :     /* Get access method OID, throwing an error if it doesn't exist. */
 2573 alvherre                  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                 :      */
 5920 tgl                       798              74 :     if (!superuser())
 7088 tgl                       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 */
  324 alvherre                  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
 5624 bruce                     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 */
 4802 rhaas                     829             223 :     tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
 5920 tgl                       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                 : 
 1601 andres                    836             220 :     amform = (Form_pg_am) GETSTRUCT(tup);
                                837             220 :     amoid = amform->oid;
 2430 tgl                       838             220 :     amroutine = GetIndexAmRoutineByAmId(amoid, false);
 2639                           839             220 :     ReleaseSysCache(tup);
                                840                 : 
                                841             220 :     maxOpNumber = amroutine->amstrategies;
                                842                 :     /* if amstrategies is zero, just enforce that op numbers fit in int16 */
 5920                           843             220 :     if (maxOpNumber <= 0)
                                844              73 :         maxOpNumber = SHRT_MAX;
 2639                           845             220 :     maxProcNumber = amroutine->amsupport;
 1105 akorotkov                 846             220 :     optsProcNumber = amroutine->amoptsprocnum;
                                847                 : 
                                848                 :     /* XXX Should we make any privilege check against the AM? */
                                849                 : 
                                850                 :     /* Look up the opfamily */
 4630 rhaas                     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                 :      */
 5920 tgl                       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)
 2890 alvherre                  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                 : 
 3753 rhaas                     874             145 :     return opfamilyoid;
                                875                 : }
                                876                 : 
                                877                 : /*
                                878                 :  * ADD part of ALTER OP FAMILY
                                879                 :  */
                                880                 : static void
 2890 alvherre                  881             184 : AlterOpFamilyAdd(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid,
                                882                 :                  int maxOpNumber, int maxProcNumber, int optsProcNumber,
                                883                 :                  List *items)
                                884                 : {
  981 tgl                       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                 : 
 5920                           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                 :     {
 2190                           898             451 :         CreateOpClassItem *item = lfirst_node(CreateOpClassItem, l);
                                899                 :         Oid         operOid;
                                900                 :         Oid         funcOid;
                                901                 :         Oid         sortfamilyOid;
                                902                 :         OpFamilyMember *member;
                                903                 : 
 5920                           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)));
 2293 peter_e                   913             300 :                 if (item->name->objargs != NIL)
                                914             297 :                     operOid = LookupOperWithArgs(item->name, false);
                                915                 :                 else
                                916                 :                 {
 5920 tgl                       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                 : 
 4519                           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 */
 5920                           943             297 :                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
  981                           944             297 :                 member->is_func = false;
 5920                           945             297 :                 member->object = operOid;
                                946             297 :                 member->number = item->number;
 4519                           947             297 :                 member->sortfamily = sortfamilyOid;
                                948                 :                 /* We can set up dependency fields immediately */
                                949                 :                 /* Historically, ALTER ADD has created soft dependencies */
  981                           950             297 :                 member->ref_is_hard = false;
                                951             297 :                 member->ref_is_family = true;
                                952             297 :                 member->refobjid = opfamilyoid;
 5920                           953             297 :                 assignOperTypes(member, amoid, InvalidOid);
  981                           954             294 :                 addFamilyMember(&operators, member);
 5920                           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)));
 1956 peter_e                   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 */
 5920 tgl                       973             133 :                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
  981                           974             133 :                 member->is_func = true;
 5920                           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 */
  981                           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 */
 5920                           984             133 :                 if (item->class_args)
                                985              68 :                     processTypesSpec(item->class_args,
                                986                 :                                      &member->lefttype, &member->righttype);
                                987                 : 
 1105 akorotkov                 988             133 :                 assignProcTypes(member, amoid, InvalidOid, optsProcNumber);
  981 tgl                       989             109 :                 addFamilyMember(&procedures, member);
 5920                           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;
 5920 tgl                       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                 :      */
  981 tgl                      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                 :      */
 2890 alvherre                 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);
 5920 tgl                      1024             124 : }
                               1025                 : 
                               1026                 : /*
                               1027                 :  * DROP part of ALTER OP FAMILY
                               1028                 :  */
                               1029                 : static void
 2890 alvherre                 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                 : 
 5920 tgl                      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                 :     {
 2190                          1045              45 :         CreateOpClassItem *item = lfirst_node(CreateOpClassItem, l);
                               1046                 :         Oid         lefttype,
                               1047                 :                     righttype;
                               1048                 :         OpFamilyMember *member;
                               1049                 : 
 5920                          1050              45 :         switch (item->itemtype)
                               1051                 :         {
                               1052              28 :             case OPCLASS_ITEM_OPERATOR:
                               1053              28 :                 if (item->number <= 0 || item->number > maxOpNumber)
 5920 tgl                      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)));
 2293 peter_e                  1059 CBC          28 :                 processTypesSpec(item->class_args, &lefttype, &righttype);
                               1060                 :                 /* Save the info */
 5920 tgl                      1061              25 :                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
  981                          1062              25 :                 member->is_func = false;
 5920                          1063              25 :                 member->number = item->number;
                               1064              25 :                 member->lefttype = lefttype;
                               1065              25 :                 member->righttype = righttype;
  981                          1066              25 :                 addFamilyMember(&operators, member);
 5920                          1067              25 :                 break;
                               1068              17 :             case OPCLASS_ITEM_FUNCTION:
                               1069              17 :                 if (item->number <= 0 || item->number > maxProcNumber)
 5920 tgl                      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)));
 2293 peter_e                  1075 CBC          17 :                 processTypesSpec(item->class_args, &lefttype, &righttype);
                               1076                 :                 /* Save the info */
 5920 tgl                      1077              17 :                 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
  981                          1078              17 :                 member->is_func = true;
 5920                          1079              17 :                 member->number = item->number;
                               1080              17 :                 member->lefttype = lefttype;
                               1081              17 :                 member->righttype = righttype;
  981                          1082              17 :                 addFamilyMember(&procedures, member);
 5920                          1083              17 :                 break;
 5920 tgl                      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                 :      */
 2890 alvherre                 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);
 5920 tgl                      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);
 4549 peter_e                  1115             113 :     *lefttype = typenameTypeId(NULL, typeName);
                               1116                 : 
 5920 tgl                      1117             113 :     if (list_length(args) > 1)
                               1118                 :     {
                               1119              85 :         typeName = (TypeName *) lsecond(args);
 4549 peter_e                  1120              85 :         *righttype = typenameTypeId(NULL, typeName);
                               1121                 :     }
                               1122                 :     else
 5920 tgl                      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
 5624 bruce                    1137            1004 : assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
                               1138                 : {
                               1139                 :     Operator    optup;
                               1140                 :     Form_pg_operator opform;
                               1141                 : 
                               1142                 :     /* Fetch the operator definition */
 4802 rhaas                    1143            1004 :     optup = SearchSysCache1(OPEROID, ObjectIdGetDatum(member->object));
 1435 tgl                      1144            1004 :     if (!HeapTupleIsValid(optup))
 5920 tgl                      1145 UBC           0 :         elog(ERROR, "cache lookup failed for operator %u", member->object);
 5920 tgl                      1146 CBC        1004 :     opform = (Form_pg_operator) GETSTRUCT(optup);
                               1147                 : 
                               1148                 :     /*
                               1149                 :      * Opfamily operators must be binary.
                               1150                 :      */
                               1151            1004 :     if (opform->oprkind != 'b')
 5920 tgl                      1152 UBC           0 :         ereport(ERROR,
                               1153                 :                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                               1154                 :                  errmsg("index operators must be binary")));
                               1155                 : 
 4519 tgl                      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                 :          */
 2430                          1168              36 :         IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
                               1169                 : 
 2639                          1170              36 :         if (!amroutine->amcanorderbyop)
 4519                          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)
 4519 tgl                      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                 :      */
 5920 tgl                      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
 1105 akorotkov                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 */
 4802 rhaas                    1210             727 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(member->object));
 1435 tgl                      1211             727 :     if (!HeapTupleIsValid(proctup))
 5920 tgl                      1212 UBC           0 :         elog(ERROR, "cache lookup failed for function %u", member->object);
 5920 tgl                      1213 CBC         727 :     procform = (Form_pg_proc) GETSTRUCT(proctup);
                               1214                 : 
                               1215                 :     /* Check the signature of the opclass options parsing function */
 1105 akorotkov                1216             727 :     if (member->number == opclassOptsProcNum)
                               1217                 :     {
                               1218              23 :         if (OidIsValid(typeoid))
                               1219                 :         {
 1105 akorotkov                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                 :         {
 1105 akorotkov                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                 :     {
 4141 tgl                      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)
 4141 tgl                      1278 UBC           0 :                 ereport(ERROR,
                               1279                 :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                               1280                 :                          errmsg("btree sort support functions must accept type \"internal\"")));
 4141 tgl                      1281 CBC           2 :             if (procform->prorettype != VOIDOID)
 4141 tgl                      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                 :         }
 1887 tgl                      1290 CBC           5 :         else if (member->number == BTINRANGE_PROC)
                               1291                 :         {
 1887 tgl                      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                 :         }
 1138 pg                       1310 CBC           5 :         else if (member->number == BTEQUALIMAGE_PROC)
                               1311                 :         {
                               1312               5 :             if (procform->pronargs != 1)
 1138 pg                       1313 UBC           0 :                 ereport(ERROR,
                               1314                 :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                               1315                 :                          errmsg("btree equal image functions must have one argument")));
 1138 pg                       1316 CBC           5 :             if (procform->prorettype != BOOLOID)
 1138 pg                       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                 :              */
 1138 pg                       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                 :     }
 5920 tgl                      1335             614 :     else if (amoid == HASH_AM_OID)
                               1336                 :     {
 2047 rhaas                    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)
 2047 rhaas                    1351 UBC           0 :                 ereport(ERROR,
                               1352                 :                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                               1353                 :                          errmsg("hash function 2 must have two arguments")));
 2047 rhaas                    1354 CBC          24 :             if (procform->prorettype != INT8OID)
 2047 rhaas                    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                 :          */
 5920 tgl                      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                 :      */
 4141                          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                 : 
 5920                          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
  981                          1392            1746 : addFamilyMember(List **list, OpFamilyMember *member)
                               1393                 : {
                               1394                 :     ListCell   *l;
                               1395                 : 
 5920                          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                 :         {
  981                          1404               6 :             if (member->is_func)
 5920                          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
 7088                          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
  981                          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                 : 
 1539 andres                   1441             313 :     rel = table_open(AccessMethodOperatorRelationId, RowExclusiveLock);
                               1442                 : 
 7088 tgl                      1443            1275 :     foreach(l, operators)
                               1444                 :     {
 5951                          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                 :          */
 5920                          1452            1229 :         if (isAdd &&
 4802 rhaas                    1453             261 :             SearchSysCacheExists4(AMOPSTRATEGY,
                               1454                 :                                   ObjectIdGetDatum(opfamilyoid),
                               1455                 :                                   ObjectIdGetDatum(op->lefttype),
                               1456                 :                                   ObjectIdGetDatum(op->righttype),
                               1457                 :                                   Int16GetDatum(op->number)))
 5920 tgl                      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                 : 
 4519                          1466             962 :         oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;
                               1467                 : 
                               1468                 :         /* Create the pg_amop entry */
 5951                          1469             962 :         memset(values, 0, sizeof(values));
 5271                          1470             962 :         memset(nulls, false, sizeof(nulls));
                               1471                 : 
 1601 andres                   1472             962 :         entryoid = GetNewOidWithIndex(rel, AccessMethodOperatorOidIndexId,
                               1473                 :                                       Anum_pg_amop_oid);
                               1474             962 :         values[Anum_pg_amop_oid - 1] = ObjectIdGetDatum(entryoid);
 5951 tgl                      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);
 4519                          1479             962 :         values[Anum_pg_amop_amoppurpose - 1] = CharGetDatum(oppurpose);
 5951                          1480             962 :         values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
                               1481             962 :         values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
 4519                          1482             962 :         values[Anum_pg_amop_amopsortfamily - 1] = ObjectIdGetDatum(op->sortfamily);
                               1483                 : 
 5271                          1484             962 :         tup = heap_form_tuple(rel->rd_att, values, nulls);
                               1485                 : 
 1601 andres                   1486             962 :         CatalogTupleInsert(rel, tup);
                               1487                 : 
 7559 tgl                      1488             962 :         heap_freetuple(tup);
                               1489                 : 
                               1490                 :         /* Make its dependencies */
 5951                          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 */
  981                          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 */
 4519                          1512             962 :         if (OidIsValid(op->sortfamily))
                               1513                 :         {
                               1514              33 :             referenced.classId = OperatorFamilyRelationId;
                               1515              33 :             referenced.objectId = op->sortfamily;
                               1516              33 :             referenced.objectSubId = 0;
                               1517                 : 
  981                          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 */
 3675 rhaas                    1523             962 :         InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
                               1524                 :                                    entryoid, 0);
                               1525                 :     }
                               1526                 : 
 1539 andres                   1527             307 :     table_close(rel, RowExclusiveLock);
 7559 tgl                      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
  981                          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                 : 
 1539 andres                   1548             307 :     rel = table_open(AccessMethodProcedureRelationId, RowExclusiveLock);
                               1549                 : 
 7088 tgl                      1550            1001 :     foreach(l, procedures)
                               1551                 :     {
 5951                          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                 :          */
 5920                          1558             794 :         if (isAdd &&
 4802 rhaas                    1559             100 :             SearchSysCacheExists4(AMPROCNUM,
                               1560                 :                                   ObjectIdGetDatum(opfamilyoid),
                               1561                 :                                   ObjectIdGetDatum(proc->lefttype),
                               1562                 :                                   ObjectIdGetDatum(proc->righttype),
                               1563                 :                                   Int16GetDatum(proc->number)))
 5920 tgl                      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 */
 5951 tgl                      1573 CBC         694 :         memset(values, 0, sizeof(values));
 5271                          1574             694 :         memset(nulls, false, sizeof(nulls));
                               1575                 : 
 1601 andres                   1576             694 :         entryoid = GetNewOidWithIndex(rel, AccessMethodProcedureOidIndexId,
                               1577                 :                                       Anum_pg_amproc_oid);
                               1578             694 :         values[Anum_pg_amproc_oid - 1] = ObjectIdGetDatum(entryoid);
 5951 tgl                      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                 : 
 5271                          1585             694 :         tup = heap_form_tuple(rel->rd_att, values, nulls);
                               1586                 : 
 1601 andres                   1587             694 :         CatalogTupleInsert(rel, tup);
                               1588                 : 
 7559 tgl                      1589             694 :         heap_freetuple(tup);
                               1590                 : 
                               1591                 :         /* Make its dependencies */
 5951                          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 */
  981                          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 */
 3675 rhaas                    1613             694 :         InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
                               1614                 :                                    entryoid, 0);
                               1615                 :     }
                               1616                 : 
 1539 andres                   1617             307 :     table_close(rel, RowExclusiveLock);
 7559 tgl                      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
 5920                          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                 : 
 1601 andres                   1639              25 :         amopid = GetSysCacheOid4(AMOPSTRATEGY, Anum_pg_amop_oid,
                               1640                 :                                  ObjectIdGetDatum(opfamilyoid),
                               1641                 :                                  ObjectIdGetDatum(op->lefttype),
                               1642                 :                                  ObjectIdGetDatum(op->righttype),
                               1643                 :                                  Int16GetDatum(op->number));
 5920 tgl                      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                 : 
 4091 rhaas                    1657              22 :         performDeletion(&object, DROP_RESTRICT, 0);
                               1658                 :     }
 5920 tgl                      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                 : 
 1601 andres                   1679              17 :         amprocid = GetSysCacheOid4(AMPROCNUM, Anum_pg_amproc_oid,
                               1680                 :                                    ObjectIdGetDatum(opfamilyoid),
                               1681                 :                                    ObjectIdGetDatum(op->lefttype),
                               1682                 :                                    ObjectIdGetDatum(op->righttype),
                               1683                 :                                    Int16GetDatum(op->number));
 5920 tgl                      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                 : 
 4091 rhaas                    1697              14 :         performDeletion(&object, DROP_RESTRICT, 0);
                               1698                 :     }
 5920 tgl                      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
 3730 alvherre                 1708              18 : IsThereOpClassInNamespace(const char *opcname, Oid opcmethod,
                               1709                 :                           Oid opcnamespace)
                               1710                 : {
                               1711                 :     /* make sure the new name doesn't exist */
 4802 rhaas                    1712              18 :     if (SearchSysCacheExists3(CLAAMNAMENSP,
                               1713                 :                               ObjectIdGetDatum(opcmethod),
                               1714                 :                               CStringGetDatum(opcname),
                               1715                 :                               ObjectIdGetDatum(opcnamespace)))
 7226 peter_e                  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
 3730 alvherre                 1731              18 : IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod,
                               1732                 :                            Oid opfnamespace)
                               1733                 : {
                               1734                 :     /* make sure the new name doesn't exist */
 4802 rhaas                    1735              18 :     if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
                               1736                 :                               ObjectIdGetDatum(opfmethod),
                               1737                 :                               CStringGetDatum(opfname),
                               1738                 :                               ObjectIdGetDatum(opfnamespace)))
 5920 tgl                      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))));
 6348 alvherre                 1745              12 : }
        

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