Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Functions

opclasscmds.c File Reference

#include "postgres.h"
#include <limits.h>
#include "access/genam.h"
#include "access/heapam.h"
#include "access/nbtree.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/alter.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
Include dependency graph for opclasscmds.c:

Go to the source code of this file.

Data Structures

struct  OpFamilyMember

Functions

static void AlterOpFamilyAdd (List *opfamilyname, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List *items)
static void AlterOpFamilyDrop (List *opfamilyname, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List *items)
static void processTypesSpec (List *args, Oid *lefttype, Oid *righttype)
static void assignOperTypes (OpFamilyMember *member, Oid amoid, Oid typeoid)
static void assignProcTypes (OpFamilyMember *member, Oid amoid, Oid typeoid)
static void addFamilyMember (List **list, OpFamilyMember *member, bool isProc)
static void storeOperators (List *opfamilyname, Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators, bool isAdd)
static void storeProcedures (List *opfamilyname, Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures, bool isAdd)
static void dropOperators (List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators)
static void dropProcedures (List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures)
static HeapTuple OpFamilyCacheLookup (Oid amID, List *opfamilyname, bool missing_ok)
Oid get_opfamily_oid (Oid amID, List *opfamilyname, bool missing_ok)
static HeapTuple OpClassCacheLookup (Oid amID, List *opclassname, bool missing_ok)
Oid get_opclass_oid (Oid amID, List *opclassname, bool missing_ok)
static Oid CreateOpFamily (char *amname, char *opfname, Oid namespaceoid, Oid amoid)
Oid DefineOpClass (CreateOpClassStmt *stmt)
Oid DefineOpFamily (CreateOpFamilyStmt *stmt)
Oid AlterOpFamily (AlterOpFamilyStmt *stmt)
void RemoveOpFamilyById (Oid opfamilyOid)
void RemoveOpClassById (Oid opclassOid)
void RemoveAmOpEntryById (Oid entryOid)
void RemoveAmProcEntryById (Oid entryOid)
static char * get_am_name (Oid amOid)
void IsThereOpClassInNamespace (const char *opcname, Oid opcmethod, Oid opcnamespace)
void IsThereOpFamilyInNamespace (const char *opfname, Oid opfmethod, Oid opfnamespace)
Oid get_am_oid (const char *amname, bool missing_ok)

Function Documentation

static void addFamilyMember ( List **  list,
OpFamilyMember member,
bool  isProc 
) [static]

Definition at line 1237 of file opclasscmds.c.

References ereport, errcode(), errmsg(), ERROR, format_type_be(), lappend(), OpFamilyMember::lefttype, lfirst, OpFamilyMember::number, and OpFamilyMember::righttype.

Referenced by AlterOpFamilyAdd(), AlterOpFamilyDrop(), and DefineOpClass().

{
    ListCell   *l;

    foreach(l, *list)
    {
        OpFamilyMember *old = (OpFamilyMember *) lfirst(l);

        if (old->number == member->number &&
            old->lefttype == member->lefttype &&
            old->righttype == member->righttype)
        {
            if (isProc)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                         errmsg("procedure number %d for (%s,%s) appears more than once",
                                member->number,
                                format_type_be(member->lefttype),
                                format_type_be(member->righttype))));
            else
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                         errmsg("operator number %d for (%s,%s) appears more than once",
                                member->number,
                                format_type_be(member->lefttype),
                                format_type_be(member->righttype))));
        }
    }
    *list = lappend(*list, member);
}

Oid AlterOpFamily ( AlterOpFamilyStmt stmt  ) 

Definition at line 770 of file opclasscmds.c.

References AlterOpFamilyAdd(), AlterOpFamilyDrop(), AlterOpFamilyStmt::amname, AMNAME, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, get_opfamily_oid(), GETSTRUCT, HeapTupleGetOid, HeapTupleIsValid, AlterOpFamilyStmt::isDrop, AlterOpFamilyStmt::items, AlterOpFamilyStmt::opfamilyname, ReleaseSysCache(), SearchSysCache1, and superuser().

Referenced by ProcessUtilitySlow().

{
    Oid         amoid,          /* our AM's oid */
                opfamilyoid;    /* oid of opfamily */
    int         maxOpNumber,    /* amstrategies value */
                maxProcNumber;  /* amsupport value */
    HeapTuple   tup;
    Form_pg_am  pg_am;

    /* Get necessary info about access method */
    tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
    if (!HeapTupleIsValid(tup))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("access method \"%s\" does not exist",
                        stmt->amname)));

    amoid = HeapTupleGetOid(tup);
    pg_am = (Form_pg_am) GETSTRUCT(tup);
    maxOpNumber = pg_am->amstrategies;
    /* if amstrategies is zero, just enforce that op numbers fit in int16 */
    if (maxOpNumber <= 0)
        maxOpNumber = SHRT_MAX;
    maxProcNumber = pg_am->amsupport;

    /* XXX Should we make any privilege check against the AM? */

    ReleaseSysCache(tup);

    /* Look up the opfamily */
    opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);

    /*
     * Currently, we require superuser privileges to alter an opfamily.
     *
     * XXX re-enable NOT_USED code sections below if you remove this test.
     */
    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("must be superuser to alter an operator family")));

    /*
     * ADD and DROP cases need separate code from here on down.
     */
    if (stmt->isDrop)
        AlterOpFamilyDrop(stmt->opfamilyname, amoid, opfamilyoid,
                          maxOpNumber, maxProcNumber,
                          stmt->items);
    else
        AlterOpFamilyAdd(stmt->opfamilyname, amoid, opfamilyoid,
                         maxOpNumber, maxProcNumber,
                         stmt->items);

    return opfamilyoid;
}

static void AlterOpFamilyAdd ( List opfamilyname,
Oid  amoid,
Oid  opfamilyoid,
int  maxOpNumber,
int  maxProcNumber,
List items 
) [static]

Definition at line 831 of file opclasscmds.c.

References ACL_KIND_OPER, ACL_KIND_PROC, aclcheck_error(), ACLCHECK_NOT_OWNER, addFamilyMember(), CreateOpClassItem::args, Assert, assignOperTypes(), assignProcTypes(), BTREE_AM_OID, CreateOpClassItem::class_args, elog, ereport, errcode(), errmsg(), ERROR, get_func_name(), get_opcode(), get_opfamily_oid(), get_opname(), GetUserId(), InvalidOid, IsA, CreateOpClassItem::itemtype, OpFamilyMember::lefttype, lfirst, linitial, LookupFuncNameTypeNames(), LookupOperNameTypeNames(), lsecond, CreateOpClassItem::name, NIL, NULL, OpFamilyMember::number, CreateOpClassItem::number, OpFamilyMember::object, OPCLASS_ITEM_FUNCTION, OPCLASS_ITEM_OPERATOR, OPCLASS_ITEM_STORAGETYPE, CreateOpClassItem::order_family, palloc0(), pg_oper_ownercheck(), pg_proc_ownercheck(), processTypesSpec(), OpFamilyMember::righttype, OpFamilyMember::sortfamily, storeOperators(), and storeProcedures().

Referenced by AlterOpFamily().

{
    List       *operators;      /* OpFamilyMember list for operators */
    List       *procedures;     /* OpFamilyMember list for support procs */
    ListCell   *l;

    operators = NIL;
    procedures = NIL;

    /*
     * Scan the "items" list to obtain additional info.
     */
    foreach(l, items)
    {
        CreateOpClassItem *item = lfirst(l);
        Oid         operOid;
        Oid         funcOid;
        Oid         sortfamilyOid;
        OpFamilyMember *member;

        Assert(IsA(item, CreateOpClassItem));
        switch (item->itemtype)
        {
            case OPCLASS_ITEM_OPERATOR:
                if (item->number <= 0 || item->number > maxOpNumber)
                    ereport(ERROR,
                            (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                             errmsg("invalid operator number %d,"
                                    " must be between 1 and %d",
                                    item->number, maxOpNumber)));
                if (item->args != NIL)
                {
                    TypeName   *typeName1 = (TypeName *) linitial(item->args);
                    TypeName   *typeName2 = (TypeName *) lsecond(item->args);

                    operOid = LookupOperNameTypeNames(NULL, item->name,
                                                      typeName1, typeName2,
                                                      false, -1);
                }
                else
                {
                    ereport(ERROR,
                            (errcode(ERRCODE_SYNTAX_ERROR),
                             errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
                    operOid = InvalidOid;       /* keep compiler quiet */
                }

                if (item->order_family)
                    sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
                                                     item->order_family,
                                                     false);
                else
                    sortfamilyOid = InvalidOid;

#ifdef NOT_USED
                /* XXX this is unnecessary given the superuser check above */
                /* Caller must own operator and its underlying function */
                if (!pg_oper_ownercheck(operOid, GetUserId()))
                    aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
                                   get_opname(operOid));
                funcOid = get_opcode(operOid);
                if (!pg_proc_ownercheck(funcOid, GetUserId()))
                    aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
                                   get_func_name(funcOid));
#endif

                /* Save the info */
                member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
                member->object = operOid;
                member->number = item->number;
                member->sortfamily = sortfamilyOid;
                assignOperTypes(member, amoid, InvalidOid);
                addFamilyMember(&operators, member, false);
                break;
            case OPCLASS_ITEM_FUNCTION:
                if (item->number <= 0 || item->number > maxProcNumber)
                    ereport(ERROR,
                            (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                             errmsg("invalid procedure number %d,"
                                    " must be between 1 and %d",
                                    item->number, maxProcNumber)));
                funcOid = LookupFuncNameTypeNames(item->name, item->args,
                                                  false);
#ifdef NOT_USED
                /* XXX this is unnecessary given the superuser check above */
                /* Caller must own function */
                if (!pg_proc_ownercheck(funcOid, GetUserId()))
                    aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
                                   get_func_name(funcOid));
#endif

                /* Save the info */
                member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
                member->object = funcOid;
                member->number = item->number;

                /* allow overriding of the function's actual arg types */
                if (item->class_args)
                    processTypesSpec(item->class_args,
                                     &member->lefttype, &member->righttype);

                assignProcTypes(member, amoid, InvalidOid);
                addFamilyMember(&procedures, member, true);
                break;
            case OPCLASS_ITEM_STORAGETYPE:
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
                break;
            default:
                elog(ERROR, "unrecognized item type: %d", item->itemtype);
                break;
        }
    }

    /*
     * Add tuples to pg_amop and pg_amproc tying in the operators and
     * functions.  Dependencies on them are inserted, too.
     */
    storeOperators(opfamilyname, amoid, opfamilyoid,
                   InvalidOid, operators, true);
    storeProcedures(opfamilyname, amoid, opfamilyoid,
                    InvalidOid, procedures, true);
}

static void AlterOpFamilyDrop ( List opfamilyname,
Oid  amoid,
Oid  opfamilyoid,
int  maxOpNumber,
int  maxProcNumber,
List items 
) [static]

Definition at line 962 of file opclasscmds.c.

References addFamilyMember(), CreateOpClassItem::args, Assert, dropOperators(), dropProcedures(), elog, ereport, errcode(), errmsg(), ERROR, IsA, CreateOpClassItem::itemtype, OpFamilyMember::lefttype, lfirst, OpFamilyMember::number, CreateOpClassItem::number, OPCLASS_ITEM_FUNCTION, OPCLASS_ITEM_OPERATOR, OPCLASS_ITEM_STORAGETYPE, palloc0(), processTypesSpec(), and OpFamilyMember::righttype.

Referenced by AlterOpFamily().

{
    List       *operators;      /* OpFamilyMember list for operators */
    List       *procedures;     /* OpFamilyMember list for support procs */
    ListCell   *l;

    operators = NIL;
    procedures = NIL;

    /*
     * Scan the "items" list to obtain additional info.
     */
    foreach(l, items)
    {
        CreateOpClassItem *item = lfirst(l);
        Oid         lefttype,
                    righttype;
        OpFamilyMember *member;

        Assert(IsA(item, CreateOpClassItem));
        switch (item->itemtype)
        {
            case OPCLASS_ITEM_OPERATOR:
                if (item->number <= 0 || item->number > maxOpNumber)
                    ereport(ERROR,
                            (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                             errmsg("invalid operator number %d,"
                                    " must be between 1 and %d",
                                    item->number, maxOpNumber)));
                processTypesSpec(item->args, &lefttype, &righttype);
                /* Save the info */
                member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
                member->number = item->number;
                member->lefttype = lefttype;
                member->righttype = righttype;
                addFamilyMember(&operators, member, false);
                break;
            case OPCLASS_ITEM_FUNCTION:
                if (item->number <= 0 || item->number > maxProcNumber)
                    ereport(ERROR,
                            (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                             errmsg("invalid procedure number %d,"
                                    " must be between 1 and %d",
                                    item->number, maxProcNumber)));
                processTypesSpec(item->args, &lefttype, &righttype);
                /* Save the info */
                member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
                member->number = item->number;
                member->lefttype = lefttype;
                member->righttype = righttype;
                addFamilyMember(&procedures, member, true);
                break;
            case OPCLASS_ITEM_STORAGETYPE:
                /* grammar prevents this from appearing */
            default:
                elog(ERROR, "unrecognized item type: %d", item->itemtype);
                break;
        }
    }

    /*
     * Remove tuples from pg_amop and pg_amproc.
     */
    dropOperators(opfamilyname, amoid, opfamilyoid, operators);
    dropProcedures(opfamilyname, amoid, opfamilyoid, procedures);
}

static void assignOperTypes ( OpFamilyMember member,
Oid  amoid,
Oid  typeoid 
) [static]

Definition at line 1065 of file opclasscmds.c.

References AMOID, BOOLOID, elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, OpFamilyMember::lefttype, NameStr, NULL, OpFamilyMember::object, ObjectIdGetDatum, OidIsValid, OPEROID, ReleaseSysCache(), OpFamilyMember::righttype, SearchSysCache1, and OpFamilyMember::sortfamily.

Referenced by AlterOpFamilyAdd(), and DefineOpClass().

{
    Operator    optup;
    Form_pg_operator opform;

    /* Fetch the operator definition */
    optup = SearchSysCache1(OPEROID, ObjectIdGetDatum(member->object));
    if (optup == NULL)
        elog(ERROR, "cache lookup failed for operator %u", member->object);
    opform = (Form_pg_operator) GETSTRUCT(optup);

    /*
     * Opfamily operators must be binary.
     */
    if (opform->oprkind != 'b')
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("index operators must be binary")));

    if (OidIsValid(member->sortfamily))
    {
        /*
         * Ordering op, check index supports that.  (We could perhaps also
         * check that the operator returns a type supported by the sortfamily,
         * but that seems more trouble than it's worth here.  If it does not,
         * the operator will never be matchable to any ORDER BY clause, but no
         * worse consequences can ensue.  Also, trying to check that would
         * create an ordering hazard during dump/reload: it's possible that
         * the family has been created but not yet populated with the required
         * operators.)
         */
        HeapTuple   amtup;
        Form_pg_am  pg_am;

        amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
        if (amtup == NULL)
            elog(ERROR, "cache lookup failed for access method %u", amoid);
        pg_am = (Form_pg_am) GETSTRUCT(amtup);

        if (!pg_am->amcanorderbyop)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
            errmsg("access method \"%s\" does not support ordering operators",
                   NameStr(pg_am->amname))));

        ReleaseSysCache(amtup);
    }
    else
    {
        /*
         * Search operators must return boolean.
         */
        if (opform->oprresult != BOOLOID)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                     errmsg("index search operators must return boolean")));
    }

    /*
     * If lefttype/righttype isn't specified, use the operator's input types
     */
    if (!OidIsValid(member->lefttype))
        member->lefttype = opform->oprleft;
    if (!OidIsValid(member->righttype))
        member->righttype = opform->oprright;

    ReleaseSysCache(optup);
}

static void assignProcTypes ( OpFamilyMember member,
Oid  amoid,
Oid  typeoid 
) [static]

Definition at line 1139 of file opclasscmds.c.

References BTORDER_PROC, BTREE_AM_OID, BTSORTSUPPORT_PROC, elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, HASH_AM_OID, INT4OID, INTERNALOID, OpFamilyMember::lefttype, NULL, OpFamilyMember::number, OpFamilyMember::object, ObjectIdGetDatum, OidIsValid, PROCOID, ReleaseSysCache(), OpFamilyMember::righttype, SearchSysCache1, and VOIDOID.

Referenced by AlterOpFamilyAdd(), and DefineOpClass().

{
    HeapTuple   proctup;
    Form_pg_proc procform;

    /* Fetch the procedure definition */
    proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(member->object));
    if (proctup == NULL)
        elog(ERROR, "cache lookup failed for function %u", member->object);
    procform = (Form_pg_proc) GETSTRUCT(proctup);

    /*
     * btree comparison procs must be 2-arg procs returning int4, while btree
     * sortsupport procs must take internal and return void.  hash support
     * procs must be 1-arg procs returning int4.  Otherwise we don't know.
     */
    if (amoid == BTREE_AM_OID)
    {
        if (member->number == BTORDER_PROC)
        {
            if (procform->pronargs != 2)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                         errmsg("btree comparison procedures must have two arguments")));
            if (procform->prorettype != INT4OID)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("btree comparison procedures must return integer")));

            /*
             * If lefttype/righttype isn't specified, use the proc's input
             * types
             */
            if (!OidIsValid(member->lefttype))
                member->lefttype = procform->proargtypes.values[0];
            if (!OidIsValid(member->righttype))
                member->righttype = procform->proargtypes.values[1];
        }
        else if (member->number == BTSORTSUPPORT_PROC)
        {
            if (procform->pronargs != 1 ||
                procform->proargtypes.values[0] != INTERNALOID)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                         errmsg("btree sort support procedures must accept type \"internal\"")));
            if (procform->prorettype != VOIDOID)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                  errmsg("btree sort support procedures must return void")));

            /*
             * Can't infer lefttype/righttype from proc, so use default rule
             */
        }
    }
    else if (amoid == HASH_AM_OID)
    {
        if (procform->pronargs != 1)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                     errmsg("hash procedures must have one argument")));
        if (procform->prorettype != INT4OID)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                     errmsg("hash procedures must return integer")));

        /*
         * If lefttype/righttype isn't specified, use the proc's input type
         */
        if (!OidIsValid(member->lefttype))
            member->lefttype = procform->proargtypes.values[0];
        if (!OidIsValid(member->righttype))
            member->righttype = procform->proargtypes.values[0];
    }

    /*
     * The default in CREATE OPERATOR CLASS is to use the class' opcintype as
     * lefttype and righttype.  In CREATE or ALTER OPERATOR FAMILY, opcintype
     * isn't available, so make the user specify the types.
     */
    if (!OidIsValid(member->lefttype))
        member->lefttype = typeoid;
    if (!OidIsValid(member->righttype))
        member->righttype = typeoid;

    if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("associated data types must be specified for index support procedure")));

    ReleaseSysCache(proctup);
}

static Oid CreateOpFamily ( char *  amname,
char *  opfname,
Oid  namespaceoid,
Oid  amoid 
) [static]

Definition at line 244 of file opclasscmds.c.

References Anum_pg_opfamily_opfmethod, Anum_pg_opfamily_opfname, Anum_pg_opfamily_opfnamespace, Anum_pg_opfamily_opfowner, CatalogUpdateIndexes(), ObjectAddress::classId, CStringGetDatum, DEPENDENCY_NORMAL, ereport, errcode(), errmsg(), ERROR, GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, NameGetDatum, namestrcpy(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OperatorFamilyRelationId, OPFAMILYAMNAMENSP, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, SearchSysCacheExists3, simple_heap_insert(), and values.

Referenced by DefineOpClass(), and DefineOpFamily().

{
    Oid         opfamilyoid;
    Relation    rel;
    HeapTuple   tup;
    Datum       values[Natts_pg_opfamily];
    bool        nulls[Natts_pg_opfamily];
    NameData    opfName;
    ObjectAddress myself,
                referenced;

    rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);

    /*
     * Make sure there is no existing opfamily of this name (this is just to
     * give a more friendly error message than "duplicate key").
     */
    if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
                              ObjectIdGetDatum(amoid),
                              CStringGetDatum(opfname),
                              ObjectIdGetDatum(namespaceoid)))
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("operator family \"%s\" for access method \"%s\" already exists",
                        opfname, amname)));

    /*
     * Okay, let's create the pg_opfamily entry.
     */
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));

    values[Anum_pg_opfamily_opfmethod - 1] = ObjectIdGetDatum(amoid);
    namestrcpy(&opfName, opfname);
    values[Anum_pg_opfamily_opfname - 1] = NameGetDatum(&opfName);
    values[Anum_pg_opfamily_opfnamespace - 1] = ObjectIdGetDatum(namespaceoid);
    values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId());

    tup = heap_form_tuple(rel->rd_att, values, nulls);

    opfamilyoid = simple_heap_insert(rel, tup);

    CatalogUpdateIndexes(rel, tup);

    heap_freetuple(tup);

    /*
     * Create dependencies for the opfamily proper.  Note: we do not create a
     * dependency link to the AM, because we don't currently support DROP
     * ACCESS METHOD.
     */
    myself.classId = OperatorFamilyRelationId;
    myself.objectId = opfamilyoid;
    myself.objectSubId = 0;

    /* dependency on namespace */
    referenced.classId = NamespaceRelationId;
    referenced.objectId = namespaceoid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

    /* dependency on owner */
    recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());

    /* dependency on extension */
    recordDependencyOnCurrentExtension(&myself, false);

    /* Post creation hook for new operator family */
    InvokeObjectPostCreateHook(OperatorFamilyRelationId, opfamilyoid, 0);

    heap_close(rel, RowExclusiveLock);

    return opfamilyoid;
}

Oid DefineOpClass ( CreateOpClassStmt stmt  ) 

Definition at line 324 of file opclasscmds.c.

References ACL_CREATE, ACL_KIND_NAMESPACE, ACL_KIND_OPER, ACL_KIND_PROC, aclcheck_error(), aclcheck_error_type(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, addFamilyMember(), CreateOpClassStmt::amname, AMNAME, Anum_pg_opclass_opcdefault, Anum_pg_opclass_opcfamily, Anum_pg_opclass_opcintype, Anum_pg_opclass_opckeytype, Anum_pg_opclass_opcmethod, Anum_pg_opclass_opcname, Anum_pg_opclass_opcnamespace, Anum_pg_opclass_opcowner, CreateOpClassItem::args, Assert, assignOperTypes(), assignProcTypes(), BoolGetDatum, BTEqualStrategyNumber, BTREE_AM_OID, CatalogUpdateIndexes(), CLAAMNAMENSP, CreateOpClassItem::class_args, ObjectAddress::classId, CreateOpFamily(), CStringGetDatum, CreateOpClassStmt::datatype, DEPENDENCY_AUTO, DEPENDENCY_NORMAL, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, get_func_name(), get_namespace_name(), get_opcode(), get_opfamily_oid(), get_opname(), GETSTRUCT, GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectPostCreateHook, IsA, CreateOpClassStmt::isDefault, CreateOpClassStmt::items, CreateOpClassItem::itemtype, OpFamilyMember::lefttype, lfirst, linitial, LookupFuncNameTypeNames(), LookupOperName(), LookupOperNameTypeNames(), lsecond, CreateOpClassItem::name, NameGetDatum, NameStr, namestrcpy(), NIL, NULL, OpFamilyMember::number, CreateOpClassItem::number, OpFamilyMember::object, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, OPCLASS_ITEM_FUNCTION, OPCLASS_ITEM_OPERATOR, OPCLASS_ITEM_STORAGETYPE, OpclassAmNameNspIndexId, CreateOpClassStmt::opclassname, OperatorClassRelationId, OPFAMILYAMNAMENSP, CreateOpClassStmt::opfamilyname, CreateOpClassItem::order_family, palloc0(), pg_namespace_aclcheck(), pg_oper_ownercheck(), pg_proc_ownercheck(), pg_type_ownercheck(), PointerGetDatum, processTypesSpec(), QualifiedNameGetCreationNamespace(), RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), ReleaseSysCache(), OpFamilyMember::righttype, RowExclusiveLock, ScanKeyInit(), SearchSysCache1, SearchSysCache3, SearchSysCacheExists3, simple_heap_insert(), SnapshotNow, OpFamilyMember::sortfamily, CreateOpClassItem::storedtype, storeOperators(), storeProcedures(), superuser(), systable_beginscan(), systable_endscan(), systable_getnext(), TypeNameToString(), typenameTypeId(), and values.

Referenced by ProcessUtilitySlow().

{
    char       *opcname;        /* name of opclass we're creating */
    Oid         amoid,          /* our AM's oid */
                typeoid,        /* indexable datatype oid */
                storageoid,     /* storage datatype oid, if any */
                namespaceoid,   /* namespace to create opclass in */
                opfamilyoid,    /* oid of containing opfamily */
                opclassoid;     /* oid of opclass we create */
    int         maxOpNumber,    /* amstrategies value */
                maxProcNumber;  /* amsupport value */
    bool        amstorage;      /* amstorage flag */
    List       *operators;      /* OpFamilyMember list for operators */
    List       *procedures;     /* OpFamilyMember list for support procs */
    ListCell   *l;
    Relation    rel;
    HeapTuple   tup;
    Form_pg_am  pg_am;
    Datum       values[Natts_pg_opclass];
    bool        nulls[Natts_pg_opclass];
    AclResult   aclresult;
    NameData    opcName;
    ObjectAddress myself,
                referenced;

    /* Convert list of names to a name and namespace */
    namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
                                                     &opcname);

    /* Check we have creation rights in target namespace */
    aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                       get_namespace_name(namespaceoid));

    /* Get necessary info about access method */
    tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
    if (!HeapTupleIsValid(tup))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("access method \"%s\" does not exist",
                        stmt->amname)));

    amoid = HeapTupleGetOid(tup);
    pg_am = (Form_pg_am) GETSTRUCT(tup);
    maxOpNumber = pg_am->amstrategies;
    /* if amstrategies is zero, just enforce that op numbers fit in int16 */
    if (maxOpNumber <= 0)
        maxOpNumber = SHRT_MAX;
    maxProcNumber = pg_am->amsupport;
    amstorage = pg_am->amstorage;

    /* XXX Should we make any privilege check against the AM? */

    ReleaseSysCache(tup);

    /*
     * The question of appropriate permissions for CREATE OPERATOR CLASS is
     * interesting.  Creating an opclass is tantamount to granting public
     * execute access on the functions involved, since the index machinery
     * generally does not check access permission before using the functions.
     * A minimum expectation therefore is that the caller have execute
     * privilege with grant option.  Since we don't have a way to make the
     * opclass go away if the grant option is revoked, we choose instead to
     * require ownership of the functions.  It's also not entirely clear what
     * permissions should be required on the datatype, but ownership seems
     * like a safe choice.
     *
     * Currently, we require superuser privileges to create an opclass. This
     * seems necessary because we have no way to validate that the offered set
     * of operators and functions are consistent with the AM's expectations.
     * It would be nice to provide such a check someday, if it can be done
     * without solving the halting problem :-(
     *
     * XXX re-enable NOT_USED code sections below if you remove this test.
     */
    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("must be superuser to create an operator class")));

    /* Look up the datatype */
    typeoid = typenameTypeId(NULL, stmt->datatype);

#ifdef NOT_USED
    /* XXX this is unnecessary given the superuser check above */
    /* Check we have ownership of the datatype */
    if (!pg_type_ownercheck(typeoid, GetUserId()))
        aclcheck_error_type(ACLCHECK_NOT_OWNER, typeoid);
#endif

    /*
     * Look up the containing operator family, or create one if FAMILY option
     * was omitted and there's not a match already.
     */
    if (stmt->opfamilyname)
    {
        opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
    }
    else
    {
        /* Lookup existing family of same name and namespace */
        tup = SearchSysCache3(OPFAMILYAMNAMENSP,
                              ObjectIdGetDatum(amoid),
                              PointerGetDatum(opcname),
                              ObjectIdGetDatum(namespaceoid));
        if (HeapTupleIsValid(tup))
        {
            opfamilyoid = HeapTupleGetOid(tup);

            /*
             * XXX given the superuser check above, there's no need for an
             * ownership check here
             */
            ReleaseSysCache(tup);
        }
        else
        {
            /*
             * Create it ... again no need for more permissions ...
             */
            opfamilyoid = CreateOpFamily(stmt->amname, opcname,
                                         namespaceoid, amoid);
        }
    }

    operators = NIL;
    procedures = NIL;

    /* Storage datatype is optional */
    storageoid = InvalidOid;

    /*
     * Scan the "items" list to obtain additional info.
     */
    foreach(l, stmt->items)
    {
        CreateOpClassItem *item = lfirst(l);
        Oid         operOid;
        Oid         funcOid;
        Oid         sortfamilyOid;
        OpFamilyMember *member;

        Assert(IsA(item, CreateOpClassItem));
        switch (item->itemtype)
        {
            case OPCLASS_ITEM_OPERATOR:
                if (item->number <= 0 || item->number > maxOpNumber)
                    ereport(ERROR,
                            (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                             errmsg("invalid operator number %d,"
                                    " must be between 1 and %d",
                                    item->number, maxOpNumber)));
                if (item->args != NIL)
                {
                    TypeName   *typeName1 = (TypeName *) linitial(item->args);
                    TypeName   *typeName2 = (TypeName *) lsecond(item->args);

                    operOid = LookupOperNameTypeNames(NULL, item->name,
                                                      typeName1, typeName2,
                                                      false, -1);
                }
                else
                {
                    /* Default to binary op on input datatype */
                    operOid = LookupOperName(NULL, item->name,
                                             typeoid, typeoid,
                                             false, -1);
                }

                if (item->order_family)
                    sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
                                                     item->order_family,
                                                     false);
                else
                    sortfamilyOid = InvalidOid;

#ifdef NOT_USED
                /* XXX this is unnecessary given the superuser check above */
                /* Caller must own operator and its underlying function */
                if (!pg_oper_ownercheck(operOid, GetUserId()))
                    aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
                                   get_opname(operOid));
                funcOid = get_opcode(operOid);
                if (!pg_proc_ownercheck(funcOid, GetUserId()))
                    aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
                                   get_func_name(funcOid));
#endif

                /* Save the info */
                member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
                member->object = operOid;
                member->number = item->number;
                member->sortfamily = sortfamilyOid;
                assignOperTypes(member, amoid, typeoid);
                addFamilyMember(&operators, member, false);
                break;
            case OPCLASS_ITEM_FUNCTION:
                if (item->number <= 0 || item->number > maxProcNumber)
                    ereport(ERROR,
                            (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                             errmsg("invalid procedure number %d,"
                                    " must be between 1 and %d",
                                    item->number, maxProcNumber)));
                funcOid = LookupFuncNameTypeNames(item->name, item->args,
                                                  false);
#ifdef NOT_USED
                /* XXX this is unnecessary given the superuser check above */
                /* Caller must own function */
                if (!pg_proc_ownercheck(funcOid, GetUserId()))
                    aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
                                   get_func_name(funcOid));
#endif

                /* Save the info */
                member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
                member->object = funcOid;
                member->number = item->number;

                /* allow overriding of the function's actual arg types */
                if (item->class_args)
                    processTypesSpec(item->class_args,
                                     &member->lefttype, &member->righttype);

                assignProcTypes(member, amoid, typeoid);
                addFamilyMember(&procedures, member, true);
                break;
            case OPCLASS_ITEM_STORAGETYPE:
                if (OidIsValid(storageoid))
                    ereport(ERROR,
                            (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                           errmsg("storage type specified more than once")));
                storageoid = typenameTypeId(NULL, item->storedtype);

#ifdef NOT_USED
                /* XXX this is unnecessary given the superuser check above */
                /* Check we have ownership of the datatype */
                if (!pg_type_ownercheck(storageoid, GetUserId()))
                    aclcheck_error_type(ACLCHECK_NOT_OWNER, storageoid);
#endif
                break;
            default:
                elog(ERROR, "unrecognized item type: %d", item->itemtype);
                break;
        }
    }

    /*
     * If storagetype is specified, make sure it's legal.
     */
    if (OidIsValid(storageoid))
    {
        /* Just drop the spec if same as column datatype */
        if (storageoid == typeoid)
            storageoid = InvalidOid;
        else if (!amstorage)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                     errmsg("storage type cannot be different from data type for access method \"%s\"",
                            stmt->amname)));
    }

    rel = heap_open(OperatorClassRelationId, RowExclusiveLock);

    /*
     * Make sure there is no existing opclass of this name (this is just to
     * give a more friendly error message than "duplicate key").
     */
    if (SearchSysCacheExists3(CLAAMNAMENSP,
                              ObjectIdGetDatum(amoid),
                              CStringGetDatum(opcname),
                              ObjectIdGetDatum(namespaceoid)))
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("operator class \"%s\" for access method \"%s\" already exists",
                        opcname, stmt->amname)));

    /*
     * If we are creating a default opclass, check there isn't one already.
     * (Note we do not restrict this test to visible opclasses; this ensures
     * that typcache.c can find unique solutions to its questions.)
     */
    if (stmt->isDefault)
    {
        ScanKeyData skey[1];
        SysScanDesc scan;

        ScanKeyInit(&skey[0],
                    Anum_pg_opclass_opcmethod,
                    BTEqualStrategyNumber, F_OIDEQ,
                    ObjectIdGetDatum(amoid));

        scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
                                  SnapshotNow, 1, skey);

        while (HeapTupleIsValid(tup = systable_getnext(scan)))
        {
            Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);

            if (opclass->opcintype == typeoid && opclass->opcdefault)
                ereport(ERROR,
                        (errcode(ERRCODE_DUPLICATE_OBJECT),
                         errmsg("could not make operator class \"%s\" be default for type %s",
                                opcname,
                                TypeNameToString(stmt->datatype)),
                   errdetail("Operator class \"%s\" already is the default.",
                             NameStr(opclass->opcname))));
        }

        systable_endscan(scan);
    }

    /*
     * Okay, let's create the pg_opclass entry.
     */
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));

    values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid);
    namestrcpy(&opcName, opcname);
    values[Anum_pg_opclass_opcname - 1] = NameGetDatum(&opcName);
    values[Anum_pg_opclass_opcnamespace - 1] = ObjectIdGetDatum(namespaceoid);
    values[Anum_pg_opclass_opcowner - 1] = ObjectIdGetDatum(GetUserId());
    values[Anum_pg_opclass_opcfamily - 1] = ObjectIdGetDatum(opfamilyoid);
    values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid);
    values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(stmt->isDefault);
    values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid);

    tup = heap_form_tuple(rel->rd_att, values, nulls);

    opclassoid = simple_heap_insert(rel, tup);

    CatalogUpdateIndexes(rel, tup);

    heap_freetuple(tup);

    /*
     * Now add tuples to pg_amop and pg_amproc tying in the operators and
     * functions.  Dependencies on them are inserted, too.
     */
    storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
                   opclassoid, operators, false);
    storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
                    opclassoid, procedures, false);

    /*
     * Create dependencies for the opclass proper.  Note: we do not create a
     * dependency link to the AM, because we don't currently support DROP
     * ACCESS METHOD.
     */
    myself.classId = OperatorClassRelationId;
    myself.objectId = opclassoid;
    myself.objectSubId = 0;

    /* dependency on namespace */
    referenced.classId = NamespaceRelationId;
    referenced.objectId = namespaceoid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

    /* dependency on opfamily */
    referenced.classId = OperatorFamilyRelationId;
    referenced.objectId = opfamilyoid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);

    /* dependency on indexed datatype */
    referenced.classId = TypeRelationId;
    referenced.objectId = typeoid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

    /* dependency on storage datatype */
    if (OidIsValid(storageoid))
    {
        referenced.classId = TypeRelationId;
        referenced.objectId = storageoid;
        referenced.objectSubId = 0;
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    }

    /* dependency on owner */
    recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());

    /* dependency on extension */
    recordDependencyOnCurrentExtension(&myself, false);

    /* Post creation hook for new operator class */
    InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);

    heap_close(rel, RowExclusiveLock);

    return opclassoid;
}

Oid DefineOpFamily ( CreateOpFamilyStmt stmt  ) 

Definition at line 725 of file opclasscmds.c.

References ACL_CREATE, ACL_KIND_NAMESPACE, aclcheck_error(), ACLCHECK_OK, CreateOpFamilyStmt::amname, CreateOpFamily(), ereport, errcode(), errmsg(), ERROR, get_am_oid(), get_namespace_name(), GetUserId(), CreateOpFamilyStmt::opfamilyname, pg_namespace_aclcheck(), QualifiedNameGetCreationNamespace(), and superuser().

Referenced by ProcessUtilitySlow().

{
    char       *opfname;        /* name of opfamily we're creating */
    Oid         amoid,          /* our AM's oid */
                namespaceoid;   /* namespace to create opfamily in */
    AclResult   aclresult;

    /* Convert list of names to a name and namespace */
    namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
                                                     &opfname);

    /* Check we have creation rights in target namespace */
    aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                       get_namespace_name(namespaceoid));

    /* Get access method OID, throwing an error if it doesn't exist. */
    amoid = get_am_oid(stmt->amname, false);

    /* XXX Should we make any privilege check against the AM? */

    /*
     * Currently, we require superuser privileges to create an opfamily. See
     * comments in DefineOpClass.
     */
    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("must be superuser to create an operator family")));

    /* Insert pg_opfamily catalog entry */
    return CreateOpFamily(stmt->amname, opfname, namespaceoid, amoid);
}

static void dropOperators ( List opfamilyname,
Oid  amoid,
Oid  opfamilyoid,
List operators 
) [static]

Definition at line 1495 of file opclasscmds.c.

References AMOPSTRATEGY, DROP_RESTRICT, ereport, errcode(), errmsg(), ERROR, format_type_be(), GetSysCacheOid4, Int16GetDatum, OpFamilyMember::lefttype, lfirst, NameListToString(), OpFamilyMember::number, ObjectIdGetDatum, OidIsValid, performDeletion(), and OpFamilyMember::righttype.

Referenced by AlterOpFamilyDrop().

{
    ListCell   *l;

    foreach(l, operators)
    {
        OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
        Oid         amopid;
        ObjectAddress object;

        amopid = GetSysCacheOid4(AMOPSTRATEGY,
                                 ObjectIdGetDatum(opfamilyoid),
                                 ObjectIdGetDatum(op->lefttype),
                                 ObjectIdGetDatum(op->righttype),
                                 Int16GetDatum(op->number));
        if (!OidIsValid(amopid))
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_OBJECT),
                     errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
                            op->number,
                            format_type_be(op->lefttype),
                            format_type_be(op->righttype),
                            NameListToString(opfamilyname))));

        object.classId = AccessMethodOperatorRelationId;
        object.objectId = amopid;
        object.objectSubId = 0;

        performDeletion(&object, DROP_RESTRICT, 0);
    }
}

static void dropProcedures ( List opfamilyname,
Oid  amoid,
Oid  opfamilyoid,
List procedures 
) [static]

Definition at line 1535 of file opclasscmds.c.

References AMPROCNUM, DROP_RESTRICT, ereport, errcode(), errmsg(), ERROR, format_type_be(), GetSysCacheOid4, Int16GetDatum, OpFamilyMember::lefttype, lfirst, NameListToString(), OpFamilyMember::number, ObjectIdGetDatum, OidIsValid, performDeletion(), and OpFamilyMember::righttype.

Referenced by AlterOpFamilyDrop().

{
    ListCell   *l;

    foreach(l, procedures)
    {
        OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
        Oid         amprocid;
        ObjectAddress object;

        amprocid = GetSysCacheOid4(AMPROCNUM,
                                   ObjectIdGetDatum(opfamilyoid),
                                   ObjectIdGetDatum(op->lefttype),
                                   ObjectIdGetDatum(op->righttype),
                                   Int16GetDatum(op->number));
        if (!OidIsValid(amprocid))
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_OBJECT),
                     errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
                            op->number,
                            format_type_be(op->lefttype),
                            format_type_be(op->righttype),
                            NameListToString(opfamilyname))));

        object.classId = AccessMethodProcedureRelationId;
        object.objectId = amprocid;
        object.objectSubId = 0;

        performDeletion(&object, DROP_RESTRICT, 0);
    }
}

static char* get_am_name ( Oid  amOid  )  [static]

Definition at line 1668 of file opclasscmds.c.

References AMOID, GETSTRUCT, HeapTupleIsValid, NameStr, ObjectIdGetDatum, pstrdup(), ReleaseSysCache(), and SearchSysCache1.

Referenced by IsThereOpClassInNamespace(), and IsThereOpFamilyInNamespace().

{
    HeapTuple   tup;
    char       *result = NULL;

    tup = SearchSysCache1(AMOID, ObjectIdGetDatum(amOid));
    if (HeapTupleIsValid(tup))
    {
        result = pstrdup(NameStr(((Form_pg_am) GETSTRUCT(tup))->amname));
        ReleaseSysCache(tup);
    }
    return result;
}

Oid get_am_oid ( const char *  amname,
bool  missing_ok 
)

Definition at line 1735 of file opclasscmds.c.

References AMNAME, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, GetSysCacheOid1, and OidIsValid.

Referenced by DefineOpFamily(), get_object_address_opcf(), and transformIndexConstraint().

{
    Oid         oid;

    oid = GetSysCacheOid1(AMNAME, CStringGetDatum(amname));
    if (!OidIsValid(oid) && !missing_ok)
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("access method \"%s\" does not exist", amname)));
    return oid;
}

Oid get_opclass_oid ( Oid  amID,
List opclassname,
bool  missing_ok 
)

Definition at line 223 of file opclasscmds.c.

References HeapTupleGetOid, HeapTupleIsValid, OpClassCacheLookup(), and ReleaseSysCache().

Referenced by findRangeSubOpclass(), and get_object_address_opcf().

{
    HeapTuple   htup;
    Oid         opcID;

    htup = OpClassCacheLookup(amID, opclassname, missing_ok);
    if (!HeapTupleIsValid(htup))
        return InvalidOid;
    opcID = HeapTupleGetOid(htup);
    ReleaseSysCache(htup);

    return opcID;
}

Oid get_opfamily_oid ( Oid  amID,
List opfamilyname,
bool  missing_ok 
)

Definition at line 147 of file opclasscmds.c.

References HeapTupleGetOid, HeapTupleIsValid, OpFamilyCacheLookup(), and ReleaseSysCache().

Referenced by AlterOpFamily(), AlterOpFamilyAdd(), DefineOpClass(), and get_object_address_opcf().

{
    HeapTuple   htup;
    Oid         opfID;

    htup = OpFamilyCacheLookup(amID, opfamilyname, missing_ok);
    if (!HeapTupleIsValid(htup))
        return InvalidOid;
    opfID = HeapTupleGetOid(htup);
    ReleaseSysCache(htup);

    return opfID;
}

void IsThereOpClassInNamespace ( const char *  opcname,
Oid  opcmethod,
Oid  opcnamespace 
)

Definition at line 1689 of file opclasscmds.c.

References CLAAMNAMENSP, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, get_am_name(), get_namespace_name(), ObjectIdGetDatum, and SearchSysCacheExists3.

Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().

{
    /* make sure the new name doesn't exist */
    if (SearchSysCacheExists3(CLAAMNAMENSP,
                              ObjectIdGetDatum(opcmethod),
                              CStringGetDatum(opcname),
                              ObjectIdGetDatum(opcnamespace)))
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
                        opcname,
                        get_am_name(opcmethod),
                        get_namespace_name(opcnamespace))));
}

void IsThereOpFamilyInNamespace ( const char *  opfname,
Oid  opfmethod,
Oid  opfnamespace 
)

Definition at line 1712 of file opclasscmds.c.

References CStringGetDatum, ereport, errcode(), errmsg(), ERROR, get_am_name(), get_namespace_name(), ObjectIdGetDatum, OPFAMILYAMNAMENSP, and SearchSysCacheExists3.

Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().

{
    /* make sure the new name doesn't exist */
    if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
                              ObjectIdGetDatum(opfmethod),
                              CStringGetDatum(opfname),
                              ObjectIdGetDatum(opfnamespace)))
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
                        opfname,
                        get_am_name(opfmethod),
                        get_namespace_name(opfnamespace))));
}

static HeapTuple OpClassCacheLookup ( Oid  amID,
List opclassname,
bool  missing_ok 
) [static]

Definition at line 168 of file opclasscmds.c.

References AMOID, CLAAMNAMENSP, CLAOID, DeconstructQualifiedName(), elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, HeapTupleIsValid, LookupExplicitNamespace(), NameListToString(), NameStr, ObjectIdGetDatum, OidIsValid, OpclassnameGetOpcid(), PointerGetDatum, SearchSysCache1, and SearchSysCache3.

Referenced by get_opclass_oid().

{
    char       *schemaname;
    char       *opcname;
    HeapTuple   htup;

    /* deconstruct the name list */
    DeconstructQualifiedName(opclassname, &schemaname, &opcname);

    if (schemaname)
    {
        /* Look in specific schema only */
        Oid         namespaceId;

        namespaceId = LookupExplicitNamespace(schemaname, false);
        htup = SearchSysCache3(CLAAMNAMENSP,
                               ObjectIdGetDatum(amID),
                               PointerGetDatum(opcname),
                               ObjectIdGetDatum(namespaceId));
    }
    else
    {
        /* Unqualified opclass name, so search the search path */
        Oid         opcID = OpclassnameGetOpcid(amID, opcname);

        if (!OidIsValid(opcID))
            htup = NULL;
        else
            htup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcID));
    }

    if (!HeapTupleIsValid(htup) && !missing_ok)
    {
        HeapTuple   amtup;

        amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
        if (!HeapTupleIsValid(amtup))
            elog(ERROR, "cache lookup failed for access method %u", amID);
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
                        NameListToString(opclassname),
                        NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname))));
    }

    return htup;
}

static HeapTuple OpFamilyCacheLookup ( Oid  amID,
List opfamilyname,
bool  missing_ok 
) [static]

Definition at line 92 of file opclasscmds.c.

References AMOID, DeconstructQualifiedName(), elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, HeapTupleIsValid, LookupExplicitNamespace(), NameListToString(), NameStr, ObjectIdGetDatum, OidIsValid, OPFAMILYAMNAMENSP, OpfamilynameGetOpfid(), OPFAMILYOID, PointerGetDatum, SearchSysCache1, and SearchSysCache3.

Referenced by get_opfamily_oid().

{
    char       *schemaname;
    char       *opfname;
    HeapTuple   htup;

    /* deconstruct the name list */
    DeconstructQualifiedName(opfamilyname, &schemaname, &opfname);

    if (schemaname)
    {
        /* Look in specific schema only */
        Oid         namespaceId;

        namespaceId = LookupExplicitNamespace(schemaname, false);
        htup = SearchSysCache3(OPFAMILYAMNAMENSP,
                               ObjectIdGetDatum(amID),
                               PointerGetDatum(opfname),
                               ObjectIdGetDatum(namespaceId));
    }
    else
    {
        /* Unqualified opfamily name, so search the search path */
        Oid         opfID = OpfamilynameGetOpfid(amID, opfname);

        if (!OidIsValid(opfID))
            htup = NULL;
        else
            htup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfID));
    }

    if (!HeapTupleIsValid(htup) && !missing_ok)
    {
        HeapTuple   amtup;

        amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
        if (!HeapTupleIsValid(amtup))
            elog(ERROR, "cache lookup failed for access method %u", amID);
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
                        NameListToString(opfamilyname),
                        NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname))));
    }

    return htup;
}

static void processTypesSpec ( List args,
Oid lefttype,
Oid righttype 
) [static]

Definition at line 1036 of file opclasscmds.c.

References Assert, ereport, errcode(), errmsg(), ERROR, linitial, list_length(), lsecond, NIL, NULL, and typenameTypeId().

Referenced by AlterOpFamilyAdd(), AlterOpFamilyDrop(), and DefineOpClass().

{
    TypeName   *typeName;

    Assert(args != NIL);

    typeName = (TypeName *) linitial(args);
    *lefttype = typenameTypeId(NULL, typeName);

    if (list_length(args) > 1)
    {
        typeName = (TypeName *) lsecond(args);
        *righttype = typenameTypeId(NULL, typeName);
    }
    else
        *righttype = *lefttype;

    if (list_length(args) > 2)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("one or two argument types must be specified")));
}

void RemoveAmOpEntryById ( Oid  entryOid  ) 
void RemoveAmProcEntryById ( Oid  entryOid  ) 
void RemoveOpClassById ( Oid  opclassOid  ) 
void RemoveOpFamilyById ( Oid  opfamilyOid  ) 
static void storeOperators ( List opfamilyname,
Oid  amoid,
Oid  opfamilyoid,
Oid  opclassoid,
List operators,
bool  isAdd 
) [static]

Definition at line 1276 of file opclasscmds.c.

References AccessMethodOperatorRelationId, AMOP_ORDER, AMOPSTRATEGY, Anum_pg_amop_amopfamily, Anum_pg_amop_amoplefttype, Anum_pg_amop_amopmethod, Anum_pg_amop_amopopr, Anum_pg_amop_amoppurpose, Anum_pg_amop_amoprighttype, Anum_pg_amop_amopsortfamily, Anum_pg_amop_amopstrategy, CatalogUpdateIndexes(), CharGetDatum, ObjectAddress::classId, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, ereport, errcode(), errmsg(), ERROR, format_type_be(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), Int16GetDatum, InvokeObjectPostCreateHook, OpFamilyMember::lefttype, lfirst, NameListToString(), OpFamilyMember::number, OpFamilyMember::object, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, RelationData::rd_att, recordDependencyOn(), OpFamilyMember::righttype, RowExclusiveLock, SearchSysCacheExists4, simple_heap_insert(), OpFamilyMember::sortfamily, and values.

Referenced by AlterOpFamilyAdd(), and DefineOpClass().

{
    Relation    rel;
    Datum       values[Natts_pg_amop];
    bool        nulls[Natts_pg_amop];
    HeapTuple   tup;
    Oid         entryoid;
    ObjectAddress myself,
                referenced;
    ListCell   *l;

    rel = heap_open(AccessMethodOperatorRelationId, RowExclusiveLock);

    foreach(l, operators)
    {
        OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
        char        oppurpose;

        /*
         * If adding to an existing family, check for conflict with an
         * existing pg_amop entry (just to give a nicer error message)
         */
        if (isAdd &&
            SearchSysCacheExists4(AMOPSTRATEGY,
                                  ObjectIdGetDatum(opfamilyoid),
                                  ObjectIdGetDatum(op->lefttype),
                                  ObjectIdGetDatum(op->righttype),
                                  Int16GetDatum(op->number)))
            ereport(ERROR,
                    (errcode(ERRCODE_DUPLICATE_OBJECT),
                     errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
                            op->number,
                            format_type_be(op->lefttype),
                            format_type_be(op->righttype),
                            NameListToString(opfamilyname))));

        oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;

        /* Create the pg_amop entry */
        memset(values, 0, sizeof(values));
        memset(nulls, false, sizeof(nulls));

        values[Anum_pg_amop_amopfamily - 1] = ObjectIdGetDatum(opfamilyoid);
        values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype);
        values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype);
        values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
        values[Anum_pg_amop_amoppurpose - 1] = CharGetDatum(oppurpose);
        values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
        values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
        values[Anum_pg_amop_amopsortfamily - 1] = ObjectIdGetDatum(op->sortfamily);

        tup = heap_form_tuple(rel->rd_att, values, nulls);

        entryoid = simple_heap_insert(rel, tup);

        CatalogUpdateIndexes(rel, tup);

        heap_freetuple(tup);

        /* Make its dependencies */
        myself.classId = AccessMethodOperatorRelationId;
        myself.objectId = entryoid;
        myself.objectSubId = 0;

        referenced.classId = OperatorRelationId;
        referenced.objectId = op->object;
        referenced.objectSubId = 0;

        if (OidIsValid(opclassoid))
        {
            /* if contained in an opclass, use a NORMAL dep on operator */
            recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

            /* ... and an INTERNAL dep on the opclass */
            referenced.classId = OperatorClassRelationId;
            referenced.objectId = opclassoid;
            referenced.objectSubId = 0;
            recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
        }
        else
        {
            /* if "loose" in the opfamily, use a AUTO dep on operator */
            recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);

            /* ... and an AUTO dep on the opfamily */
            referenced.classId = OperatorFamilyRelationId;
            referenced.objectId = opfamilyoid;
            referenced.objectSubId = 0;
            recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
        }

        /* A search operator also needs a dep on the referenced opfamily */
        if (OidIsValid(op->sortfamily))
        {
            referenced.classId = OperatorFamilyRelationId;
            referenced.objectId = op->sortfamily;
            referenced.objectSubId = 0;
            recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
        }
        /* Post create hook of this access method operator */
        InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
                                   entryoid, 0);
    }

    heap_close(rel, RowExclusiveLock);
}

static void storeProcedures ( List opfamilyname,
Oid  amoid,
Oid  opfamilyoid,
Oid  opclassoid,
List procedures,
bool  isAdd 
) [static]

Definition at line 1393 of file opclasscmds.c.

References AccessMethodProcedureRelationId, AMPROCNUM, Anum_pg_amproc_amproc, Anum_pg_amproc_amprocfamily, Anum_pg_amproc_amproclefttype, Anum_pg_amproc_amprocnum, Anum_pg_amproc_amprocrighttype, CatalogUpdateIndexes(), ObjectAddress::classId, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, ereport, errcode(), errmsg(), ERROR, format_type_be(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), Int16GetDatum, InvokeObjectPostCreateHook, OpFamilyMember::lefttype, lfirst, NameListToString(), OpFamilyMember::number, OpFamilyMember::object, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, RelationData::rd_att, recordDependencyOn(), OpFamilyMember::righttype, RowExclusiveLock, SearchSysCacheExists4, simple_heap_insert(), and values.

Referenced by AlterOpFamilyAdd(), and DefineOpClass().

{
    Relation    rel;
    Datum       values[Natts_pg_amproc];
    bool        nulls[Natts_pg_amproc];
    HeapTuple   tup;
    Oid         entryoid;
    ObjectAddress myself,
                referenced;
    ListCell   *l;

    rel = heap_open(AccessMethodProcedureRelationId, RowExclusiveLock);

    foreach(l, procedures)
    {
        OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);

        /*
         * If adding to an existing family, check for conflict with an
         * existing pg_amproc entry (just to give a nicer error message)
         */
        if (isAdd &&
            SearchSysCacheExists4(AMPROCNUM,
                                  ObjectIdGetDatum(opfamilyoid),
                                  ObjectIdGetDatum(proc->lefttype),
                                  ObjectIdGetDatum(proc->righttype),
                                  Int16GetDatum(proc->number)))
            ereport(ERROR,
                    (errcode(ERRCODE_DUPLICATE_OBJECT),
                     errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
                            proc->number,
                            format_type_be(proc->lefttype),
                            format_type_be(proc->righttype),
                            NameListToString(opfamilyname))));

        /* Create the pg_amproc entry */
        memset(values, 0, sizeof(values));
        memset(nulls, false, sizeof(nulls));

        values[Anum_pg_amproc_amprocfamily - 1] = ObjectIdGetDatum(opfamilyoid);
        values[Anum_pg_amproc_amproclefttype - 1] = ObjectIdGetDatum(proc->lefttype);
        values[Anum_pg_amproc_amprocrighttype - 1] = ObjectIdGetDatum(proc->righttype);
        values[Anum_pg_amproc_amprocnum - 1] = Int16GetDatum(proc->number);
        values[Anum_pg_amproc_amproc - 1] = ObjectIdGetDatum(proc->object);

        tup = heap_form_tuple(rel->rd_att, values, nulls);

        entryoid = simple_heap_insert(rel, tup);

        CatalogUpdateIndexes(rel, tup);

        heap_freetuple(tup);

        /* Make its dependencies */
        myself.classId = AccessMethodProcedureRelationId;
        myself.objectId = entryoid;
        myself.objectSubId = 0;

        referenced.classId = ProcedureRelationId;
        referenced.objectId = proc->object;
        referenced.objectSubId = 0;

        if (OidIsValid(opclassoid))
        {
            /* if contained in an opclass, use a NORMAL dep on procedure */
            recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

            /* ... and an INTERNAL dep on the opclass */
            referenced.classId = OperatorClassRelationId;
            referenced.objectId = opclassoid;
            referenced.objectSubId = 0;
            recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
        }
        else
        {
            /* if "loose" in the opfamily, use a AUTO dep on procedure */
            recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);

            /* ... and an AUTO dep on the opfamily */
            referenced.classId = OperatorFamilyRelationId;
            referenced.objectId = opfamilyoid;
            referenced.objectSubId = 0;
            recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
        }
        /* Post create hook of access method procedure */
        InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
                                   entryoid, 0);
    }

    heap_close(rel, RowExclusiveLock);
}