> Once again, many thanks for the review. Here's a new version. I have
> added operator classes for int8, text, and actually everything that btree
> supports except:
> bool
> record
> oidvector
> anyarray
> tsvector
> tsquery
> jsonb
> range
>
> since I'm not sure that it makes sense to have opclasses for any of
> these -- at least not regular minmax opclasses. There are some
> interesting possibilities, for example for range types, whereby we store
> in the index tuple the union of all the range in the block range.
I thought we can do better than minmax for the inet data type,
and ended up with a generalized opclass supporting both inet and range
types. Patch based on minmax-v20 attached. It works well except
a few small problems. I will improve the patch and add into
a commitfest after BRIN framework is committed.
To support more operators I needed to change amstrategies and
amsupport on the catalog. It would be nice if amsupport can be set
to 0 like amstrategies.
Inet data types accept IP version 4 and version 6. It is not possible
to represent union of addresses from different versions with a valid
inet type. So, I made the union function return NULL in this case.
Then, I tried to store if returned value is NULL or not, in
column->values[] as boolean, but it failed on the pfree() inside
brin_dtuple_initilize(). It doesn't seem right to free the values
based on attr->attbyval.
I think the same opclass can be used for geometric types. I can
rename it to inclusion_ops instead of range_ops. The GiST opclasses
for the geometric types use bounding boxes. It wouldn't be possible
to use a different data type in a generic oplass. Maybe STORAGE
parameter can be used for that purpose.
> (I had an opclass for anyenum too, but on further thought I removed it
> because it is going to be pointless in nearly all cases.)
It can be useful in some circumstances. We wouldn't lose anything
by supporting more types. I think we should even add an operator
class for boolean.
diff --git a/doc/src/sgml/brin.sgml b/doc/src/sgml/brin.sgml
index 12ba3f4..7663113 100644
--- a/doc/src/sgml/brin.sgml
+++ b/doc/src/sgml/brin.sgml
@@ -249,6 +249,18 @@
</entry>
</row>
<row>
+ <entry><literal>inet_range_ops</literal></entry>
+ <entry><type>inet</type></entry>
+ <entry>
+ <literal>&&</>
+ <literal>>></>
+ <literal>>>=</>
+ <literal><<</literal>
+ <literal><<=</literal>
+ <literal>=</>
+ </entry>
+ </row>
+ <row>
<entry><literal>bpchar_minmax_ops</literal></entry>
<entry><type>character</type></entry>
<entry>
@@ -370,6 +382,23 @@
</entry>
</row>
<row>
+ <entry><literal>range_ops</></entry>
+ <entry>any range type</entry>
+ <entry>
+ <literal>&&</>
+ <literal>&></>
+ <literal>&<</>
+ <literal>>></>
+ <literal><<</>
+ <literal><@</>
+ <literal>=</>
+ <literal>@></>
+ <literal>@></>
+ </entry>
+ <entry>
+ </entry>
+ </row>
+ <row>
<entry><literal>pg_lsn_minmax_ops</literal></entry>
<entry><type>pg_lsn</type></entry>
<entry>
diff --git a/src/backend/access/brin/Makefile b/src/backend/access/brin/Makefile
index ac44fcd..019c582 100644
--- a/src/backend/access/brin/Makefile
+++ b/src/backend/access/brin/Makefile
@@ -12,7 +12,7 @@ subdir = src/backend/access/brin
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
-OBJS = brin.o brin_pageops.o brin_revmap.o brin_tuple.o brin_xlog.o \
- brin_minmax.o
+OBJS = brin.o brin_pageops.o brin_range.o brin_revmap.o brin_tuple.o \
+ brin_xlog.o brin_minmax.o
include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/access/brin/brin_range.c b/src/backend/access/brin/brin_range.c
new file mode 100644
index 0000000..b63b80a
--- /dev/null
+++ b/src/backend/access/brin/brin_range.c
@@ -0,0 +1,323 @@
+/*
+ * brin_range.c
+ * Implementation of range opclass for BRIN
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * src/backend/access/brin/brin_range.c
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/brin_internal.h"
+#include "access/brin_tuple.h"
+#include "access/skey.h"
+#include "catalog/pg_type.h"
+#include "utils/datum.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+
+
+/*
+ * Procedure numbers must not collide with BRIN_PROCNUM defines in
+ * brin_internal.h. Note we only need inequality functions.
+ */
+#define RANGE_NUM_PROCNUMS 10 /* # support procs */
+#define PROCNUM_CONTAINS 5
+#define PROCNUM_UNION 6
+#define PROCNUM_BEFORE 7 /* required for overright strategy */
+#define PROCNUM_OVERLEFT 8 /* required for after strategy */
+#define PROCNUM_OVERLAPS 9 /* required for overlaps strategy */
+#define PROCNUM_OVERRIGHT 10 /* required for before strategy */
+#define PROCNUM_AFTER 11 /* required for after strategy */
+#define PROCNUM_ADJACENT 12 /* required for adjacent strategy */
+#define PROCNUM_CONTAINS_ELEM 13 /* required for contains element strategy */
+#define PROCNUM_CONTAINS_NOTEQ 14 /* required for contains but not equals strategy */
+
+/*
+ * Subtract this from procnum to obtain index in RangeOpaque arrays
+ * (Must be equal to minimum of private procnums)
+ */
+#define PROCNUM_BASE 5
+
+static FmgrInfo *range_get_procinfo(BrinDesc *bdesc, uint16 attno,
+ uint16 procnum);
+
+PG_FUNCTION_INFO_V1(rangeOpcInfo);
+PG_FUNCTION_INFO_V1(rangeAddValue);
+PG_FUNCTION_INFO_V1(rangeConsistent);
+PG_FUNCTION_INFO_V1(rangeUnion);
+
+
+typedef struct RangeOpaque
+{
+ FmgrInfo operators[RANGE_NUM_PROCNUMS];
+ bool inited[RANGE_NUM_PROCNUMS];
+} RangeOpaque;
+
+Datum
+rangeOpcInfo(PG_FUNCTION_ARGS)
+{
+ Oid typoid = PG_GETARG_OID(0);
+ BrinOpcInfo *result;
+
+ /*
+ * opaque->operators is initialized lazily, as indicated by 'inited'
+ * which is initialized to all false by palloc0.
+ */
+
+ result = palloc0(MAXALIGN(SizeofBrinOpcInfo(2)) + sizeof(RangeOpaque));
+ result->oi_nstored = 1;
+ result->oi_opaque = (RangeOpaque *)
+ MAXALIGN((char *) result + SizeofBrinOpcInfo(2));
+ result->oi_typids[0] = typoid;
+
+ PG_RETURN_POINTER(result);
+}
+
+/*
+ * Examine the given index tuple (which contains partial status of a certain
+ * page range) by comparing it to the given value that comes from another heap
+ * tuple. If the new value is outside the min/max range specified by the
+ * existing tuple values, update the index tuple and return true. Otherwise,
+ * return false and do not modify in this case.
+ */
+Datum
+rangeAddValue(PG_FUNCTION_ARGS)
+{
+ BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
+ BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
+ Datum newval = PG_GETARG_DATUM(2);
+ bool isnull = PG_GETARG_BOOL(3);
+ Oid colloid = PG_GET_COLLATION();
+ FmgrInfo *frmg;
+ Datum result;
+ AttrNumber attno;
+ Form_pg_attribute attr;
+ FunctionCallInfoData newfcinfo;
+
+ /*
+ * If the new value is null, we record that we saw it if it's the first
+ * one; otherwise, there's nothing to do.
+ */
+ if (isnull)
+ {
+ if (column->hasnulls)
+ PG_RETURN_BOOL(false);
+
+ column->hasnulls = true;
+ PG_RETURN_BOOL(true);
+ }
+
+ attno = column->attno;
+ attr = bdesc->bd_tupdesc->attrs[attno - 1];
+
+ /*
+ * If the recorded value is null, store the new value (which we know to be
+ * not null) as both minimum and maximum, and we're done.
+ */
+ if (column->allnulls)
+ {
+ column->values[0] = datumCopy(newval, attr->attbyval, attr->attlen);
+ column->allnulls = false;
+ PG_RETURN_BOOL(true);
+ }
+
+ frmg = range_get_procinfo(bdesc, attno, PROCNUM_CONTAINS);
+ result = FunctionCall2Coll(frmg, colloid, column->values[0], newval);
+ if (DatumGetBool(result))
+ PG_RETURN_BOOL(false);
+
+ frmg = range_get_procinfo(bdesc, attno, PROCNUM_UNION);
+
+ /* FunctionCall2Coll() cannot be used because NULL is expected. */
+ InitFunctionCallInfoData(newfcinfo, frmg, 2, colloid, NULL, NULL);
+ newfcinfo.arg[0] = column->values[0];
+ newfcinfo.arg[1] = newval;
+ newfcinfo.argnull[0] = false;
+ newfcinfo.argnull[1] = false;
+ result = FunctionCallInvoke(&newfcinfo);
+
+ if (!attr->attbyval)
+ pfree(DatumGetPointer(column->values[0]));
+
+ column->values[0] = result;
+
+ PG_RETURN_BOOL(true);
+}
+
+/*
+ * Given an index tuple corresponding to a certain page range and a scan key,
+ * return whether the scan key is consistent with the index tuple's min/max
+ * values. Return true if so, false otherwise.
+ */
+Datum
+rangeConsistent(PG_FUNCTION_ARGS)
+{
+ BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
+ BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
+ ScanKey key = (ScanKey) PG_GETARG_POINTER(2);
+ Oid colloid = PG_GET_COLLATION();
+ AttrNumber attno;
+ Datum query;
+ FmgrInfo *frmg;
+ Datum result;
+
+ Assert(key->sk_attno == column->attno);
+
+ /* handle IS NULL/IS NOT NULL tests */
+ if (key->sk_flags & SK_ISNULL)
+ {
+ if (key->sk_flags & SK_SEARCHNULL)
+ {
+ if (column->allnulls || column->hasnulls)
+ PG_RETURN_BOOL(true);
+ PG_RETURN_BOOL(false);
+ }
+
+ /*
+ * For IS NOT NULL, we can only skip ranges that are known to have
+ * only nulls.
+ */
+ Assert(key->sk_flags & SK_SEARCHNOTNULL);
+ PG_RETURN_BOOL(!column->allnulls);
+ }
+
+ attno = key->sk_attno;
+ query = key->sk_argument;
+ switch (key->sk_strategy)
+ {
+ case RANGESTRAT_CONTAINS:
+ case RANGESTRAT_EQ:
+ frmg = range_get_procinfo(bdesc, attno, PROCNUM_CONTAINS);
+ result = FunctionCall2Coll(frmg, colloid, column->values[0], query);
+ PG_RETURN_DATUM(result);
+
+ /* Remaining are the optional strategies. */
+
+ case RANGESTRAT_BEFORE:
+ frmg = range_get_procinfo(bdesc, attno, PROCNUM_OVERRIGHT);
+ result = FunctionCall2Coll(frmg, colloid, column->values[0], query);
+ PG_RETURN_BOOL(!DatumGetBool(result));
+
+ case RANGESTRAT_OVERLEFT:
+ frmg = range_get_procinfo(bdesc, attno, PROCNUM_AFTER);
+ result = FunctionCall2Coll(frmg, colloid, column->values[0], query);
+ PG_RETURN_BOOL(!DatumGetBool(result));
+
+ case RANGESTRAT_OVERLAPS:
+ case RANGESTRAT_CONTAINED_BY:
+ case RANGESTRAT_CONTAINED_BY_NOTEQ:
+ frmg = range_get_procinfo(bdesc, attno, PROCNUM_OVERLAPS);
+ result = FunctionCall2Coll(frmg, colloid, column->values[0], query);
+ PG_RETURN_DATUM(result);
+
+ case RANGESTRAT_OVERRIGHT:
+ frmg = range_get_procinfo(bdesc, attno, PROCNUM_BEFORE);
+ result = FunctionCall2Coll(frmg, colloid, column->values[0], query);
+ PG_RETURN_BOOL(!DatumGetBool(result));
+
+ case RANGESTRAT_AFTER:
+ frmg = range_get_procinfo(bdesc, attno, PROCNUM_OVERLEFT);
+ result = FunctionCall2Coll(frmg, colloid, column->values[0], query);
+ PG_RETURN_BOOL(!DatumGetBool(result));
+
+ case RANGESTRAT_ADJACENT:
+ frmg = range_get_procinfo(bdesc, attno, PROCNUM_OVERLAPS);
+ result = FunctionCall2Coll(frmg, colloid, column->values[0], query);
+ if (DatumGetBool(result))
+ PG_RETURN_BOOL(true);
+ frmg = range_get_procinfo(bdesc, attno, PROCNUM_ADJACENT);
+ result = FunctionCall2Coll(frmg, colloid, column->values[0], query);
+ PG_RETURN_DATUM(result);
+
+ case RANGESTRAT_CONTAINS_ELEM:
+ frmg = range_get_procinfo(bdesc, attno, PROCNUM_CONTAINS_ELEM);
+ result = FunctionCall2Coll(frmg, colloid, column->values[0], query);
+ PG_RETURN_DATUM(result);
+
+ case RANGESTRAT_CONTAINS_NOTEQ:
+ frmg = range_get_procinfo(bdesc, attno, PROCNUM_CONTAINS_NOTEQ);
+ result = FunctionCall2Coll(frmg, colloid, column->values[0], query);
+ PG_RETURN_DATUM(result);
+
+ default:
+ /* shouldn't happen */
+ elog(ERROR, "invalid strategy number %d", key->sk_strategy);
+ PG_RETURN_BOOL(false); /* keep compiler quiet */
+ }
+}
+
+/*
+ * Given two BrinValues, update the first of them as a union of the summary
+ * values contained in both. The second one is untouched.
+ */
+Datum
+rangeUnion(PG_FUNCTION_ARGS)
+{
+ BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
+ BrinValues *col_a = (BrinValues *) PG_GETARG_POINTER(1);
+ BrinValues *col_b = (BrinValues *) PG_GETARG_POINTER(2);
+ Oid colloid = PG_GET_COLLATION();
+ AttrNumber attno;
+ Form_pg_attribute attr;
+ FmgrInfo *frmg;
+ FunctionCallInfoData newfcinfo;
+ Datum result;
+
+ Assert(col_a->attno == col_b->attno);
+
+ attno = col_a->attno;
+ attr = bdesc->bd_tupdesc->attrs[attno - 1];
+
+ /* Adjust null flags */
+ if (col_a->allnulls && !col_b->allnulls)
+ col_a->allnulls = false;
+ if (!col_a->hasnulls && col_b->hasnulls)
+ col_a->hasnulls = true;
+
+ frmg = range_get_procinfo(bdesc, attno, PROCNUM_UNION);
+
+ /* FunctionCall2Coll() cannot be used because NULL is expected. */
+ InitFunctionCallInfoData(newfcinfo, frmg, 2, colloid, NULL, NULL);
+ newfcinfo.arg[0] = col_a->values[0];
+ newfcinfo.arg[1] = col_b->values[0];
+ newfcinfo.argnull[0] = false;
+ newfcinfo.argnull[1] = false;
+ result = FunctionCallInvoke(&newfcinfo);
+
+ if (!attr->attbyval)
+ pfree(DatumGetPointer(col_a->values[0]));
+
+ col_a->values[0] = result;
+
+ PG_RETURN_VOID();
+}
+
+/*
+ * Return the procedure corresponding to the given function support number.
+ */
+static FmgrInfo *
+range_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
+{
+ RangeOpaque *opaque;
+ uint16 basenum = procnum - PROCNUM_BASE;
+
+ opaque = (RangeOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
+
+ /*
+ * We cache these in the opaque struct, to avoid repetitive syscache
+ * lookups.
+ */
+ if (!opaque->inited[basenum])
+ {
+ fmgr_info_copy(&opaque->operators[basenum],
+ index_getprocinfo(bdesc->bd_index, attno, procnum),
+ bdesc->bd_context);
+ opaque->inited[basenum] = true;
+ }
+
+ return &opaque->operators[basenum];
+}
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index 3a705da..485d932 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -888,6 +888,45 @@ network_hostmask(PG_FUNCTION_ARGS)
}
/*
+ * Returns the network which contain both of the inputs. Note that return
+ * value isn't trimmed. It wouldn't be nice to display it directly. Use
+ * inet_to_cidr() to get the network address. Returns null for inputs which
+ * are not from the same IP family.
+ */
+Datum
+inet_merge(PG_FUNCTION_ARGS)
+{
+ inet *a1 = PG_GETARG_INET_PP(0),
+ *a2 = PG_GETARG_INET_PP(1),
+ *result;
+ int commonbits;
+
+ if (ip_family(a1) != ip_family(a2))
+ {
+ elog(LOG, "bok %d %d", ip_family(a1), ip_family(a2));
+ PG_RETURN_NULL();
+ }
+
+ commonbits = bitncommon(ip_addr(a1), ip_addr(a2),
+ Min(ip_bits(a1), ip_bits(a2)));
+
+ /* Make sure any unused bits are zeroed. */
+ result = (inet *) palloc0(sizeof(inet));
+
+ ip_family(result) = ip_family(a1);
+ ip_bits(result) = commonbits;
+
+ /* Clone appropriate bytes of the address. */
+ if (commonbits > 0)
+ memcpy(ip_addr(result), ip_addr(a1), (commonbits + 7) / 8);
+
+ /* Set varlena header correctly. */
+ SET_INET_VARSIZE(result);
+
+ PG_RETURN_INET_P(result);
+}
+
+/*
* Convert a value of a network datatype to an approximate scalar value.
* This is used for estimating selectivities of inequality operators
* involving network types.
diff --git a/src/backend/utils/adt/rangetypes.c b/src/backend/utils/adt/rangetypes.c
index c1c3091..f96ddab 100644
--- a/src/backend/utils/adt/rangetypes.c
+++ b/src/backend/utils/adt/rangetypes.c
@@ -1007,12 +1007,10 @@ range_minus(PG_FUNCTION_ARGS)
}
/* set union */
-Datum
-range_union(PG_FUNCTION_ARGS)
+static RangeType *
+range_union_internal(TypeCacheEntry *typcache, RangeType *r1, RangeType *r2,
+ bool strict)
{
- RangeType *r1 = PG_GETARG_RANGE(0);
- RangeType *r2 = PG_GETARG_RANGE(1);
- TypeCacheEntry *typcache;
RangeBound lower1,
lower2;
RangeBound upper1,
@@ -1026,19 +1024,18 @@ range_union(PG_FUNCTION_ARGS)
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);
+ return r2;
if (empty2)
- PG_RETURN_RANGE(r1);
+ return r1;
- if (!DatumGetBool(range_overlaps(fcinfo)) &&
- !DatumGetBool(range_adjacent(fcinfo)))
+ if (strict &&
+ !DatumGetBool(range_overlaps_internal(typcache, r1, r2)) &&
+ !DatumGetBool(range_adjacent_internal(typcache, r1, r2)))
ereport(ERROR,
(errcode(ERRCODE_DATA_EXCEPTION),
errmsg("result of range union would not be contiguous")));
@@ -1053,7 +1050,31 @@ range_union(PG_FUNCTION_ARGS)
else
result_upper = &upper2;
- PG_RETURN_RANGE(make_range(typcache, result_lower, result_upper, false));
+ return make_range(typcache, result_lower, result_upper, false);
+}
+
+Datum
+range_union(PG_FUNCTION_ARGS)
+{
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r2 = PG_GETARG_RANGE(1);
+ TypeCacheEntry *typcache;
+
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+ PG_RETURN_RANGE(range_union_internal(typcache, r1, r2, true));
+}
+
+Datum
+range_merge(PG_FUNCTION_ARGS)
+{
+ RangeType *r1 = PG_GETARG_RANGE(0);
+ RangeType *r2 = PG_GETARG_RANGE(1);
+ TypeCacheEntry *typcache;
+
+ typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r1));
+
+ PG_RETURN_RANGE(range_union_internal(typcache, r1, r2, false));
}
/* set intersection */
diff --git a/src/include/access/skey.h b/src/include/access/skey.h
index bb96808..fec0aea 100644
--- a/src/include/access/skey.h
+++ b/src/include/access/skey.h
@@ -40,6 +40,22 @@ typedef uint16 StrategyNumber;
#define BTMaxStrategyNumber 5
+/* Operator strategy numbers used in the GiST and SP-GiST range opclasses */
+/* Numbers are chosen to match up operator names with existing usages */
+#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_NOTEQ 9
+#define RANGESTRAT_CONTAINED_BY_NOTEQ 10
+#define RANGESTRAT_CONTAINS_ELEM 16
+#define RANGESTRAT_EQ 18
+
+
/*
* A ScanKey represents the application of a comparison operator between
* a table or index column and a constant. When it's part of an array of
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
index b03e5d4..5416707 100644
--- a/src/include/catalog/pg_am.h
+++ b/src/include/catalog/pg_am.h
@@ -132,7 +132,7 @@ DESCR("GIN index access method");
DATA(insert OID = 4000 ( spgist 0 5 f f f f f t f t f f f 0 spginsert spgbeginscan spggettuple spggetbitmap spgrescan spgendscan spgmarkpos spgrestrpos spgbuild spgbuildempty spgbulkdelete spgvacuumcleanup spgcanreturn spgcostestimate spgoptions ));
DESCR("SP-GiST index access method");
#define SPGIST_AM_OID 4000
-DATA(insert OID = 3580 ( brin 5 8 f f f f t t f t t f f 0 brininsert brinbeginscan - bringetbitmap brinrescan brinendscan brinmarkpos brinrestrpos brinbuild brinbuildempty brinbulkdelete brinvacuumcleanup - brincostestimate brinoptions ));
+DATA(insert OID = 3580 ( brin 0 14 f f f f t t f t t f f 0 brininsert brinbeginscan - bringetbitmap brinrescan brinendscan brinmarkpos brinrestrpos brinbuild brinbuildempty brinbulkdelete brinvacuumcleanup - brincostestimate brinoptions ));
#define BRIN_AM_OID 3580
#endif /* PG_AM_H */
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index e72cc6c..40b93f2 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -936,6 +936,13 @@ DATA(insert ( 4075 869 869 2 s 1204 3580 0 ));
DATA(insert ( 4075 869 869 3 s 1201 3580 0 ));
DATA(insert ( 4075 869 869 4 s 1206 3580 0 ));
DATA(insert ( 4075 869 869 5 s 1205 3580 0 ));
+/* range inet */
+DATA(insert ( 4051 869 869 3 s 3552 3580 0 ));
+DATA(insert ( 4051 869 869 7 s 934 3580 0 ));
+DATA(insert ( 4051 869 869 8 s 932 3580 0 ));
+DATA(insert ( 4051 869 869 9 s 933 3580 0 ));
+DATA(insert ( 4051 869 869 10 s 931 3580 0 ));
+DATA(insert ( 4051 869 869 18 s 1201 3580 0 ));
/* minmax character */
DATA(insert ( 4076 1042 1042 1 s 1058 3580 0 ));
DATA(insert ( 4076 1042 1042 2 s 1059 3580 0 ));
@@ -1002,6 +1009,17 @@ DATA(insert ( 4081 2950 2950 2 s 2976 3580 0 ));
DATA(insert ( 4081 2950 2950 3 s 2972 3580 0 ));
DATA(insert ( 4081 2950 2950 4 s 2977 3580 0 ));
DATA(insert ( 4081 2950 2950 5 s 2975 3580 0 ));
+/* range types */
+DATA(insert ( 4053 3831 3831 1 s 3893 3580 0 ));
+DATA(insert ( 4053 3831 3831 2 s 3895 3580 0 ));
+DATA(insert ( 4053 3831 3831 3 s 3888 3580 0 ));
+DATA(insert ( 4053 3831 3831 4 s 3896 3580 0 ));
+DATA(insert ( 4053 3831 3831 5 s 3894 3580 0 ));
+DATA(insert ( 4053 3831 3831 6 s 3897 3580 0 ));
+DATA(insert ( 4053 3831 3831 7 s 3890 3580 0 ));
+DATA(insert ( 4053 3831 3831 8 s 3892 3580 0 ));
+DATA(insert ( 4053 3831 2283 16 s 3889 3580 0 ));
+DATA(insert ( 4053 3831 3831 18 s 3882 3580 0 ));
/* minmax pg_lsn */
DATA(insert ( 4082 3220 3220 1 s 3224 3580 0 ));
DATA(insert ( 4082 3220 3220 2 s 3226 3580 0 ));
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index 9ffe1a9..db380fe 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -568,6 +568,15 @@ DATA(insert ( 4075 869 869 5 921 ));
DATA(insert ( 4075 869 869 6 922 ));
DATA(insert ( 4075 869 869 7 924 ));
DATA(insert ( 4075 869 869 8 923 ));
+/* range inet */
+DATA(insert ( 4051 869 869 1 3387 ));
+DATA(insert ( 4051 869 869 2 3388 ));
+DATA(insert ( 4051 869 869 3 3389 ));
+DATA(insert ( 4051 869 869 4 3390 ));
+DATA(insert ( 4051 869 869 5 930 ));
+DATA(insert ( 4051 869 869 6 4052 ));
+DATA(insert ( 4051 869 869 9 3551 ));
+DATA(insert ( 4051 869 869 14 929 ));
/* minmax character */
DATA(insert ( 4076 1042 1042 1 3383 ));
DATA(insert ( 4076 1042 1042 2 3384 ));
@@ -667,6 +676,20 @@ DATA(insert ( 4081 2950 2950 5 2954 ));
DATA(insert ( 4081 2950 2950 6 2955 ));
DATA(insert ( 4081 2950 2950 7 2957 ));
DATA(insert ( 4081 2950 2950 8 2958 ));
+/* range types */
+DATA(insert ( 4053 3831 3831 1 3387 ));
+DATA(insert ( 4053 3831 3831 2 3388 ));
+DATA(insert ( 4053 3831 3831 3 3389 ));
+DATA(insert ( 4053 3831 3831 4 3390 ));
+DATA(insert ( 4053 3831 3831 5 3859 ));
+DATA(insert ( 4053 3831 3831 6 4057 ));
+DATA(insert ( 4053 3831 3831 7 3863 ));
+DATA(insert ( 4053 3831 3831 8 3865 ));
+DATA(insert ( 4053 3831 3831 9 3857 ));
+DATA(insert ( 4053 3831 3831 10 3866 ));
+DATA(insert ( 4053 3831 3831 11 3864 ));
+DATA(insert ( 4053 3831 3831 12 3862 ));
+DATA(insert ( 4053 3831 3831 13 3858 ));
/* minmax pg_lsn */
DATA(insert ( 4082 3220 3220 1 3383 ));
DATA(insert ( 4082 3220 3220 2 3384 ));
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 595cd7f..d4f50c5 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -252,7 +252,8 @@ DATA(insert ( 3580 float8_minmax_ops PGNSP PGUID 4071 701 t 0 ));
DATA(insert ( 3580 abstime_minmax_ops PGNSP PGUID 4072 702 t 0 ));
DATA(insert ( 3580 reltime_minmax_ops PGNSP PGUID 4073 703 t 0 ));
DATA(insert ( 3580 macaddr_minmax_ops PGNSP PGUID 4074 829 t 0 ));
-DATA(insert ( 3580 inet_minmax_ops PGNSP PGUID 4075 869 t 0 ));
+DATA(insert ( 3580 inet_minmax_ops PGNSP PGUID 4075 869 f 0 ));
+DATA(insert ( 3580 inet_range_ops PGNSP PGUID 4051 869 t 0 ));
DATA(insert ( 3580 bpchar_minmax_ops PGNSP PGUID 4076 1042 t 0 ));
DATA(insert ( 3580 date_minmax_ops PGNSP PGUID 4061 1082 t 0 ));
DATA(insert ( 3580 time_minmax_ops PGNSP PGUID 4077 1083 t 0 ));
@@ -265,7 +266,8 @@ DATA(insert ( 3580 varbit_minmax_ops PGNSP PGUID 4080 1562 t 0 ));
DATA(insert ( 3580 numeric_minmax_ops PGNSP PGUID 4055 1700 t 0 ));
/* no brin opclass for record, anyarray */
DATA(insert ( 3580 uuid_minmax_ops PGNSP PGUID 4081 2950 t 0 ));
+DATA(insert ( 3580 range_ops PGNSP PGUID 4053 3831 t 0 ));
DATA(insert ( 3580 pg_lsn_minmax_ops PGNSP PGUID 4082 3220 t 0 ));
-/* no brin opclass for enum, tsvector, tsquery, jsonb, range */
+/* no brin opclass for enum, tsvector, tsquery, jsonb */
#endif /* PG_OPCLASS_H */
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index 2d8af76..a574a9f 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -147,6 +147,7 @@ DATA(insert OID = 3901 ( 403 range_ops PGNSP PGUID ));
DATA(insert OID = 3903 ( 405 range_ops PGNSP PGUID ));
DATA(insert OID = 3919 ( 783 range_ops PGNSP PGUID ));
DATA(insert OID = 3474 ( 4000 range_ops PGNSP PGUID ));
+DATA(insert OID = 4053 ( 3580 range_ops PGNSP PGUID ));
DATA(insert OID = 4015 ( 4000 quad_point_ops PGNSP PGUID ));
DATA(insert OID = 4016 ( 4000 kd_point_ops PGNSP PGUID ));
DATA(insert OID = 4017 ( 4000 text_ops PGNSP PGUID ));
@@ -177,6 +178,7 @@ DATA(insert OID = 4072 ( 3580 abstime_minmax_ops PGNSP PGUID ));
DATA(insert OID = 4073 ( 3580 reltime_minmax_ops PGNSP PGUID ));
DATA(insert OID = 4074 ( 3580 macaddr_minmax_ops PGNSP PGUID ));
DATA(insert OID = 4075 ( 3580 inet_minmax_ops PGNSP PGUID ));
+DATA(insert OID = 4051 ( 3580 inet_range_ops PGNSP PGUID ));
DATA(insert OID = 4076 ( 3580 bpchar_minmax_ops PGNSP PGUID ));
DATA(insert OID = 4077 ( 3580 time_minmax_ops PGNSP PGUID ));
DATA(insert OID = 4078 ( 3580 interval_minmax_ops PGNSP PGUID ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 91cb911..6cb8a1e 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2210,6 +2210,8 @@ DATA(insert OID = 2630 ( inetpl PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 869
DATA(insert OID = 2631 ( int8pl_inet PGNSP PGUID 14 1 0 0 0 f f f f t f i 2 0 869 "20 869" _null_ _null_ _null_ _null_ "select $2 + $1" _null_ _null_ _null_ ));
DATA(insert OID = 2632 ( inetmi_int8 PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 869 "869 20" _null_ _null_ _null_ _null_ inetmi_int8 _null_ _null_ _null_ ));
DATA(insert OID = 2633 ( inetmi PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 20 "869 869" _null_ _null_ _null_ _null_ inetmi _null_ _null_ _null_ ));
+DATA(insert OID = 4052 ( inet_merge PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 869 "869 869" _null_ _null_ _null_ _null_ inet_merge _null_ _null_ _null_ ));
+DESCR("union of two networks");
/* GiST support for inet and cidr */
DATA(insert OID = 3553 ( inet_gist_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 5 0 16 "2281 869 23 26 2281" _null_ _null_ _null_ _null_ inet_gist_consistent _null_ _null_ _null_ ));
@@ -4116,6 +4118,16 @@ DESCR("BRIN minmax support");
DATA(insert OID = 3386 ( brin_minmax_union PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 16 "2281 2281 2281" _null_ _null_ _null_ _null_ minmaxUnion _null_ _null_ _null_ ));
DESCR("BRIN minmax support");
+/* BRIN range */
+DATA(insert OID = 3387 ( brin_range_opcinfo PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ rangeOpcInfo _null_ _null_ _null_ ));
+DESCR("BRIN range support");
+DATA(insert OID = 3388 ( brin_range_add_value PGNSP PGUID 12 1 0 0 0 f f f f t f i 4 0 16 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ rangeAddValue _null_ _null_ _null_ ));
+DESCR("BRIN range support");
+DATA(insert OID = 3389 ( brin_range_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 16 "2281 2281 2281" _null_ _null_ _null_ _null_ rangeConsistent _null_ _null_ _null_ ));
+DESCR("BRIN range support");
+DATA(insert OID = 3390 ( brin_range_union PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 16 "2281 2281 2281" _null_ _null_ _null_ _null_ rangeUnion _null_ _null_ _null_ ));
+DESCR("BRIN range support");
+
/* userlock replacements */
DATA(insert OID = 2880 ( pg_advisory_lock PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 2278 "20" _null_ _null_ _null_ _null_ pg_advisory_lock_int8 _null_ _null_ _null_ ));
DESCR("obtain exclusive advisory lock");
@@ -4843,6 +4855,8 @@ DATA(insert OID = 3866 ( range_overright PGNSP PGUID 12 1 0 0 0 f f f f t f i 2
DESCR("implementation of &> operator");
DATA(insert OID = 3867 ( range_union PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ range_union _null_ _null_ _null_ ));
DESCR("implementation of + operator");
+DATA(insert OID = 4057 ( range_merge PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ range_merge _null_ _null_ _null_ ));
+DESCR("merge two ranges");
DATA(insert OID = 3868 ( range_intersect PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ range_intersect _null_ _null_ _null_ ));
DESCR("implementation of * operator");
DATA(insert OID = 3869 ( range_minus PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 3831 "3831 3831" _null_ _null_ _null_ _null_ range_minus _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index d88e7a3..63fc362 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -944,6 +944,7 @@ extern Datum inetpl(PG_FUNCTION_ARGS);
extern Datum inetmi_int8(PG_FUNCTION_ARGS);
extern Datum inetmi(PG_FUNCTION_ARGS);
extern void clean_ipv6_addr(int addr_family, char *addr);
+extern Datum inet_merge(PG_FUNCTION_ARGS);
/* mac.c */
extern Datum macaddr_in(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/rangetypes.h b/src/include/utils/rangetypes.h
index b1d17b9..0146166 100644
--- a/src/include/utils/rangetypes.h
+++ b/src/include/utils/rangetypes.h
@@ -75,19 +75,6 @@ typedef struct
#define PG_GETARG_RANGE_COPY(n) DatumGetRangeTypeCopy(PG_GETARG_DATUM(n))
#define PG_RETURN_RANGE(x) return RangeTypeGetDatum(x)
-/* Operator strategy numbers used in the GiST and SP-GiST range opclasses */
-/* Numbers are chosen to match up operator names with existing usages */
-#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
-
/*
* prototypes for functions defined in rangetypes.c
*/
@@ -156,6 +143,7 @@ extern bool range_overright_internal(TypeCacheEntry *typcache, RangeType *r1,
/* range, range -> range */
extern Datum range_minus(PG_FUNCTION_ARGS);
extern Datum range_union(PG_FUNCTION_ARGS);
+extern Datum range_merge(PG_FUNCTION_ARGS);
extern Datum range_intersect(PG_FUNCTION_ARGS);
/* BTree support */
diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out
index d58bf01..e897b2e 100644
--- a/src/test/regress/expected/inet.out
+++ b/src/test/regress/expected/inet.out
@@ -392,6 +392,91 @@ SELECT * FROM inet_tbl WHERE i <> '192.168.1.0/24'::cidr ORDER BY i;
SET enable_seqscan TO on;
DROP INDEX inet_idx2;
+-- check that brin opclasses work correctly
+CREATE TABLE inet_brin_tbl AS
+SELECT (i::text || '.' || j::text || '/16')::cidr AS addr
+FROM generate_series(0, 255) AS i, generate_series(0, 255) AS j;
+CREATE INDEX inet_brin_idx1 ON inet_brin_tbl using brin (addr inet_minmax_ops);
+SET enable_seqscan TO off;
+SELECT count(*) FROM inet_brin_tbl WHERE addr < '10/8'::cidr;
+ count
+-------
+ 2560
+(1 row)
+
+SELECT count(*) FROM inet_brin_tbl WHERE addr <= '10.0/16'::cidr;
+ count
+-------
+ 2561
+(1 row)
+
+SELECT count(*) FROM inet_brin_tbl WHERE addr = '10.0/16'::cidr;
+ count
+-------
+ 1
+(1 row)
+
+SELECT count(*) FROM inet_brin_tbl WHERE addr >= '200.0/16'::cidr;
+ count
+-------
+ 14336
+(1 row)
+
+SELECT count(*) FROM inet_brin_tbl WHERE addr > '200.0.0.0'::inet;
+ count
+-------
+ 14335
+(1 row)
+
+SELECT count(*) FROM inet_brin_tbl WHERE addr <> '200.0/16'::cidr;
+ count
+-------
+ 65535
+(1 row)
+
+SET enable_seqscan TO on;
+DROP INDEX inet_brin_idx1;
+SET enable_seqscan TO off;
+CREATE INDEX inet_brin_idx2 ON inet_brin_tbl using brin (addr inet_range_ops);
+SELECT count(*) FROM inet_brin_tbl WHERE addr << '10/8'::cidr;
+ count
+-------
+ 256
+(1 row)
+
+SELECT count(*) FROM inet_brin_tbl WHERE addr <<= '10.0/16'::cidr;
+ count
+-------
+ 1
+(1 row)
+
+SELECT count(*) FROM inet_brin_tbl WHERE addr && '10.0/16'::cidr;
+ count
+-------
+ 1
+(1 row)
+
+SELECT count(*) FROM inet_brin_tbl WHERE addr >>= '200.0/16'::cidr;
+ count
+-------
+ 1
+(1 row)
+
+SELECT count(*) FROM inet_brin_tbl WHERE addr >> '200.0.0.0'::inet;
+ count
+-------
+ 1
+(1 row)
+
+SELECT count(*) FROM inet_brin_tbl WHERE addr = '200.0/16'::cidr;
+ count
+-------
+ 1
+(1 row)
+
+SET enable_seqscan TO on;
+DROP INDEX inet_brin_idx2;
+DROP TABLE inet_brin_tbl;
-- simple tests of inet boolean and arithmetic operators
SELECT i, ~i AS "~i" FROM inet_tbl;
i | ~i
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 932e89a..085c3db 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -1659,10 +1659,24 @@ ORDER BY 1, 2, 3;
2742 | 10 | ?|
2742 | 11 | ?&
3580 | 1 | <
+ 3580 | 1 | <<
+ 3580 | 2 | &<
3580 | 2 | <=
+ 3580 | 3 | &&
3580 | 3 | =
+ 3580 | 4 | &>
3580 | 4 | >=
3580 | 5 | >
+ 3580 | 5 | >>
+ 3580 | 6 | -|-
+ 3580 | 7 | >>=
+ 3580 | 7 | @>
+ 3580 | 8 | <<=
+ 3580 | 8 | <@
+ 3580 | 9 | >>
+ 3580 | 10 | <<
+ 3580 | 16 | @>
+ 3580 | 18 | =
4000 | 1 | <<
4000 | 1 | ~<~
4000 | 2 | &<
@@ -1685,7 +1699,7 @@ ORDER BY 1, 2, 3;
4000 | 15 | >
4000 | 16 | @>
4000 | 18 | =
-(85 rows)
+(99 rows)
-- Check that all opclass search operators have selectivity estimators.
-- This is not absolutely required, but it seems a reasonable thing
@@ -1847,13 +1861,14 @@ WHERE NOT (
-- GIN has six support functions. 1-3 are mandatory, 5 is optional, and
-- at least one of 4 and 6 must be given.
-- SP-GiST has five support functions, all mandatory
- -- BRIN has eight support functions, all mandatory
+ -- BRIN has four mandatory support functions, in-core implementations
+ -- have 2 more mandatory and up to eight more optional
amname = 'btree' AND procnums @> '{1}' OR
amname = 'hash' AND procnums = '{1}' OR
amname = 'gist' AND procnums @> '{1, 2, 3, 4, 5, 6, 7}' OR
amname = 'gin' AND (procnums @> '{1, 2, 3}' AND (procnums && '{4, 6}')) OR
amname = 'spgist' AND procnums = '{1, 2, 3, 4, 5}' OR
- amname = 'brin' AND procnums = '{1, 2, 3, 4, 5, 6, 7, 8}'
+ amname = 'brin' AND procnums @> '{1, 2, 3, 4, 5, 6}'
);
amname | opfname | amproclefttype | amprocrighttype | procnums
--------+---------+----------------+-----------------+----------
@@ -1875,7 +1890,7 @@ WHERE NOT (
amname = 'gist' AND procnums @> '{1, 2, 3, 4, 5, 6, 7}' OR
amname = 'gin' AND (procnums @> '{1, 2, 3}' AND (procnums && '{4, 6}')) OR
amname = 'spgist' AND procnums = '{1, 2, 3, 4, 5}' OR
- amname = 'brin' AND procnums = '{1, 2, 3, 4, 5, 6, 7, 8}'
+ amname = 'brin' AND procnums @> '{1, 2, 3, 4, 5, 6}'
);
amname | opcname | procnums
--------+---------+----------
diff --git a/src/test/regress/expected/rangetypes.out b/src/test/regress/expected/rangetypes.out
index 39db992..fba7685 100644
--- a/src/test/regress/expected/rangetypes.out
+++ b/src/test/regress/expected/rangetypes.out
@@ -1043,6 +1043,225 @@ select count(*) from test_range_spgist where ir -|- int4range(100,500);
RESET enable_seqscan;
RESET enable_indexscan;
RESET enable_bitmapscan;
+-- test brin that's been built incrementally
+create table test_range_brin(ir int4range);
+create index test_range_brin_idx on test_range_brin using brin (ir);
+insert into test_range_brin select int4range(g, g+10) from generate_series(1,2000) g;
+insert into test_range_brin select 'empty'::int4range from generate_series(1,500) g;
+insert into test_range_brin select int4range(g, g+10000) from generate_series(1,1000) g;
+insert into test_range_brin select 'empty'::int4range from generate_series(1,500) g;
+insert into test_range_brin select int4range(NULL,g*10,'(]') from generate_series(1,100) g;
+insert into test_range_brin select int4range(g*10,NULL,'(]') from generate_series(1,100) g;
+insert into test_range_brin select int4range(g, g+10) from generate_series(1,2000) g;
+-- first, verify non-indexed results
+SET enable_seqscan = t;
+SET enable_bitmapscan = f;
+select count(*) from test_range_brin where ir @> 'empty'::int4range;
+ count
+-------
+ 6200
+(1 row)
+
+select count(*) from test_range_brin where ir = int4range(10,20);
+ count
+-------
+ 2
+(1 row)
+
+select count(*) from test_range_brin where ir @> 10;
+ count
+-------
+ 130
+(1 row)
+
+select count(*) from test_range_brin where ir @> int4range(10,20);
+ count
+-------
+ 111
+(1 row)
+
+select count(*) from test_range_brin where ir && int4range(10,20);
+ count
+-------
+ 158
+(1 row)
+
+select count(*) from test_range_brin where ir <@ int4range(10,50);
+ count
+-------
+ 1062
+(1 row)
+
+select count(*) from test_range_brin where ir << int4range(100,500);
+ count
+-------
+ 189
+(1 row)
+
+select count(*) from test_range_brin where ir >> int4range(100,500);
+ count
+-------
+ 3554
+(1 row)
+
+select count(*) from test_range_brin where ir &< int4range(100,500);
+ count
+-------
+ 1029
+(1 row)
+
+select count(*) from test_range_brin where ir &> int4range(100,500);
+ count
+-------
+ 4794
+(1 row)
+
+select count(*) from test_range_brin where ir -|- int4range(100,500);
+ count
+-------
+ 5
+(1 row)
+
+-- now check same queries using index
+SET enable_seqscan = f;
+SET enable_bitmapscan = t;
+select count(*) from test_range_brin where ir @> 'empty'::int4range;
+ count
+-------
+ 6200
+(1 row)
+
+select count(*) from test_range_brin where ir = int4range(10,20);
+ count
+-------
+ 2
+(1 row)
+
+select count(*) from test_range_brin where ir @> 10;
+ count
+-------
+ 130
+(1 row)
+
+select count(*) from test_range_brin where ir @> int4range(10,20);
+ count
+-------
+ 111
+(1 row)
+
+select count(*) from test_range_brin where ir && int4range(10,20);
+ count
+-------
+ 158
+(1 row)
+
+select count(*) from test_range_brin where ir <@ int4range(10,50);
+ count
+-------
+ 1062
+(1 row)
+
+select count(*) from test_range_brin where ir << int4range(100,500);
+ count
+-------
+ 189
+(1 row)
+
+select count(*) from test_range_brin where ir >> int4range(100,500);
+ count
+-------
+ 3554
+(1 row)
+
+select count(*) from test_range_brin where ir &< int4range(100,500);
+ count
+-------
+ 1029
+(1 row)
+
+select count(*) from test_range_brin where ir &> int4range(100,500);
+ count
+-------
+ 4794
+(1 row)
+
+select count(*) from test_range_brin where ir -|- int4range(100,500);
+ count
+-------
+ 5
+(1 row)
+
+-- now check same queries using a bulk-loaded index
+drop index test_range_brin_idx;
+create index test_range_brin_idx on test_range_brin using brin (ir);
+select count(*) from test_range_brin where ir @> 'empty'::int4range;
+ count
+-------
+ 6200
+(1 row)
+
+select count(*) from test_range_brin where ir = int4range(10,20);
+ count
+-------
+ 2
+(1 row)
+
+select count(*) from test_range_brin where ir @> 10;
+ count
+-------
+ 130
+(1 row)
+
+select count(*) from test_range_brin where ir @> int4range(10,20);
+ count
+-------
+ 111
+(1 row)
+
+select count(*) from test_range_brin where ir && int4range(10,20);
+ count
+-------
+ 158
+(1 row)
+
+select count(*) from test_range_brin where ir <@ int4range(10,50);
+ count
+-------
+ 1062
+(1 row)
+
+select count(*) from test_range_brin where ir << int4range(100,500);
+ count
+-------
+ 189
+(1 row)
+
+select count(*) from test_range_brin where ir >> int4range(100,500);
+ count
+-------
+ 3554
+(1 row)
+
+select count(*) from test_range_brin where ir &< int4range(100,500);
+ count
+-------
+ 1029
+(1 row)
+
+select count(*) from test_range_brin where ir &> int4range(100,500);
+ count
+-------
+ 4794
+(1 row)
+
+select count(*) from test_range_brin where ir -|- int4range(100,500);
+ count
+-------
+ 5
+(1 row)
+
+RESET enable_seqscan;
+RESET enable_bitmapscan;
-- test elem <@ range operator
create table test_range_elem(i int4);
create index test_range_elem_idx on test_range_elem (i);
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index 2c8ec11..325aa03 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -157,6 +157,7 @@ stud_emp|f
student|f
tenk1|t
tenk2|t
+test_range_brin|t
test_range_excl|t
test_range_gist|t
test_range_spgist|t
diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql
index c9792b7..24ddde5 100644
--- a/src/test/regress/sql/inet.sql
+++ b/src/test/regress/sql/inet.sql
@@ -87,6 +87,32 @@ SELECT * FROM inet_tbl WHERE i <> '192.168.1.0/24'::cidr ORDER BY i;
SET enable_seqscan TO on;
DROP INDEX inet_idx2;
+-- check that brin opclasses work correctly
+CREATE TABLE inet_brin_tbl AS
+SELECT (i::text || '.' || j::text || '/16')::cidr AS addr
+FROM generate_series(0, 255) AS i, generate_series(0, 255) AS j;
+CREATE INDEX inet_brin_idx1 ON inet_brin_tbl using brin (addr inet_minmax_ops);
+SET enable_seqscan TO off;
+SELECT count(*) FROM inet_brin_tbl WHERE addr < '10/8'::cidr;
+SELECT count(*) FROM inet_brin_tbl WHERE addr <= '10.0/16'::cidr;
+SELECT count(*) FROM inet_brin_tbl WHERE addr = '10.0/16'::cidr;
+SELECT count(*) FROM inet_brin_tbl WHERE addr >= '200.0/16'::cidr;
+SELECT count(*) FROM inet_brin_tbl WHERE addr > '200.0.0.0'::inet;
+SELECT count(*) FROM inet_brin_tbl WHERE addr <> '200.0/16'::cidr;
+SET enable_seqscan TO on;
+DROP INDEX inet_brin_idx1;
+SET enable_seqscan TO off;
+CREATE INDEX inet_brin_idx2 ON inet_brin_tbl using brin (addr inet_range_ops);
+SELECT count(*) FROM inet_brin_tbl WHERE addr << '10/8'::cidr;
+SELECT count(*) FROM inet_brin_tbl WHERE addr <<= '10.0/16'::cidr;
+SELECT count(*) FROM inet_brin_tbl WHERE addr && '10.0/16'::cidr;
+SELECT count(*) FROM inet_brin_tbl WHERE addr >>= '200.0/16'::cidr;
+SELECT count(*) FROM inet_brin_tbl WHERE addr >> '200.0.0.0'::inet;
+SELECT count(*) FROM inet_brin_tbl WHERE addr = '200.0/16'::cidr;
+SET enable_seqscan TO on;
+DROP INDEX inet_brin_idx2;
+DROP TABLE inet_brin_tbl;
+
-- simple tests of inet boolean and arithmetic operators
SELECT i, ~i AS "~i" FROM inet_tbl;
SELECT i, c, i & c AS "and" FROM inet_tbl;
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index bd83d00..c7d08a1 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -1195,13 +1195,14 @@ WHERE NOT (
-- GIN has six support functions. 1-3 are mandatory, 5 is optional, and
-- at least one of 4 and 6 must be given.
-- SP-GiST has five support functions, all mandatory
- -- BRIN has eight support functions, all mandatory
+ -- BRIN has four mandatory support functions, in-core implementations
+ -- have 2 more mandatory and up to eight more optional
amname = 'btree' AND procnums @> '{1}' OR
amname = 'hash' AND procnums = '{1}' OR
amname = 'gist' AND procnums @> '{1, 2, 3, 4, 5, 6, 7}' OR
amname = 'gin' AND (procnums @> '{1, 2, 3}' AND (procnums && '{4, 6}')) OR
amname = 'spgist' AND procnums = '{1, 2, 3, 4, 5}' OR
- amname = 'brin' AND procnums = '{1, 2, 3, 4, 5, 6, 7, 8}'
+ amname = 'brin' AND procnums @> '{1, 2, 3, 4, 5, 6}'
);
-- Also, check if there are any pg_opclass entries that don't seem to have
@@ -1221,7 +1222,7 @@ WHERE NOT (
amname = 'gist' AND procnums @> '{1, 2, 3, 4, 5, 6, 7}' OR
amname = 'gin' AND (procnums @> '{1, 2, 3}' AND (procnums && '{4, 6}')) OR
amname = 'spgist' AND procnums = '{1, 2, 3, 4, 5}' OR
- amname = 'brin' AND procnums = '{1, 2, 3, 4, 5, 6, 7, 8}'
+ amname = 'brin' AND procnums @> '{1, 2, 3, 4, 5, 6}'
);
-- Unfortunately, we can't check the amproc link very well because the
diff --git a/src/test/regress/sql/rangetypes.sql b/src/test/regress/sql/rangetypes.sql
index fad843a..ed998eb 100644
--- a/src/test/regress/sql/rangetypes.sql
+++ b/src/test/regress/sql/rangetypes.sql
@@ -286,6 +286,69 @@ RESET enable_seqscan;
RESET enable_indexscan;
RESET enable_bitmapscan;
+-- test brin that's been built incrementally
+create table test_range_brin(ir int4range);
+create index test_range_brin_idx on test_range_brin using brin (ir);
+
+insert into test_range_brin select int4range(g, g+10) from generate_series(1,2000) g;
+insert into test_range_brin select 'empty'::int4range from generate_series(1,500) g;
+insert into test_range_brin select int4range(g, g+10000) from generate_series(1,1000) g;
+insert into test_range_brin select 'empty'::int4range from generate_series(1,500) g;
+insert into test_range_brin select int4range(NULL,g*10,'(]') from generate_series(1,100) g;
+insert into test_range_brin select int4range(g*10,NULL,'(]') from generate_series(1,100) g;
+insert into test_range_brin select int4range(g, g+10) from generate_series(1,2000) g;
+
+-- first, verify non-indexed results
+SET enable_seqscan = t;
+SET enable_bitmapscan = f;
+
+select count(*) from test_range_brin where ir @> 'empty'::int4range;
+select count(*) from test_range_brin where ir = int4range(10,20);
+select count(*) from test_range_brin where ir @> 10;
+select count(*) from test_range_brin where ir @> int4range(10,20);
+select count(*) from test_range_brin where ir && int4range(10,20);
+select count(*) from test_range_brin where ir <@ int4range(10,50);
+select count(*) from test_range_brin where ir << int4range(100,500);
+select count(*) from test_range_brin where ir >> int4range(100,500);
+select count(*) from test_range_brin where ir &< int4range(100,500);
+select count(*) from test_range_brin where ir &> int4range(100,500);
+select count(*) from test_range_brin where ir -|- int4range(100,500);
+
+-- now check same queries using index
+SET enable_seqscan = f;
+SET enable_bitmapscan = t;
+
+select count(*) from test_range_brin where ir @> 'empty'::int4range;
+select count(*) from test_range_brin where ir = int4range(10,20);
+select count(*) from test_range_brin where ir @> 10;
+select count(*) from test_range_brin where ir @> int4range(10,20);
+select count(*) from test_range_brin where ir && int4range(10,20);
+select count(*) from test_range_brin where ir <@ int4range(10,50);
+select count(*) from test_range_brin where ir << int4range(100,500);
+select count(*) from test_range_brin where ir >> int4range(100,500);
+select count(*) from test_range_brin where ir &< int4range(100,500);
+select count(*) from test_range_brin where ir &> int4range(100,500);
+select count(*) from test_range_brin where ir -|- int4range(100,500);
+
+-- now check same queries using a bulk-loaded index
+drop index test_range_brin_idx;
+create index test_range_brin_idx on test_range_brin using brin (ir);
+
+select count(*) from test_range_brin where ir @> 'empty'::int4range;
+select count(*) from test_range_brin where ir = int4range(10,20);
+select count(*) from test_range_brin where ir @> 10;
+select count(*) from test_range_brin where ir @> int4range(10,20);
+select count(*) from test_range_brin where ir && int4range(10,20);
+select count(*) from test_range_brin where ir <@ int4range(10,50);
+select count(*) from test_range_brin where ir << int4range(100,500);
+select count(*) from test_range_brin where ir >> int4range(100,500);
+select count(*) from test_range_brin where ir &< int4range(100,500);
+select count(*) from test_range_brin where ir &> int4range(100,500);
+select count(*) from test_range_brin where ir -|- int4range(100,500);
+
+RESET enable_seqscan;
+RESET enable_bitmapscan;
+
-- test elem <@ range operator
create table test_range_elem(i int4);
create index test_range_elem_idx on test_range_elem (i);
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers