aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/multirangetypes.c21
-rw-r--r--src/backend/utils/adt/rangetypes_gist.c393
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/catalog/pg_amop.dat80
-rw-r--r--src/include/catalog/pg_amproc.dat18
-rw-r--r--src/include/catalog/pg_opclass.dat2
-rw-r--r--src/include/catalog/pg_opfamily.dat2
-rw-r--r--src/include/catalog/pg_proc.dat8
-rw-r--r--src/include/utils/multirangetypes.h2
-rw-r--r--src/test/regress/expected/multirangetypes.out257
-rw-r--r--src/test/regress/expected/rangetypes.out162
-rw-r--r--src/test/regress/sql/multirangetypes.sql63
-rw-r--r--src/test/regress/sql/rangetypes.sql27
13 files changed, 973 insertions, 64 deletions
diff --git a/src/backend/utils/adt/multirangetypes.c b/src/backend/utils/adt/multirangetypes.c
index a77299147e7..2d4cee92bcc 100644
--- a/src/backend/utils/adt/multirangetypes.c
+++ b/src/backend/utils/adt/multirangetypes.c
@@ -769,6 +769,27 @@ multirange_get_bounds(TypeCacheEntry *rangetyp,
}
/*
+ * Construct union range from the multirange.
+ */
+RangeType *
+multirange_get_union_range(TypeCacheEntry *rangetyp,
+ const MultirangeType *mr)
+{
+ RangeBound lower,
+ upper,
+ tmp;
+
+ if (MultirangeIsEmpty(mr))
+ return make_empty_range(rangetyp);
+
+ multirange_get_bounds(rangetyp, mr, 0, &lower, &tmp);
+ multirange_get_bounds(rangetyp, mr, mr->rangeCount - 1, &tmp, &upper);
+
+ return make_range(rangetyp, &lower, &upper, false);
+}
+
+
+/*
* multirange_deserialize: deconstruct a multirange value
*
* NB: the given multirange object must be fully detoasted; it cannot have a
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index 75069c3ac2c..435b242c8ab 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -19,6 +19,7 @@
#include "utils/datum.h"
#include "utils/float.h"
#include "utils/fmgrprotos.h"
+#include "utils/multirangetypes.h"
#include "utils/rangetypes.h"
/*
@@ -135,12 +136,30 @@ typedef struct
static RangeType *range_super_union(TypeCacheEntry *typcache, RangeType *r1,
RangeType *r2);
-static bool range_gist_consistent_int(TypeCacheEntry *typcache,
- StrategyNumber strategy, const RangeType *key,
- Datum query);
-static bool range_gist_consistent_leaf(TypeCacheEntry *typcache,
- StrategyNumber strategy, const RangeType *key,
- Datum query);
+static bool range_gist_consistent_int_range(TypeCacheEntry *typcache,
+ StrategyNumber strategy,
+ const RangeType *key,
+ const RangeType *query);
+static bool range_gist_consistent_int_multirange(TypeCacheEntry *typcache,
+ StrategyNumber strategy,
+ const RangeType *key,
+ const MultirangeType *query);
+static bool range_gist_consistent_int_element(TypeCacheEntry *typcache,
+ StrategyNumber strategy,
+ const RangeType *key,
+ Datum query);
+static bool range_gist_consistent_leaf_range(TypeCacheEntry *typcache,
+ StrategyNumber strategy,
+ const RangeType *key,
+ const RangeType *query);
+static bool range_gist_consistent_leaf_multirange(TypeCacheEntry *typcache,
+ StrategyNumber strategy,
+ const RangeType *key,
+ const MultirangeType *query);
+static bool range_gist_consistent_leaf_element(TypeCacheEntry *typcache,
+ StrategyNumber strategy,
+ const RangeType *key,
+ Datum query);
static void range_gist_fallback_split(TypeCacheEntry *typcache,
GistEntryVector *entryvec,
GIST_SPLITVEC *v);
@@ -174,8 +193,8 @@ range_gist_consistent(PG_FUNCTION_ARGS)
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 result;
+ Oid subtype = PG_GETARG_OID(3);
bool *recheck = (bool *) PG_GETARG_POINTER(4);
RangeType *key = DatumGetRangeTypeP(entry->key);
TypeCacheEntry *typcache;
@@ -185,12 +204,119 @@ range_gist_consistent(PG_FUNCTION_ARGS)
typcache = range_get_typcache(fcinfo, RangeTypeGetOid(key));
+ /*
+ * Perform consistent checking using function corresponding to key type
+ * (leaf or internal) and query subtype (range, multirange, or element).
+ * Note that invalid subtype means that query type matches key type
+ * (range).
+ */
if (GIST_LEAF(entry))
- PG_RETURN_BOOL(range_gist_consistent_leaf(typcache, strategy,
- key, query));
+ {
+ if (!OidIsValid(subtype) || subtype == ANYRANGEOID)
+ result = range_gist_consistent_leaf_range(typcache, strategy, key,
+ DatumGetRangeTypeP(query));
+ else if (subtype == ANYMULTIRANGEOID)
+ result = range_gist_consistent_leaf_multirange(typcache, strategy, key,
+ DatumGetMultirangeTypeP(query));
+ else
+ result = range_gist_consistent_leaf_element(typcache, strategy,
+ key, query);
+ }
else
- PG_RETURN_BOOL(range_gist_consistent_int(typcache, strategy,
- key, query));
+ {
+ if (!OidIsValid(subtype) || subtype == ANYRANGEOID)
+ result = range_gist_consistent_int_range(typcache, strategy, key,
+ DatumGetRangeTypeP(query));
+ else if (subtype == ANYMULTIRANGEOID)
+ result = range_gist_consistent_int_multirange(typcache, strategy, key,
+ DatumGetMultirangeTypeP(query));
+ else
+ result = range_gist_consistent_int_element(typcache, strategy,
+ key, query);
+ }
+ PG_RETURN_BOOL(result);
+}
+
+/*
+ * GiST compress method for multiranges: multirange is approximated as union
+ * range with no gaps.
+ */
+Datum
+multirange_gist_compress(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+ if (entry->leafkey)
+ {
+ MultirangeType *mr = DatumGetMultirangeTypeP(entry->key);
+ RangeType *r;
+ TypeCacheEntry *typcache;
+ GISTENTRY *retval = palloc(sizeof(GISTENTRY));
+
+ typcache = multirange_get_typcache(fcinfo, MultirangeTypeGetOid(mr));
+ r = multirange_get_union_range(typcache->rngtype, mr);
+
+ gistentryinit(*retval, RangeTypePGetDatum(r),
+ entry->rel, entry->page, entry->offset, false);
+
+ PG_RETURN_POINTER(retval);
+ }
+
+ PG_RETURN_POINTER(entry);
+}
+
+/* GiST query consistency check for multiranges */
+Datum
+multirange_gist_consistent(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ Datum query = PG_GETARG_DATUM(1);
+ StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+ bool result;
+ Oid subtype = PG_GETARG_OID(3);
+ bool *recheck = (bool *) PG_GETARG_POINTER(4);
+ RangeType *key = DatumGetRangeTypeP(entry->key);
+ TypeCacheEntry *typcache;
+
+ /*
+ * All operators served by this function are inexact because multirange is
+ * approximated by union range with no gaps.
+ */
+ *recheck = true;
+
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(key));
+
+ /*
+ * Perform consistent checking using function corresponding to key type
+ * (leaf or internal) and query subtype (range, multirange, or element).
+ * Note that invalid subtype means that query type matches key type
+ * (multirange).
+ */
+ if (GIST_LEAF(entry))
+ {
+ if (!OidIsValid(subtype) || subtype == ANYMULTIRANGEOID)
+ result = range_gist_consistent_leaf_multirange(typcache, strategy, key,
+ DatumGetMultirangeTypeP(query));
+ else if (subtype == ANYRANGEOID)
+ result = range_gist_consistent_leaf_range(typcache, strategy, key,
+ DatumGetRangeTypeP(query));
+ else
+ result = range_gist_consistent_leaf_element(typcache, strategy,
+ key, query);
+ }
+ else
+ {
+ if (!OidIsValid(subtype) || subtype == ANYMULTIRANGEOID)
+ result = range_gist_consistent_int_multirange(typcache, strategy, key,
+ DatumGetMultirangeTypeP(query));
+ else if (subtype == ANYRANGEOID)
+ result = range_gist_consistent_int_range(typcache, strategy, key,
+ DatumGetRangeTypeP(query));
+ else
+ result = range_gist_consistent_int_element(typcache, strategy,
+ key, query);
+ }
+ PG_RETURN_BOOL(result);
}
/* form union range */
@@ -758,49 +884,67 @@ range_super_union(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2)
return result;
}
+static bool
+multirange_union_range_equal(TypeCacheEntry *typcache,
+ const RangeType *r,
+ const MultirangeType *mr)
+{
+ RangeBound lower1,
+ upper1,
+ lower2,
+ upper2,
+ tmp;
+ bool empty;
+
+ if (RangeIsEmpty(r) || MultirangeIsEmpty(mr))
+ return (RangeIsEmpty(r) && MultirangeIsEmpty(mr));
+
+ range_deserialize(typcache, r, &lower1, &upper1, &empty);
+ Assert(!empty);
+ multirange_get_bounds(typcache, mr, 0, &lower2, &tmp);
+ multirange_get_bounds(typcache, mr, mr->rangeCount - 1, &tmp, &upper2);
+
+ return (range_cmp_bounds(typcache, &lower1, &lower2) == 0 &&
+ range_cmp_bounds(typcache, &upper1, &upper2) == 0);
+}
+
/*
- * GiST consistent test on an index internal page
+ * GiST consistent test on an index internal page with range query
*/
static bool
-range_gist_consistent_int(TypeCacheEntry *typcache, StrategyNumber strategy,
- const RangeType *key, Datum query)
+range_gist_consistent_int_range(TypeCacheEntry *typcache,
+ StrategyNumber strategy,
+ const RangeType *key,
+ const RangeType *query)
{
switch (strategy)
{
case RANGESTRAT_BEFORE:
- if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeTypeP(query)))
+ if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false;
- return (!range_overright_internal(typcache, key,
- DatumGetRangeTypeP(query)));
+ return (!range_overright_internal(typcache, key, query));
case RANGESTRAT_OVERLEFT:
- if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeTypeP(query)))
+ if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false;
- return (!range_after_internal(typcache, key,
- DatumGetRangeTypeP(query)));
+ return (!range_after_internal(typcache, key, query));
case RANGESTRAT_OVERLAPS:
- return range_overlaps_internal(typcache, key,
- DatumGetRangeTypeP(query));
+ return range_overlaps_internal(typcache, key, query);
case RANGESTRAT_OVERRIGHT:
- if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeTypeP(query)))
+ if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false;
- return (!range_before_internal(typcache, key,
- DatumGetRangeTypeP(query)));
+ return (!range_before_internal(typcache, key, query));
case RANGESTRAT_AFTER:
- if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeTypeP(query)))
+ if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false;
- return (!range_overleft_internal(typcache, key,
- DatumGetRangeTypeP(query)));
+ return (!range_overleft_internal(typcache, key, query));
case RANGESTRAT_ADJACENT:
- if (RangeIsEmpty(key) || RangeIsEmpty(DatumGetRangeTypeP(query)))
+ if (RangeIsEmpty(key) || RangeIsEmpty(query))
return false;
- if (range_adjacent_internal(typcache, key,
- DatumGetRangeTypeP(query)))
+ if (range_adjacent_internal(typcache, key, query))
return true;
- return range_overlaps_internal(typcache, key,
- DatumGetRangeTypeP(query));
+ return range_overlaps_internal(typcache, key, query);
case RANGESTRAT_CONTAINS:
- return range_contains_internal(typcache, key,
- DatumGetRangeTypeP(query));
+ return range_contains_internal(typcache, key, query);
case RANGESTRAT_CONTAINED_BY:
/*
@@ -810,20 +954,16 @@ range_gist_consistent_int(TypeCacheEntry *typcache, StrategyNumber strategy,
*/
if (RangeIsOrContainsEmpty(key))
return true;
- return range_overlaps_internal(typcache, key,
- DatumGetRangeTypeP(query));
- case RANGESTRAT_CONTAINS_ELEM:
- return range_contains_elem_internal(typcache, key, query);
+ return range_overlaps_internal(typcache, key, query);
case RANGESTRAT_EQ:
/*
* If query is empty, descend only if the key is or contains any
* empty ranges. Otherwise, descend if key contains query.
*/
- if (RangeIsEmpty(DatumGetRangeTypeP(query)))
+ if (RangeIsEmpty(query))
return RangeIsOrContainsEmpty(key);
- return range_contains_internal(typcache, key,
- DatumGetRangeTypeP(query));
+ return range_contains_internal(typcache, key, query);
default:
elog(ERROR, "unrecognized range strategy: %d", strategy);
return false; /* keep compiler quiet */
@@ -831,42 +971,169 @@ range_gist_consistent_int(TypeCacheEntry *typcache, StrategyNumber strategy,
}
/*
- * GiST consistent test on an index leaf page
+ * GiST consistent test on an index internal page with multirange query
*/
static bool
-range_gist_consistent_leaf(TypeCacheEntry *typcache, StrategyNumber strategy,
- const RangeType *key, Datum query)
+range_gist_consistent_int_multirange(TypeCacheEntry *typcache,
+ StrategyNumber strategy,
+ const RangeType *key,
+ const MultirangeType *query)
{
switch (strategy)
{
case RANGESTRAT_BEFORE:
- return range_before_internal(typcache, key,
- DatumGetRangeTypeP(query));
+ if (RangeIsEmpty(key) || MultirangeIsEmpty(query))
+ return false;
+ return (!range_overright_multirange_internal(typcache, key, query));
case RANGESTRAT_OVERLEFT:
- return range_overleft_internal(typcache, key,
- DatumGetRangeTypeP(query));
+ if (RangeIsEmpty(key) || MultirangeIsEmpty(query))
+ return false;
+ return (!range_after_multirange_internal(typcache, key, query));
case RANGESTRAT_OVERLAPS:
- return range_overlaps_internal(typcache, key,
- DatumGetRangeTypeP(query));
+ return range_overlaps_multirange_internal(typcache, key, query);
case RANGESTRAT_OVERRIGHT:
- return range_overright_internal(typcache, key,
- DatumGetRangeTypeP(query));
+ if (RangeIsEmpty(key) || MultirangeIsEmpty(query))
+ return false;
+ return (!range_before_multirange_internal(typcache, key, query));
case RANGESTRAT_AFTER:
- return range_after_internal(typcache, key,
- DatumGetRangeTypeP(query));
+ if (RangeIsEmpty(key) || MultirangeIsEmpty(query))
+ return false;
+ return (!range_overleft_multirange_internal(typcache, key, query));
case RANGESTRAT_ADJACENT:
- return range_adjacent_internal(typcache, key,
- DatumGetRangeTypeP(query));
+ if (RangeIsEmpty(key) || MultirangeIsEmpty(query))
+ return false;
+ if (range_adjacent_multirange_internal(typcache, key, query))
+ return true;
+ return range_overlaps_multirange_internal(typcache, key, query);
case RANGESTRAT_CONTAINS:
- return range_contains_internal(typcache, key,
- DatumGetRangeTypeP(query));
+ return range_contains_multirange_internal(typcache, key, query);
case RANGESTRAT_CONTAINED_BY:
- return range_contained_by_internal(typcache, key,
- DatumGetRangeTypeP(query));
+
+ /*
+ * Empty ranges are contained by anything, so if key is or
+ * contains any empty ranges, we must descend into it. Otherwise,
+ * descend only if key overlaps the query.
+ */
+ if (RangeIsOrContainsEmpty(key))
+ return true;
+ return range_overlaps_multirange_internal(typcache, key, query);
+ case RANGESTRAT_EQ:
+
+ /*
+ * If query is empty, descend only if the key is or contains any
+ * empty ranges. Otherwise, descend if key contains query.
+ */
+ if (MultirangeIsEmpty(query))
+ return RangeIsOrContainsEmpty(key);
+ return range_contains_multirange_internal(typcache, key, query);
+ default:
+ elog(ERROR, "unrecognized range strategy: %d", strategy);
+ return false; /* keep compiler quiet */
+ }
+}
+
+/*
+ * GiST consistent test on an index internal page with element query
+ */
+static bool
+range_gist_consistent_int_element(TypeCacheEntry *typcache,
+ StrategyNumber strategy,
+ const RangeType *key,
+ Datum query)
+{
+ switch (strategy)
+ {
case RANGESTRAT_CONTAINS_ELEM:
return range_contains_elem_internal(typcache, key, query);
+ default:
+ elog(ERROR, "unrecognized range strategy: %d", strategy);
+ return false; /* keep compiler quiet */
+ }
+}
+
+/*
+ * GiST consistent test on an index leaf page with range query
+ */
+static bool
+range_gist_consistent_leaf_range(TypeCacheEntry *typcache,
+ StrategyNumber strategy,
+ const RangeType *key,
+ const RangeType *query)
+{
+ switch (strategy)
+ {
+ case RANGESTRAT_BEFORE:
+ return range_before_internal(typcache, key, query);
+ case RANGESTRAT_OVERLEFT:
+ return range_overleft_internal(typcache, key, query);
+ case RANGESTRAT_OVERLAPS:
+ return range_overlaps_internal(typcache, key, query);
+ case RANGESTRAT_OVERRIGHT:
+ return range_overright_internal(typcache, key, query);
+ case RANGESTRAT_AFTER:
+ return range_after_internal(typcache, key, query);
+ case RANGESTRAT_ADJACENT:
+ return range_adjacent_internal(typcache, key, query);
+ case RANGESTRAT_CONTAINS:
+ return range_contains_internal(typcache, key, query);
+ case RANGESTRAT_CONTAINED_BY:
+ return range_contained_by_internal(typcache, key, query);
+ case RANGESTRAT_EQ:
+ return range_eq_internal(typcache, key, query);
+ default:
+ elog(ERROR, "unrecognized range strategy: %d", strategy);
+ return false; /* keep compiler quiet */
+ }
+}
+
+/*
+ * GiST consistent test on an index leaf page with multirange query
+ */
+static bool
+range_gist_consistent_leaf_multirange(TypeCacheEntry *typcache,
+ StrategyNumber strategy,
+ const RangeType *key,
+ const MultirangeType *query)
+{
+ switch (strategy)
+ {
+ case RANGESTRAT_BEFORE:
+ return range_before_multirange_internal(typcache, key, query);
+ case RANGESTRAT_OVERLEFT:
+ return range_overleft_multirange_internal(typcache, key, query);
+ case RANGESTRAT_OVERLAPS:
+ return range_overlaps_multirange_internal(typcache, key, query);
+ case RANGESTRAT_OVERRIGHT:
+ return range_overright_multirange_internal(typcache, key, query);
+ case RANGESTRAT_AFTER:
+ return range_after_multirange_internal(typcache, key, query);
+ case RANGESTRAT_ADJACENT:
+ return range_adjacent_multirange_internal(typcache, key, query);
+ case RANGESTRAT_CONTAINS:
+ return range_contains_multirange_internal(typcache, key, query);
+ case RANGESTRAT_CONTAINED_BY:
+ return multirange_contains_range_internal(typcache, query, key);
case RANGESTRAT_EQ:
- return range_eq_internal(typcache, key, DatumGetRangeTypeP(query));
+ return multirange_union_range_equal(typcache, key, query);
+ default:
+ elog(ERROR, "unrecognized range strategy: %d", strategy);
+ return false; /* keep compiler quiet */
+ }
+}
+
+/*
+ * GiST consistent test on an index leaf page with element query
+ */
+static bool
+range_gist_consistent_leaf_element(TypeCacheEntry *typcache,
+ StrategyNumber strategy,
+ const RangeType *key,
+ Datum query)
+{
+ switch (strategy)
+ {
+ case RANGESTRAT_CONTAINS_ELEM:
+ return range_contains_elem_internal(typcache, key, query);
default:
elog(ERROR, "unrecognized range strategy: %d", strategy);
return false; /* keep compiler quiet */
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 4fd88a47730..db4814e57af 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202012291
+#define CATALOG_VERSION_NO 202012293
#endif
diff --git a/src/include/catalog/pg_amop.dat b/src/include/catalog/pg_amop.dat
index 78d7d2c5232..bbe1a6ddf8e 100644
--- a/src/include/catalog/pg_amop.dat
+++ b/src/include/catalog/pg_amop.dat
@@ -1347,33 +1347,113 @@
amoprighttype => 'anyrange', amopstrategy => '1',
amopopr => '<<(anyrange,anyrange)', amopmethod => 'gist' },
{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
+ amoprighttype => 'anymultirange', amopstrategy => '1',
+ amopopr => '<<(anyrange,anymultirange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
amoprighttype => 'anyrange', amopstrategy => '2',
amopopr => '&<(anyrange,anyrange)', amopmethod => 'gist' },
{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
+ amoprighttype => 'anymultirange', amopstrategy => '2',
+ amopopr => '&<(anyrange,anymultirange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
amoprighttype => 'anyrange', amopstrategy => '3',
amopopr => '&&(anyrange,anyrange)', amopmethod => 'gist' },
{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
+ amoprighttype => 'anymultirange', amopstrategy => '3',
+ amopopr => '&&(anyrange,anymultirange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
amoprighttype => 'anyrange', amopstrategy => '4',
amopopr => '&>(anyrange,anyrange)', amopmethod => 'gist' },
{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
+ amoprighttype => 'anymultirange', amopstrategy => '4',
+ amopopr => '&>(anyrange,anymultirange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
amoprighttype => 'anyrange', amopstrategy => '5',
amopopr => '>>(anyrange,anyrange)', amopmethod => 'gist' },
{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
+ amoprighttype => 'anymultirange', amopstrategy => '5',
+ amopopr => '>>(anyrange,anymultirange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
amoprighttype => 'anyrange', amopstrategy => '6',
amopopr => '-|-(anyrange,anyrange)', amopmethod => 'gist' },
{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
+ amoprighttype => 'anymultirange', amopstrategy => '6',
+ amopopr => '-|-(anyrange,anymultirange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
amoprighttype => 'anyrange', amopstrategy => '7',
amopopr => '@>(anyrange,anyrange)', amopmethod => 'gist' },
{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
+ amoprighttype => 'anymultirange', amopstrategy => '7',
+ amopopr => '@>(anyrange,anymultirange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
amoprighttype => 'anyrange', amopstrategy => '8',
amopopr => '<@(anyrange,anyrange)', amopmethod => 'gist' },
{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
+ amoprighttype => 'anymultirange', amopstrategy => '8',
+ amopopr => '<@(anyrange,anymultirange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
amoprighttype => 'anyelement', amopstrategy => '16',
amopopr => '@>(anyrange,anyelement)', amopmethod => 'gist' },
{ amopfamily => 'gist/range_ops', amoplefttype => 'anyrange',
amoprighttype => 'anyrange', amopstrategy => '18',
amopopr => '=(anyrange,anyrange)', amopmethod => 'gist' },
+# GiST multirange_ops
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anymultirange', amopstrategy => '1',
+ amopopr => '<<(anymultirange,anymultirange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anyrange', amopstrategy => '1',
+ amopopr => '<<(anymultirange,anyrange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anymultirange', amopstrategy => '2',
+ amopopr => '&<(anymultirange,anymultirange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anyrange', amopstrategy => '2',
+ amopopr => '&<(anymultirange,anyrange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anymultirange', amopstrategy => '3',
+ amopopr => '&&(anymultirange,anymultirange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anyrange', amopstrategy => '3',
+ amopopr => '&&(anymultirange,anyrange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anymultirange', amopstrategy => '4',
+ amopopr => '&>(anymultirange,anymultirange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anyrange', amopstrategy => '4',
+ amopopr => '&>(anymultirange,anyrange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anymultirange', amopstrategy => '5',
+ amopopr => '>>(anymultirange,anymultirange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anyrange', amopstrategy => '5',
+ amopopr => '>>(anymultirange,anyrange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anymultirange', amopstrategy => '6',
+ amopopr => '-|-(anymultirange,anymultirange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anyrange', amopstrategy => '6',
+ amopopr => '-|-(anymultirange,anyrange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anymultirange', amopstrategy => '7',
+ amopopr => '@>(anymultirange,anymultirange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anyrange', amopstrategy => '7',
+ amopopr => '@>(anymultirange,anyrange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anymultirange', amopstrategy => '8',
+ amopopr => '<@(anymultirange,anymultirange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anyrange', amopstrategy => '8',
+ amopopr => '<@(anymultirange,anyrange)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anyelement', amopstrategy => '16',
+ amopopr => '@>(anymultirange,anyelement)', amopmethod => 'gist' },
+{ amopfamily => 'gist/multirange_ops', amoplefttype => 'anymultirange',
+ amoprighttype => 'anymultirange', amopstrategy => '18',
+ amopopr => '=(anymultirange,anymultirange)', amopmethod => 'gist' },
+
# btree multirange_ops
{ amopfamily => 'btree/multirange_ops', amoplefttype => 'anymultirange',
amoprighttype => 'anymultirange', amopstrategy => '1',
diff --git a/src/include/catalog/pg_amproc.dat b/src/include/catalog/pg_amproc.dat
index 9d423d535cd..68d72ec732a 100644
--- a/src/include/catalog/pg_amproc.dat
+++ b/src/include/catalog/pg_amproc.dat
@@ -612,6 +612,24 @@
amprocrighttype => 'inet', amprocnum => '7', amproc => 'inet_gist_same' },
{ amprocfamily => 'gist/network_ops', amproclefttype => 'inet',
amprocrighttype => 'inet', amprocnum => '9', amproc => 'inet_gist_fetch' },
+{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange',
+ amprocrighttype => 'anymultirange', amprocnum => '1',
+ amproc => 'multirange_gist_consistent' },
+{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange',
+ amprocrighttype => 'anymultirange', amprocnum => '2',
+ amproc => 'range_gist_union' },
+{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange',
+ amprocrighttype => 'anymultirange', amprocnum => '3',
+ amproc => 'multirange_gist_compress' },
+{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange',
+ amprocrighttype => 'anymultirange', amprocnum => '5',
+ amproc => 'range_gist_penalty' },
+{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange',
+ amprocrighttype => 'anymultirange', amprocnum => '6',
+ amproc => 'range_gist_picksplit' },
+{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange',
+ amprocrighttype => 'anymultirange', amprocnum => '7',
+ amproc => 'range_gist_same' },
# gin
{ amprocfamily => 'gin/array_ops', amproclefttype => 'anyarray',
diff --git a/src/include/catalog/pg_opclass.dat b/src/include/catalog/pg_opclass.dat
index 4c5e475ff7b..12cad694186 100644
--- a/src/include/catalog/pg_opclass.dat
+++ b/src/include/catalog/pg_opclass.dat
@@ -236,6 +236,8 @@
opcintype => 'anymultirange' },
{ opcmethod => 'hash', opcname => 'multirange_ops', opcfamily => 'hash/multirange_ops',
opcintype => 'anymultirange' },
+{ opcmethod => 'gist', opcname => 'multirange_ops', opcfamily => 'gist/multirange_ops',
+ opcintype => 'anymultirange', opckeytype => 'anyrange' },
{ opcmethod => 'spgist', opcname => 'box_ops', opcfamily => 'spgist/box_ops',
opcintype => 'box' },
{ opcmethod => 'spgist', opcname => 'quad_point_ops',
diff --git a/src/include/catalog/pg_opfamily.dat b/src/include/catalog/pg_opfamily.dat
index fe42dfc0f8f..ac8338f34b1 100644
--- a/src/include/catalog/pg_opfamily.dat
+++ b/src/include/catalog/pg_opfamily.dat
@@ -236,5 +236,7 @@
opfmethod => 'btree', opfname => 'multirange_ops' },
{ oid => '4225',
opfmethod => 'hash', opfname => 'multirange_ops' },
+{ oid => '8021',
+ opfmethod => 'gist', opfname => 'multirange_ops' },
]
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 834ee86c791..139f4a08bd5 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -9922,6 +9922,14 @@
{ oid => '3881', descr => 'GiST support',
proname => 'range_gist_same', prorettype => 'internal',
proargtypes => 'anyrange anyrange internal', prosrc => 'range_gist_same' },
+{ oid => '8017', descr => 'GiST support',
+ proname => 'multirange_gist_consistent', prorettype => 'bool',
+ proargtypes => 'internal anymultirange int2 oid internal',
+ prosrc => 'multirange_gist_consistent' },
+{ oid => '8019', descr => 'GiST support',
+ proname => 'multirange_gist_compress', prorettype => 'internal',
+ proargtypes => 'internal',
+ prosrc => 'multirange_gist_compress' },
{ oid => '3902', descr => 'hash a range',
proname => 'hash_range', prorettype => 'int4', proargtypes => 'anyrange',
prosrc => 'hash_range' },
diff --git a/src/include/utils/multirangetypes.h b/src/include/utils/multirangetypes.h
index ff2e58744a9..1d877f08b56 100644
--- a/src/include/utils/multirangetypes.h
+++ b/src/include/utils/multirangetypes.h
@@ -129,5 +129,7 @@ extern void multirange_get_bounds(TypeCacheEntry *rangetyp,
RangeBound *lower, RangeBound *upper);
extern RangeType *multirange_get_range(TypeCacheEntry *rangetyp,
const MultirangeType *multirange, int i);
+extern RangeType *multirange_get_union_range(TypeCacheEntry *rangetyp,
+ const MultirangeType *mr);
#endif /* MULTIRANGETYPES_H */
diff --git a/src/test/regress/expected/multirangetypes.out b/src/test/regress/expected/multirangetypes.out
index aa7232efc57..86011a02a1e 100644
--- a/src/test/regress/expected/multirangetypes.out
+++ b/src/test/regress/expected/multirangetypes.out
@@ -2219,6 +2219,263 @@ SELECT '{[1,4), [7,10)}'::nummultirange * '{[0,2), [3,8), [9,12)}'::nummultirang
{[1,2),[3,4),[7,8),[9,10)}
(1 row)
+-- test GiST index
+create table test_multirange_gist(mr int4multirange);
+insert into test_multirange_gist select int4multirange(int4range(g, g+10),int4range(g+20, g+30),int4range(g+40, g+50)) from generate_series(1,2000) g;
+insert into test_multirange_gist select '{}'::int4multirange from generate_series(1,500) g;
+insert into test_multirange_gist select int4multirange(int4range(g, g+10000)) from generate_series(1,1000) g;
+insert into test_multirange_gist select int4multirange(int4range(NULL, g*10, '(]'), int4range(g*10, g*20, '(]')) from generate_series(1,100) g;
+insert into test_multirange_gist select int4multirange(int4range(g*10, g*20, '(]'), int4range(g*20, NULL, '(]')) from generate_series(1,100) g;
+create index test_mulrirange_gist_idx on test_multirange_gist using gist (mr);
+-- first, verify non-indexed results
+SET enable_seqscan = t;
+SET enable_indexscan = f;
+SET enable_bitmapscan = f;
+select count(*) from test_multirange_gist where mr @> 'empty'::int4range;
+ count
+-------
+ 3700
+(1 row)
+
+select count(*) from test_multirange_gist where mr = int4multirange(int4range(10,20), int4range(30,40), int4range(50,60));
+ count
+-------
+ 1
+(1 row)
+
+select count(*) from test_multirange_gist where mr @> 10;
+ count
+-------
+ 120
+(1 row)
+
+select count(*) from test_multirange_gist where mr @> int4range(10,20);
+ count
+-------
+ 111
+(1 row)
+
+select count(*) from test_multirange_gist where mr && int4range(10,20);
+ count
+-------
+ 139
+(1 row)
+
+select count(*) from test_multirange_gist where mr <@ int4range(10,50);
+ count
+-------
+ 500
+(1 row)
+
+select count(*) from test_multirange_gist where mr << int4range(100,500);
+ count
+-------
+ 54
+(1 row)
+
+select count(*) from test_multirange_gist where mr >> int4range(100,500);
+ count
+-------
+ 2053
+(1 row)
+
+select count(*) from test_multirange_gist where mr &< int4range(100,500);
+ count
+-------
+ 474
+(1 row)
+
+select count(*) from test_multirange_gist where mr &> int4range(100,500);
+ count
+-------
+ 2893
+(1 row)
+
+select count(*) from test_multirange_gist where mr -|- int4range(100,500);
+ count
+-------
+ 3
+(1 row)
+
+select count(*) from test_multirange_gist where mr @> '{}'::int4multirange;
+ count
+-------
+ 3700
+(1 row)
+
+select count(*) from test_multirange_gist where mr @> int4multirange(int4range(10,20), int4range(30,40));
+ count
+-------
+ 110
+(1 row)
+
+select count(*) from test_multirange_gist where mr && '{(10,20),(30,40),(50,60)}'::int4multirange;
+ count
+-------
+ 218
+(1 row)
+
+select count(*) from test_multirange_gist where mr <@ '{(10,30),(40,60),(70,90)}'::int4multirange;
+ count
+-------
+ 500
+(1 row)
+
+select count(*) from test_multirange_gist where mr << int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 54
+(1 row)
+
+select count(*) from test_multirange_gist where mr >> int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 2053
+(1 row)
+
+select count(*) from test_multirange_gist where mr &< int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 474
+(1 row)
+
+select count(*) from test_multirange_gist where mr &> int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 2893
+(1 row)
+
+select count(*) from test_multirange_gist where mr -|- int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 3
+(1 row)
+
+-- now check same queries using index
+SET enable_seqscan = f;
+SET enable_indexscan = t;
+SET enable_bitmapscan = f;
+select count(*) from test_multirange_gist where mr @> 'empty'::int4range;
+ count
+-------
+ 3700
+(1 row)
+
+select count(*) from test_multirange_gist where mr = int4multirange(int4range(10,20), int4range(30,40), int4range(50,60));
+ count
+-------
+ 1
+(1 row)
+
+select count(*) from test_multirange_gist where mr @> 10;
+ count
+-------
+ 120
+(1 row)
+
+select count(*) from test_multirange_gist where mr @> int4range(10,20);
+ count
+-------
+ 111
+(1 row)
+
+select count(*) from test_multirange_gist where mr && int4range(10,20);
+ count
+-------
+ 139
+(1 row)
+
+select count(*) from test_multirange_gist where mr <@ int4range(10,50);
+ count
+-------
+ 500
+(1 row)
+
+select count(*) from test_multirange_gist where mr << int4range(100,500);
+ count
+-------
+ 54
+(1 row)
+
+select count(*) from test_multirange_gist where mr >> int4range(100,500);
+ count
+-------
+ 2053
+(1 row)
+
+select count(*) from test_multirange_gist where mr &< int4range(100,500);
+ count
+-------
+ 474
+(1 row)
+
+select count(*) from test_multirange_gist where mr &> int4range(100,500);
+ count
+-------
+ 2893
+(1 row)
+
+select count(*) from test_multirange_gist where mr -|- int4range(100,500);
+ count
+-------
+ 3
+(1 row)
+
+select count(*) from test_multirange_gist where mr @> '{}'::int4multirange;
+ count
+-------
+ 3700
+(1 row)
+
+select count(*) from test_multirange_gist where mr @> int4multirange(int4range(10,20), int4range(30,40));
+ count
+-------
+ 110
+(1 row)
+
+select count(*) from test_multirange_gist where mr && '{(10,20),(30,40),(50,60)}'::int4multirange;
+ count
+-------
+ 218
+(1 row)
+
+select count(*) from test_multirange_gist where mr <@ '{(10,30),(40,60),(70,90)}'::int4multirange;
+ count
+-------
+ 500
+(1 row)
+
+select count(*) from test_multirange_gist where mr << int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 54
+(1 row)
+
+select count(*) from test_multirange_gist where mr >> int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 2053
+(1 row)
+
+select count(*) from test_multirange_gist where mr &< int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 474
+(1 row)
+
+select count(*) from test_multirange_gist where mr &> int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 2893
+(1 row)
+
+select count(*) from test_multirange_gist where mr -|- int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 3
+(1 row)
+
+drop table test_multirange_gist;
--
-- range_agg function
--
diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index 6a1bbadc91a..28dc995e599 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -862,6 +862,60 @@ select count(*) from test_range_gist where ir -|- int4range(100,500);
5
(1 row)
+select count(*) from test_range_gist where ir @> '{}'::int4multirange;
+ count
+-------
+ 6200
+(1 row)
+
+select count(*) from test_range_gist where ir @> int4multirange(int4range(10,20), int4range(30,40));
+ count
+-------
+ 107
+(1 row)
+
+select count(*) from test_range_gist where ir && '{(10,20),(30,40),(50,60)}'::int4multirange;
+ count
+-------
+ 271
+(1 row)
+
+select count(*) from test_range_gist where ir <@ '{(10,30),(40,60),(70,90)}'::int4multirange;
+ count
+-------
+ 1060
+(1 row)
+
+select count(*) from test_range_gist where ir << int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 189
+(1 row)
+
+select count(*) from test_range_gist where ir >> int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 3554
+(1 row)
+
+select count(*) from test_range_gist where ir &< int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 1029
+(1 row)
+
+select count(*) from test_range_gist where ir &> int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 4794
+(1 row)
+
+select count(*) from test_range_gist where ir -|- int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 5
+(1 row)
+
-- now check same queries using index
SET enable_seqscan = f;
SET enable_indexscan = t;
@@ -932,6 +986,60 @@ select count(*) from test_range_gist where ir -|- int4range(100,500);
5
(1 row)
+select count(*) from test_range_gist where ir @> '{}'::int4multirange;
+ count
+-------
+ 6200
+(1 row)
+
+select count(*) from test_range_gist where ir @> int4multirange(int4range(10,20), int4range(30,40));
+ count
+-------
+ 107
+(1 row)
+
+select count(*) from test_range_gist where ir && '{(10,20),(30,40),(50,60)}'::int4multirange;
+ count
+-------
+ 271
+(1 row)
+
+select count(*) from test_range_gist where ir <@ '{(10,30),(40,60),(70,90)}'::int4multirange;
+ count
+-------
+ 1060
+(1 row)
+
+select count(*) from test_range_gist where ir << int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 189
+(1 row)
+
+select count(*) from test_range_gist where ir >> int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 3554
+(1 row)
+
+select count(*) from test_range_gist where ir &< int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 1029
+(1 row)
+
+select count(*) from test_range_gist where ir &> int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 4794
+(1 row)
+
+select count(*) from test_range_gist where ir -|- int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 5
+(1 row)
+
-- now check same queries using a bulk-loaded index
drop index test_range_gist_idx;
create index test_range_gist_idx on test_range_gist using gist (ir);
@@ -1001,6 +1109,60 @@ select count(*) from test_range_gist where ir -|- int4range(100,500);
5
(1 row)
+select count(*) from test_range_gist where ir @> '{}'::int4multirange;
+ count
+-------
+ 6200
+(1 row)
+
+select count(*) from test_range_gist where ir @> int4multirange(int4range(10,20), int4range(30,40));
+ count
+-------
+ 107
+(1 row)
+
+select count(*) from test_range_gist where ir && '{(10,20),(30,40),(50,60)}'::int4multirange;
+ count
+-------
+ 271
+(1 row)
+
+select count(*) from test_range_gist where ir <@ '{(10,30),(40,60),(70,90)}'::int4multirange;
+ count
+-------
+ 1060
+(1 row)
+
+select count(*) from test_range_gist where ir << int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 189
+(1 row)
+
+select count(*) from test_range_gist where ir >> int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 3554
+(1 row)
+
+select count(*) from test_range_gist where ir &< int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 1029
+(1 row)
+
+select count(*) from test_range_gist where ir &> int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 4794
+(1 row)
+
+select count(*) from test_range_gist where ir -|- int4multirange(int4range(100,200), int4range(400,500));
+ count
+-------
+ 5
+(1 row)
+
-- test SP-GiST index that's been built incrementally
create table test_range_spgist(ir int4range);
create index test_range_spgist_idx on test_range_spgist using spgist (ir);
diff --git a/src/test/regress/sql/multirangetypes.sql b/src/test/regress/sql/multirangetypes.sql
index 9d7af404c98..2a2ee4dcdfd 100644
--- a/src/test/regress/sql/multirangetypes.sql
+++ b/src/test/regress/sql/multirangetypes.sql
@@ -414,6 +414,69 @@ SELECT '{[1,4), [7,10)}'::nummultirange * '{[-5,-4), [5,6), [9,12)}'::nummultira
SELECT '{[1,4), [7,10)}'::nummultirange * '{[0,2), [3,8), [9,12)}'::nummultirange;
SELECT '{[1,4), [7,10)}'::nummultirange * '{[0,2), [3,8), [9,12)}'::nummultirange;
+-- test GiST index
+create table test_multirange_gist(mr int4multirange);
+insert into test_multirange_gist select int4multirange(int4range(g, g+10),int4range(g+20, g+30),int4range(g+40, g+50)) from generate_series(1,2000) g;
+insert into test_multirange_gist select '{}'::int4multirange from generate_series(1,500) g;
+insert into test_multirange_gist select int4multirange(int4range(g, g+10000)) from generate_series(1,1000) g;
+insert into test_multirange_gist select int4multirange(int4range(NULL, g*10, '(]'), int4range(g*10, g*20, '(]')) from generate_series(1,100) g;
+insert into test_multirange_gist select int4multirange(int4range(g*10, g*20, '(]'), int4range(g*20, NULL, '(]')) from generate_series(1,100) g;
+create index test_mulrirange_gist_idx on test_multirange_gist using gist (mr);
+
+-- first, verify non-indexed results
+SET enable_seqscan = t;
+SET enable_indexscan = f;
+SET enable_bitmapscan = f;
+
+select count(*) from test_multirange_gist where mr @> 'empty'::int4range;
+select count(*) from test_multirange_gist where mr = int4multirange(int4range(10,20), int4range(30,40), int4range(50,60));
+select count(*) from test_multirange_gist where mr @> 10;
+select count(*) from test_multirange_gist where mr @> int4range(10,20);
+select count(*) from test_multirange_gist where mr && int4range(10,20);
+select count(*) from test_multirange_gist where mr <@ int4range(10,50);
+select count(*) from test_multirange_gist where mr << int4range(100,500);
+select count(*) from test_multirange_gist where mr >> int4range(100,500);
+select count(*) from test_multirange_gist where mr &< int4range(100,500);
+select count(*) from test_multirange_gist where mr &> int4range(100,500);
+select count(*) from test_multirange_gist where mr -|- int4range(100,500);
+select count(*) from test_multirange_gist where mr @> '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr @> int4multirange(int4range(10,20), int4range(30,40));
+select count(*) from test_multirange_gist where mr && '{(10,20),(30,40),(50,60)}'::int4multirange;
+select count(*) from test_multirange_gist where mr <@ '{(10,30),(40,60),(70,90)}'::int4multirange;
+select count(*) from test_multirange_gist where mr << int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_multirange_gist where mr >> int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_multirange_gist where mr &< int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_multirange_gist where mr &> int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_multirange_gist where mr -|- int4multirange(int4range(100,200), int4range(400,500));
+
+-- now check same queries using index
+SET enable_seqscan = f;
+SET enable_indexscan = t;
+SET enable_bitmapscan = f;
+
+select count(*) from test_multirange_gist where mr @> 'empty'::int4range;
+select count(*) from test_multirange_gist where mr = int4multirange(int4range(10,20), int4range(30,40), int4range(50,60));
+select count(*) from test_multirange_gist where mr @> 10;
+select count(*) from test_multirange_gist where mr @> int4range(10,20);
+select count(*) from test_multirange_gist where mr && int4range(10,20);
+select count(*) from test_multirange_gist where mr <@ int4range(10,50);
+select count(*) from test_multirange_gist where mr << int4range(100,500);
+select count(*) from test_multirange_gist where mr >> int4range(100,500);
+select count(*) from test_multirange_gist where mr &< int4range(100,500);
+select count(*) from test_multirange_gist where mr &> int4range(100,500);
+select count(*) from test_multirange_gist where mr -|- int4range(100,500);
+select count(*) from test_multirange_gist where mr @> '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr @> int4multirange(int4range(10,20), int4range(30,40));
+select count(*) from test_multirange_gist where mr && '{(10,20),(30,40),(50,60)}'::int4multirange;
+select count(*) from test_multirange_gist where mr <@ '{(10,30),(40,60),(70,90)}'::int4multirange;
+select count(*) from test_multirange_gist where mr << int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_multirange_gist where mr >> int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_multirange_gist where mr &< int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_multirange_gist where mr &> int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_multirange_gist where mr -|- int4multirange(int4range(100,200), int4range(400,500));
+
+drop table test_multirange_gist;
+
--
-- range_agg function
--
diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql
index b69efede3ae..51eddabf60f 100644
--- a/src/test/regress/sql/rangetypes.sql
+++ b/src/test/regress/sql/rangetypes.sql
@@ -232,6 +232,15 @@ select count(*) from test_range_gist where ir >> int4range(100,500);
select count(*) from test_range_gist where ir &< int4range(100,500);
select count(*) from test_range_gist where ir &> int4range(100,500);
select count(*) from test_range_gist where ir -|- int4range(100,500);
+select count(*) from test_range_gist where ir @> '{}'::int4multirange;
+select count(*) from test_range_gist where ir @> int4multirange(int4range(10,20), int4range(30,40));
+select count(*) from test_range_gist where ir && '{(10,20),(30,40),(50,60)}'::int4multirange;
+select count(*) from test_range_gist where ir <@ '{(10,30),(40,60),(70,90)}'::int4multirange;
+select count(*) from test_range_gist where ir << int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_range_gist where ir >> int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_range_gist where ir &< int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_range_gist where ir &> int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_range_gist where ir -|- int4multirange(int4range(100,200), int4range(400,500));
-- now check same queries using index
SET enable_seqscan = f;
@@ -249,6 +258,15 @@ select count(*) from test_range_gist where ir >> int4range(100,500);
select count(*) from test_range_gist where ir &< int4range(100,500);
select count(*) from test_range_gist where ir &> int4range(100,500);
select count(*) from test_range_gist where ir -|- int4range(100,500);
+select count(*) from test_range_gist where ir @> '{}'::int4multirange;
+select count(*) from test_range_gist where ir @> int4multirange(int4range(10,20), int4range(30,40));
+select count(*) from test_range_gist where ir && '{(10,20),(30,40),(50,60)}'::int4multirange;
+select count(*) from test_range_gist where ir <@ '{(10,30),(40,60),(70,90)}'::int4multirange;
+select count(*) from test_range_gist where ir << int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_range_gist where ir >> int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_range_gist where ir &< int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_range_gist where ir &> int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_range_gist where ir -|- int4multirange(int4range(100,200), int4range(400,500));
-- now check same queries using a bulk-loaded index
drop index test_range_gist_idx;
@@ -265,6 +283,15 @@ select count(*) from test_range_gist where ir >> int4range(100,500);
select count(*) from test_range_gist where ir &< int4range(100,500);
select count(*) from test_range_gist where ir &> int4range(100,500);
select count(*) from test_range_gist where ir -|- int4range(100,500);
+select count(*) from test_range_gist where ir @> '{}'::int4multirange;
+select count(*) from test_range_gist where ir @> int4multirange(int4range(10,20), int4range(30,40));
+select count(*) from test_range_gist where ir && '{(10,20),(30,40),(50,60)}'::int4multirange;
+select count(*) from test_range_gist where ir <@ '{(10,30),(40,60),(70,90)}'::int4multirange;
+select count(*) from test_range_gist where ir << int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_range_gist where ir >> int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_range_gist where ir &< int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_range_gist where ir &> int4multirange(int4range(100,200), int4range(400,500));
+select count(*) from test_range_gist where ir -|- int4multirange(int4range(100,200), int4range(400,500));
-- test SP-GiST index that's been built incrementally
create table test_range_spgist(ir int4range);