Header And Logo

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

Data Structures | Defines | Functions

rangetypes.h File Reference

#include "utils/typcache.h"
Include dependency graph for rangetypes.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  RangeType
struct  RangeBound

Defines

#define RangeTypeGetOid(r)   ((r)->rangetypid)
#define RANGE_EMPTY   0x01
#define RANGE_LB_INC   0x02
#define RANGE_UB_INC   0x04
#define RANGE_LB_INF   0x08
#define RANGE_UB_INF   0x10
#define RANGE_LB_NULL   0x20
#define RANGE_UB_NULL   0x40
#define RANGE_CONTAIN_EMPTY   0x80
#define RANGE_HAS_LBOUND(flags)
#define RANGE_HAS_UBOUND(flags)
#define RangeIsEmpty(r)   ((range_get_flags(r) & RANGE_EMPTY) != 0)
#define RangeIsOrContainsEmpty(r)   ((range_get_flags(r) & (RANGE_EMPTY | RANGE_CONTAIN_EMPTY)) != 0)
#define DatumGetRangeType(X)   ((RangeType *) PG_DETOAST_DATUM(X))
#define DatumGetRangeTypeCopy(X)   ((RangeType *) PG_DETOAST_DATUM_COPY(X))
#define RangeTypeGetDatum(X)   PointerGetDatum(X)
#define PG_GETARG_RANGE(n)   DatumGetRangeType(PG_GETARG_DATUM(n))
#define PG_GETARG_RANGE_COPY(n)   DatumGetRangeTypeCopy(PG_GETARG_DATUM(n))
#define PG_RETURN_RANGE(x)   return RangeTypeGetDatum(x)
#define RANGESTRAT_BEFORE   1
#define RANGESTRAT_OVERLEFT   2
#define RANGESTRAT_OVERLAPS   3
#define RANGESTRAT_OVERRIGHT   4
#define RANGESTRAT_AFTER   5
#define RANGESTRAT_ADJACENT   6
#define RANGESTRAT_CONTAINS   7
#define RANGESTRAT_CONTAINED_BY   8
#define RANGESTRAT_CONTAINS_ELEM   16
#define RANGESTRAT_EQ   18

Functions

Datum range_in (PG_FUNCTION_ARGS)
Datum range_out (PG_FUNCTION_ARGS)
Datum range_recv (PG_FUNCTION_ARGS)
Datum range_send (PG_FUNCTION_ARGS)
Datum range_constructor2 (PG_FUNCTION_ARGS)
Datum range_constructor3 (PG_FUNCTION_ARGS)
Datum range_lower (PG_FUNCTION_ARGS)
Datum range_upper (PG_FUNCTION_ARGS)
Datum range_empty (PG_FUNCTION_ARGS)
Datum range_lower_inc (PG_FUNCTION_ARGS)
Datum range_upper_inc (PG_FUNCTION_ARGS)
Datum range_lower_inf (PG_FUNCTION_ARGS)
Datum range_upper_inf (PG_FUNCTION_ARGS)
Datum range_contains_elem (PG_FUNCTION_ARGS)
Datum elem_contained_by_range (PG_FUNCTION_ARGS)
bool range_contains_elem_internal (TypeCacheEntry *typcache, RangeType *r, Datum val)
Datum range_eq (PG_FUNCTION_ARGS)
Datum range_ne (PG_FUNCTION_ARGS)
Datum range_contains (PG_FUNCTION_ARGS)
Datum range_contained_by (PG_FUNCTION_ARGS)
Datum range_before (PG_FUNCTION_ARGS)
Datum range_after (PG_FUNCTION_ARGS)
Datum range_adjacent (PG_FUNCTION_ARGS)
Datum range_overlaps (PG_FUNCTION_ARGS)
Datum range_overleft (PG_FUNCTION_ARGS)
Datum range_overright (PG_FUNCTION_ARGS)
bool range_eq_internal (TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
bool range_ne_internal (TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
bool range_contains_internal (TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
bool range_contained_by_internal (TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
bool range_before_internal (TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
bool range_after_internal (TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
bool range_adjacent_internal (TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
bool range_overlaps_internal (TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
bool range_overleft_internal (TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
bool range_overright_internal (TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
Datum range_minus (PG_FUNCTION_ARGS)
Datum range_union (PG_FUNCTION_ARGS)
Datum range_intersect (PG_FUNCTION_ARGS)
Datum range_cmp (PG_FUNCTION_ARGS)
Datum range_lt (PG_FUNCTION_ARGS)
Datum range_le (PG_FUNCTION_ARGS)
Datum range_ge (PG_FUNCTION_ARGS)
Datum range_gt (PG_FUNCTION_ARGS)
Datum hash_range (PG_FUNCTION_ARGS)
Datum range_typanalyze (PG_FUNCTION_ARGS)
Datum rangesel (PG_FUNCTION_ARGS)
Datum int4range_canonical (PG_FUNCTION_ARGS)
Datum int8range_canonical (PG_FUNCTION_ARGS)
Datum daterange_canonical (PG_FUNCTION_ARGS)
Datum int4range_subdiff (PG_FUNCTION_ARGS)
Datum int8range_subdiff (PG_FUNCTION_ARGS)
Datum numrange_subdiff (PG_FUNCTION_ARGS)
Datum daterange_subdiff (PG_FUNCTION_ARGS)
Datum tsrange_subdiff (PG_FUNCTION_ARGS)
Datum tstzrange_subdiff (PG_FUNCTION_ARGS)
TypeCacheEntryrange_get_typcache (FunctionCallInfo fcinfo, Oid rngtypid)
RangeTyperange_serialize (TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, bool empty)
void range_deserialize (TypeCacheEntry *typcache, RangeType *range, RangeBound *lower, RangeBound *upper, bool *empty)
char range_get_flags (RangeType *range)
void range_set_contain_empty (RangeType *range)
RangeTypemake_range (TypeCacheEntry *typcache, RangeBound *lower, RangeBound *upper, bool empty)
int range_cmp_bounds (TypeCacheEntry *typcache, RangeBound *b1, RangeBound *b2)
int range_cmp_bound_values (TypeCacheEntry *typcache, RangeBound *b1, RangeBound *b2)
bool bounds_adjacent (TypeCacheEntry *typcache, RangeBound bound1, RangeBound bound2)
RangeTypemake_empty_range (TypeCacheEntry *typcache)
Datum range_gist_consistent (PG_FUNCTION_ARGS)
Datum range_gist_compress (PG_FUNCTION_ARGS)
Datum range_gist_decompress (PG_FUNCTION_ARGS)
Datum range_gist_union (PG_FUNCTION_ARGS)
Datum range_gist_penalty (PG_FUNCTION_ARGS)
Datum range_gist_picksplit (PG_FUNCTION_ARGS)
Datum range_gist_same (PG_FUNCTION_ARGS)

Define Documentation

#define DatumGetRangeType (   X  )     ((RangeType *) PG_DETOAST_DATUM(X))
#define DatumGetRangeTypeCopy (   X  )     ((RangeType *) PG_DETOAST_DATUM_COPY(X))

Definition at line 72 of file rangetypes.h.

#define PG_GETARG_RANGE (   n  )     DatumGetRangeType(PG_GETARG_DATUM(n))
#define PG_GETARG_RANGE_COPY (   n  )     DatumGetRangeTypeCopy(PG_GETARG_DATUM(n))

Definition at line 75 of file rangetypes.h.

#define PG_RETURN_RANGE (   x  )     return RangeTypeGetDatum(x)
#define RANGE_CONTAIN_EMPTY   0x80

Definition at line 43 of file rangetypes.h.

Referenced by get_gist_range_class(), and range_super_union().

#define RANGE_EMPTY   0x01
#define RANGE_HAS_LBOUND (   flags  ) 
#define RANGE_HAS_UBOUND (   flags  ) 
#define RANGE_LB_INC   0x02

Definition at line 37 of file rangetypes.h.

Referenced by range_deparse(), range_lower_inc(), and range_recv().

#define RANGE_LB_INF   0x08

Definition at line 39 of file rangetypes.h.

Referenced by get_gist_range_class(), range_lower_inf(), and range_recv().

#define RANGE_LB_NULL   0x20

Definition at line 41 of file rangetypes.h.

#define RANGE_UB_INC   0x04

Definition at line 38 of file rangetypes.h.

Referenced by range_deparse(), range_recv(), and range_upper_inc().

#define RANGE_UB_INF   0x10

Definition at line 40 of file rangetypes.h.

Referenced by get_gist_range_class(), and range_upper_inf().

#define RANGE_UB_NULL   0x40

Definition at line 42 of file rangetypes.h.

#define RangeIsEmpty (   r  )     ((range_get_flags(r) & RANGE_EMPTY) != 0)
#define RangeIsOrContainsEmpty (   r  )     ((range_get_flags(r) & (RANGE_EMPTY | RANGE_CONTAIN_EMPTY)) != 0)

Definition at line 55 of file rangetypes.h.

Referenced by range_gist_consistent_int(), and range_gist_penalty().

#define RANGESTRAT_ADJACENT   6
#define RANGESTRAT_AFTER   5
#define RANGESTRAT_BEFORE   1
#define RANGESTRAT_CONTAINED_BY   8
#define RANGESTRAT_CONTAINS   7
#define RANGESTRAT_CONTAINS_ELEM   16
#define RANGESTRAT_EQ   18
#define RANGESTRAT_OVERLAPS   3
#define RANGESTRAT_OVERLEFT   2
#define RANGESTRAT_OVERRIGHT   4
#define RangeTypeGetDatum (   X  )     PointerGetDatum(X)
#define RangeTypeGetOid (   r  )     ((r)->rangetypid)

Function Documentation

bool bounds_adjacent ( TypeCacheEntry typcache,
RangeBound  bound1,
RangeBound  bound2 
)

Definition at line 731 of file rangetypes.c.

References Assert, FmgrInfo::fn_oid, RangeBound::inclusive, RangeBound::lower, make_range(), OidIsValid, range_cmp_bound_values(), RangeIsEmpty, and TypeCacheEntry::rng_canonical_finfo.

Referenced by range_adjacent_internal(), and spg_range_quad_inner_consistent().

{
    int         cmp;

    Assert(!boundA.lower && boundB.lower);

    cmp = range_cmp_bound_values(typcache, &boundA, &boundB);
    if (cmp < 0)
    {
        RangeType *r;

        /*
         * Bounds do not overlap; see if there are points in between.
         */

        /* in a continuous subtype, there are assumed to be points between */
        if (!OidIsValid(typcache->rng_canonical_finfo.fn_oid))
            return false;

        /*
         * The bounds are of a discrete range type; so make a range A..B and
         * see if it's empty.
         */

        /* flip the inclusion flags */
        boundA.inclusive = !boundA.inclusive;
        boundB.inclusive = !boundB.inclusive;
        /* change upper/lower labels to avoid Assert failures */
        boundA.lower = true;
        boundB.lower = false;
        r = make_range(typcache, &boundA, &boundB, false);
        return RangeIsEmpty(r);
    }
    else if (cmp == 0)
        return boundA.inclusive != boundB.inclusive;
    else
        return false;       /* bounds overlap */
}

Datum daterange_canonical ( PG_FUNCTION_ARGS   ) 

Definition at line 1307 of file rangetypes.c.

References date_pli(), DirectFunctionCall2, RangeBound::inclusive, RangeBound::infinite, Int32GetDatum, PG_GETARG_RANGE, PG_RETURN_RANGE, range_deserialize(), range_get_typcache(), range_serialize(), RangeTypeGetOid, and RangeBound::val.

{
    RangeType  *r = PG_GETARG_RANGE(0);
    TypeCacheEntry *typcache;
    RangeBound  lower;
    RangeBound  upper;
    bool        empty;

    typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));

    range_deserialize(typcache, r, &lower, &upper, &empty);

    if (empty)
        PG_RETURN_RANGE(r);

    if (!lower.infinite && !lower.inclusive)
    {
        lower.val = DirectFunctionCall2(date_pli, lower.val, Int32GetDatum(1));
        lower.inclusive = true;
    }

    if (!upper.infinite && upper.inclusive)
    {
        upper.val = DirectFunctionCall2(date_pli, upper.val, Int32GetDatum(1));
        upper.inclusive = false;
    }

    PG_RETURN_RANGE(range_serialize(typcache, &lower, &upper, false));
}

Datum daterange_subdiff ( PG_FUNCTION_ARGS   ) 

Definition at line 1384 of file rangetypes.c.

References PG_GETARG_INT32, and PG_RETURN_FLOAT8.

Datum elem_contained_by_range ( PG_FUNCTION_ARGS   ) 
Datum hash_range ( PG_FUNCTION_ARGS   ) 

Definition at line 1177 of file rangetypes.c.

References DatumGetUInt32, ereport, errcode(), errmsg(), ERROR, FmgrInfo::fn_oid, format_type_be(), FunctionCall1Coll(), TypeCacheEntry::hash_proc_finfo, hash_uint32(), lookup_type_cache(), OidIsValid, PG_GETARG_RANGE, PG_RETURN_INT32, range_deserialize(), range_get_flags(), range_get_typcache(), RANGE_HAS_LBOUND, RANGE_HAS_UBOUND, RangeTypeGetOid, TypeCacheEntry::rng_collation, TypeCacheEntry::rngelemtype, TypeCacheEntry::type_id, TYPECACHE_HASH_PROC_FINFO, and RangeBound::val.

{
    RangeType  *r = PG_GETARG_RANGE(0);
    uint32      result;
    TypeCacheEntry *typcache;
    TypeCacheEntry *scache;
    RangeBound  lower;
    RangeBound  upper;
    bool        empty;
    char        flags;
    uint32      lower_hash;
    uint32      upper_hash;

    typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));

    /* deserialize */
    range_deserialize(typcache, r, &lower, &upper, &empty);
    flags = range_get_flags(r);

    /*
     * Look up the element type's hash function, if not done already.
     */
    scache = typcache->rngelemtype;
    if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
    {
        scache = lookup_type_cache(scache->type_id, TYPECACHE_HASH_PROC_FINFO);
        if (!OidIsValid(scache->hash_proc_finfo.fn_oid))
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_FUNCTION),
                     errmsg("could not identify a hash function for type %s",
                            format_type_be(scache->type_id))));
    }

    /*
     * Apply the hash function to each bound.
     */
    if (RANGE_HAS_LBOUND(flags))
        lower_hash = DatumGetUInt32(FunctionCall1Coll(&scache->hash_proc_finfo,
                                                      typcache->rng_collation,
                                                      lower.val));
    else
        lower_hash = 0;

    if (RANGE_HAS_UBOUND(flags))
        upper_hash = DatumGetUInt32(FunctionCall1Coll(&scache->hash_proc_finfo,
                                                      typcache->rng_collation,
                                                      upper.val));
    else
        upper_hash = 0;

    /* Merge hashes of flags and bounds */
    result = hash_uint32((uint32) flags);
    result ^= lower_hash;
    result = (result << 1) | (result >> 31);
    result ^= upper_hash;

    PG_RETURN_INT32(result);
}

Datum int4range_canonical ( PG_FUNCTION_ARGS   ) 

Definition at line 1245 of file rangetypes.c.

References DirectFunctionCall2, RangeBound::inclusive, RangeBound::infinite, Int32GetDatum, int4pl(), PG_GETARG_RANGE, PG_RETURN_RANGE, range_deserialize(), range_get_typcache(), range_serialize(), RangeTypeGetOid, and RangeBound::val.

{
    RangeType  *r = PG_GETARG_RANGE(0);
    TypeCacheEntry *typcache;
    RangeBound  lower;
    RangeBound  upper;
    bool        empty;

    typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));

    range_deserialize(typcache, r, &lower, &upper, &empty);

    if (empty)
        PG_RETURN_RANGE(r);

    if (!lower.infinite && !lower.inclusive)
    {
        lower.val = DirectFunctionCall2(int4pl, lower.val, Int32GetDatum(1));
        lower.inclusive = true;
    }

    if (!upper.infinite && upper.inclusive)
    {
        upper.val = DirectFunctionCall2(int4pl, upper.val, Int32GetDatum(1));
        upper.inclusive = false;
    }

    PG_RETURN_RANGE(range_serialize(typcache, &lower, &upper, false));
}

Datum int4range_subdiff ( PG_FUNCTION_ARGS   ) 

Definition at line 1350 of file rangetypes.c.

References PG_GETARG_INT32, and PG_RETURN_FLOAT8.

Datum int8range_canonical ( PG_FUNCTION_ARGS   ) 

Definition at line 1276 of file rangetypes.c.

References DirectFunctionCall2, RangeBound::inclusive, RangeBound::infinite, Int64GetDatum(), int8pl(), PG_GETARG_RANGE, PG_RETURN_RANGE, range_deserialize(), range_get_typcache(), range_serialize(), RangeTypeGetOid, and RangeBound::val.

{
    RangeType  *r = PG_GETARG_RANGE(0);
    TypeCacheEntry *typcache;
    RangeBound  lower;
    RangeBound  upper;
    bool        empty;

    typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));

    range_deserialize(typcache, r, &lower, &upper, &empty);

    if (empty)
        PG_RETURN_RANGE(r);

    if (!lower.infinite && !lower.inclusive)
    {
        lower.val = DirectFunctionCall2(int8pl, lower.val, Int64GetDatum(1));
        lower.inclusive = true;
    }

    if (!upper.infinite && upper.inclusive)
    {
        upper.val = DirectFunctionCall2(int8pl, upper.val, Int64GetDatum(1));
        upper.inclusive = false;
    }

    PG_RETURN_RANGE(range_serialize(typcache, &lower, &upper, false));
}

Datum int8range_subdiff ( PG_FUNCTION_ARGS   ) 

Definition at line 1359 of file rangetypes.c.

References PG_GETARG_INT64, and PG_RETURN_FLOAT8.

{
    int64       v1 = PG_GETARG_INT64(0);
    int64       v2 = PG_GETARG_INT64(1);

    PG_RETURN_FLOAT8((float8) v1 - (float8) v2);
}

RangeType* make_empty_range ( TypeCacheEntry typcache  ) 

Definition at line 1840 of file rangetypes.c.

References RangeBound::inclusive, RangeBound::infinite, RangeBound::lower, make_range(), and RangeBound::val.

Referenced by range_intersect(), and range_minus().

{
    RangeBound  lower;
    RangeBound  upper;

    lower.val = (Datum) 0;
    lower.infinite = false;
    lower.inclusive = false;
    lower.lower = true;

    upper.val = (Datum) 0;
    upper.infinite = false;
    upper.inclusive = false;
    upper.lower = false;

    return make_range(typcache, &lower, &upper, true);
}

RangeType* make_range ( TypeCacheEntry typcache,
RangeBound lower,
RangeBound upper,
bool  empty 
)
Datum numrange_subdiff ( PG_FUNCTION_ARGS   ) 

Definition at line 1368 of file rangetypes.c.

References DatumGetFloat8, DirectFunctionCall1, DirectFunctionCall2, numeric_float8(), numeric_sub(), PG_GETARG_DATUM, and PG_RETURN_FLOAT8.

{
    Datum       v1 = PG_GETARG_DATUM(0);
    Datum       v2 = PG_GETARG_DATUM(1);
    Datum       numresult;
    float8      floatresult;

    numresult = DirectFunctionCall2(numeric_sub, v1, v2);

    floatresult = DatumGetFloat8(DirectFunctionCall1(numeric_float8,
                                                     numresult));

    PG_RETURN_FLOAT8(floatresult);
}

Datum range_adjacent ( PG_FUNCTION_ARGS   ) 
bool range_adjacent_internal ( TypeCacheEntry typcache,
RangeType r1,
RangeType r2 
)

Definition at line 772 of file rangetypes.c.

References bounds_adjacent(), elog, ERROR, range_deserialize(), and RangeTypeGetOid.

Referenced by range_adjacent(), range_gist_consistent_int(), range_gist_consistent_leaf(), and spg_range_quad_leaf_consistent().

{
    RangeBound  lower1,
                lower2;
    RangeBound  upper1,
                upper2;
    bool        empty1,
                empty2;

    /* Different types should be prevented by ANYRANGE matching rules */
    if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
        elog(ERROR, "range types do not match");

    range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
    range_deserialize(typcache, r2, &lower2, &upper2, &empty2);

    /* An empty range is not adjacent to any other range */
    if (empty1 || empty2)
        return false;

    /*
     * Given two ranges A..B and C..D, the ranges are adjacent if and only if
     * B is adjacent to C, or D is adjacent to A.
     */
    return (bounds_adjacent(typcache, upper1, lower2) ||
            bounds_adjacent(typcache, upper2, lower1));
}

Datum range_after ( PG_FUNCTION_ARGS   ) 
bool range_after_internal ( TypeCacheEntry typcache,
RangeType r1,
RangeType r2 
)

Definition at line 676 of file rangetypes.c.

References elog, ERROR, range_cmp_bounds(), range_deserialize(), and RangeTypeGetOid.

Referenced by range_after(), range_gist_consistent_int(), range_gist_consistent_leaf(), and spg_range_quad_leaf_consistent().

{
    RangeBound  lower1,
                lower2;
    RangeBound  upper1,
                upper2;
    bool        empty1,
                empty2;

    /* Different types should be prevented by ANYRANGE matching rules */
    if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
        elog(ERROR, "range types do not match");

    range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
    range_deserialize(typcache, r2, &lower2, &upper2, &empty2);

    /* An empty range is neither before nor after any other range */
    if (empty1 || empty2)
        return false;

    return (range_cmp_bounds(typcache, &lower1, &upper2) > 0);
}

Datum range_before ( PG_FUNCTION_ARGS   ) 
bool range_before_internal ( TypeCacheEntry typcache,
RangeType r1,
RangeType r2 
)

Definition at line 638 of file rangetypes.c.

References elog, ERROR, range_cmp_bounds(), range_deserialize(), and RangeTypeGetOid.

Referenced by range_before(), range_gist_consistent_int(), range_gist_consistent_leaf(), and spg_range_quad_leaf_consistent().

{
    RangeBound  lower1,
                lower2;
    RangeBound  upper1,
                upper2;
    bool        empty1,
                empty2;

    /* Different types should be prevented by ANYRANGE matching rules */
    if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
        elog(ERROR, "range types do not match");

    range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
    range_deserialize(typcache, r2, &lower2, &upper2, &empty2);

    /* An empty range is neither before nor after any other range */
    if (empty1 || empty2)
        return false;

    return (range_cmp_bounds(typcache, &upper1, &lower2) < 0);
}

Datum range_cmp ( PG_FUNCTION_ARGS   ) 

Definition at line 1104 of file rangetypes.c.

References elog, ERROR, PG_GETARG_RANGE, PG_RETURN_INT32, range_cmp_bounds(), range_deserialize(), range_get_typcache(), and RangeTypeGetOid.

Referenced by range_ge(), range_gt(), range_le(), and range_lt().

{
    RangeType  *r1 = PG_GETARG_RANGE(0);
    RangeType  *r2 = PG_GETARG_RANGE(1);
    TypeCacheEntry *typcache;
    RangeBound  lower1,
                lower2;
    RangeBound  upper1,
                upper2;
    bool        empty1,
                empty2;
    int         cmp;

    /* Different types should be prevented by ANYRANGE matching rules */
    if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
        elog(ERROR, "range types do not match");

    typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));

    range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
    range_deserialize(typcache, r2, &lower2, &upper2, &empty2);

    /* For b-tree use, empty ranges sort before all else */
    if (empty1 && empty2)
        PG_RETURN_INT32(0);
    else if (empty1)
        PG_RETURN_INT32(-1);
    else if (empty2)
        PG_RETURN_INT32(1);

    if ((cmp = range_cmp_bounds(typcache, &lower1, &lower2)) != 0)
        PG_RETURN_INT32(cmp);

    PG_RETURN_INT32(range_cmp_bounds(typcache, &upper1, &upper2));
}

int range_cmp_bound_values ( TypeCacheEntry typcache,
RangeBound b1,
RangeBound b2 
)

Definition at line 1805 of file rangetypes.c.

References DatumGetInt32, FunctionCall2Coll(), RangeBound::infinite, RangeBound::lower, TypeCacheEntry::rng_cmp_proc_finfo, TypeCacheEntry::rng_collation, and RangeBound::val.

Referenced by bounds_adjacent(), and range_serialize().

{
    /*
     * First, handle cases involving infinity, which don't require invoking
     * the comparison proc.
     */
    if (b1->infinite && b2->infinite)
    {
        /*
         * Both are infinity, so they are equal unless one is lower and the
         * other not.
         */
        if (b1->lower == b2->lower)
            return 0;
        else
            return b1->lower ? -1 : 1;
    }
    else if (b1->infinite)
        return b1->lower ? -1 : 1;
    else if (b2->infinite)
        return b2->lower ? 1 : -1;

    /*
     * Both boundaries are finite, so compare the held values.
     */
    return DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
                                           typcache->rng_collation,
                                           b1->val, b2->val));
}

int range_cmp_bounds ( TypeCacheEntry typcache,
RangeBound b1,
RangeBound b2 
)

Definition at line 1731 of file rangetypes.c.

References DatumGetInt32, FunctionCall2Coll(), RangeBound::inclusive, RangeBound::infinite, RangeBound::lower, TypeCacheEntry::rng_cmp_proc_finfo, TypeCacheEntry::rng_collation, and RangeBound::val.

Referenced by bound_cmp(), calc_hist_selectivity_contained(), getQuadrant(), interval_cmp_lower(), interval_cmp_upper(), range_after_internal(), range_before_internal(), range_bound_qsort_cmp(), range_cmp(), range_contains_internal(), range_eq_internal(), range_gist_double_sorting_split(), range_gist_penalty(), range_intersect(), range_minus(), range_overlaps_internal(), range_overleft_internal(), range_overright_internal(), range_super_union(), range_union(), rbound_bsearch(), single_bound_cmp(), and spg_range_quad_inner_consistent().

{
    int32       result;

    /*
     * First, handle cases involving infinity, which don't require invoking
     * the comparison proc.
     */
    if (b1->infinite && b2->infinite)
    {
        /*
         * Both are infinity, so they are equal unless one is lower and the
         * other not.
         */
        if (b1->lower == b2->lower)
            return 0;
        else
            return b1->lower ? -1 : 1;
    }
    else if (b1->infinite)
        return b1->lower ? -1 : 1;
    else if (b2->infinite)
        return b2->lower ? 1 : -1;

    /*
     * Both boundaries are finite, so compare the held values.
     */
    result = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
                                             typcache->rng_collation,
                                             b1->val, b2->val));

    /*
     * If the comparison is anything other than equal, we're done. If they
     * compare equal though, we still have to consider whether the boundaries
     * are inclusive or exclusive.
     */
    if (result == 0)
    {
        if (!b1->inclusive && !b2->inclusive)
        {
            /* both are exclusive */
            if (b1->lower == b2->lower)
                return 0;
            else
                return b1->lower ? 1 : -1;
        }
        else if (!b1->inclusive)
            return b1->lower ? 1 : -1;
        else if (!b2->inclusive)
            return b2->lower ? -1 : 1;
        else
        {
            /*
             * Both are inclusive and the values held are equal, so they are
             * equal regardless of whether they are upper or lower boundaries,
             * or a mix.
             */
            return 0;
        }
    }

    return result;
}

Datum range_constructor2 ( PG_FUNCTION_ARGS   ) 

Definition at line 351 of file rangetypes.c.

References get_fn_expr_rettype(), RangeBound::inclusive, RangeBound::infinite, RangeBound::lower, make_range(), PG_ARGISNULL, PG_GETARG_DATUM, PG_RETURN_RANGE, range_get_typcache(), and RangeBound::val.

{
    Datum       arg1 = PG_GETARG_DATUM(0);
    Datum       arg2 = PG_GETARG_DATUM(1);
    Oid         rngtypid = get_fn_expr_rettype(fcinfo->flinfo);
    RangeType  *range;
    TypeCacheEntry *typcache;
    RangeBound  lower;
    RangeBound  upper;

    typcache = range_get_typcache(fcinfo, rngtypid);

    lower.val = PG_ARGISNULL(0) ? (Datum) 0 : arg1;
    lower.infinite = PG_ARGISNULL(0);
    lower.inclusive = true;
    lower.lower = true;

    upper.val = PG_ARGISNULL(1) ? (Datum) 0 : arg2;
    upper.infinite = PG_ARGISNULL(1);
    upper.inclusive = false;
    upper.lower = false;

    range = make_range(typcache, &lower, &upper, false);

    PG_RETURN_RANGE(range);
}

Datum range_constructor3 ( PG_FUNCTION_ARGS   ) 

Definition at line 380 of file rangetypes.c.

References ereport, errcode(), errmsg(), ERROR, get_fn_expr_rettype(), RangeBound::inclusive, RangeBound::infinite, RangeBound::lower, make_range(), PG_ARGISNULL, PG_GETARG_DATUM, PG_GETARG_TEXT_P, PG_RETURN_RANGE, range_get_typcache(), range_parse_flags(), text_to_cstring(), and RangeBound::val.

{
    Datum       arg1 = PG_GETARG_DATUM(0);
    Datum       arg2 = PG_GETARG_DATUM(1);
    Oid         rngtypid = get_fn_expr_rettype(fcinfo->flinfo);
    RangeType  *range;
    TypeCacheEntry *typcache;
    RangeBound  lower;
    RangeBound  upper;
    char        flags;

    typcache = range_get_typcache(fcinfo, rngtypid);

    if (PG_ARGISNULL(2))
        ereport(ERROR,
                (errcode(ERRCODE_DATA_EXCEPTION),
               errmsg("range constructor flags argument must not be null")));

    flags = range_parse_flags(text_to_cstring(PG_GETARG_TEXT_P(2)));

    lower.val = PG_ARGISNULL(0) ? (Datum) 0 : arg1;
    lower.infinite = PG_ARGISNULL(0);
    lower.inclusive = (flags & RANGE_LB_INC) != 0;
    lower.lower = true;

    upper.val = PG_ARGISNULL(1) ? (Datum) 0 : arg2;
    upper.infinite = PG_ARGISNULL(1);
    upper.inclusive = (flags & RANGE_UB_INC) != 0;
    upper.lower = false;

    range = make_range(typcache, &lower, &upper, false);

    PG_RETURN_RANGE(range);
}

Datum range_contained_by ( PG_FUNCTION_ARGS   ) 
bool range_contained_by_internal ( TypeCacheEntry typcache,
RangeType r1,
RangeType r2 
)

Definition at line 2231 of file rangetypes.c.

References range_contains_internal().

Referenced by range_contained_by(), range_gist_consistent_leaf(), and spg_range_quad_leaf_consistent().

{
    return range_contains_internal(typcache, r2, r1);
}

Datum range_contains ( PG_FUNCTION_ARGS   ) 
Datum range_contains_elem ( PG_FUNCTION_ARGS   ) 
bool range_contains_elem_internal ( TypeCacheEntry typcache,
RangeType r,
Datum  val 
)

Definition at line 2240 of file rangetypes.c.

References DatumGetInt32, FunctionCall2Coll(), RangeBound::inclusive, RangeBound::infinite, range_deserialize(), TypeCacheEntry::rng_cmp_proc_finfo, TypeCacheEntry::rng_collation, and RangeBound::val.

Referenced by elem_contained_by_range(), range_contains_elem(), range_gist_consistent_int(), range_gist_consistent_leaf(), and spg_range_quad_leaf_consistent().

{
    RangeBound  lower;
    RangeBound  upper;
    bool        empty;
    int32       cmp;

    range_deserialize(typcache, r, &lower, &upper, &empty);

    if (empty)
        return false;

    if (!lower.infinite)
    {
        cmp = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
                                              typcache->rng_collation,
                                              lower.val, val));
        if (cmp > 0)
            return false;
        if (cmp == 0 && !lower.inclusive)
            return false;
    }

    if (!upper.infinite)
    {
        cmp = DatumGetInt32(FunctionCall2Coll(&typcache->rng_cmp_proc_finfo,
                                              typcache->rng_collation,
                                              upper.val, val));
        if (cmp < 0)
            return false;
        if (cmp == 0 && !upper.inclusive)
            return false;
    }

    return true;
}

bool range_contains_internal ( TypeCacheEntry typcache,
RangeType r1,
RangeType r2 
)

Definition at line 2199 of file rangetypes.c.

References elog, ERROR, range_cmp_bounds(), range_deserialize(), and RangeTypeGetOid.

Referenced by range_contained_by_internal(), range_contains(), range_gist_consistent_int(), range_gist_consistent_leaf(), and spg_range_quad_leaf_consistent().

{
    RangeBound  lower1;
    RangeBound  upper1;
    bool        empty1;
    RangeBound  lower2;
    RangeBound  upper2;
    bool        empty2;

    /* Different types should be prevented by ANYRANGE matching rules */
    if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
        elog(ERROR, "range types do not match");

    range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
    range_deserialize(typcache, r2, &lower2, &upper2, &empty2);

    /* If either range is empty, the answer is easy */
    if (empty2)
        return true;
    else if (empty1)
        return false;

    /* Else we must have lower1 <= lower2 and upper1 >= upper2 */
    if (range_cmp_bounds(typcache, &lower1, &lower2) > 0)
        return false;
    if (range_cmp_bounds(typcache, &upper1, &upper2) < 0)
        return false;

    return true;
}

void range_deserialize ( TypeCacheEntry typcache,
RangeType range,
RangeBound lower,
RangeBound upper,
bool empty 
)

Definition at line 1595 of file rangetypes.c.

References Assert, att_addlength_pointer, att_align_pointer, fetch_att, RangeBound::inclusive, RangeBound::infinite, RangeBound::lower, RANGE_HAS_LBOUND, RANGE_HAS_UBOUND, RangeTypeGetOid, TypeCacheEntry::rngelemtype, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TypeCacheEntry::typlen, RangeBound::val, and VARSIZE.

Referenced by calc_hist_selectivity(), compute_range_stats(), daterange_canonical(), getQuadrant(), hash_range(), int4range_canonical(), int8range_canonical(), range_adjacent_internal(), range_after_internal(), range_before_internal(), range_cmp(), range_contains_elem_internal(), range_contains_internal(), range_eq_internal(), range_gist_double_sorting_split(), range_gist_penalty(), range_gist_single_sorting_split(), range_intersect(), range_lower(), range_minus(), range_out(), range_overlaps_internal(), range_overleft_internal(), range_overright_internal(), range_send(), range_super_union(), range_union(), range_upper(), spg_range_quad_inner_consistent(), and spg_range_quad_picksplit().

{
    char        flags;
    int16       typlen;
    bool        typbyval;
    char        typalign;
    Pointer     ptr;
    Datum       lbound;
    Datum       ubound;

    /* assert caller passed the right typcache entry */
    Assert(RangeTypeGetOid(range) == typcache->type_id);

    /* fetch the flag byte from datum's last byte */
    flags = *((char *) range + VARSIZE(range) - 1);

    /* fetch information about range's element type */
    typlen = typcache->rngelemtype->typlen;
    typbyval = typcache->rngelemtype->typbyval;
    typalign = typcache->rngelemtype->typalign;

    /* initialize data pointer just after the range OID */
    ptr = (Pointer) (range + 1);

    /* fetch lower bound, if any */
    if (RANGE_HAS_LBOUND(flags))
    {
        /* att_align_pointer cannot be necessary here */
        lbound = fetch_att(ptr, typbyval, typlen);
        ptr = (Pointer) att_addlength_pointer(ptr, typlen, ptr);
    }
    else
        lbound = (Datum) 0;

    /* fetch upper bound, if any */
    if (RANGE_HAS_UBOUND(flags))
    {
        ptr = (Pointer) att_align_pointer(ptr, typalign, typlen, ptr);
        ubound = fetch_att(ptr, typbyval, typlen);
        /* no need for att_addlength_pointer */
    }
    else
        ubound = (Datum) 0;

    /* emit results */

    *empty = (flags & RANGE_EMPTY) != 0;

    lower->val = lbound;
    lower->infinite = (flags & RANGE_LB_INF) != 0;
    lower->inclusive = (flags & RANGE_LB_INC) != 0;
    lower->lower = true;

    upper->val = ubound;
    upper->infinite = (flags & RANGE_UB_INF) != 0;
    upper->inclusive = (flags & RANGE_UB_INC) != 0;
    upper->lower = false;
}

Datum range_empty ( PG_FUNCTION_ARGS   ) 

Definition at line 465 of file rangetypes.c.

References PG_GETARG_RANGE, PG_RETURN_BOOL, RANGE_EMPTY, and range_get_flags().

{
    RangeType  *r1 = PG_GETARG_RANGE(0);
    char        flags = range_get_flags(r1);

    PG_RETURN_BOOL(flags & RANGE_EMPTY);
}

Datum range_eq ( PG_FUNCTION_ARGS   ) 
bool range_eq_internal ( TypeCacheEntry typcache,
RangeType r1,
RangeType r2 
)

Definition at line 547 of file rangetypes.c.

References elog, ERROR, range_cmp_bounds(), range_deserialize(), and RangeTypeGetOid.

Referenced by range_eq(), range_gist_consistent_leaf(), range_gist_same(), range_ne_internal(), and spg_range_quad_leaf_consistent().

{
    RangeBound  lower1,
                lower2;
    RangeBound  upper1,
                upper2;
    bool        empty1,
                empty2;

    /* Different types should be prevented by ANYRANGE matching rules */
    if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
        elog(ERROR, "range types do not match");

    range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
    range_deserialize(typcache, r2, &lower2, &upper2, &empty2);

    if (empty1 && empty2)
        return true;
    if (empty1 != empty2)
        return false;

    if (range_cmp_bounds(typcache, &lower1, &lower2) != 0)
        return false;

    if (range_cmp_bounds(typcache, &upper1, &upper2) != 0)
        return false;

    return true;
}

Datum range_ge ( PG_FUNCTION_ARGS   ) 

Definition at line 1158 of file rangetypes.c.

References cmp(), PG_RETURN_BOOL, and range_cmp().

{
    int         cmp = range_cmp(fcinfo);

    PG_RETURN_BOOL(cmp >= 0);
}

char range_get_flags ( RangeType range  ) 

Definition at line 1662 of file rangetypes.c.

References VARSIZE.

Referenced by get_gist_range_class(), hash_range(), range_empty(), range_gist_same(), range_lower_inc(), range_lower_inf(), range_out(), range_send(), range_super_union(), range_upper_inc(), and range_upper_inf().

{
    /* fetch the flag byte from datum's last byte */
    return *((char *) range + VARSIZE(range) - 1);
}

TypeCacheEntry* range_get_typcache ( FunctionCallInfo  fcinfo,
Oid  rngtypid 
)
Datum range_gist_compress ( PG_FUNCTION_ARGS   ) 

Definition at line 221 of file rangetypes_gist.c.

References PG_GETARG_POINTER, and PG_RETURN_POINTER.

Datum range_gist_consistent ( PG_FUNCTION_ARGS   ) 

Definition at line 172 of file rangetypes_gist.c.

References DatumGetRangeType, GIST_LEAF, GISTENTRY::key, PG_GETARG_DATUM, PG_GETARG_POINTER, PG_GETARG_UINT16, PG_RETURN_BOOL, range_get_typcache(), range_gist_consistent_int(), range_gist_consistent_leaf(), and RangeTypeGetOid.

{
    GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
    Datum       query = PG_GETARG_DATUM(1);
    StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);

    /* Oid subtype = PG_GETARG_OID(3); */
    bool       *recheck = (bool *) PG_GETARG_POINTER(4);
    RangeType  *key = DatumGetRangeType(entry->key);
    TypeCacheEntry *typcache;

    /* All operators served by this function are exact */
    *recheck = false;

    typcache = range_get_typcache(fcinfo, RangeTypeGetOid(key));

    if (GIST_LEAF(entry))
        PG_RETURN_BOOL(range_gist_consistent_leaf(typcache, strategy,
                                                  key, query));
    else
        PG_RETURN_BOOL(range_gist_consistent_int(typcache, strategy,
                                                 key, query));
}

Datum range_gist_decompress ( PG_FUNCTION_ARGS   ) 

Definition at line 229 of file rangetypes_gist.c.

References PG_GETARG_POINTER, and PG_RETURN_POINTER.

Datum range_gist_penalty ( PG_FUNCTION_ARGS   ) 

Definition at line 247 of file rangetypes_gist.c.

References call_subtype_diff(), DatumGetRangeType, elog, ERROR, FmgrInfo::fn_oid, get_float4_infinity(), RangeBound::infinite, GISTENTRY::key, OidIsValid, PG_GETARG_POINTER, PG_RETURN_POINTER, range_cmp_bounds(), range_deserialize(), range_get_typcache(), RangeIsOrContainsEmpty, RangeTypeGetOid, TypeCacheEntry::rng_subdiff_finfo, and RangeBound::val.

{
    GISTENTRY  *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
    GISTENTRY  *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
    float      *penalty = (float *) PG_GETARG_POINTER(2);
    RangeType  *orig = DatumGetRangeType(origentry->key);
    RangeType  *new = DatumGetRangeType(newentry->key);
    TypeCacheEntry *typcache;
    bool        has_subtype_diff;
    RangeBound  orig_lower,
                new_lower,
                orig_upper,
                new_upper;
    bool        orig_empty,
                new_empty;

    if (RangeTypeGetOid(orig) != RangeTypeGetOid(new))
        elog(ERROR, "range types do not match");

    typcache = range_get_typcache(fcinfo, RangeTypeGetOid(orig));

    has_subtype_diff = OidIsValid(typcache->rng_subdiff_finfo.fn_oid);

    range_deserialize(typcache, orig, &orig_lower, &orig_upper, &orig_empty);
    range_deserialize(typcache, new, &new_lower, &new_upper, &new_empty);

    /*
     * Distinct branches for handling distinct classes of ranges.  Note that
     * penalty values only need to be commensurate within the same class of
     * new range.
     */
    if (new_empty)
    {
        /* Handle insertion of empty range */
        if (orig_empty)
        {
            /*
             * The best case is to insert it to empty original range.
             * Insertion here means no broadening of original range. Also
             * original range is the most narrow.
             */
            *penalty = 0.0;
        }
        else if (RangeIsOrContainsEmpty(orig))
        {
            /*
             * The second case is to insert empty range into range which
             * contains at least one underlying empty range.  There is still
             * no broadening of original range, but original range is not as
             * narrow as possible.
             */
            *penalty = CONTAIN_EMPTY_PENALTY;
        }
        else if (orig_lower.infinite && orig_upper.infinite)
        {
            /*
             * Original range requires broadening.  (-inf; +inf) is most far
             * from normal range in this case.
             */
            *penalty = 2 * CONTAIN_EMPTY_PENALTY;
        }
        else if (orig_lower.infinite || orig_upper.infinite)
        {
            /*
             * (-inf, x) or (x, +inf) original ranges are closer to normal
             * ranges, so it's worse to mix it with empty ranges.
             */
            *penalty = 3 * CONTAIN_EMPTY_PENALTY;
        }
        else
        {
            /*
             * The least preferred case is broadening of normal range.
             */
            *penalty = 4 * CONTAIN_EMPTY_PENALTY;
        }
    }
    else if (new_lower.infinite && new_upper.infinite)
    {
        /* Handle insertion of (-inf, +inf) range */
        if (orig_lower.infinite && orig_upper.infinite)
        {
            /*
             * Best case is inserting to (-inf, +inf) original range.
             */
            *penalty = 0.0;
        }
        else if (orig_lower.infinite || orig_upper.infinite)
        {
            /*
             * When original range is (-inf, x) or (x, +inf) it requires
             * broadening of original range (extension of one bound to
             * infinity).
             */
            *penalty = INFINITE_BOUND_PENALTY;
        }
        else
        {
            /*
             * Insertion to normal original range is least preferred.
             */
            *penalty = 2 * INFINITE_BOUND_PENALTY;
        }

        if (RangeIsOrContainsEmpty(orig))
        {
            /*
             * Original range is narrower when it doesn't contain empty
             * ranges. Add additional penalty otherwise.
             */
            *penalty += CONTAIN_EMPTY_PENALTY;
        }
    }
    else if (new_lower.infinite)
    {
        /* Handle insertion of (-inf, x) range */
        if (!orig_empty && orig_lower.infinite)
        {
            if (orig_upper.infinite)
            {
                /*
                 * (-inf, +inf) range won't be extended by insertion of (-inf,
                 * x) range. It's a less desirable case than insertion to
                 * (-inf, y) original range without extension, because in that
                 * case original range is narrower. But we can't express that
                 * in single float value.
                 */
                *penalty = 0.0;
            }
            else
            {
                if (range_cmp_bounds(typcache, &new_upper, &orig_upper) > 0)
                {
                    /*
                     * Get extension of original range using subtype_diff. Use
                     * constant if subtype_diff unavailable.
                     */
                    if (has_subtype_diff)
                        *penalty = call_subtype_diff(typcache,
                                                     new_upper.val,
                                                     orig_upper.val);
                    else
                        *penalty = DEFAULT_SUBTYPE_DIFF_PENALTY;
                }
                else
                {
                    /* No extension of original range */
                    *penalty = 0.0;
                }
            }
        }
        else
        {
            /*
             * If lower bound of original range is not -inf, then extension of
             * it is infinity.
             */
            *penalty = get_float4_infinity();
        }
    }
    else if (new_upper.infinite)
    {
        /* Handle insertion of (x, +inf) range */
        if (!orig_empty && orig_upper.infinite)
        {
            if (orig_lower.infinite)
            {
                /*
                 * (-inf, +inf) range won't be extended by insertion of (x,
                 * +inf) range. It's a less desirable case than insertion to
                 * (y, +inf) original range without extension, because in that
                 * case original range is narrower. But we can't express that
                 * in single float value.
                 */
                *penalty = 0.0;
            }
            else
            {
                if (range_cmp_bounds(typcache, &new_lower, &orig_lower) < 0)
                {
                    /*
                     * Get extension of original range using subtype_diff. Use
                     * constant if subtype_diff unavailable.
                     */
                    if (has_subtype_diff)
                        *penalty = call_subtype_diff(typcache,
                                                     orig_lower.val,
                                                     new_lower.val);
                    else
                        *penalty = DEFAULT_SUBTYPE_DIFF_PENALTY;
                }
                else
                {
                    /* No extension of original range */
                    *penalty = 0.0;
                }
            }
        }
        else
        {
            /*
             * If upper bound of original range is not +inf, then extension of
             * it is infinity.
             */
            *penalty = get_float4_infinity();
        }
    }
    else
    {
        /* Handle insertion of normal (non-empty, non-infinite) range */
        if (orig_empty || orig_lower.infinite || orig_upper.infinite)
        {
            /*
             * Avoid mixing normal ranges with infinite and empty ranges.
             */
            *penalty = get_float4_infinity();
        }
        else
        {
            /*
             * Calculate extension of original range by calling subtype_diff.
             * Use constant if subtype_diff unavailable.
             */
            float8      diff = 0.0;

            if (range_cmp_bounds(typcache, &new_lower, &orig_lower) < 0)
            {
                if (has_subtype_diff)
                    diff += call_subtype_diff(typcache,
                                              orig_lower.val,
                                              new_lower.val);
                else
                    diff += DEFAULT_SUBTYPE_DIFF_PENALTY;
            }
            if (range_cmp_bounds(typcache, &new_upper, &orig_upper) > 0)
            {
                if (has_subtype_diff)
                    diff += call_subtype_diff(typcache,
                                              new_upper.val,
                                              orig_upper.val);
                else
                    diff += DEFAULT_SUBTYPE_DIFF_PENALTY;
            }
            *penalty = diff;
        }
    }

    PG_RETURN_POINTER(penalty);
}

Datum range_gist_picksplit ( PG_FUNCTION_ARGS   ) 

Definition at line 504 of file rangetypes_gist.c.

References Abs, Assert, CLS_CONTAIN_EMPTY, CLS_LOWER_INF, CLS_NORMAL, CLS_UPPER_INF, DatumGetRangeType, FirstOffsetNumber, get_gist_range_class(), i, GISTENTRY::key, GistEntryVector::n, OffsetNumberNext, palloc(), PG_GETARG_POINTER, PG_RETURN_POINTER, range(), range_get_typcache(), range_gist_class_split(), range_gist_double_sorting_split(), range_gist_fallback_split(), range_gist_single_sorting_split(), RangeTypeGetOid, GIST_SPLITVEC::spl_left, GIST_SPLITVEC::spl_right, and GistEntryVector::vector.

{
    GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
    GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
    TypeCacheEntry *typcache;
    OffsetNumber i;
    RangeType  *pred_left;
    int         nbytes;
    OffsetNumber maxoff;
    int         count_in_classes[CLS_COUNT];
    int         j;
    int         non_empty_classes_count = 0;
    int         biggest_class = -1;
    int         biggest_class_count = 0;
    int         total_count;

    /* use first item to look up range type's info */
    pred_left = DatumGetRangeType(entryvec->vector[FirstOffsetNumber].key);
    typcache = range_get_typcache(fcinfo, RangeTypeGetOid(pred_left));

    maxoff = entryvec->n - 1;
    nbytes = (maxoff + 1) * sizeof(OffsetNumber);
    v->spl_left = (OffsetNumber *) palloc(nbytes);
    v->spl_right = (OffsetNumber *) palloc(nbytes);

    /*
     * Get count distribution of range classes.
     */
    memset(count_in_classes, 0, sizeof(count_in_classes));
    for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
    {
        RangeType  *range = DatumGetRangeType(entryvec->vector[i].key);

        count_in_classes[get_gist_range_class(range)]++;
    }

    /*
     * Count non-empty classes and find biggest class.
     */
    total_count = maxoff;
    for (j = 0; j < CLS_COUNT; j++)
    {
        if (count_in_classes[j] > 0)
        {
            if (count_in_classes[j] > biggest_class_count)
            {
                biggest_class_count = count_in_classes[j];
                biggest_class = j;
            }
            non_empty_classes_count++;
        }
    }

    Assert(non_empty_classes_count > 0);

    if (non_empty_classes_count == 1)
    {
        /* One non-empty class, so split inside class */
        if ((biggest_class & ~CLS_CONTAIN_EMPTY) == CLS_NORMAL)
        {
            /* double sorting split for normal ranges */
            range_gist_double_sorting_split(typcache, entryvec, v);
        }
        else if ((biggest_class & ~CLS_CONTAIN_EMPTY) == CLS_LOWER_INF)
        {
            /* upper bound sorting split for (-inf, x) ranges */
            range_gist_single_sorting_split(typcache, entryvec, v, true);
        }
        else if ((biggest_class & ~CLS_CONTAIN_EMPTY) == CLS_UPPER_INF)
        {
            /* lower bound sorting split for (x, +inf) ranges */
            range_gist_single_sorting_split(typcache, entryvec, v, false);
        }
        else
        {
            /* trivial split for all (-inf, +inf) or all empty ranges */
            range_gist_fallback_split(typcache, entryvec, v);
        }
    }
    else
    {
        /*
         * Class based split.
         *
         * To which side of the split should each class go?  Initialize them
         * all to go to the left side.
         */
        SplitLR     classes_groups[CLS_COUNT];

        memset(classes_groups, 0, sizeof(classes_groups));

        if (count_in_classes[CLS_NORMAL] > 0)
        {
            /* separate normal ranges if any */
            classes_groups[CLS_NORMAL] = SPLIT_RIGHT;
        }
        else
        {
            /*----------
             * Try to split classes in one of two ways:
             *  1) containing infinities - not containing infinities
             *  2) containing empty - not containing empty
             *
             * Select the way which balances the ranges between left and right
             * the best. If split in these ways is not possible, there are at
             * most 3 classes, so just separate biggest class.
             *----------
             */
            int         infCount,
                        nonInfCount;
            int         emptyCount,
                        nonEmptyCount;

            nonInfCount =
                count_in_classes[CLS_NORMAL] +
                count_in_classes[CLS_CONTAIN_EMPTY] +
                count_in_classes[CLS_EMPTY];
            infCount = total_count - nonInfCount;

            nonEmptyCount =
                count_in_classes[CLS_NORMAL] +
                count_in_classes[CLS_LOWER_INF] +
                count_in_classes[CLS_UPPER_INF] +
                count_in_classes[CLS_LOWER_INF | CLS_UPPER_INF];
            emptyCount = total_count - nonEmptyCount;

            if (infCount > 0 && nonInfCount > 0 &&
                (Abs(infCount - nonInfCount) <=
                 Abs(emptyCount - nonEmptyCount)))
            {
                classes_groups[CLS_NORMAL] = SPLIT_RIGHT;
                classes_groups[CLS_CONTAIN_EMPTY] = SPLIT_RIGHT;
                classes_groups[CLS_EMPTY] = SPLIT_RIGHT;
            }
            else if (emptyCount > 0 && nonEmptyCount > 0)
            {
                classes_groups[CLS_NORMAL] = SPLIT_RIGHT;
                classes_groups[CLS_LOWER_INF] = SPLIT_RIGHT;
                classes_groups[CLS_UPPER_INF] = SPLIT_RIGHT;
                classes_groups[CLS_LOWER_INF | CLS_UPPER_INF] = SPLIT_RIGHT;
            }
            else
            {
                /*
                 * Either total_count == emptyCount or total_count ==
                 * infCount.
                 */
                classes_groups[biggest_class] = SPLIT_RIGHT;
            }
        }

        range_gist_class_split(typcache, entryvec, v, classes_groups);
    }

    PG_RETURN_POINTER(v);
}

Datum range_gist_same ( PG_FUNCTION_ARGS   ) 

Definition at line 663 of file rangetypes_gist.c.

References PG_GETARG_POINTER, PG_GETARG_RANGE, PG_RETURN_POINTER, range_eq_internal(), range_get_flags(), range_get_typcache(), and RangeTypeGetOid.

{
    RangeType  *r1 = PG_GETARG_RANGE(0);
    RangeType  *r2 = PG_GETARG_RANGE(1);
    bool       *result = (bool *) PG_GETARG_POINTER(2);

    /*
     * range_eq will ignore the RANGE_CONTAIN_EMPTY flag, so we have to check
     * that for ourselves.  More generally, if the entries have been properly
     * normalized, then unequal flags bytes must mean unequal ranges ... so
     * let's just test all the flag bits at once.
     */
    if (range_get_flags(r1) != range_get_flags(r2))
        *result = false;
    else
    {
        TypeCacheEntry *typcache;
        typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));

        *result = range_eq_internal(typcache, r1, r2);
    }

    PG_RETURN_POINTER(result);
}

Datum range_gist_union ( PG_FUNCTION_ARGS   ) 

Definition at line 198 of file rangetypes_gist.c.

References DatumGetRangeType, i, GistEntryVector::n, PG_GETARG_POINTER, PG_RETURN_RANGE, range_get_typcache(), range_super_union(), RangeTypeGetOid, and GistEntryVector::vector.

{
    GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
    GISTENTRY  *ent = entryvec->vector;
    RangeType  *result_range;
    TypeCacheEntry *typcache;
    int         i;

    result_range = DatumGetRangeType(ent[0].key);

    typcache = range_get_typcache(fcinfo, RangeTypeGetOid(result_range));

    for (i = 1; i < entryvec->n; i++)
    {
        result_range = range_super_union(typcache, result_range,
                                         DatumGetRangeType(ent[i].key));
    }

    PG_RETURN_RANGE(result_range);
}

Datum range_gt ( PG_FUNCTION_ARGS   ) 

Definition at line 1166 of file rangetypes.c.

References cmp(), PG_RETURN_BOOL, and range_cmp().

{
    int         cmp = range_cmp(fcinfo);

    PG_RETURN_BOOL(cmp > 0);
}

Datum range_in ( PG_FUNCTION_ARGS   ) 

Definition at line 79 of file rangetypes.c.

References get_range_io_data(), RangeBound::inclusive, RangeBound::infinite, InputFunctionCall(), IOFunc_input, RangeBound::lower, make_range(), PG_GETARG_CSTRING, PG_GETARG_INT32, PG_GETARG_OID, PG_RETURN_RANGE, RangeIOData::proc, RANGE_EMPTY, RANGE_HAS_LBOUND, RANGE_HAS_UBOUND, range_parse(), RangeIOData::typcache, RangeIOData::typioparam, and RangeBound::val.

{
    char       *input_str = PG_GETARG_CSTRING(0);
    Oid         rngtypoid = PG_GETARG_OID(1);
    Oid         typmod = PG_GETARG_INT32(2);
    RangeType  *range;
    RangeIOData *cache;
    char        flags;
    char       *lbound_str;
    char       *ubound_str;
    RangeBound  lower;
    RangeBound  upper;

    cache = get_range_io_data(fcinfo, rngtypoid, IOFunc_input);

    /* parse */
    range_parse(input_str, &flags, &lbound_str, &ubound_str);

    /* call element type's input function */
    if (RANGE_HAS_LBOUND(flags))
        lower.val = InputFunctionCall(&cache->proc, lbound_str,
                                      cache->typioparam, typmod);
    if (RANGE_HAS_UBOUND(flags))
        upper.val = InputFunctionCall(&cache->proc, ubound_str,
                                      cache->typioparam, typmod);

    lower.infinite = (flags & RANGE_LB_INF) != 0;
    lower.inclusive = (flags & RANGE_LB_INC) != 0;
    lower.lower = true;
    upper.infinite = (flags & RANGE_UB_INF) != 0;
    upper.inclusive = (flags & RANGE_UB_INC) != 0;
    upper.lower = false;

    /* serialize and canonicalize */
    range = make_range(cache->typcache, &lower, &upper, flags & RANGE_EMPTY);

    PG_RETURN_RANGE(range);
}

Datum range_intersect ( PG_FUNCTION_ARGS   ) 

Definition at line 1061 of file rangetypes.c.

References DatumGetBool, elog, ERROR, make_empty_range(), make_range(), PG_GETARG_RANGE, PG_RETURN_RANGE, range_cmp_bounds(), range_deserialize(), range_get_typcache(), range_overlaps(), and RangeTypeGetOid.

{
    RangeType  *r1 = PG_GETARG_RANGE(0);
    RangeType  *r2 = PG_GETARG_RANGE(1);
    TypeCacheEntry *typcache;
    RangeBound  lower1,
                lower2;
    RangeBound  upper1,
                upper2;
    bool        empty1,
                empty2;
    RangeBound *result_lower;
    RangeBound *result_upper;

    /* Different types should be prevented by ANYRANGE matching rules */
    if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
        elog(ERROR, "range types do not match");

    typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));

    range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
    range_deserialize(typcache, r2, &lower2, &upper2, &empty2);

    if (empty1 || empty2 || !DatumGetBool(range_overlaps(fcinfo)))
        PG_RETURN_RANGE(make_empty_range(typcache));

    if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0)
        result_lower = &lower1;
    else
        result_lower = &lower2;

    if (range_cmp_bounds(typcache, &upper1, &upper2) <= 0)
        result_upper = &upper1;
    else
        result_upper = &upper2;

    PG_RETURN_RANGE(make_range(typcache, result_lower, result_upper, false));
}

Datum range_le ( PG_FUNCTION_ARGS   ) 

Definition at line 1150 of file rangetypes.c.

References cmp(), PG_RETURN_BOOL, and range_cmp().

{
    int         cmp = range_cmp(fcinfo);

    PG_RETURN_BOOL(cmp <= 0);
}

Datum range_lower ( PG_FUNCTION_ARGS   ) 

Definition at line 420 of file rangetypes.c.

References RangeBound::infinite, PG_GETARG_RANGE, PG_RETURN_DATUM, PG_RETURN_NULL, range_deserialize(), range_get_typcache(), RangeTypeGetOid, and RangeBound::val.

{
    RangeType  *r1 = PG_GETARG_RANGE(0);
    TypeCacheEntry *typcache;
    RangeBound  lower;
    RangeBound  upper;
    bool        empty;

    typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));

    range_deserialize(typcache, r1, &lower, &upper, &empty);

    /* Return NULL if there's no finite lower bound */
    if (empty || lower.infinite)
        PG_RETURN_NULL();

    PG_RETURN_DATUM(lower.val);
}

Datum range_lower_inc ( PG_FUNCTION_ARGS   ) 

Definition at line 475 of file rangetypes.c.

References PG_GETARG_RANGE, PG_RETURN_BOOL, range_get_flags(), and RANGE_LB_INC.

{
    RangeType  *r1 = PG_GETARG_RANGE(0);
    char        flags = range_get_flags(r1);

    PG_RETURN_BOOL(flags & RANGE_LB_INC);
}

Datum range_lower_inf ( PG_FUNCTION_ARGS   ) 

Definition at line 495 of file rangetypes.c.

References PG_GETARG_RANGE, PG_RETURN_BOOL, range_get_flags(), and RANGE_LB_INF.

{
    RangeType  *r1 = PG_GETARG_RANGE(0);
    char        flags = range_get_flags(r1);

    PG_RETURN_BOOL(flags & RANGE_LB_INF);
}

Datum range_lt ( PG_FUNCTION_ARGS   ) 

Definition at line 1142 of file rangetypes.c.

References cmp(), PG_RETURN_BOOL, and range_cmp().

{
    int         cmp = range_cmp(fcinfo);

    PG_RETURN_BOOL(cmp < 0);
}

Datum range_minus ( PG_FUNCTION_ARGS   ) 

Definition at line 946 of file rangetypes.c.

References elog, ereport, errcode(), errmsg(), ERROR, RangeBound::inclusive, RangeBound::lower, make_empty_range(), make_range(), PG_GETARG_RANGE, PG_RETURN_NULL, PG_RETURN_RANGE, range_cmp_bounds(), range_deserialize(), range_get_typcache(), and RangeTypeGetOid.

{
    RangeType  *r1 = PG_GETARG_RANGE(0);
    RangeType  *r2 = PG_GETARG_RANGE(1);
    TypeCacheEntry *typcache;
    RangeBound  lower1,
                lower2;
    RangeBound  upper1,
                upper2;
    bool        empty1,
                empty2;
    int         cmp_l1l2,
                cmp_l1u2,
                cmp_u1l2,
                cmp_u1u2;

    /* Different types should be prevented by ANYRANGE matching rules */
    if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
        elog(ERROR, "range types do not match");

    typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));

    range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
    range_deserialize(typcache, r2, &lower2, &upper2, &empty2);

    /* if either is empty, r1 is the correct answer */
    if (empty1 || empty2)
        PG_RETURN_RANGE(r1);

    cmp_l1l2 = range_cmp_bounds(typcache, &lower1, &lower2);
    cmp_l1u2 = range_cmp_bounds(typcache, &lower1, &upper2);
    cmp_u1l2 = range_cmp_bounds(typcache, &upper1, &lower2);
    cmp_u1u2 = range_cmp_bounds(typcache, &upper1, &upper2);

    if (cmp_l1l2 < 0 && cmp_u1u2 > 0)
        ereport(ERROR,
                (errcode(ERRCODE_DATA_EXCEPTION),
              errmsg("result of range difference would not be contiguous")));

    if (cmp_l1u2 > 0 || cmp_u1l2 < 0)
        PG_RETURN_RANGE(r1);

    if (cmp_l1l2 >= 0 && cmp_u1u2 <= 0)
        PG_RETURN_RANGE(make_empty_range(typcache));

    if (cmp_l1l2 <= 0 && cmp_u1l2 >= 0 && cmp_u1u2 <= 0)
    {
        lower2.inclusive = !lower2.inclusive;
        lower2.lower = false;   /* it will become the upper bound */
        PG_RETURN_RANGE(make_range(typcache, &lower1, &lower2, false));
    }

    if (cmp_l1l2 >= 0 && cmp_u1u2 >= 0 && cmp_l1u2 <= 0)
    {
        upper2.inclusive = !upper2.inclusive;
        upper2.lower = true;    /* it will become the lower bound */
        PG_RETURN_RANGE(make_range(typcache, &upper2, &upper1, false));
    }

    elog(ERROR, "unexpected case in range_minus");
    PG_RETURN_NULL();
}

Datum range_ne ( PG_FUNCTION_ARGS   ) 
bool range_ne_internal ( TypeCacheEntry typcache,
RangeType r1,
RangeType r2 
)

Definition at line 592 of file rangetypes.c.

References range_eq_internal().

Referenced by range_ne().

{
    return (!range_eq_internal(typcache, r1, r2));
}

Datum range_out ( PG_FUNCTION_ARGS   ) 

Definition at line 119 of file rangetypes.c.

References get_range_io_data(), IOFunc_output, OutputFunctionCall(), PG_GETARG_RANGE, PG_RETURN_CSTRING, RangeIOData::proc, range(), range_deparse(), range_deserialize(), range_get_flags(), RANGE_HAS_LBOUND, RANGE_HAS_UBOUND, RangeTypeGetOid, RangeIOData::typcache, and RangeBound::val.

Referenced by anyrange_out().

{
    RangeType  *range = PG_GETARG_RANGE(0);
    char       *output_str;
    RangeIOData *cache;
    char        flags;
    char       *lbound_str = NULL;
    char       *ubound_str = NULL;
    RangeBound  lower;
    RangeBound  upper;
    bool        empty;

    cache = get_range_io_data(fcinfo, RangeTypeGetOid(range), IOFunc_output);

    /* deserialize */
    range_deserialize(cache->typcache, range, &lower, &upper, &empty);
    flags = range_get_flags(range);

    /* call element type's output function */
    if (RANGE_HAS_LBOUND(flags))
        lbound_str = OutputFunctionCall(&cache->proc, lower.val);
    if (RANGE_HAS_UBOUND(flags))
        ubound_str = OutputFunctionCall(&cache->proc, upper.val);

    /* construct result string */
    output_str = range_deparse(flags, lbound_str, ubound_str);

    PG_RETURN_CSTRING(output_str);
}

Datum range_overlaps ( PG_FUNCTION_ARGS   ) 
bool range_overlaps_internal ( TypeCacheEntry typcache,
RangeType r1,
RangeType r2 
)

Definition at line 815 of file rangetypes.c.

References elog, ERROR, range_cmp_bounds(), range_deserialize(), and RangeTypeGetOid.

Referenced by range_gist_consistent_int(), range_gist_consistent_leaf(), range_overlaps(), and spg_range_quad_leaf_consistent().

{
    RangeBound  lower1,
                lower2;
    RangeBound  upper1,
                upper2;
    bool        empty1,
                empty2;

    /* Different types should be prevented by ANYRANGE matching rules */
    if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
        elog(ERROR, "range types do not match");

    range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
    range_deserialize(typcache, r2, &lower2, &upper2, &empty2);

    /* An empty range does not overlap any other range */
    if (empty1 || empty2)
        return false;

    if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0 &&
        range_cmp_bounds(typcache, &lower1, &upper2) <= 0)
        return true;

    if (range_cmp_bounds(typcache, &lower2, &lower1) >= 0 &&
        range_cmp_bounds(typcache, &lower2, &upper1) <= 0)
        return true;

    return false;
}

Datum range_overleft ( PG_FUNCTION_ARGS   ) 
bool range_overleft_internal ( TypeCacheEntry typcache,
RangeType r1,
RangeType r2 
)

Definition at line 861 of file rangetypes.c.

References elog, ERROR, range_cmp_bounds(), range_deserialize(), and RangeTypeGetOid.

Referenced by range_gist_consistent_int(), range_gist_consistent_leaf(), range_overleft(), and spg_range_quad_leaf_consistent().

{
    RangeBound  lower1,
                lower2;
    RangeBound  upper1,
                upper2;
    bool        empty1,
                empty2;

    /* Different types should be prevented by ANYRANGE matching rules */
    if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
        elog(ERROR, "range types do not match");

    range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
    range_deserialize(typcache, r2, &lower2, &upper2, &empty2);

    /* An empty range is neither before nor after any other range */
    if (empty1 || empty2)
        return false;

    if (range_cmp_bounds(typcache, &upper1, &upper2) <= 0)
        return true;

    return false;
}

Datum range_overright ( PG_FUNCTION_ARGS   ) 
bool range_overright_internal ( TypeCacheEntry typcache,
RangeType r1,
RangeType r2 
)

Definition at line 902 of file rangetypes.c.

References elog, ERROR, PG_RETURN_BOOL, range_cmp_bounds(), range_deserialize(), and RangeTypeGetOid.

Referenced by range_gist_consistent_int(), range_gist_consistent_leaf(), range_overright(), and spg_range_quad_leaf_consistent().

{
    RangeBound  lower1,
                lower2;
    RangeBound  upper1,
                upper2;
    bool        empty1,
                empty2;

    /* Different types should be prevented by ANYRANGE matching rules */
    if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
        elog(ERROR, "range types do not match");

    range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
    range_deserialize(typcache, r2, &lower2, &upper2, &empty2);

    /* An empty range is neither before nor after any other range */
    if (empty1 || empty2)
        PG_RETURN_BOOL(false);

    if (range_cmp_bounds(typcache, &lower1, &lower2) >= 0)
        PG_RETURN_BOOL(true);

    PG_RETURN_BOOL(false);
}

Datum range_recv ( PG_FUNCTION_ARGS   ) 

Definition at line 157 of file rangetypes.c.

References appendBinaryStringInfo(), buf, StringInfoData::data, get_range_io_data(), RangeBound::inclusive, RangeBound::infinite, initStringInfo(), IOFunc_receive, RangeBound::lower, make_range(), pfree(), PG_GETARG_INT32, PG_GETARG_OID, PG_GETARG_POINTER, PG_RETURN_RANGE, pq_getmsgbyte(), pq_getmsgbytes(), pq_getmsgend(), pq_getmsgint(), RangeIOData::proc, RANGE_EMPTY, RANGE_HAS_LBOUND, RANGE_HAS_UBOUND, RANGE_LB_INC, RANGE_LB_INF, RANGE_UB_INC, ReceiveFunctionCall(), RangeIOData::typcache, RangeIOData::typioparam, and RangeBound::val.

{
    StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
    Oid         rngtypoid = PG_GETARG_OID(1);
    int32       typmod = PG_GETARG_INT32(2);
    RangeType  *range;
    RangeIOData *cache;
    char        flags;
    RangeBound  lower;
    RangeBound  upper;

    cache = get_range_io_data(fcinfo, rngtypoid, IOFunc_receive);

    /* receive the flags... */
    flags = (unsigned char) pq_getmsgbyte(buf);

    /*
     * Mask out any unsupported flags, particularly RANGE_xB_NULL which would
     * confuse following tests.  Note that range_serialize will take care of
     * cleaning up any inconsistencies in the remaining flags.
     */
    flags &= (RANGE_EMPTY |
              RANGE_LB_INC |
              RANGE_LB_INF |
              RANGE_UB_INC |
              RANGE_UB_INF);

    /* receive the bounds ... */
    if (RANGE_HAS_LBOUND(flags))
    {
        uint32      bound_len = pq_getmsgint(buf, 4);
        const char *bound_data = pq_getmsgbytes(buf, bound_len);
        StringInfoData bound_buf;

        initStringInfo(&bound_buf);
        appendBinaryStringInfo(&bound_buf, bound_data, bound_len);

        lower.val = ReceiveFunctionCall(&cache->proc,
                                        &bound_buf,
                                        cache->typioparam,
                                        typmod);
        pfree(bound_buf.data);
    }
    else
        lower.val = (Datum) 0;

    if (RANGE_HAS_UBOUND(flags))
    {
        uint32      bound_len = pq_getmsgint(buf, 4);
        const char *bound_data = pq_getmsgbytes(buf, bound_len);
        StringInfoData bound_buf;

        initStringInfo(&bound_buf);
        appendBinaryStringInfo(&bound_buf, bound_data, bound_len);

        upper.val = ReceiveFunctionCall(&cache->proc,
                                        &bound_buf,
                                        cache->typioparam,
                                        typmod);
        pfree(bound_buf.data);
    }
    else
        upper.val = (Datum) 0;

    pq_getmsgend(buf);

    /* finish constructing RangeBound representation */
    lower.infinite = (flags & RANGE_LB_INF) != 0;
    lower.inclusive = (flags & RANGE_LB_INC) != 0;
    lower.lower = true;
    upper.infinite = (flags & RANGE_UB_INF) != 0;
    upper.inclusive = (flags & RANGE_UB_INC) != 0;
    upper.lower = false;

    /* serialize and canonicalize */
    range = make_range(cache->typcache, &lower, &upper, flags & RANGE_EMPTY);

    PG_RETURN_RANGE(range);
}

Datum range_send ( PG_FUNCTION_ARGS   ) 

Definition at line 238 of file rangetypes.c.

References buf, get_range_io_data(), IOFunc_send, makeStringInfo(), PG_GETARG_RANGE, PG_RETURN_BYTEA_P, PointerGetDatum, pq_begintypsend(), pq_endtypsend(), pq_sendbyte(), pq_sendbytes(), pq_sendint(), RangeIOData::proc, range(), range_deserialize(), range_get_flags(), RANGE_HAS_LBOUND, RANGE_HAS_UBOUND, RangeTypeGetOid, SendFunctionCall(), RangeIOData::typcache, RangeBound::val, VARDATA, and VARSIZE.

{
    RangeType  *range = PG_GETARG_RANGE(0);
    StringInfo  buf = makeStringInfo();
    RangeIOData *cache;
    char        flags;
    RangeBound  lower;
    RangeBound  upper;
    bool        empty;

    cache = get_range_io_data(fcinfo, RangeTypeGetOid(range), IOFunc_send);

    /* deserialize */
    range_deserialize(cache->typcache, range, &lower, &upper, &empty);
    flags = range_get_flags(range);

    /* construct output */
    pq_begintypsend(buf);

    pq_sendbyte(buf, flags);

    if (RANGE_HAS_LBOUND(flags))
    {
        Datum       bound = PointerGetDatum(SendFunctionCall(&cache->proc,
                                                             lower.val));
        uint32      bound_len = VARSIZE(bound) - VARHDRSZ;
        char       *bound_data = VARDATA(bound);

        pq_sendint(buf, bound_len, 4);
        pq_sendbytes(buf, bound_data, bound_len);
    }

    if (RANGE_HAS_UBOUND(flags))
    {
        Datum       bound = PointerGetDatum(SendFunctionCall(&cache->proc,
                                                             upper.val));
        uint32      bound_len = VARSIZE(bound) - VARHDRSZ;
        char       *bound_data = VARDATA(bound);

        pq_sendint(buf, bound_len, 4);
        pq_sendbytes(buf, bound_data, bound_len);
    }

    PG_RETURN_BYTEA_P(pq_endtypsend(buf));
}

RangeType* range_serialize ( TypeCacheEntry typcache,
RangeBound lower,
RangeBound upper,
bool  empty 
)

Definition at line 1466 of file rangetypes.c.

References Assert, datum_compute_size(), datum_write(), ereport, errcode(), errmsg(), ERROR, RangeBound::inclusive, RangeBound::infinite, RangeBound::lower, MAXALIGN, palloc0(), PG_DETOAST_DATUM_PACKED, PointerGetDatum, range_cmp_bound_values(), RANGE_HAS_LBOUND, RANGE_HAS_UBOUND, RangeType::rangetypid, TypeCacheEntry::rngelemtype, SET_VARSIZE, TypeCacheEntry::typalign, TypeCacheEntry::typbyval, TypeCacheEntry::type_id, TypeCacheEntry::typlen, TypeCacheEntry::typstorage, and RangeBound::val.

Referenced by compute_range_stats(), daterange_canonical(), int4range_canonical(), int8range_canonical(), make_range(), rangesel(), and spg_range_quad_picksplit().

{
    RangeType  *range;
    int         cmp;
    Size        msize;
    Pointer     ptr;
    int16       typlen;
    bool        typbyval;
    char        typalign;
    char        typstorage;
    char        flags = 0;

    /*
     * Verify range is not invalid on its face, and construct flags value,
     * preventing any non-canonical combinations such as infinite+inclusive.
     */
    Assert(lower->lower);
    Assert(!upper->lower);

    if (empty)
        flags |= RANGE_EMPTY;
    else
    {
        cmp = range_cmp_bound_values(typcache, lower, upper);

        /* error check: if lower bound value is above upper, it's wrong */
        if (cmp > 0)
            ereport(ERROR,
                    (errcode(ERRCODE_DATA_EXCEPTION),
                     errmsg("range lower bound must be less than or equal to range upper bound")));

        /* if bounds are equal, and not both inclusive, range is empty */
        if (cmp == 0 && !(lower->inclusive && upper->inclusive))
            flags |= RANGE_EMPTY;
        else
        {
            /* infinite boundaries are never inclusive */
            if (lower->infinite)
                flags |= RANGE_LB_INF;
            else if (lower->inclusive)
                flags |= RANGE_LB_INC;
            if (upper->infinite)
                flags |= RANGE_UB_INF;
            else if (upper->inclusive)
                flags |= RANGE_UB_INC;
        }
    }

    /* Fetch information about range's element type */
    typlen = typcache->rngelemtype->typlen;
    typbyval = typcache->rngelemtype->typbyval;
    typalign = typcache->rngelemtype->typalign;
    typstorage = typcache->rngelemtype->typstorage;

    /* Count space for varlena header and range type's OID */
    msize = sizeof(RangeType);
    Assert(msize == MAXALIGN(msize));

    /* Count space for bounds */
    if (RANGE_HAS_LBOUND(flags))
    {
        /*
         * Make sure item to be inserted is not toasted.  It is essential that
         * we not insert an out-of-line toast value pointer into a range
         * object, for the same reasons that arrays and records can't contain
         * them.  It would work to store a compressed-in-line value, but we
         * prefer to decompress and then let compression be applied to the
         * whole range object if necessary.  But, unlike arrays, we do allow
         * short-header varlena objects to stay as-is.
         */
        if (typlen == -1)
            lower->val = PointerGetDatum(PG_DETOAST_DATUM_PACKED(lower->val));

        msize = datum_compute_size(msize, lower->val, typbyval, typalign,
                                   typlen, typstorage);
    }

    if (RANGE_HAS_UBOUND(flags))
    {
        /* Make sure item to be inserted is not toasted */
        if (typlen == -1)
            upper->val = PointerGetDatum(PG_DETOAST_DATUM_PACKED(upper->val));

        msize = datum_compute_size(msize, upper->val, typbyval, typalign,
                                   typlen, typstorage);
    }

    /* Add space for flag byte */
    msize += sizeof(char);

    /* Note: zero-fill is required here, just as in heap tuples */
    range = (RangeType *) palloc0(msize);
    SET_VARSIZE(range, msize);

    /* Now fill in the datum */
    range->rangetypid = typcache->type_id;

    ptr = (char *) (range + 1);

    if (RANGE_HAS_LBOUND(flags))
    {
        Assert(lower->lower);
        ptr = datum_write(ptr, lower->val, typbyval, typalign, typlen,
                          typstorage);
    }

    if (RANGE_HAS_UBOUND(flags))
    {
        Assert(!upper->lower);
        ptr = datum_write(ptr, upper->val, typbyval, typalign, typlen,
                          typstorage);
    }

    *((char *) ptr) = flags;

    return range;
}

void range_set_contain_empty ( RangeType range  ) 

Definition at line 1676 of file rangetypes.c.

References VARSIZE.

Referenced by range_super_union().

{
    char       *flagsp;

    /* flag byte is datum's last byte */
    flagsp = (char *) range + VARSIZE(range) - 1;

    *flagsp |= RANGE_CONTAIN_EMPTY;
}

Datum range_typanalyze ( PG_FUNCTION_ARGS   ) 

Definition at line 41 of file rangetypes_typanalyze.c.

References VacAttrStats::attr, VacAttrStats::attrtypid, VacAttrStats::compute_stats, default_statistics_target, VacAttrStats::extra_data, VacAttrStats::minrows, PG_GETARG_POINTER, PG_RETURN_BOOL, and range_get_typcache().

{
    VacAttrStats *stats = (VacAttrStats *) PG_GETARG_POINTER(0);
    TypeCacheEntry *typcache;
    Form_pg_attribute attr = stats->attr;

    /* Get information about range type */
    typcache = range_get_typcache(fcinfo, stats->attrtypid);

    if (attr->attstattarget < 0)
        attr->attstattarget = default_statistics_target;

    stats->compute_stats = compute_range_stats;
    stats->extra_data = typcache;
    /* same as in std_typanalyze */
    stats->minrows = 300 * attr->attstattarget;

    PG_RETURN_BOOL(true);
}

Datum range_union ( PG_FUNCTION_ARGS   ) 

Definition at line 1011 of file rangetypes.c.

References DatumGetBool, elog, ereport, errcode(), errmsg(), ERROR, make_range(), PG_GETARG_RANGE, PG_RETURN_RANGE, range_adjacent(), range_cmp_bounds(), range_deserialize(), range_get_typcache(), range_overlaps(), and RangeTypeGetOid.

{
    RangeType  *r1 = PG_GETARG_RANGE(0);
    RangeType  *r2 = PG_GETARG_RANGE(1);
    TypeCacheEntry *typcache;
    RangeBound  lower1,
                lower2;
    RangeBound  upper1,
                upper2;
    bool        empty1,
                empty2;
    RangeBound *result_lower;
    RangeBound *result_upper;

    /* Different types should be prevented by ANYRANGE matching rules */
    if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
        elog(ERROR, "range types do not match");

    typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));

    range_deserialize(typcache, r1, &lower1, &upper1, &empty1);
    range_deserialize(typcache, r2, &lower2, &upper2, &empty2);

    /* if either is empty, the other is the correct answer */
    if (empty1)
        PG_RETURN_RANGE(r2);
    if (empty2)
        PG_RETURN_RANGE(r1);

    if (!DatumGetBool(range_overlaps(fcinfo)) &&
        !DatumGetBool(range_adjacent(fcinfo)))
        ereport(ERROR,
                (errcode(ERRCODE_DATA_EXCEPTION),
                 errmsg("result of range union would not be contiguous")));

    if (range_cmp_bounds(typcache, &lower1, &lower2) < 0)
        result_lower = &lower1;
    else
        result_lower = &lower2;

    if (range_cmp_bounds(typcache, &upper1, &upper2) > 0)
        result_upper = &upper1;
    else
        result_upper = &upper2;

    PG_RETURN_RANGE(make_range(typcache, result_lower, result_upper, false));
}

Datum range_upper ( PG_FUNCTION_ARGS   ) 

Definition at line 441 of file rangetypes.c.

References RangeBound::infinite, PG_GETARG_RANGE, PG_RETURN_DATUM, PG_RETURN_NULL, range_deserialize(), range_get_typcache(), RangeTypeGetOid, and RangeBound::val.

{
    RangeType  *r1 = PG_GETARG_RANGE(0);
    TypeCacheEntry *typcache;
    RangeBound  lower;
    RangeBound  upper;
    bool        empty;

    typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));

    range_deserialize(typcache, r1, &lower, &upper, &empty);

    /* Return NULL if there's no finite upper bound */
    if (empty || upper.infinite)
        PG_RETURN_NULL();

    PG_RETURN_DATUM(upper.val);
}

Datum range_upper_inc ( PG_FUNCTION_ARGS   ) 

Definition at line 485 of file rangetypes.c.

References PG_GETARG_RANGE, PG_RETURN_BOOL, range_get_flags(), and RANGE_UB_INC.

{
    RangeType  *r1 = PG_GETARG_RANGE(0);
    char        flags = range_get_flags(r1);

    PG_RETURN_BOOL(flags & RANGE_UB_INC);
}

Datum range_upper_inf ( PG_FUNCTION_ARGS   ) 

Definition at line 505 of file rangetypes.c.

References PG_GETARG_RANGE, PG_RETURN_BOOL, range_get_flags(), and RANGE_UB_INF.

{
    RangeType  *r1 = PG_GETARG_RANGE(0);
    char        flags = range_get_flags(r1);

    PG_RETURN_BOOL(flags & RANGE_UB_INF);
}

Datum rangesel ( PG_FUNCTION_ARGS   ) 

Definition at line 101 of file rangetypes_selfuncs.c.

References calc_rangesel(), CLAMP_PROBABILITY, DatumGetRangeType, default_range_selectivity(), get_restriction_variable(), RangeBound::inclusive, RangeBound::infinite, IsA, RangeBound::lower, OID_RANGE_CONTAINS_ELEM_OP, PG_GETARG_INT32, PG_GETARG_POINTER, PG_RETURN_FLOAT8, range_get_typcache(), range_serialize(), ReleaseVariableStats, TypeCacheEntry::rngelemtype, TypeCacheEntry::type_id, RangeBound::val, and VariableStatData::vartype.

{
    PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);
    Oid         operator = PG_GETARG_OID(1);
    List       *args = (List *) PG_GETARG_POINTER(2);
    int         varRelid = PG_GETARG_INT32(3);
    VariableStatData vardata;
    Node       *other;
    bool        varonleft;
    Selectivity selec;
    TypeCacheEntry *typcache;
    RangeType  *constrange = NULL;

    /*
     * If expression is not (variable op something) or (something op
     * variable), then punt and return a default estimate.
     */
    if (!get_restriction_variable(root, args, varRelid,
                                  &vardata, &other, &varonleft))
        PG_RETURN_FLOAT8(default_range_selectivity(operator));

    /*
     * Can't do anything useful if the something is not a constant, either.
     */
    if (!IsA(other, Const))
    {
        ReleaseVariableStats(vardata);
        PG_RETURN_FLOAT8(default_range_selectivity(operator));
    }

    /*
     * All the range operators are strict, so we can cope with a NULL constant
     * right away.
     */
    if (((Const *) other)->constisnull)
    {
        ReleaseVariableStats(vardata);
        PG_RETURN_FLOAT8(0.0);
    }

    /*
     * If var is on the right, commute the operator, so that we can assume the
     * var is on the left in what follows.
     */
    if (!varonleft)
    {
        /* we have other Op var, commute to make var Op other */
        operator = get_commutator(operator);
        if (!operator)
        {
            /* Use default selectivity (should we raise an error instead?) */
            ReleaseVariableStats(vardata);
            PG_RETURN_FLOAT8(default_range_selectivity(operator));
        }
    }

    /*
     * OK, there's a Var and a Const we're dealing with here.  We need the
     * Const to be of same range type as the column, else we can't do anything
     * useful. (Such cases will likely fail at runtime, but here we'd rather
     * just return a default estimate.)
     *
     * If the operator is "range @> element", the constant should be of the
     * element type of the range column. Convert it to a range that includes
     * only that single point, so that we don't need special handling for
     * that in what follows.
     */
    if (operator == OID_RANGE_CONTAINS_ELEM_OP)
    {
        typcache = range_get_typcache(fcinfo, vardata.vartype);

        if (((Const *) other)->consttype == typcache->rngelemtype->type_id)
        {
            RangeBound lower, upper;
            lower.inclusive = true;
            lower.val = ((Const *) other)->constvalue;
            lower.infinite = false;
            lower.lower = true;
            upper.inclusive = true;
            upper.val = ((Const *) other)->constvalue;
            upper.infinite = false;
            upper.lower = false;
            constrange = range_serialize(typcache, &lower, &upper, false);
        }
    }
    else
    {
        typcache = range_get_typcache(fcinfo, ((Const *) other)->consttype);

        if (((Const *) other)->consttype == vardata.vartype)
            constrange = DatumGetRangeType(((Const *) other)->constvalue);
    }

    /*
     * If we got a valid constant on one side of the operator, proceed to
     * estimate using statistics. Otherwise punt and return a default
     * constant estimate.
     */
    if (constrange)
        selec = calc_rangesel(typcache, &vardata, constrange, operator);
    else
        selec = default_range_selectivity(operator);

    ReleaseVariableStats(vardata);

    CLAMP_PROBABILITY(selec);

    PG_RETURN_FLOAT8((float8) selec);
}

Datum tsrange_subdiff ( PG_FUNCTION_ARGS   ) 

Definition at line 1393 of file rangetypes.c.

References PG_GETARG_TIMESTAMP, PG_RETURN_FLOAT8, and USECS_PER_SEC.

{
    Timestamp   v1 = PG_GETARG_TIMESTAMP(0);
    Timestamp   v2 = PG_GETARG_TIMESTAMP(1);
    float8      result;

#ifdef HAVE_INT64_TIMESTAMP
    result = ((float8) v1 - (float8) v2) / USECS_PER_SEC;
#else
    result = v1 - v2;
#endif

    PG_RETURN_FLOAT8(result);
}

Datum tstzrange_subdiff ( PG_FUNCTION_ARGS   ) 

Definition at line 1409 of file rangetypes.c.

References PG_GETARG_TIMESTAMP, PG_RETURN_FLOAT8, and USECS_PER_SEC.

{
    Timestamp   v1 = PG_GETARG_TIMESTAMP(0);
    Timestamp   v2 = PG_GETARG_TIMESTAMP(1);
    float8      result;

#ifdef HAVE_INT64_TIMESTAMP
    result = ((float8) v1 - (float8) v2) / USECS_PER_SEC;
#else
    result = v1 - v2;
#endif

    PG_RETURN_FLOAT8(result);
}