Header And Logo

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

Functions

operatorcmds.c File Reference

#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/pg_operator.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/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for operatorcmds.c:

Go to the source code of this file.

Functions

Oid DefineOperator (List *names, List *parameters)
void RemoveOperatorById (Oid operOid)

Function Documentation

Oid DefineOperator ( List names,
List parameters 
)

Definition at line 63 of file operatorcmds.c.

References ACL_CREATE, ACL_EXECUTE, ACL_KIND_NAMESPACE, ACL_KIND_PROC, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, defGetBoolean(), defGetQualifiedName(), defGetTypeName(), DefElem::defname, ereport, errcode(), errdetail(), errmsg(), ERROR, FLOAT8OID, get_func_rettype(), get_namespace_name(), GetUserId(), lfirst, LookupFuncName(), NameListToString(), NIL, NULL, OidIsValid, OperatorCreate(), pg_namespace_aclcheck(), pg_proc_aclcheck(), pg_strcasecmp(), pg_type_aclcheck(), QualifiedNameGetCreationNamespace(), TypeName::setof, typenameTypeId(), and WARNING.

Referenced by ProcessUtilitySlow().

{
    char       *oprName;
    Oid         oprNamespace;
    AclResult   aclresult;
    bool        canMerge = false;       /* operator merges */
    bool        canHash = false;    /* operator hashes */
    List       *functionName = NIL;     /* function for operator */
    TypeName   *typeName1 = NULL;       /* first type name */
    TypeName   *typeName2 = NULL;       /* second type name */
    Oid         typeId1 = InvalidOid;   /* types converted to OID */
    Oid         typeId2 = InvalidOid;
    Oid         rettype;
    List       *commutatorName = NIL;   /* optional commutator operator name */
    List       *negatorName = NIL;      /* optional negator operator name */
    List       *restrictionName = NIL;  /* optional restrict. sel. procedure */
    List       *joinName = NIL; /* optional join sel. procedure */
    Oid         functionOid;    /* functions converted to OID */
    Oid         restrictionOid;
    Oid         joinOid;
    Oid         typeId[5];      /* only need up to 5 args here */
    int         nargs;
    ListCell   *pl;

    /* Convert list of names to a name and namespace */
    oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);

    /*
     * The SQL standard committee has decided that => should be used for named
     * parameters; therefore, a future release of PostgreSQL may disallow it
     * as the name of a user-defined operator.
     */
    if (strcmp(oprName, "=>") == 0)
        ereport(WARNING,
                (errmsg("=> is deprecated as an operator name"),
                 errdetail("This name may be disallowed altogether in future versions of PostgreSQL.")));

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

    /*
     * loop over the definition list and extract the information we need.
     */
    foreach(pl, parameters)
    {
        DefElem    *defel = (DefElem *) lfirst(pl);

        if (pg_strcasecmp(defel->defname, "leftarg") == 0)
        {
            typeName1 = defGetTypeName(defel);
            if (typeName1->setof)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                    errmsg("SETOF type not allowed for operator argument")));
        }
        else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
        {
            typeName2 = defGetTypeName(defel);
            if (typeName2->setof)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                    errmsg("SETOF type not allowed for operator argument")));
        }
        else if (pg_strcasecmp(defel->defname, "procedure") == 0)
            functionName = defGetQualifiedName(defel);
        else if (pg_strcasecmp(defel->defname, "commutator") == 0)
            commutatorName = defGetQualifiedName(defel);
        else if (pg_strcasecmp(defel->defname, "negator") == 0)
            negatorName = defGetQualifiedName(defel);
        else if (pg_strcasecmp(defel->defname, "restrict") == 0)
            restrictionName = defGetQualifiedName(defel);
        else if (pg_strcasecmp(defel->defname, "join") == 0)
            joinName = defGetQualifiedName(defel);
        else if (pg_strcasecmp(defel->defname, "hashes") == 0)
            canHash = defGetBoolean(defel);
        else if (pg_strcasecmp(defel->defname, "merges") == 0)
            canMerge = defGetBoolean(defel);
        /* These obsolete options are taken as meaning canMerge */
        else if (pg_strcasecmp(defel->defname, "sort1") == 0)
            canMerge = true;
        else if (pg_strcasecmp(defel->defname, "sort2") == 0)
            canMerge = true;
        else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
            canMerge = true;
        else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
            canMerge = true;
        else
            ereport(WARNING,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("operator attribute \"%s\" not recognized",
                            defel->defname)));
    }

    /*
     * make sure we have our required definitions
     */
    if (functionName == NIL)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                 errmsg("operator procedure must be specified")));

    /* Transform type names to type OIDs */
    if (typeName1)
        typeId1 = typenameTypeId(NULL, typeName1);
    if (typeName2)
        typeId2 = typenameTypeId(NULL, typeName2);

    if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
           errmsg("at least one of leftarg or rightarg must be specified")));

    if (typeName1)
    {
        aclresult = pg_type_aclcheck(typeId1, GetUserId(), ACL_USAGE);
        if (aclresult != ACLCHECK_OK)
            aclcheck_error_type(aclresult, typeId1);
    }

    if (typeName2)
    {
        aclresult = pg_type_aclcheck(typeId2, GetUserId(), ACL_USAGE);
        if (aclresult != ACLCHECK_OK)
            aclcheck_error_type(aclresult, typeId2);
    }

    /*
     * Look up the operator's underlying function.
     */
    if (!OidIsValid(typeId1))
    {
        typeId[0] = typeId2;
        nargs = 1;
    }
    else if (!OidIsValid(typeId2))
    {
        typeId[0] = typeId1;
        nargs = 1;
    }
    else
    {
        typeId[0] = typeId1;
        typeId[1] = typeId2;
        nargs = 2;
    }
    functionOid = LookupFuncName(functionName, nargs, typeId, false);

    /*
     * We require EXECUTE rights for the function.  This isn't strictly
     * necessary, since EXECUTE will be checked at any attempted use of the
     * operator, but it seems like a good idea anyway.
     */
    aclresult = pg_proc_aclcheck(functionOid, GetUserId(), ACL_EXECUTE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_PROC,
                       NameListToString(functionName));

    rettype = get_func_rettype(functionOid);
    aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error_type(aclresult, rettype);

    /*
     * Look up restriction estimator if specified
     */
    if (restrictionName)
    {
        typeId[0] = INTERNALOID;    /* PlannerInfo */
        typeId[1] = OIDOID;     /* operator OID */
        typeId[2] = INTERNALOID;    /* args list */
        typeId[3] = INT4OID;    /* varRelid */

        restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);

        /* estimators must return float8 */
        if (get_func_rettype(restrictionOid) != FLOAT8OID)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                     errmsg("restriction estimator function %s must return type \"float8\"",
                            NameListToString(restrictionName))));

        /* Require EXECUTE rights for the estimator */
        aclresult = pg_proc_aclcheck(restrictionOid, GetUserId(), ACL_EXECUTE);
        if (aclresult != ACLCHECK_OK)
            aclcheck_error(aclresult, ACL_KIND_PROC,
                           NameListToString(restrictionName));
    }
    else
        restrictionOid = InvalidOid;

    /*
     * Look up join estimator if specified
     */
    if (joinName)
    {
        typeId[0] = INTERNALOID;    /* PlannerInfo */
        typeId[1] = OIDOID;     /* operator OID */
        typeId[2] = INTERNALOID;    /* args list */
        typeId[3] = INT2OID;    /* jointype */
        typeId[4] = INTERNALOID;    /* SpecialJoinInfo */

        /*
         * As of Postgres 8.4, the preferred signature for join estimators has
         * 5 arguments, but we still allow the old 4-argument form. Try the
         * preferred form first.
         */
        joinOid = LookupFuncName(joinName, 5, typeId, true);
        if (!OidIsValid(joinOid))
            joinOid = LookupFuncName(joinName, 4, typeId, true);
        /* If not found, reference the 5-argument signature in error msg */
        if (!OidIsValid(joinOid))
            joinOid = LookupFuncName(joinName, 5, typeId, false);

        /* estimators must return float8 */
        if (get_func_rettype(joinOid) != FLOAT8OID)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
             errmsg("join estimator function %s must return type \"float8\"",
                    NameListToString(joinName))));

        /* Require EXECUTE rights for the estimator */
        aclresult = pg_proc_aclcheck(joinOid, GetUserId(), ACL_EXECUTE);
        if (aclresult != ACLCHECK_OK)
            aclcheck_error(aclresult, ACL_KIND_PROC,
                           NameListToString(joinName));
    }
    else
        joinOid = InvalidOid;

    /*
     * now have OperatorCreate do all the work..
     */
    return
        OperatorCreate(oprName,     /* operator name */
                       oprNamespace,    /* namespace */
                       typeId1,     /* left type id */
                       typeId2,     /* right type id */
                       functionOid, /* function for operator */
                       commutatorName,      /* optional commutator operator name */
                       negatorName, /* optional negator operator name */
                       restrictionOid,      /* optional restrict. sel. procedure */
                       joinOid,     /* optional join sel. procedure name */
                       canMerge,    /* operator merges */
                       canHash);    /* operator hashes */
}

void RemoveOperatorById ( Oid  operOid  ) 

Definition at line 316 of file operatorcmds.c.

References elog, ERROR, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, OperatorRelationId, OPEROID, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, simple_heap_delete(), and HeapTupleData::t_self.

Referenced by doDeletion().

{
    Relation    relation;
    HeapTuple   tup;

    relation = heap_open(OperatorRelationId, RowExclusiveLock);

    tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
    if (!HeapTupleIsValid(tup)) /* should not happen */
        elog(ERROR, "cache lookup failed for operator %u", operOid);

    simple_heap_delete(relation, &tup->t_self);

    ReleaseSysCache(tup);

    heap_close(relation, RowExclusiveLock);
}