Commit 317dd55a authored by Heikki Linnakangas's avatar Heikki Linnakangas

Add SP-GiST support for range types.

The implementation is a quad-tree, largely copied from the quad-tree
implementation for points. The lower and upper bound of ranges are the 2d
coordinates, with some extra code to handle empty ranges.

I left out the support for adjacent operator, -|-, from the original patch.
Not because there was necessarily anything wrong with it, but it was more
complicated than the other operators, and I only have limited time for
reviewing. That will follow as a separate patch.

Alexander Korotkov, reviewed by Jeff Davis and me.
parent 89911b3a
...@@ -30,7 +30,7 @@ OBJS = acl.o arrayfuncs.o array_selfuncs.o array_typanalyze.o \ ...@@ -30,7 +30,7 @@ OBJS = acl.o arrayfuncs.o array_selfuncs.o array_typanalyze.o \
tsginidx.o tsgistidx.o tsquery.o tsquery_cleanup.o tsquery_gist.o \ tsginidx.o tsgistidx.o tsquery.o tsquery_cleanup.o tsquery_gist.o \
tsquery_op.o tsquery_rewrite.o tsquery_util.o tsrank.o \ tsquery_op.o tsquery_rewrite.o tsquery_util.o tsrank.o \
tsvector.o tsvector_op.o tsvector_parser.o \ tsvector.o tsvector_op.o tsvector_parser.o \
txid.o uuid.o windowfuncs.o xml.o txid.o uuid.o windowfuncs.o xml.o rangetypes_spgist.o
like.o: like.c like_match.c like.o: like.c like_match.c
......
...@@ -21,19 +21,6 @@ ...@@ -21,19 +21,6 @@
#include "utils/rangetypes.h" #include "utils/rangetypes.h"
/* Operator strategy numbers used in the GiST range opclass */
/* 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
/* /*
* Range class properties used to segregate different classes of ranges in * Range class properties used to segregate different classes of ranges in
* GiST. Each unique combination of properties is a class. CLS_EMPTY cannot * GiST. Each unique combination of properties is a class. CLS_EMPTY cannot
......
This diff is collapsed.
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 201208071 #define CATALOG_VERSION_NO 201208161
#endif #endif
...@@ -767,4 +767,17 @@ DATA(insert ( 4017 25 25 12 s 665 4000 0 )); ...@@ -767,4 +767,17 @@ DATA(insert ( 4017 25 25 12 s 665 4000 0 ));
DATA(insert ( 4017 25 25 14 s 667 4000 0 )); DATA(insert ( 4017 25 25 14 s 667 4000 0 ));
DATA(insert ( 4017 25 25 15 s 666 4000 0 )); DATA(insert ( 4017 25 25 15 s 666 4000 0 ));
/*
* SP-GiST range_ops
*/
DATA(insert ( 3474 3831 3831 1 s 3893 4000 0 ));
DATA(insert ( 3474 3831 3831 2 s 3895 4000 0 ));
DATA(insert ( 3474 3831 3831 3 s 3888 4000 0 ));
DATA(insert ( 3474 3831 3831 4 s 3896 4000 0 ));
DATA(insert ( 3474 3831 3831 5 s 3894 4000 0 ));
DATA(insert ( 3474 3831 3831 7 s 3890 4000 0 ));
DATA(insert ( 3474 3831 3831 8 s 3892 4000 0 ));
DATA(insert ( 3474 3831 2283 16 s 3889 4000 0 ));
DATA(insert ( 3474 3831 3831 18 s 3882 4000 0 ));
#endif /* PG_AMOP_H */ #endif /* PG_AMOP_H */
...@@ -373,5 +373,10 @@ DATA(insert ( 4017 25 25 2 4028 )); ...@@ -373,5 +373,10 @@ DATA(insert ( 4017 25 25 2 4028 ));
DATA(insert ( 4017 25 25 3 4029 )); DATA(insert ( 4017 25 25 3 4029 ));
DATA(insert ( 4017 25 25 4 4030 )); DATA(insert ( 4017 25 25 4 4030 ));
DATA(insert ( 4017 25 25 5 4031 )); DATA(insert ( 4017 25 25 5 4031 ));
DATA(insert ( 3474 3831 3831 1 3469 ));
DATA(insert ( 3474 3831 3831 2 3470 ));
DATA(insert ( 3474 3831 3831 3 3471 ));
DATA(insert ( 3474 3831 3831 4 3472 ));
DATA(insert ( 3474 3831 3831 5 3473 ));
#endif /* PG_AMPROC_H */ #endif /* PG_AMPROC_H */
...@@ -223,6 +223,7 @@ DATA(insert ( 783 tsquery_ops PGNSP PGUID 3702 3615 t 20 )); ...@@ -223,6 +223,7 @@ DATA(insert ( 783 tsquery_ops PGNSP PGUID 3702 3615 t 20 ));
DATA(insert ( 403 range_ops PGNSP PGUID 3901 3831 t 0 )); DATA(insert ( 403 range_ops PGNSP PGUID 3901 3831 t 0 ));
DATA(insert ( 405 range_ops PGNSP PGUID 3903 3831 t 0 )); DATA(insert ( 405 range_ops PGNSP PGUID 3903 3831 t 0 ));
DATA(insert ( 783 range_ops PGNSP PGUID 3919 3831 t 0 )); DATA(insert ( 783 range_ops PGNSP PGUID 3919 3831 t 0 ));
DATA(insert ( 4000 range_ops PGNSP PGUID 3474 3831 t 0 ));
DATA(insert ( 4000 quad_point_ops PGNSP PGUID 4015 600 t 0 )); DATA(insert ( 4000 quad_point_ops PGNSP PGUID 4015 600 t 0 ));
DATA(insert ( 4000 kd_point_ops PGNSP PGUID 4016 600 f 0 )); DATA(insert ( 4000 kd_point_ops PGNSP PGUID 4016 600 f 0 ));
DATA(insert ( 4000 text_ops PGNSP PGUID 4017 25 t 0 )); DATA(insert ( 4000 text_ops PGNSP PGUID 4017 25 t 0 ));
......
...@@ -142,6 +142,7 @@ DATA(insert OID = 3702 ( 783 tsquery_ops PGNSP PGUID )); ...@@ -142,6 +142,7 @@ DATA(insert OID = 3702 ( 783 tsquery_ops PGNSP PGUID ));
DATA(insert OID = 3901 ( 403 range_ops PGNSP PGUID )); DATA(insert OID = 3901 ( 403 range_ops PGNSP PGUID ));
DATA(insert OID = 3903 ( 405 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 = 3919 ( 783 range_ops PGNSP PGUID ));
DATA(insert OID = 3474 ( 4000 range_ops PGNSP PGUID ));
DATA(insert OID = 4015 ( 4000 quad_point_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 = 4016 ( 4000 kd_point_ops PGNSP PGUID ));
DATA(insert OID = 4017 ( 4000 text_ops PGNSP PGUID )); DATA(insert OID = 4017 ( 4000 text_ops PGNSP PGUID ));
......
...@@ -4653,6 +4653,17 @@ DESCR("SP-GiST support for suffix tree over text"); ...@@ -4653,6 +4653,17 @@ DESCR("SP-GiST support for suffix tree over text");
DATA(insert OID = 4031 ( spg_text_leaf_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ spg_text_leaf_consistent _null_ _null_ _null_ )); DATA(insert OID = 4031 ( spg_text_leaf_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ spg_text_leaf_consistent _null_ _null_ _null_ ));
DESCR("SP-GiST support for suffix tree over text"); DESCR("SP-GiST support for suffix tree over text");
DATA(insert OID = 3469 ( spg_range_quad_config PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ spg_range_quad_config _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over range");
DATA(insert OID = 3470 ( spg_range_quad_choose PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ spg_range_quad_choose _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over range");
DATA(insert OID = 3471 ( spg_range_quad_picksplit PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ spg_range_quad_picksplit _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over range");
DATA(insert OID = 3472 ( spg_range_quad_inner_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ spg_range_quad_inner_consistent _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over range");
DATA(insert OID = 3473 ( spg_range_quad_leaf_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ spg_range_quad_leaf_consistent _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over range");
/* /*
* Symbolic values for provolatile column: these indicate whether the result * Symbolic values for provolatile column: these indicate whether the result
......
...@@ -75,6 +75,19 @@ typedef struct ...@@ -75,6 +75,19 @@ typedef struct
#define PG_GETARG_RANGE_COPY(n) DatumGetRangeTypeCopy(PG_GETARG_DATUM(n)) #define PG_GETARG_RANGE_COPY(n) DatumGetRangeTypeCopy(PG_GETARG_DATUM(n))
#define PG_RETURN_RANGE(x) return RangeTypeGetDatum(x) #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 * prototypes for functions defined in rangetypes.c
*/ */
......
...@@ -1068,12 +1068,16 @@ ORDER BY 1, 2, 3; ...@@ -1068,12 +1068,16 @@ ORDER BY 1, 2, 3;
2742 | 4 | = 2742 | 4 | =
4000 | 1 | << 4000 | 1 | <<
4000 | 1 | ~<~ 4000 | 1 | ~<~
4000 | 2 | &<
4000 | 2 | ~<=~ 4000 | 2 | ~<=~
4000 | 3 | &&
4000 | 3 | = 4000 | 3 | =
4000 | 4 | &>
4000 | 4 | ~>=~ 4000 | 4 | ~>=~
4000 | 5 | >> 4000 | 5 | >>
4000 | 5 | ~>~ 4000 | 5 | ~>~
4000 | 6 | ~= 4000 | 6 | ~=
4000 | 7 | @>
4000 | 8 | <@ 4000 | 8 | <@
4000 | 10 | <^ 4000 | 10 | <^
4000 | 11 | < 4000 | 11 | <
...@@ -1081,7 +1085,9 @@ ORDER BY 1, 2, 3; ...@@ -1081,7 +1085,9 @@ ORDER BY 1, 2, 3;
4000 | 12 | <= 4000 | 12 | <=
4000 | 14 | >= 4000 | 14 | >=
4000 | 15 | > 4000 | 15 | >
(55 rows) 4000 | 16 | @>
4000 | 18 | =
(61 rows)
-- Check that all opclass search operators have selectivity estimators. -- Check that all opclass search operators have selectivity estimators.
-- This is not absolutely required, but it seems a reasonable thing -- This is not absolutely required, but it seems a reasonable thing
......
...@@ -821,6 +821,225 @@ select count(*) from test_range_gist where ir -|- int4range(100,500); ...@@ -821,6 +821,225 @@ select count(*) from test_range_gist where ir -|- int4range(100,500);
5 5
(1 row) (1 row)
-- test SP-GiST index that's been built incrementally
create table test_range_spgist(ir int4range);
create index test_range_spgist_idx on test_range_spgist using spgist (ir);
insert into test_range_spgist select int4range(g, g+10) from generate_series(1,2000) g;
insert into test_range_spgist select 'empty'::int4range from generate_series(1,500) g;
insert into test_range_spgist select int4range(g, g+10000) from generate_series(1,1000) g;
insert into test_range_spgist select 'empty'::int4range from generate_series(1,500) g;
insert into test_range_spgist select int4range(NULL,g*10,'(]') from generate_series(1,100) g;
insert into test_range_spgist select int4range(g*10,NULL,'(]') from generate_series(1,100) g;
insert into test_range_spgist select int4range(g, g+10) from generate_series(1,2000) g;
-- first, verify non-indexed results
SET enable_seqscan = t;
SET enable_indexscan = f;
SET enable_bitmapscan = f;
select count(*) from test_range_spgist where ir @> 'empty'::int4range;
count
-------
6200
(1 row)
select count(*) from test_range_spgist where ir = int4range(10,20);
count
-------
2
(1 row)
select count(*) from test_range_spgist where ir @> 10;
count
-------
130
(1 row)
select count(*) from test_range_spgist where ir @> int4range(10,20);
count
-------
111
(1 row)
select count(*) from test_range_spgist where ir && int4range(10,20);
count
-------
158
(1 row)
select count(*) from test_range_spgist where ir <@ int4range(10,50);
count
-------
1062
(1 row)
select count(*) from test_range_spgist where ir << int4range(100,500);
count
-------
189
(1 row)
select count(*) from test_range_spgist where ir >> int4range(100,500);
count
-------
3554
(1 row)
select count(*) from test_range_spgist where ir &< int4range(100,500);
count
-------
1029
(1 row)
select count(*) from test_range_spgist where ir &> int4range(100,500);
count
-------
4794
(1 row)
select count(*) from test_range_spgist where ir -|- int4range(100,500);
count
-------
5
(1 row)
-- now check same queries using index
SET enable_seqscan = f;
SET enable_indexscan = t;
SET enable_bitmapscan = f;
select count(*) from test_range_spgist where ir @> 'empty'::int4range;
count
-------
6200
(1 row)
select count(*) from test_range_spgist where ir = int4range(10,20);
count
-------
2
(1 row)
select count(*) from test_range_spgist where ir @> 10;
count
-------
130
(1 row)
select count(*) from test_range_spgist where ir @> int4range(10,20);
count
-------
111
(1 row)
select count(*) from test_range_spgist where ir && int4range(10,20);
count
-------
158
(1 row)
select count(*) from test_range_spgist where ir <@ int4range(10,50);
count
-------
1062
(1 row)
select count(*) from test_range_spgist where ir << int4range(100,500);
count
-------
189
(1 row)
select count(*) from test_range_spgist where ir >> int4range(100,500);
count
-------
3554
(1 row)
select count(*) from test_range_spgist where ir &< int4range(100,500);
count
-------
1029
(1 row)
select count(*) from test_range_spgist where ir &> int4range(100,500);
count
-------
4794
(1 row)
select count(*) from test_range_spgist where ir -|- int4range(100,500);
count
-------
5
(1 row)
-- now check same queries using a bulk-loaded index
drop index test_range_spgist_idx;
create index test_range_spgist_idx on test_range_spgist using spgist (ir);
select count(*) from test_range_spgist where ir @> 'empty'::int4range;
count
-------
6200
(1 row)
select count(*) from test_range_spgist where ir = int4range(10,20);
count
-------
2
(1 row)
select count(*) from test_range_spgist where ir @> 10;
count
-------
130
(1 row)
select count(*) from test_range_spgist where ir @> int4range(10,20);
count
-------
111
(1 row)
select count(*) from test_range_spgist where ir && int4range(10,20);
count
-------
158
(1 row)
select count(*) from test_range_spgist where ir <@ int4range(10,50);
count
-------
1062
(1 row)
select count(*) from test_range_spgist where ir << int4range(100,500);
count
-------
189
(1 row)
select count(*) from test_range_spgist where ir >> int4range(100,500);
count
-------
3554
(1 row)
select count(*) from test_range_spgist where ir &< int4range(100,500);
count
-------
1029
(1 row)
select count(*) from test_range_spgist where ir &> int4range(100,500);
count
-------
4794
(1 row)
select count(*) from test_range_spgist where ir -|- int4range(100,500);
count
-------
5
(1 row)
RESET enable_seqscan; RESET enable_seqscan;
RESET enable_indexscan; RESET enable_indexscan;
RESET enable_bitmapscan; RESET enable_bitmapscan;
......
...@@ -157,6 +157,7 @@ SELECT relname, relhasindex ...@@ -157,6 +157,7 @@ SELECT relname, relhasindex
tenk2 | t tenk2 | t
test_range_excl | t test_range_excl | t
test_range_gist | t test_range_gist | t
test_range_spgist | t
test_tsvector | f test_tsvector | f
text_tbl | f text_tbl | f
time_tbl | f time_tbl | f
...@@ -165,7 +166,7 @@ SELECT relname, relhasindex ...@@ -165,7 +166,7 @@ SELECT relname, relhasindex
timetz_tbl | f timetz_tbl | f
tinterval_tbl | f tinterval_tbl | f
varchar_tbl | f varchar_tbl | f
(154 rows) (155 rows)
-- --
-- another sanity check: every system catalog that has OIDs should have -- another sanity check: every system catalog that has OIDs should have
......
...@@ -675,6 +675,7 @@ SELECT user_relns() AS user_relns ...@@ -675,6 +675,7 @@ SELECT user_relns() AS user_relns
tenk2 tenk2
test_range_excl test_range_excl
test_range_gist test_range_gist
test_range_spgist
test_tsvector test_tsvector
text_tbl text_tbl
time_tbl time_tbl
...@@ -685,7 +686,7 @@ SELECT user_relns() AS user_relns ...@@ -685,7 +686,7 @@ SELECT user_relns() AS user_relns
toyemp toyemp
varchar_tbl varchar_tbl
xacttest xacttest
(107 rows) (108 rows)
SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))); SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer')));
name name
......
...@@ -220,6 +220,68 @@ select count(*) from test_range_gist where ir &< int4range(100,500); ...@@ -220,6 +220,68 @@ select count(*) from test_range_gist where ir &< int4range(100,500);
select count(*) from test_range_gist where ir &> int4range(100,500); select count(*) from test_range_gist where ir &> int4range(100,500);
select count(*) from test_range_gist where ir -|- int4range(100,500); select count(*) from test_range_gist where ir -|- int4range(100,500);
-- test SP-GiST index that's been built incrementally
create table test_range_spgist(ir int4range);
create index test_range_spgist_idx on test_range_spgist using spgist (ir);
insert into test_range_spgist select int4range(g, g+10) from generate_series(1,2000) g;
insert into test_range_spgist select 'empty'::int4range from generate_series(1,500) g;
insert into test_range_spgist select int4range(g, g+10000) from generate_series(1,1000) g;
insert into test_range_spgist select 'empty'::int4range from generate_series(1,500) g;
insert into test_range_spgist select int4range(NULL,g*10,'(]') from generate_series(1,100) g;
insert into test_range_spgist select int4range(g*10,NULL,'(]') from generate_series(1,100) g;
insert into test_range_spgist select int4range(g, g+10) from generate_series(1,2000) g;
-- first, verify non-indexed results
SET enable_seqscan = t;
SET enable_indexscan = f;
SET enable_bitmapscan = f;
select count(*) from test_range_spgist where ir @> 'empty'::int4range;
select count(*) from test_range_spgist where ir = int4range(10,20);
select count(*) from test_range_spgist where ir @> 10;
select count(*) from test_range_spgist where ir @> int4range(10,20);
select count(*) from test_range_spgist where ir && int4range(10,20);
select count(*) from test_range_spgist where ir <@ int4range(10,50);
select count(*) from test_range_spgist where ir << int4range(100,500);
select count(*) from test_range_spgist where ir >> int4range(100,500);
select count(*) from test_range_spgist where ir &< int4range(100,500);
select count(*) from test_range_spgist where ir &> int4range(100,500);
select count(*) from test_range_spgist where ir -|- int4range(100,500);
-- now check same queries using index
SET enable_seqscan = f;
SET enable_indexscan = t;
SET enable_bitmapscan = f;
select count(*) from test_range_spgist where ir @> 'empty'::int4range;
select count(*) from test_range_spgist where ir = int4range(10,20);
select count(*) from test_range_spgist where ir @> 10;
select count(*) from test_range_spgist where ir @> int4range(10,20);
select count(*) from test_range_spgist where ir && int4range(10,20);
select count(*) from test_range_spgist where ir <@ int4range(10,50);
select count(*) from test_range_spgist where ir << int4range(100,500);
select count(*) from test_range_spgist where ir >> int4range(100,500);
select count(*) from test_range_spgist where ir &< int4range(100,500);
select count(*) from test_range_spgist where ir &> int4range(100,500);
select count(*) from test_range_spgist where ir -|- int4range(100,500);
-- now check same queries using a bulk-loaded index
drop index test_range_spgist_idx;
create index test_range_spgist_idx on test_range_spgist using spgist (ir);
select count(*) from test_range_spgist where ir @> 'empty'::int4range;
select count(*) from test_range_spgist where ir = int4range(10,20);
select count(*) from test_range_spgist where ir @> 10;
select count(*) from test_range_spgist where ir @> int4range(10,20);
select count(*) from test_range_spgist where ir && int4range(10,20);
select count(*) from test_range_spgist where ir <@ int4range(10,50);
select count(*) from test_range_spgist where ir << int4range(100,500);
select count(*) from test_range_spgist where ir >> int4range(100,500);
select count(*) from test_range_spgist where ir &< int4range(100,500);
select count(*) from test_range_spgist where ir &> int4range(100,500);
select count(*) from test_range_spgist where ir -|- int4range(100,500);
RESET enable_seqscan; RESET enable_seqscan;
RESET enable_indexscan; RESET enable_indexscan;
RESET enable_bitmapscan; RESET enable_bitmapscan;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment