> 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 (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers