Header And Logo

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

Data Structures | Defines | Typedefs | Functions | Variables

parse_oper.c File Reference

#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "lib/stringinfo.h"
#include "nodes/nodeFuncs.h"
#include "parser/parse_coerce.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
Include dependency graph for parse_oper.c:

Go to the source code of this file.

Data Structures

struct  OprCacheKey
struct  OprCacheEntry

Defines

#define MAX_CACHED_PATH_LEN   16

Typedefs

typedef struct OprCacheKey OprCacheKey
typedef struct OprCacheEntry OprCacheEntry

Functions

static Oid binary_oper_exact (List *opname, Oid arg1, Oid arg2)
static FuncDetailCode oper_select_candidate (int nargs, Oid *input_typeids, FuncCandidateList candidates, Oid *operOid)
static const char * op_signature_string (List *op, char oprkind, Oid arg1, Oid arg2)
static void op_error (ParseState *pstate, List *op, char oprkind, Oid arg1, Oid arg2, FuncDetailCode fdresult, int location)
static bool make_oper_cache_key (OprCacheKey *key, List *opname, Oid ltypeId, Oid rtypeId)
static Oid find_oper_cache_entry (OprCacheKey *key)
static void make_oper_cache_entry (OprCacheKey *key, Oid opr_oid)
static void InvalidateOprCacheCallBack (Datum arg, int cacheid, uint32 hashvalue)
Oid LookupOperName (ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Oid LookupOperNameTypeNames (ParseState *pstate, List *opername, TypeName *oprleft, TypeName *oprright, bool noError, int location)
void get_sort_group_operators (Oid argtype, bool needLT, bool needEQ, bool needGT, Oid *ltOpr, Oid *eqOpr, Oid *gtOpr, bool *isHashable)
Oid oprid (Operator op)
Oid oprfuncid (Operator op)
Operator oper (ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Operator compatible_oper (ParseState *pstate, List *op, Oid arg1, Oid arg2, bool noError, int location)
Oid compatible_oper_opid (List *op, Oid arg1, Oid arg2, bool noError)
Operator right_oper (ParseState *pstate, List *op, Oid arg, bool noError, int location)
Operator left_oper (ParseState *pstate, List *op, Oid arg, bool noError, int location)
Exprmake_op (ParseState *pstate, List *opname, Node *ltree, Node *rtree, int location)
Exprmake_scalar_array_op (ParseState *pstate, List *opname, bool useOr, Node *ltree, Node *rtree, int location)

Variables

static HTABOprCacheHash = NULL

Define Documentation

#define MAX_CACHED_PATH_LEN   16

Definition at line 49 of file parse_oper.c.

Referenced by make_oper_cache_key().


Typedef Documentation

typedef struct OprCacheEntry OprCacheEntry
typedef struct OprCacheKey OprCacheKey

Function Documentation

static Oid binary_oper_exact ( List opname,
Oid  arg1,
Oid  arg2 
) [static]

Definition at line 266 of file parse_oper.c.

References getBaseType(), InvalidOid, OidIsValid, OpernameGetOprid(), and UNKNOWNOID.

Referenced by oper().

{
    Oid         result;
    bool        was_unknown = false;

    /* Unspecified type for one of the arguments? then use the other */
    if ((arg1 == UNKNOWNOID) && (arg2 != InvalidOid))
    {
        arg1 = arg2;
        was_unknown = true;
    }
    else if ((arg2 == UNKNOWNOID) && (arg1 != InvalidOid))
    {
        arg2 = arg1;
        was_unknown = true;
    }

    result = OpernameGetOprid(opname, arg1, arg2);
    if (OidIsValid(result))
        return result;

    if (was_unknown)
    {
        /* arg1 and arg2 are the same here, need only look at arg1 */
        Oid         basetype = getBaseType(arg1);

        if (basetype != arg1)
        {
            result = OpernameGetOprid(opname, basetype, basetype);
            if (OidIsValid(result))
                return result;
        }
    }

    return InvalidOid;
}

Operator compatible_oper ( ParseState pstate,
List op,
Oid  arg1,
Oid  arg2,
bool  noError,
int  location 
)

Definition at line 453 of file parse_oper.c.

References ereport, errcode(), errmsg(), ERROR, GETSTRUCT, IsBinaryCoercible(), NULL, op_signature_string(), oper(), parser_errposition(), and ReleaseSysCache().

Referenced by compatible_oper_opid().

{
    Operator    optup;
    Form_pg_operator opform;

    /* oper() will find the best available match */
    optup = oper(pstate, op, arg1, arg2, noError, location);
    if (optup == (Operator) NULL)
        return (Operator) NULL; /* must be noError case */

    /* but is it good enough? */
    opform = (Form_pg_operator) GETSTRUCT(optup);
    if (IsBinaryCoercible(arg1, opform->oprleft) &&
        IsBinaryCoercible(arg2, opform->oprright))
        return optup;

    /* nope... */
    ReleaseSysCache(optup);

    if (!noError)
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_FUNCTION),
                 errmsg("operator requires run-time type coercion: %s",
                        op_signature_string(op, 'b', arg1, arg2)),
                 parser_errposition(pstate, location)));

    return (Operator) NULL;
}

Oid compatible_oper_opid ( List op,
Oid  arg1,
Oid  arg2,
bool  noError 
)

Definition at line 490 of file parse_oper.c.

References compatible_oper(), NULL, oprid(), and ReleaseSysCache().

Referenced by addTargetToSortList(), and ComputeIndexAttrs().

{
    Operator    optup;
    Oid         result;

    optup = compatible_oper(NULL, op, arg1, arg2, noError, -1);
    if (optup != NULL)
    {
        result = oprid(optup);
        ReleaseSysCache(optup);
        return result;
    }
    return InvalidOid;
}

static Oid find_oper_cache_entry ( OprCacheKey key  )  [static]

Definition at line 1050 of file parse_oper.c.

References CacheRegisterSyscacheCallback(), CASTSOURCETARGET, HASHCTL::entrysize, HASHCTL::hash, hash_create(), HASH_ELEM, HASH_FUNCTION, hash_search(), InvalidateOprCacheCallBack(), HASHCTL::keysize, MemSet, NULL, OPERNAMENSP, and OprCacheEntry::opr_oid.

Referenced by left_oper(), oper(), and right_oper().

{
    OprCacheEntry *oprentry;

    if (OprCacheHash == NULL)
    {
        /* First time through: initialize the hash table */
        HASHCTL     ctl;

        MemSet(&ctl, 0, sizeof(ctl));
        ctl.keysize = sizeof(OprCacheKey);
        ctl.entrysize = sizeof(OprCacheEntry);
        ctl.hash = tag_hash;
        OprCacheHash = hash_create("Operator lookup cache", 256,
                                   &ctl, HASH_ELEM | HASH_FUNCTION);

        /* Arrange to flush cache on pg_operator and pg_cast changes */
        CacheRegisterSyscacheCallback(OPERNAMENSP,
                                      InvalidateOprCacheCallBack,
                                      (Datum) 0);
        CacheRegisterSyscacheCallback(CASTSOURCETARGET,
                                      InvalidateOprCacheCallBack,
                                      (Datum) 0);
    }

    /* Look for an existing entry */
    oprentry = (OprCacheEntry *) hash_search(OprCacheHash,
                                             (void *) key,
                                             HASH_FIND, NULL);
    if (oprentry == NULL)
        return InvalidOid;

    return oprentry->opr_oid;
}

void get_sort_group_operators ( Oid  argtype,
bool  needLT,
bool  needEQ,
bool  needGT,
Oid ltOpr,
Oid eqOpr,
Oid gtOpr,
bool isHashable 
)

Definition at line 184 of file parse_oper.c.

References TypeCacheEntry::eq_opr, ereport, errcode(), errhint(), errmsg(), ERROR, format_type_be(), TypeCacheEntry::gt_opr, TypeCacheEntry::hash_proc, lookup_type_cache(), TypeCacheEntry::lt_opr, NULL, OidIsValid, TYPECACHE_EQ_OPR, TYPECACHE_GT_OPR, and TYPECACHE_LT_OPR.

Referenced by addTargetToGroupList(), addTargetToSortList(), std_typanalyze(), and transformSetOperationTree().

{
    TypeCacheEntry *typentry;
    int         cache_flags;
    Oid         lt_opr;
    Oid         eq_opr;
    Oid         gt_opr;
    bool        hashable;

    /*
     * Look up the operators using the type cache.
     *
     * Note: the search algorithm used by typcache.c ensures that the results
     * are consistent, ie all from matching opclasses.
     */
    if (isHashable != NULL)
        cache_flags = TYPECACHE_LT_OPR | TYPECACHE_EQ_OPR | TYPECACHE_GT_OPR |
            TYPECACHE_HASH_PROC;
    else
        cache_flags = TYPECACHE_LT_OPR | TYPECACHE_EQ_OPR | TYPECACHE_GT_OPR;

    typentry = lookup_type_cache(argtype, cache_flags);
    lt_opr = typentry->lt_opr;
    eq_opr = typentry->eq_opr;
    gt_opr = typentry->gt_opr;
    hashable = OidIsValid(typentry->hash_proc);

    /* Report errors if needed */
    if ((needLT && !OidIsValid(lt_opr)) ||
        (needGT && !OidIsValid(gt_opr)))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_FUNCTION),
                 errmsg("could not identify an ordering operator for type %s",
                        format_type_be(argtype)),
         errhint("Use an explicit ordering operator or modify the query.")));
    if (needEQ && !OidIsValid(eq_opr))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_FUNCTION),
                 errmsg("could not identify an equality operator for type %s",
                        format_type_be(argtype))));

    /* Return results as needed */
    if (ltOpr)
        *ltOpr = lt_opr;
    if (eqOpr)
        *eqOpr = eq_opr;
    if (gtOpr)
        *gtOpr = gt_opr;
    if (isHashable)
        *isHashable = hashable;
}

static void InvalidateOprCacheCallBack ( Datum  arg,
int  cacheid,
uint32  hashvalue 
) [static]

Definition at line 1107 of file parse_oper.c.

References Assert, elog, ERROR, HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), OprCacheEntry::key, and NULL.

Referenced by find_oper_cache_entry().

{
    HASH_SEQ_STATUS status;
    OprCacheEntry *hentry;

    Assert(OprCacheHash != NULL);

    /* Currently we just flush all entries; hard to be smarter ... */
    hash_seq_init(&status, OprCacheHash);

    while ((hentry = (OprCacheEntry *) hash_seq_search(&status)) != NULL)
    {
        if (hash_search(OprCacheHash,
                        (void *) &hentry->key,
                        HASH_REMOVE, NULL) == NULL)
            elog(ERROR, "hash table corrupted");
    }
}

Operator left_oper ( ParseState pstate,
List op,
Oid  arg,
bool  noError,
int  location 
)

Definition at line 599 of file parse_oper.c.

References _FuncCandidateList::args, find_oper_cache_entry(), HeapTupleIsValid, InvalidOid, make_oper_cache_entry(), make_oper_cache_key(), _FuncCandidateList::next, NULL, ObjectIdGetDatum, OidIsValid, op_error(), oper_select_candidate(), OpernameGetCandidates(), OpernameGetOprid(), OPEROID, and SearchSysCache1.

Referenced by generate_operator_name(), and make_op().

{
    Oid         operOid;
    OprCacheKey key;
    bool        key_ok;
    FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
    HeapTuple   tup = NULL;

    /*
     * Try to find the mapping in the lookaside cache.
     */
    key_ok = make_oper_cache_key(&key, op, InvalidOid, arg);
    if (key_ok)
    {
        operOid = find_oper_cache_entry(&key);
        if (OidIsValid(operOid))
        {
            tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
            if (HeapTupleIsValid(tup))
                return (Operator) tup;
        }
    }

    /*
     * First try for an "exact" match.
     */
    operOid = OpernameGetOprid(op, InvalidOid, arg);
    if (!OidIsValid(operOid))
    {
        /*
         * Otherwise, search for the most suitable candidate.
         */
        FuncCandidateList clist;

        /* Get prefix operators of given name */
        clist = OpernameGetCandidates(op, 'l');

        /* No operators found? Then fail... */
        if (clist != NULL)
        {
            /*
             * The returned list has args in the form (0, oprright). Move the
             * useful data into args[0] to keep oper_select_candidate simple.
             * XXX we are assuming here that we may scribble on the list!
             */
            FuncCandidateList clisti;

            for (clisti = clist; clisti != NULL; clisti = clisti->next)
            {
                clisti->args[0] = clisti->args[1];
            }

            /*
             * We must run oper_select_candidate even if only one candidate,
             * otherwise we may falsely return a non-type-compatible operator.
             */
            fdresult = oper_select_candidate(1, &arg, clist, &operOid);
        }
    }

    if (OidIsValid(operOid))
        tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));

    if (HeapTupleIsValid(tup))
    {
        if (key_ok)
            make_oper_cache_entry(&key, operOid);
    }
    else if (!noError)
        op_error(pstate, op, 'l', InvalidOid, arg, fdresult, location);

    return (Operator) tup;
}

Oid LookupOperName ( ParseState pstate,
List opername,
Oid  oprleft,
Oid  oprright,
bool  noError,
int  location 
)

Definition at line 101 of file parse_oper.c.

References ereport, errcode(), errmsg(), ERROR, OidIsValid, op_signature_string(), OpernameGetOprid(), and parser_errposition().

Referenced by AggregateCreate(), DefineOpClass(), and LookupOperNameTypeNames().

{
    Oid         result;

    result = OpernameGetOprid(opername, oprleft, oprright);
    if (OidIsValid(result))
        return result;

    /* we don't use op_error here because only an exact match is wanted */
    if (!noError)
    {
        char        oprkind;

        if (!OidIsValid(oprleft))
            oprkind = 'l';
        else if (!OidIsValid(oprright))
            oprkind = 'r';
        else
            oprkind = 'b';

        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_FUNCTION),
                 errmsg("operator does not exist: %s",
                        op_signature_string(opername, oprkind,
                                            oprleft, oprright)),
                 parser_errposition(pstate, location)));
    }

    return InvalidOid;
}

Oid LookupOperNameTypeNames ( ParseState pstate,
List opername,
TypeName oprleft,
TypeName oprright,
bool  noError,
int  location 
)

Definition at line 141 of file parse_oper.c.

References LookupOperName(), NULL, and typenameTypeId().

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

{
    Oid         leftoid,
                rightoid;

    if (oprleft == NULL)
        leftoid = InvalidOid;
    else
        leftoid = typenameTypeId(pstate, oprleft);

    if (oprright == NULL)
        rightoid = InvalidOid;
    else
        rightoid = typenameTypeId(pstate, oprright);

    return LookupOperName(pstate, opername, leftoid, rightoid,
                          noError, location);
}

Expr* make_op ( ParseState pstate,
List opname,
Node ltree,
Node rtree,
int  location 
)

Definition at line 736 of file parse_oper.c.

References OpExpr::args, enforce_generic_type_consistency(), ereport, errcode(), errmsg(), ERROR, exprType(), get_func_retset(), GETSTRUCT, left_oper(), list_make1, list_make2, OpExpr::location, make_fn_arguments(), makeNode, NULL, op_signature_string(), oper(), OpExpr::opfuncid, OpExpr::opno, OpExpr::opresulttype, OpExpr::opretset, oprid(), parser_errposition(), RegProcedureIsValid, ReleaseSysCache(), and right_oper().

Referenced by make_distinct_op(), make_row_comparison_op(), transformAExprIn(), transformAExprNullIf(), and transformAExprOp().

{
    Oid         ltypeId,
                rtypeId;
    Operator    tup;
    Form_pg_operator opform;
    Oid         actual_arg_types[2];
    Oid         declared_arg_types[2];
    int         nargs;
    List       *args;
    Oid         rettype;
    OpExpr     *result;

    /* Select the operator */
    if (rtree == NULL)
    {
        /* right operator */
        ltypeId = exprType(ltree);
        rtypeId = InvalidOid;
        tup = right_oper(pstate, opname, ltypeId, false, location);
    }
    else if (ltree == NULL)
    {
        /* left operator */
        rtypeId = exprType(rtree);
        ltypeId = InvalidOid;
        tup = left_oper(pstate, opname, rtypeId, false, location);
    }
    else
    {
        /* otherwise, binary operator */
        ltypeId = exprType(ltree);
        rtypeId = exprType(rtree);
        tup = oper(pstate, opname, ltypeId, rtypeId, false, location);
    }

    opform = (Form_pg_operator) GETSTRUCT(tup);

    /* Check it's not a shell */
    if (!RegProcedureIsValid(opform->oprcode))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_FUNCTION),
                 errmsg("operator is only a shell: %s",
                        op_signature_string(opname,
                                            opform->oprkind,
                                            opform->oprleft,
                                            opform->oprright)),
                 parser_errposition(pstate, location)));

    /* Do typecasting and build the expression tree */
    if (rtree == NULL)
    {
        /* right operator */
        args = list_make1(ltree);
        actual_arg_types[0] = ltypeId;
        declared_arg_types[0] = opform->oprleft;
        nargs = 1;
    }
    else if (ltree == NULL)
    {
        /* left operator */
        args = list_make1(rtree);
        actual_arg_types[0] = rtypeId;
        declared_arg_types[0] = opform->oprright;
        nargs = 1;
    }
    else
    {
        /* otherwise, binary operator */
        args = list_make2(ltree, rtree);
        actual_arg_types[0] = ltypeId;
        actual_arg_types[1] = rtypeId;
        declared_arg_types[0] = opform->oprleft;
        declared_arg_types[1] = opform->oprright;
        nargs = 2;
    }

    /*
     * enforce consistency with polymorphic argument and return types,
     * possibly adjusting return type or declared_arg_types (which will be
     * used as the cast destination by make_fn_arguments)
     */
    rettype = enforce_generic_type_consistency(actual_arg_types,
                                               declared_arg_types,
                                               nargs,
                                               opform->oprresult,
                                               false);

    /* perform the necessary typecasting of arguments */
    make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types);

    /* and build the expression node */
    result = makeNode(OpExpr);
    result->opno = oprid(tup);
    result->opfuncid = opform->oprcode;
    result->opresulttype = rettype;
    result->opretset = get_func_retset(opform->oprcode);
    /* opcollid and inputcollid will be set by parse_collate.c */
    result->args = args;
    result->location = location;

    ReleaseSysCache(tup);

    return (Expr *) result;
}

static void make_oper_cache_entry ( OprCacheKey key,
Oid  opr_oid 
) [static]

Definition at line 1091 of file parse_oper.c.

References Assert, hash_search(), NULL, and OprCacheEntry::opr_oid.

Referenced by left_oper(), oper(), and right_oper().

{
    OprCacheEntry *oprentry;

    Assert(OprCacheHash != NULL);

    oprentry = (OprCacheEntry *) hash_search(OprCacheHash,
                                             (void *) key,
                                             HASH_ENTER, NULL);
    oprentry->opr_oid = opr_oid;
}

static bool make_oper_cache_key ( OprCacheKey key,
List opname,
Oid  ltypeId,
Oid  rtypeId 
) [static]

Definition at line 1011 of file parse_oper.c.

References DeconstructQualifiedName(), fetch_search_path_array(), OprCacheKey::left_arg, LookupExplicitNamespace(), MAX_CACHED_PATH_LEN, MemSet, NAMEDATALEN, OprCacheKey::oprname, OprCacheKey::right_arg, OprCacheKey::search_path, and strlcpy().

Referenced by left_oper(), oper(), and right_oper().

{
    char       *schemaname;
    char       *opername;

    /* deconstruct the name list */
    DeconstructQualifiedName(opname, &schemaname, &opername);

    /* ensure zero-fill for stable hashing */
    MemSet(key, 0, sizeof(OprCacheKey));

    /* save operator name and input types into key */
    strlcpy(key->oprname, opername, NAMEDATALEN);
    key->left_arg = ltypeId;
    key->right_arg = rtypeId;

    if (schemaname)
    {
        /* search only in exact schema given */
        key->search_path[0] = LookupExplicitNamespace(schemaname, false);
    }
    else
    {
        /* get the active search path */
        if (fetch_search_path_array(key->search_path,
                                  MAX_CACHED_PATH_LEN) > MAX_CACHED_PATH_LEN)
            return false;       /* oops, didn't fit */
    }

    return true;
}

Expr* make_scalar_array_op ( ParseState pstate,
List opname,
bool  useOr,
Node ltree,
Node rtree,
int  location 
)

Definition at line 848 of file parse_oper.c.

References ScalarArrayOpExpr::args, BOOLOID, enforce_generic_type_consistency(), ereport, errcode(), errmsg(), ERROR, exprType(), format_type_be(), get_array_type(), get_base_element_type(), get_func_retset(), GETSTRUCT, IsPolymorphicType, list_make2, ScalarArrayOpExpr::location, make_fn_arguments(), makeNode, OidIsValid, op_signature_string(), oper(), ScalarArrayOpExpr::opfuncid, ScalarArrayOpExpr::opno, oprid(), parser_errposition(), RegProcedureIsValid, ReleaseSysCache(), UNKNOWNOID, and ScalarArrayOpExpr::useOr.

Referenced by transformAExprIn(), transformAExprOpAll(), and transformAExprOpAny().

{
    Oid         ltypeId,
                rtypeId,
                atypeId,
                res_atypeId;
    Operator    tup;
    Form_pg_operator opform;
    Oid         actual_arg_types[2];
    Oid         declared_arg_types[2];
    List       *args;
    Oid         rettype;
    ScalarArrayOpExpr *result;

    ltypeId = exprType(ltree);
    atypeId = exprType(rtree);

    /*
     * The right-hand input of the operator will be the element type of the
     * array.  However, if we currently have just an untyped literal on the
     * right, stay with that and hope we can resolve the operator.
     */
    if (atypeId == UNKNOWNOID)
        rtypeId = UNKNOWNOID;
    else
    {
        rtypeId = get_base_element_type(atypeId);
        if (!OidIsValid(rtypeId))
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                   errmsg("op ANY/ALL (array) requires array on right side"),
                     parser_errposition(pstate, location)));
    }

    /* Now resolve the operator */
    tup = oper(pstate, opname, ltypeId, rtypeId, false, location);
    opform = (Form_pg_operator) GETSTRUCT(tup);

    /* Check it's not a shell */
    if (!RegProcedureIsValid(opform->oprcode))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_FUNCTION),
                 errmsg("operator is only a shell: %s",
                        op_signature_string(opname,
                                            opform->oprkind,
                                            opform->oprleft,
                                            opform->oprright)),
                 parser_errposition(pstate, location)));

    args = list_make2(ltree, rtree);
    actual_arg_types[0] = ltypeId;
    actual_arg_types[1] = rtypeId;
    declared_arg_types[0] = opform->oprleft;
    declared_arg_types[1] = opform->oprright;

    /*
     * enforce consistency with polymorphic argument and return types,
     * possibly adjusting return type or declared_arg_types (which will be
     * used as the cast destination by make_fn_arguments)
     */
    rettype = enforce_generic_type_consistency(actual_arg_types,
                                               declared_arg_types,
                                               2,
                                               opform->oprresult,
                                               false);

    /*
     * Check that operator result is boolean
     */
    if (rettype != BOOLOID)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
             errmsg("op ANY/ALL (array) requires operator to yield boolean"),
                 parser_errposition(pstate, location)));
    if (get_func_retset(opform->oprcode))
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
          errmsg("op ANY/ALL (array) requires operator not to return a set"),
                 parser_errposition(pstate, location)));

    /*
     * Now switch back to the array type on the right, arranging for any
     * needed cast to be applied.  Beware of polymorphic operators here;
     * enforce_generic_type_consistency may or may not have replaced a
     * polymorphic type with a real one.
     */
    if (IsPolymorphicType(declared_arg_types[1]))
    {
        /* assume the actual array type is OK */
        res_atypeId = atypeId;
    }
    else
    {
        res_atypeId = get_array_type(declared_arg_types[1]);
        if (!OidIsValid(res_atypeId))
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_OBJECT),
                     errmsg("could not find array type for data type %s",
                            format_type_be(declared_arg_types[1])),
                     parser_errposition(pstate, location)));
    }
    actual_arg_types[1] = atypeId;
    declared_arg_types[1] = res_atypeId;

    /* perform the necessary typecasting of arguments */
    make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types);

    /* and build the expression node */
    result = makeNode(ScalarArrayOpExpr);
    result->opno = oprid(tup);
    result->opfuncid = opform->oprcode;
    result->useOr = useOr;
    /* inputcollid will be set by parse_collate.c */
    result->args = args;
    result->location = location;

    ReleaseSysCache(tup);

    return (Expr *) result;
}

static void op_error ( ParseState pstate,
List op,
char  oprkind,
Oid  arg1,
Oid  arg2,
FuncDetailCode  fdresult,
int  location 
) [static]

Definition at line 703 of file parse_oper.c.

References ereport, errcode(), errhint(), errmsg(), ERROR, FUNCDETAIL_MULTIPLE, op_signature_string(), and parser_errposition().

Referenced by left_oper(), oper(), and right_oper().

{
    if (fdresult == FUNCDETAIL_MULTIPLE)
        ereport(ERROR,
                (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
                 errmsg("operator is not unique: %s",
                        op_signature_string(op, oprkind, arg1, arg2)),
                 errhint("Could not choose a best candidate operator. "
                         "You might need to add explicit type casts."),
                 parser_errposition(pstate, location)));
    else
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_FUNCTION),
                 errmsg("operator does not exist: %s",
                        op_signature_string(op, oprkind, arg1, arg2)),
          errhint("No operator matches the given name and argument type(s). "
                  "You might need to add explicit type casts."),
                 parser_errposition(pstate, location)));
}

static const char * op_signature_string ( List op,
char  oprkind,
Oid  arg1,
Oid  arg2 
) [static]

Definition at line 682 of file parse_oper.c.

References appendStringInfo(), appendStringInfoString(), StringInfoData::data, format_type_be(), initStringInfo(), and NameListToString().

Referenced by compatible_oper(), LookupOperName(), make_op(), make_scalar_array_op(), and op_error().

{
    StringInfoData argbuf;

    initStringInfo(&argbuf);

    if (oprkind != 'l')
        appendStringInfo(&argbuf, "%s ", format_type_be(arg1));

    appendStringInfoString(&argbuf, NameListToString(op));

    if (oprkind != 'r')
        appendStringInfo(&argbuf, " %s", format_type_be(arg2));

    return argbuf.data;         /* return palloc'd string buffer */
}

Operator oper ( ParseState pstate,
List opname,
Oid  ltypeId,
Oid  rtypeId,
bool  noError,
int  location 
)

Definition at line 374 of file parse_oper.c.

References binary_oper_exact(), find_oper_cache_entry(), HeapTupleIsValid, InvalidOid, make_oper_cache_entry(), make_oper_cache_key(), NULL, ObjectIdGetDatum, OidIsValid, op_error(), oper_select_candidate(), OpernameGetCandidates(), OPEROID, and SearchSysCache1.

Referenced by compatible_oper(), generate_operator_name(), make_op(), make_scalar_array_op(), makeOperatorDependencies(), and tsquery_opr_selec().

{
    Oid         operOid;
    OprCacheKey key;
    bool        key_ok;
    FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
    HeapTuple   tup = NULL;

    /*
     * Try to find the mapping in the lookaside cache.
     */
    key_ok = make_oper_cache_key(&key, opname, ltypeId, rtypeId);
    if (key_ok)
    {
        operOid = find_oper_cache_entry(&key);
        if (OidIsValid(operOid))
        {
            tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
            if (HeapTupleIsValid(tup))
                return (Operator) tup;
        }
    }

    /*
     * First try for an "exact" match.
     */
    operOid = binary_oper_exact(opname, ltypeId, rtypeId);
    if (!OidIsValid(operOid))
    {
        /*
         * Otherwise, search for the most suitable candidate.
         */
        FuncCandidateList clist;

        /* Get binary operators of given name */
        clist = OpernameGetCandidates(opname, 'b');

        /* No operators found? Then fail... */
        if (clist != NULL)
        {
            /*
             * Unspecified type for one of the arguments? then use the other
             * (XXX this is probably dead code?)
             */
            Oid         inputOids[2];

            if (rtypeId == InvalidOid)
                rtypeId = ltypeId;
            else if (ltypeId == InvalidOid)
                ltypeId = rtypeId;
            inputOids[0] = ltypeId;
            inputOids[1] = rtypeId;
            fdresult = oper_select_candidate(2, inputOids, clist, &operOid);
        }
    }

    if (OidIsValid(operOid))
        tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));

    if (HeapTupleIsValid(tup))
    {
        if (key_ok)
            make_oper_cache_entry(&key, operOid);
    }
    else if (!noError)
        op_error(pstate, opname, 'b', ltypeId, rtypeId, fdresult, location);

    return (Operator) tup;
}

static FuncDetailCode oper_select_candidate ( int  nargs,
Oid input_typeids,
FuncCandidateList  candidates,
Oid operOid 
) [static]

Definition at line 316 of file parse_oper.c.

References func_match_argtypes(), func_select_candidate(), and _FuncCandidateList::oid.

Referenced by left_oper(), oper(), and right_oper().

{
    int         ncandidates;

    /*
     * Delete any candidates that cannot actually accept the given input
     * types, whether directly or by coercion.
     */
    ncandidates = func_match_argtypes(nargs, input_typeids,
                                      candidates, &candidates);

    /* Done if no candidate or only one candidate survives */
    if (ncandidates == 0)
    {
        *operOid = InvalidOid;
        return FUNCDETAIL_NOTFOUND;
    }
    if (ncandidates == 1)
    {
        *operOid = candidates->oid;
        return FUNCDETAIL_NORMAL;
    }

    /*
     * Use the same heuristics as for ambiguous functions to resolve the
     * conflict.
     */
    candidates = func_select_candidate(nargs, input_typeids, candidates);

    if (candidates)
    {
        *operOid = candidates->oid;
        return FUNCDETAIL_NORMAL;
    }

    *operOid = InvalidOid;
    return FUNCDETAIL_MULTIPLE; /* failed to select a best candidate */
}

Oid oprfuncid ( Operator  op  ) 

Definition at line 249 of file parse_oper.c.

References GETSTRUCT.

{
    Form_pg_operator pgopform = (Form_pg_operator) GETSTRUCT(op);

    return pgopform->oprcode;
}

Oid oprid ( Operator  op  ) 
Operator right_oper ( ParseState pstate,
List op,
Oid  arg,
bool  noError,
int  location 
)

Definition at line 521 of file parse_oper.c.

References find_oper_cache_entry(), HeapTupleIsValid, InvalidOid, make_oper_cache_entry(), make_oper_cache_key(), NULL, ObjectIdGetDatum, OidIsValid, op_error(), oper_select_candidate(), OpernameGetCandidates(), OpernameGetOprid(), OPEROID, and SearchSysCache1.

Referenced by generate_operator_name(), and make_op().

{
    Oid         operOid;
    OprCacheKey key;
    bool        key_ok;
    FuncDetailCode fdresult = FUNCDETAIL_NOTFOUND;
    HeapTuple   tup = NULL;

    /*
     * Try to find the mapping in the lookaside cache.
     */
    key_ok = make_oper_cache_key(&key, op, arg, InvalidOid);
    if (key_ok)
    {
        operOid = find_oper_cache_entry(&key);
        if (OidIsValid(operOid))
        {
            tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
            if (HeapTupleIsValid(tup))
                return (Operator) tup;
        }
    }

    /*
     * First try for an "exact" match.
     */
    operOid = OpernameGetOprid(op, arg, InvalidOid);
    if (!OidIsValid(operOid))
    {
        /*
         * Otherwise, search for the most suitable candidate.
         */
        FuncCandidateList clist;

        /* Get postfix operators of given name */
        clist = OpernameGetCandidates(op, 'r');

        /* No operators found? Then fail... */
        if (clist != NULL)
        {
            /*
             * We must run oper_select_candidate even if only one candidate,
             * otherwise we may falsely return a non-type-compatible operator.
             */
            fdresult = oper_select_candidate(1, &arg, clist, &operOid);
        }
    }

    if (OidIsValid(operOid))
        tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));

    if (HeapTupleIsValid(tup))
    {
        if (key_ok)
            make_oper_cache_entry(&key, operOid);
    }
    else if (!noError)
        op_error(pstate, op, 'r', arg, InvalidOid, fdresult, location);

    return (Operator) tup;
}


Variable Documentation

HTAB* OprCacheHash = NULL [static]

Definition at line 1000 of file parse_oper.c.