static char *range_bound_escape(const char *value);
static bool range_contains_internal(TypeCacheEntry *typcache,
RangeType *r1, RangeType *r2);
+static bool range_contains_elem_internal(TypeCacheEntry *typcache,
+ RangeType *r, Datum val);
static Size datum_compute_size(Size sz, Datum datum, bool typbyval,
char typalign, int16 typlen, char typstorage);
static Pointer datum_write(Pointer ptr, Datum datum, bool typbyval,
Datum
range_contains_elem(PG_FUNCTION_ARGS)
{
- RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r = PG_GETARG_RANGE(0);
Datum val = PG_GETARG_DATUM(1);
TypeCacheEntry *typcache;
- RangeType *r2;
- typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
-
- /* Construct a singleton range representing just "val" */
- r2 = make_singleton_range(typcache, val);
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
- /* And use range_contains */
- PG_RETURN_BOOL(range_contains_internal(typcache, r1, r2));
+ PG_RETURN_BOOL(range_contains_elem_internal(typcache, r, val));
}
/* contained by? */
elem_contained_by_range(PG_FUNCTION_ARGS)
{
Datum val = PG_GETARG_DATUM(0);
- RangeType *r1 = PG_GETARG_RANGE(1);
+ RangeType *r = PG_GETARG_RANGE(1);
TypeCacheEntry *typcache;
- RangeType *r2;
-
- typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
- /* Construct a singleton range representing just "val" */
- r2 = make_singleton_range(typcache, val);
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
- /* And use range_contains */
- PG_RETURN_BOOL(range_contains_internal(typcache, r1, r2));
+ PG_RETURN_BOOL(range_contains_elem_internal(typcache, r, val));
}
return true;
}
+/*
+ * Test whether range r contains a specific element value.
+ */
+static bool
+range_contains_elem_internal(TypeCacheEntry *typcache, RangeType *r, Datum val)
+{
+ 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;
+}
+
/*
* datum_compute_size() and datum_write() are used to insert the bound
#define RANGESTRAT_CONTAINS 7
#define RANGESTRAT_CONTAINED_BY 8
#define RANGESTRAT_CONTAINS_ELEM 16
-#define RANGESTRAT_ELEM_CONTAINED_BY 17
#define RANGESTRAT_EQ 18
#define RANGESTRAT_NE 19
static RangeType *range_super_union(TypeCacheEntry *typcache, RangeType * r1,
RangeType * r2);
static bool range_gist_consistent_int(FmgrInfo *flinfo,
- StrategyNumber strategy, RangeType * key,
- RangeType * query);
+ StrategyNumber strategy, RangeType *key,
+ Datum query);
static bool range_gist_consistent_leaf(FmgrInfo *flinfo,
- StrategyNumber strategy, RangeType * key,
- RangeType * query);
+ StrategyNumber strategy, RangeType *key,
+ Datum query);
static int sort_item_cmp(const void *a, const void *b);
range_gist_consistent(PG_FUNCTION_ARGS)
{
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
- Datum dquery = PG_GETARG_DATUM(1);
+ 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;
- RangeType *query;
/* All operators served by this function are exact */
*recheck = false;
- switch (strategy)
- {
- /*
- * For element contains and contained by operators, the other operand
- * is a "point" of the subtype. Construct a singleton range
- * containing just that value. (Since range_contains_elem and
- * elem_contained_by_range would do that anyway, it's actually more
- * efficient not less so to merge these cases into range containment
- * at this step. But revisit this if we ever change the implementation
- * of those functions.)
- */
- case RANGESTRAT_CONTAINS_ELEM:
- case RANGESTRAT_ELEM_CONTAINED_BY:
- typcache = range_get_typcache(fcinfo, RangeTypeGetOid(key));
- query = make_singleton_range(typcache, dquery);
- break;
-
- default:
- query = DatumGetRangeType(dquery);
- break;
- }
-
if (GIST_LEAF(entry))
PG_RETURN_BOOL(range_gist_consistent_leaf(fcinfo->flinfo, strategy,
key, query));
subtype_diff = &typcache->rng_subdiff_finfo;
- /* we want to compare the size of "orig" to size of "orig union new" */
+ /*
+ * We want to compare the size of "orig" to size of "orig union new".
+ * The penalty will be the sum of the reduction in the lower bound plus
+ * the increase in the upper bound.
+ */
s_union = range_super_union(typcache, orig, new);
range_deserialize(typcache, orig, &lower1, &upper1, &empty1);
range_deserialize(typcache, s_union, &lower2, &upper2, &empty2);
- /* if orig isn't empty, s_union can't be either */
- Assert(empty1 || !empty2);
-
+ /* handle cases where orig is empty */
if (empty1 && empty2)
{
*penalty = 0;
PG_RETURN_POINTER(penalty);
}
- else if (empty1 && !empty2)
+ else if (empty1)
{
if (lower2.infinite || upper2.infinite)
{
typcache->rng_collation,
upper2.val,
lower2.val));
+ /* upper2 must be >= lower2 */
if (*penalty < 0)
*penalty = 0; /* subtype_diff is broken */
PG_RETURN_POINTER(penalty);
}
}
+ /* if orig isn't empty, s_union can't be either */
+ Assert(!empty2);
+
+ /* similarly, if orig's lower bound is infinite, s_union's must be too */
Assert(lower2.infinite || !lower1.infinite);
- if (lower2.infinite && !lower1.infinite)
- lower_diff = get_float8_infinity();
- else if (lower2.infinite && lower1.infinite)
+ if (lower2.infinite && lower1.infinite)
lower_diff = 0;
+ else if (lower2.infinite)
+ lower_diff = get_float8_infinity();
else if (OidIsValid(subtype_diff->fn_oid))
{
lower_diff = DatumGetFloat8(FunctionCall2Coll(subtype_diff,
typcache->rng_collation,
lower1.val,
lower2.val));
+ /* orig's lower bound must be >= s_union's */
if (lower_diff < 0)
lower_diff = 0; /* subtype_diff is broken */
}
else
{
/* only know whether there is a difference or not */
- lower_diff = (float) range_cmp_bounds(typcache, &lower1, &lower2);
+ lower_diff = range_cmp_bounds(typcache, &lower1, &lower2) > 0 ? 1 : 0;
}
+ /* similarly, if orig's upper bound is infinite, s_union's must be too */
Assert(upper2.infinite || !upper1.infinite);
- if (upper2.infinite && !upper1.infinite)
- upper_diff = get_float8_infinity();
- else if (upper2.infinite && upper1.infinite)
+ if (upper2.infinite && upper1.infinite)
upper_diff = 0;
+ else if (upper2.infinite)
+ upper_diff = get_float8_infinity();
else if (OidIsValid(subtype_diff->fn_oid))
{
upper_diff = DatumGetFloat8(FunctionCall2Coll(subtype_diff,
typcache->rng_collation,
upper2.val,
upper1.val));
+ /* orig's upper bound must be <= s_union's */
if (upper_diff < 0)
upper_diff = 0; /* subtype_diff is broken */
}
else
{
/* only know whether there is a difference or not */
- upper_diff = (float) range_cmp_bounds(typcache, &upper2, &upper1);
+ upper_diff = range_cmp_bounds(typcache, &upper2, &upper1) > 0 ? 1 : 0;
}
Assert(lower_diff >= 0 && upper_diff >= 0);
*/
static bool
range_gist_consistent_int(FmgrInfo *flinfo, StrategyNumber strategy,
- RangeType * key, RangeType * query)
+ RangeType *key, Datum query)
{
PGFunction proc;
bool negate = false;
negate = true;
break;
case RANGESTRAT_ADJACENT:
- if (RangeIsEmpty(key) || RangeIsEmpty(query))
+ if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeType(query)))
return false;
if (DatumGetBool(TrickFunctionCall2(range_adjacent, flinfo,
RangeTypeGetDatum(key),
- RangeTypeGetDatum(query))))
+ query)))
return true;
proc = range_overlaps;
break;
case RANGESTRAT_CONTAINS:
- case RANGESTRAT_CONTAINS_ELEM:
proc = range_contains;
break;
case RANGESTRAT_CONTAINED_BY:
- case RANGESTRAT_ELEM_CONTAINED_BY:
return true;
break;
+ case RANGESTRAT_CONTAINS_ELEM:
+ proc = range_contains_elem;
+ break;
case RANGESTRAT_EQ:
proc = range_contains;
break;
retval = DatumGetBool(TrickFunctionCall2(proc, flinfo,
RangeTypeGetDatum(key),
- RangeTypeGetDatum(query)));
+ query));
if (negate)
retval = !retval;
*/
static bool
range_gist_consistent_leaf(FmgrInfo *flinfo, StrategyNumber strategy,
- RangeType * key, RangeType * query)
+ RangeType *key, Datum query)
{
PGFunction proc;
switch (strategy)
{
case RANGESTRAT_BEFORE:
- if (RangeIsEmpty(key) || RangeIsEmpty(query))
- return false;
proc = range_before;
break;
case RANGESTRAT_OVERLEFT:
- if (RangeIsEmpty(key) || RangeIsEmpty(query))
- return false;
proc = range_overleft;
break;
case RANGESTRAT_OVERLAPS:
proc = range_overlaps;
break;
case RANGESTRAT_OVERRIGHT:
- if (RangeIsEmpty(key) || RangeIsEmpty(query))
- return false;
proc = range_overright;
break;
case RANGESTRAT_AFTER:
- if (RangeIsEmpty(key) || RangeIsEmpty(query))
- return false;
proc = range_after;
break;
case RANGESTRAT_ADJACENT:
- if (RangeIsEmpty(key) || RangeIsEmpty(query))
- return false;
proc = range_adjacent;
break;
case RANGESTRAT_CONTAINS:
- case RANGESTRAT_CONTAINS_ELEM:
proc = range_contains;
break;
case RANGESTRAT_CONTAINED_BY:
- case RANGESTRAT_ELEM_CONTAINED_BY:
proc = range_contained_by;
break;
+ case RANGESTRAT_CONTAINS_ELEM:
+ proc = range_contains_elem;
+ break;
case RANGESTRAT_EQ:
proc = range_eq;
break;
return DatumGetBool(TrickFunctionCall2(proc, flinfo,
RangeTypeGetDatum(key),
- RangeTypeGetDatum(query)));
+ query));
}
/*
else if (lower2.infinite)
return 1;
else if (upper1.infinite && upper2.infinite)
- return -1 * range_cmp_bounds(typcache, &lower1, &lower2);
+ return -(range_cmp_bounds(typcache, &lower1, &lower2));
else if (upper1.infinite)
return 1;
else if (upper2.infinite)