diff --git a/Makefile b/Makefile index 062aab6..2589494 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ MODULE_big = pg_sphere OBJS = src/sscan.o src/sparse.o src/sbuffer.o src/vector3d.o src/point.o \ src/euler.o src/circle.o src/line.o src/ellipse.o src/polygon.o \ src/path.o src/box.o src/output.o src/gq_cache.o src/gist.o \ - src/key.o src/gnomo.o src/epochprop.o + src/key.o src/gnomo.o src/epochprop.o src/brin.o ifneq ($(USE_HEALPIX),0) OBJS += src/healpix.o src/moc.o src/process_moc.o \ @@ -33,7 +33,7 @@ DATA_built = $(RELEASE_SQL) \ DOCS = README.pg_sphere COPYRIGHT.pg_sphere REGRESS = init tables points euler circle line ellipse poly path box index \ contains_ops contains_ops_compat bounding_box_gist gnomo epochprop \ - contains overlaps + contains overlaps spoint_brin sbox_brin ifneq ($(USE_HEALPIX),0) REGRESS += healpix moc mocautocast @@ -43,7 +43,7 @@ REGRESS_9_5 = index_9.5 # experimental for spoint3 TESTS = init_test tables points euler circle line ellipse poly path box \ index contains_ops contains_ops_compat bounding_box_gist gnomo \ - epochprop contains overlaps + epochprop contains overlaps spoint_brin sbox_brin ifneq ($(USE_HEALPIX),0) TESTS += healpix moc mocautocast @@ -66,7 +66,7 @@ CRUSH_TESTS = init_extended circle_extended PGS_SQL = pgs_types.sql pgs_point.sql pgs_euler.sql pgs_circle.sql \ pgs_line.sql pgs_ellipse.sql pgs_polygon.sql pgs_path.sql \ pgs_box.sql pgs_contains_ops.sql pgs_contains_ops_compat.sql \ - pgs_gist.sql gnomo.sql + pgs_gist.sql gnomo.sql pgs_brin.sql ifneq ($(USE_HEALPIX),0) PGS_SQL += healpix.sql @@ -262,7 +262,7 @@ endif pg_sphere--1.2.2--1.2.3.sql: cat upgrade_scripts/$@.in > $@ -pg_sphere--1.2.3--1.3.0.sql: +pg_sphere--1.2.3--1.3.0.sql: pgs_brin.sql.in cat upgrade_scripts/$@.in > $@ # end of local stuff diff --git a/README.pg_sphere b/README.pg_sphere index 8a85c39..95a2563 100644 --- a/README.pg_sphere +++ b/README.pg_sphere @@ -9,8 +9,9 @@ It provides: * Object rotation by Euler angles * Indexing of spherical data types -This is an R-Tree implementation using GiST for spherical objects like +This is an R-tree implementation using GiST for spherical objects like spherical points and spherical circles with useful functions and operators. +It also supports the Block Range INdexing (BRIN) for large datasets. NOTICE: This version will work only with PostgreSQL version 10 and above. diff --git a/doc/indices.sgm b/doc/indices.sgm index 8103072..11940c2 100644 --- a/doc/indices.sgm +++ b/doc/indices.sgm @@ -8,15 +8,29 @@ pgSphere uses GiST - to create spherical indices. An index speeds up the execution - time of operators BRIN) algorithms to create + spherical indices. + GiST indexes utilize an R-tree implementation for + spherical objects, while BRIN indexes are based on the "summarization" + of data blocks (pages) on physical storage in order to + organize data searches on ranges of summarized data that can be easily skipped + on the base of search filters (see + PostgreSQL documentation for further details on BRIN indexes). + As a consequence, BRIN indexes are very small indexes (up to 1000 times smaller + than GiST ones), generally with lower performance compared with a GiST one, + but up to 100 times faster than a full sequential scan of a table performed + without any index. So BRIN indexes are particularly suitable in a big data context. + An index speeds up the execution time of searches based on operators <@, @, &&, #, =, and !=. You can create - an index with the following spherical data types: + linkend="op.equal">!=. + + + You can create a GiST index with the following spherical data types: @@ -55,6 +69,10 @@ + + BRIN indexing supports just spherical points (spoint) + and spherical coordinates range (sbox) at the moment. + Simple index of spherical points @@ -65,6 +83,23 @@ + + BRIN index can be created through the following syntax: + + + + + + By default, BRIN indexes summarize blocks of 128 pages. The smaller the + number of pages specified, the higher the granularity in searches, + and the gap in performance between GiST indexes and BRIN indexes will be + decreased. Note that the size of the BRIN indexes increases as well. + Different summarizations can be specified with the following + command: + + + + diff --git a/expected/init_test_healpix.out.in b/expected/init_test_healpix.out.in index 4195603..b87a70d 100644 --- a/expected/init_test_healpix.out.in +++ b/expected/init_test_healpix.out.in @@ -1,2 +1,2 @@ -psql:pg_sphere.test.sql:9271: NOTICE: return type smoc is only a shell -psql:pg_sphere.test.sql:9277: NOTICE: argument type smoc is only a shell +psql:pg_sphere.test.sql:9684: NOTICE: return type smoc is only a shell +psql:pg_sphere.test.sql:9690: NOTICE: argument type smoc is only a shell diff --git a/expected/sbox_brin.out b/expected/sbox_brin.out new file mode 100644 index 0000000..43fd87c --- /dev/null +++ b/expected/sbox_brin.out @@ -0,0 +1,91 @@ +SELECT set_sphere_output_precision(8); + set_sphere_output_precision +----------------------------- + SET 8 +(1 row) + +CREATE TABLE test_boxes ( + b sbox +); +COPY test_boxes (b) FROM stdin; +CREATE OR REPLACE FUNCTION qnodes(q text) RETURNS text +LANGUAGE 'plpgsql' AS +$$ +DECLARE + exp TEXT; + mat TEXT[]; + ret TEXT[]; +BEGIN + FOR exp IN EXECUTE 'EXPLAIN ' || q + LOOP + --RAISE NOTICE 'EXP: %', exp; + mat := regexp_matches(exp, ' *(?:-> *)?(.*Scan on (test_boxes|test_boxes_brin_idx))'); + --RAISE NOTICE 'MAT: %', mat; + IF mat IS NOT NULL THEN + ret := array_append(ret, mat[1]); + END IF; + --RAISE NOTICE 'RET: %', ret; + END LOOP; + RETURN array_to_string(ret,','); +END; +$$; +CREATE INDEX test_boxes_brin_idx ON test_boxes USING brin (b); +SET enable_indexscan = OFF; +SET enable_bitmapscan = OFF; +SET enable_seqscan = ON; +SELECT 'scan_seq', qnodes('SELECT * FROM test_boxes WHERE b <@ sbox ''( (10d,10d), (20d,20d) )'''); + ?column? | qnodes +----------+------------------------ + scan_seq | Seq Scan on test_boxes +(1 row) + +SELECT * FROM test_boxes WHERE b <@ sbox '( (10d,10d), (20d,20d) )'; + b +--- +(0 rows) + +SELECT 'scan_seq', qnodes('SELECT * FROM test_boxes WHERE b && sbox ''( (10d,10d), (20d,20d) )'''); + ?column? | qnodes +----------+------------------------ + scan_seq | Seq Scan on test_boxes +(1 row) + +SELECT * FROM test_boxes WHERE b && sbox '( (10d,10d), (20d,20d) )'; + b +-------------------------------------------------------- + ((0.34906585 , 0.17453293), (0.35006585 , 0.17463293)) +(1 row) + +SET enable_indexscan = OFF; +SET enable_bitmapscan = ON; +SET enable_seqscan = OFF; +SELECT 'scan_idx', qnodes('SELECT * FROM test_boxes WHERE b <@ sbox ''( (10d,10d), (20d,20d) )'''); + ?column? | qnodes +----------+------------------------------------------------------------------------- + scan_idx | Bitmap Heap Scan on test_boxes,Bitmap Index Scan on test_boxes_brin_idx +(1 row) + +SELECT * FROM test_boxes WHERE b <@ sbox '( (10d,10d), (20d,20d) )'; + b +--- +(0 rows) + +SELECT 'scan_idx', qnodes('SELECT * FROM test_boxes WHERE b && sbox ''( (10d,10d), (20d,20d) )'''); + ?column? | qnodes +----------+------------------------------------------------------------------------- + scan_idx | Bitmap Heap Scan on test_boxes,Bitmap Index Scan on test_boxes_brin_idx +(1 row) + +SELECT * FROM test_boxes WHERE b && sbox '( (10d,10d), (20d,20d) )'; + b +-------------------------------------------------------- + ((0.34906585 , 0.17453293), (0.35006585 , 0.17463293)) +(1 row) + +---- cleanup +DROP INDEX test_boxes_brin_idx; +DROP TABLE test_boxes; +DROP FUNCTION qnodes(text); +SET enable_indexscan = ON; +SET enable_bitmapscan = ON; +SET enable_seqscan = ON; diff --git a/expected/spoint_brin.out b/expected/spoint_brin.out new file mode 100644 index 0000000..958c709 --- /dev/null +++ b/expected/spoint_brin.out @@ -0,0 +1,87 @@ +CREATE TABLE test_points ( + p spoint +); +COPY test_points (p) FROM stdin; +CREATE OR REPLACE FUNCTION qnodes(q text) RETURNS text +LANGUAGE 'plpgsql' AS +$$ +DECLARE + exp TEXT; + mat TEXT[]; + ret TEXT[]; +BEGIN + FOR exp IN EXECUTE 'EXPLAIN ' || q + LOOP + --RAISE NOTICE 'EXP: %', exp; + mat := regexp_matches(exp, ' *(?:-> *)?(.*Scan on (test_points|brin_spoint))'); + --RAISE NOTICE 'MAT: %', mat; + IF mat IS NOT NULL THEN + ret := array_append(ret, mat[1]); + END IF; + --RAISE NOTICE 'RET: %', ret; + END LOOP; + RETURN array_to_string(ret,','); +END; +$$; +CREATE INDEX brin_spoint ON test_points USING brin (p) WITH (pages_per_range = 16); +set enable_indexscan = off; +set enable_bitmapscan = off; +set enable_seqscan = on; +SELECT 'scan_seq', qnodes('SELECT * FROM test_points WHERE p <@ sbox ''( (10d,10d), (20d,20d) )'''); + ?column? | qnodes +----------+------------------------- + scan_seq | Seq Scan on test_points +(1 row) + +SELECT * FROM test_points WHERE p <@ sbox '( (10d,10d), (20d,20d) )'; + p +----------------------------------------- + (0.349065850398866 , 0.174532925199433) +(1 row) + +SELECT 'scan_seq', qnodes('SELECT * FROM test_points WHERE p && sbox ''( (10d,10d), (20d,20d) )'''); + ?column? | qnodes +----------+------------------------- + scan_seq | Seq Scan on test_points +(1 row) + +SELECT * FROM test_points WHERE p && sbox '( (10d,10d), (20d,20d) )'; + p +----------------------------------------- + (0.349065850398866 , 0.174532925199433) +(1 row) + +set enable_indexscan = off; +set enable_bitmapscan = on; +set enable_seqscan = off; +SELECT 'scan_idx', qnodes('SELECT * FROM test_points WHERE p <@ sbox ''( (10d,10d), (20d,20d) )'''); + ?column? | qnodes +----------+------------------------------------------------------------------ + scan_idx | Bitmap Heap Scan on test_points,Bitmap Index Scan on brin_spoint +(1 row) + +SELECT * FROM test_points WHERE p <@ sbox '( (10d,10d), (20d,20d) )'; + p +----------------------------------------- + (0.349065850398866 , 0.174532925199433) +(1 row) + +SELECT 'scan_idx', qnodes('SELECT * FROM test_points WHERE p && sbox ''( (10d,10d), (20d,20d) )'''); + ?column? | qnodes +----------+------------------------------------------------------------------ + scan_idx | Bitmap Heap Scan on test_points,Bitmap Index Scan on brin_spoint +(1 row) + +SELECT * FROM test_points WHERE p && sbox '( (10d,10d), (20d,20d) )'; + p +----------------------------------------- + (0.349065850398866 , 0.174532925199433) +(1 row) + +-- cleanup +DROP INDEX brin_spoint; +DROP TABLE test_points; +DROP FUNCTION qnodes(text); +set enable_indexscan = on; +set enable_bitmapscan = on; +set enable_seqscan = on; diff --git a/pgs_brin.sql.in b/pgs_brin.sql.in new file mode 100644 index 0000000..4b0fba5 --- /dev/null +++ b/pgs_brin.sql.in @@ -0,0 +1,413 @@ + +-------------------------------------------------------------------- +-- BRIN support -- +-------------------------------------------------------------------- + +-------------------------------- +-- the Operators -- +-------------------------------- + +CREATE FUNCTION spoint_overlaps_spherekey(spoint, spherekey) + RETURNS boolean + AS 'MODULE_PATHNAME', 'spoint_overlaps_spherekey' + LANGUAGE 'c' IMMUTABLE STRICT; + +CREATE FUNCTION spoint_contains_spherekey(spoint, spherekey) + RETURNS boolean + AS 'MODULE_PATHNAME', 'spoint_contains_spherekey' + LANGUAGE 'c' IMMUTABLE STRICT; + +CREATE FUNCTION spoint_iscontained_spherekey(spoint, spherekey) + RETURNS boolean + AS 'MODULE_PATHNAME', 'spoint_iscontained_spherekey' + LANGUAGE 'c' IMMUTABLE STRICT; + +CREATE FUNCTION sbox_overlaps_spherekey(sbox, spherekey) + RETURNS boolean + AS 'MODULE_PATHNAME', 'sbox_overlaps_spherekey' + LANGUAGE 'c' IMMUTABLE STRICT; + +CREATE FUNCTION sbox_contains_spherekey(sbox, spherekey) + RETURNS boolean + AS 'MODULE_PATHNAME', 'sbox_contains_spherekey' + LANGUAGE 'c' IMMUTABLE STRICT; + +CREATE FUNCTION sbox_iscontained_spherekey(sbox, spherekey) + RETURNS boolean + AS 'MODULE_PATHNAME', 'sbox_iscontained_spherekey' + LANGUAGE 'c' IMMUTABLE STRICT; + +CREATE FUNCTION spherekey_overlaps_spherekey(spherekey, spherekey) + RETURNS boolean + AS 'MODULE_PATHNAME', 'spherekey_overlaps_spherekey' + LANGUAGE 'c' IMMUTABLE STRICT; + +CREATE FUNCTION spherekey_contains_spherekey(spherekey, spherekey) + RETURNS boolean + AS 'MODULE_PATHNAME', 'spherekey_contains_spherekey' + LANGUAGE 'c' IMMUTABLE STRICT; + +CREATE FUNCTION spherekey_iscontained_spherekey(spherekey, spherekey) + RETURNS boolean + AS 'MODULE_PATHNAME', 'spoint_iscontained_spherekey' + LANGUAGE 'c' IMMUTABLE STRICT; + +CREATE OPERATOR && ( + LEFTARG = spoint, + RIGHTARG = spherekey, + PROCEDURE = spoint_overlaps_spherekey, + COMMUTATOR = '&&', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR && (spoint, spherekey) IS + 'true, if the spherical point overlaps a spherekey'; + +CREATE OPERATOR @> ( + LEFTARG = spoint, + RIGHTARG = spherekey, + PROCEDURE = spoint_contains_spherekey, + COMMUTATOR = '<@', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR @> (spoint, spherekey) IS + 'true, if the spherical point contains a spherekey - just needed to define the OpFamily'; + +CREATE OPERATOR <@ ( + LEFTARG = spoint, + RIGHTARG = spherekey, + PROCEDURE = spoint_iscontained_spherekey, + COMMUTATOR = '@>', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR <@ (spoint, spherekey) IS + 'true, if the spherical point is contained in a spherekey'; + +CREATE OPERATOR && ( + LEFTARG = sbox, + RIGHTARG = spherekey, + PROCEDURE = sbox_overlaps_spherekey, + COMMUTATOR = '&&', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR && (sbox, spherekey) IS + 'true, if the spherical box overlaps a spherekey'; + +CREATE OPERATOR @> ( + LEFTARG = sbox, + RIGHTARG = spherekey, + PROCEDURE = sbox_contains_spherekey, + COMMUTATOR = '<@', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR @> (sbox, spherekey) IS + 'true, if the spherical box contains a spherekey'; + +CREATE OPERATOR <@ ( + LEFTARG = sbox, + RIGHTARG = spherekey, + PROCEDURE = sbox_iscontained_spherekey, + COMMUTATOR = '@>', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR <@ (sbox, spherekey) IS + 'true, if the spherical box is contained in a spherekey'; + +CREATE OPERATOR && ( + LEFTARG = spherekey, + RIGHTARG = spherekey, + PROCEDURE = spherekey_overlaps_spherekey, + COMMUTATOR = '&&', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR && (spherekey, spherekey) IS + 'true, if the spherekey overlaps another spherekey'; + +CREATE OPERATOR @> ( + LEFTARG = spherekey, + RIGHTARG = spherekey, + PROCEDURE = spherekey_contains_spherekey, + COMMUTATOR = '<@', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR @> (spoint, spherekey) IS + 'true, if the spherekey contains another spherekey'; + +CREATE OPERATOR <@ ( + LEFTARG = spherekey, + RIGHTARG = spherekey, + PROCEDURE = spherekey_iscontained_spherekey, + COMMUTATOR = '@>', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR <@ (spherekey, spherekey) IS + 'true, if the spherical point is contained in another spherekey'; + +--------------------------------------------- +-- create operators with crossed datatypes -- +--------------------------------------------- + +CREATE FUNCTION spherekey_overlaps_spoint(spherekey, spoint) + RETURNS boolean + AS $$ + SELECT $2 && $1; + $$ LANGUAGE SQL IMMUTABLE STRICT; + +CREATE FUNCTION spherekey_contains_spoint(spherekey, spoint) + RETURNS boolean + AS $$ + SELECT $2 <@ $1; + $$ LANGUAGE SQL IMMUTABLE STRICT; + +CREATE FUNCTION spherekey_iscontained_spoint(spherekey, spoint) + RETURNS boolean + AS $$ + SELECT $2 @> $1; + $$ LANGUAGE SQL IMMUTABLE STRICT; + +CREATE FUNCTION spherekey_overlaps_sbox(spherekey, sbox) + RETURNS boolean + AS $$ + SELECT $2 && $1; + $$ LANGUAGE SQL IMMUTABLE STRICT; + +CREATE FUNCTION spherekey_contains_sbox(spherekey, sbox) + RETURNS boolean + AS $$ + SELECT $2 <@ $1; + $$ LANGUAGE SQL IMMUTABLE STRICT; + +CREATE FUNCTION spherekey_iscontained_sbox(spherekey, sbox) + RETURNS boolean + AS $$ + SELECT $2 @> $1; + $$ LANGUAGE SQL IMMUTABLE STRICT; + +CREATE OPERATOR && ( + LEFTARG = spherekey, + RIGHTARG = spoint, + PROCEDURE = spherekey_overlaps_spoint, + COMMUTATOR = '&&', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR && (spherekey, spoint) IS + 'true, if the spherekey overlaps a spoint'; + +CREATE OPERATOR @> ( + LEFTARG = spherekey, + RIGHTARG = spoint, + PROCEDURE = spherekey_contains_spoint, + COMMUTATOR = '<@', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR @> (spherekey, spoint) IS + 'true, if the spherekey contains a spherical point'; + +CREATE OPERATOR <@ ( + LEFTARG = spherekey, + RIGHTARG = spoint, + PROCEDURE = spherekey_iscontained_spoint, + COMMUTATOR = '@>', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR <@ (spherekey, spoint) IS + 'true, if the spherekey is contained in a spherical point - just needed to define the OpFamily'; + +CREATE OPERATOR && ( + LEFTARG = spherekey, + RIGHTARG = sbox, + PROCEDURE = spherekey_overlaps_sbox, + COMMUTATOR = '&&', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR && (spherekey, sbox) IS + 'true, if the spherekey overlaps a spherical point'; + +CREATE OPERATOR @> ( + LEFTARG = spherekey, + RIGHTARG = sbox, + PROCEDURE = spherekey_contains_sbox, + COMMUTATOR = '<@', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR @> (spherekey, sbox) IS + 'true, if the spherekey contains a spherical point'; + +CREATE OPERATOR <@ ( + LEFTARG = spherekey, + RIGHTARG = sbox, + PROCEDURE = spherekey_iscontained_sbox, + COMMUTATOR = '@>', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR <@ (spherekey, sbox) IS + 'true, if the spherekey is contained in a spherical point'; + +------------------------------------------------- +-- create operators that will actually be used -- +------------------------------------------------- + +CREATE FUNCTION spoint_overlaps_sbox(spoint, sbox) + RETURNS boolean + AS 'MODULE_PATHNAME', 'spoint_overlaps_sbox' + LANGUAGE 'c' IMMUTABLE STRICT; + +CREATE OPERATOR && ( + LEFTARG = spoint, + RIGHTARG = sbox, + PROCEDURE = spoint_overlaps_sbox, + COMMUTATOR = '&&', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR && (spoint, sbox) IS + 'true, if the spherical point overlaps a spherical box'; + +------------------------------------------------------------ +-- Complementar operators, needed for OpFamily definition -- +------------------------------------------------------------ + +CREATE FUNCTION sbox_overlaps_spoint(sbox, spoint) + RETURNS boolean + AS $$ + SELECT $2 && $1; + $$ LANGUAGE SQL IMMUTABLE STRICT; + +CREATE OPERATOR && ( + LEFTARG = sbox, + RIGHTARG = spoint, + PROCEDURE = sbox_overlaps_spoint, + COMMUTATOR = '&&', + RESTRICT = contsel, + JOIN = contjoinsel +); + +COMMENT ON OPERATOR && (sbox, spoint) IS + 'true, if the spherical box overlaps a spherical point'; + +CREATE FUNCTION sbox_iscontained_spoint(sbox, spoint) + RETURNS boolean + AS 'MODULE_PATHNAME', 'sbox_iscontained_spoint' + LANGUAGE 'c' IMMUTABLE STRICT; + +CREATE OPERATOR <@ ( + LEFTARG = sbox, + RIGHTARG = spoint, + PROCEDURE = sbox_iscontained_spoint, + COMMUTATOR = '@>', + RESTRICT = contsel, + JOIN = contjoinsel +); + +CREATE FUNCTION spoint_contains_sbox(spoint, sbox) + RETURNS boolean + AS $$ + SELECT $2 <@ $1; + $$ LANGUAGE SQL IMMUTABLE STRICT; + +CREATE OPERATOR @> ( + LEFTARG = spoint, + RIGHTARG = sbox, + PROCEDURE = spoint_contains_sbox, + COMMUTATOR = '<@', + RESTRICT = contsel, + JOIN = contjoinsel +); + +-------------------------------- +-- the OpFamily -- +-------------------------------- + +CREATE OPERATOR FAMILY brin_inclusion_spheric_ops USING brin; + +CREATE OR REPLACE FUNCTION spoint_brin_inclusion_add_value(internal, internal, internal, internal) + RETURNS boolean + AS 'MODULE_PATHNAME','spoint_brin_inclusion_add_value' + LANGUAGE 'c'; + +CREATE OR REPLACE FUNCTION sbox_brin_inclusion_add_value(internal, internal, internal, internal) + RETURNS boolean + AS 'MODULE_PATHNAME','sbox_brin_inclusion_add_value' + LANGUAGE 'c'; + +CREATE OPERATOR CLASS brin_spoint_inclusion_ops + DEFAULT FOR TYPE spoint + USING brin + FAMILY brin_inclusion_spheric_ops AS + FUNCTION 1 brin_inclusion_opcinfo(internal) , + FUNCTION 2 spoint_brin_inclusion_add_value(internal, internal, internal, internal) , + FUNCTION 3 brin_inclusion_consistent(internal, internal, internal) , + FUNCTION 4 brin_inclusion_union(internal, internal, internal) , + STORAGE spherekey; + +CREATE OPERATOR CLASS brin_sbox_inclusion_ops + DEFAULT FOR TYPE sbox + USING brin + FAMILY brin_inclusion_spheric_ops AS + FUNCTION 1 brin_inclusion_opcinfo(internal) , + FUNCTION 2 sbox_brin_inclusion_add_value(internal, internal, internal, internal) , + FUNCTION 3 brin_inclusion_consistent(internal, internal, internal) , + FUNCTION 4 brin_inclusion_union(internal, internal, internal) , + STORAGE spherekey; + +ALTER OPERATOR FAMILY brin_inclusion_spheric_ops USING brin ADD + OPERATOR 3 &&(spherekey, spoint), + OPERATOR 7 @>(spherekey, spoint), + OPERATOR 8 <@(spherekey, spoint), + + OPERATOR 3 &&(spoint, spherekey), + OPERATOR 7 @>(spoint, spherekey), + OPERATOR 8 <@(spoint, spherekey), + + OPERATOR 3 &&(spherekey, sbox), + OPERATOR 7 @>(spherekey, sbox), + OPERATOR 8 <@(spherekey, sbox), + + OPERATOR 3 &&(sbox, spherekey), + OPERATOR 7 @>(sbox, spherekey), + OPERATOR 8 <@(sbox, spherekey), + + OPERATOR 3 &&(spherekey, spherekey), + OPERATOR 7 @>(spherekey, spherekey), + OPERATOR 8 <@(spherekey, spherekey), + + OPERATOR 3 &&(spoint, sbox), + OPERATOR 3 &&(sbox, spoint), + OPERATOR 7 @>(sbox, spoint), + OPERATOR 7 @>(spoint, sbox), + OPERATOR 8 <@(sbox, spoint), + OPERATOR 8 <@(spoint, sbox), + + OPERATOR 3 &&(sbox, sbox), + OPERATOR 7 @>(sbox, sbox), + OPERATOR 8 <@(sbox, sbox); diff --git a/sql/sbox_brin.sql b/sql/sbox_brin.sql new file mode 100644 index 0000000..24f30d0 --- /dev/null +++ b/sql/sbox_brin.sql @@ -0,0 +1,138 @@ +SELECT set_sphere_output_precision(8); + +CREATE TABLE test_boxes ( + b sbox +); + +COPY test_boxes (b) FROM stdin; +( (0.349065850398866, 0.174532925199433), (0.350065850398866, 0.174632925199433) ) +( (1.59875999207035, 0.771416330759722), (1.5997599920703498, 0.771516330759722) ) +( (1.59876348272885, 0.77141458543047), (1.5997634827288498, 0.77151458543047) ) +( (1.59876697338736, 0.771412840101218), (1.5997669733873598, 0.771512840101218) ) +( (1.59877046404586, 0.771411094771966), (1.5997704640458599, 0.771511094771966) ) +( (1.59877395470437, 0.771409349442714), (1.59977395470437, 0.771509349442714) ) +( (1.59877744536287, 0.771407604113461), (1.59977744536287, 0.771507604113461) ) +( (1.59878093602137, 0.77140585878421), (1.59978093602137, 0.77150585878421) ) +( (1.59878442667988, 0.771404113454958), (1.59978442667988, 0.771504113454958) ) +( (1.59878791733838, 0.771402368125706), (1.59978791733838, 0.7715023681257059) ) +( (1.59879140799689, 0.771400622796454), (1.5997914079968898, 0.771500622796454) ) +( (1.59879489865539, 0.771398877467202), (1.5997948986553898, 0.771498877467202) ) +( (1.59879838931389, 0.77139713213795), (1.5997983893138898, 0.77149713213795) ) +( (1.5988018799724, 0.771395386808698), (1.5998018799723999, 0.771495386808698) ) +( (1.5988053706309, 0.771393641479446), (1.5998053706309, 0.771493641479446) ) +( (1.59880886128941, 0.771391896150194), (1.59980886128941, 0.771491896150194) ) +( (1.59881235194791, 0.771390150820941), (1.59981235194791, 0.771490150820941) ) +( (1.59881584260641, 0.77138840549169), (1.59981584260641, 0.77148840549169) ) +( (1.59881933326492, 0.771386660162438), (1.59981933326492, 0.7714866601624379) ) +( (1.59882282392342, 0.771384914833186), (1.5998228239234198, 0.771484914833186) ) +( (1.59882631458193, 0.771383169503934), (1.5998263145819298, 0.771483169503934) ) +( (1.59882980524043, 0.771381424174682), (1.5998298052404298, 0.771481424174682) ) +( (1.59883329589893, 0.77137967884543), (1.5998332958989299, 0.77147967884543) ) +( (1.59883678655744, 0.771377933516178), (1.5998367865574399, 0.771477933516178) ) +( (1.59884027721594, 0.771376188186926), (1.59984027721594, 0.771476188186926) ) +( (1.59884376787445, 0.771374442857673), (1.59984376787445, 0.771474442857673) ) +( (1.59884725853295, 0.771372697528422), (1.59984725853295, 0.771472697528422) ) +( (1.59885074919145, 0.77137095219917), (1.59985074919145, 0.77147095219917) ) +( (1.59885423984996, 0.771369206869918), (1.5998542398499598, 0.7714692068699179) ) +( (1.59885773050846, 0.771367461540666), (1.5998577305084598, 0.771467461540666) ) +( (1.59886122116697, 0.771365716211414), (1.5998612211669698, 0.771465716211414) ) +( (1.59886471182547, 0.771363970882162), (1.5998647118254699, 0.771463970882162) ) +( (1.59886820248397, 0.77136222555291), (1.5998682024839699, 0.77146222555291) ) +( (1.59887169314248, 0.771360480223658), (1.59987169314248, 0.771460480223658) ) +( (1.59887518380098, 0.771358734894406), (1.59987518380098, 0.771458734894406) ) +( (1.59887867445948, 0.771356989565154), (1.59987867445948, 0.771456989565154) ) +( (1.59888216511799, 0.771355244235902), (1.59988216511799, 0.771455244235902) ) +( (1.59888565577649, 0.77135349890665), (1.5998856557764898, 0.7714534989066499) ) +( (1.598889146435, 0.771351753577398), (1.5998891464349998, 0.771451753577398) ) +( (1.5988926370935, 0.771350008248146), (1.5998926370934998, 0.771450008248146) ) +( (1.59889612775201, 0.771348262918894), (1.5998961277520098, 0.771448262918894) ) +( (1.59889961841051, 0.771346517589642), (1.5998996184105099, 0.771446517589642) ) +( (1.59890310906901, 0.77134477226039), (1.59990310906901, 0.77144477226039) ) +( (1.59890659972752, 0.771343026931138), (1.59990659972752, 0.771443026931138) ) +( (1.59891009038602, 0.771341281601886), (1.59991009038602, 0.771441281601886) ) +( (1.59891358104452, 0.771339536272634), (1.59991358104452, 0.771439536272634) ) +( (1.59891707170303, 0.771337790943382), (1.59991707170303, 0.7714377909433819) ) +( (1.59892056236153, 0.77133604561413), (1.5999205623615298, 0.77143604561413) ) +( (1.59892405302004, 0.771334300284878), (1.5999240530200398, 0.771434300284878) ) +( (1.59892754367854, 0.771332554955626), (1.5999275436785398, 0.771432554955626) ) +( (1.59893103433705, 0.771330809626374), (1.5999310343370499, 0.771430809626374) ) +( (1.59893452499555, 0.771329064297122), (1.59993452499555, 0.771429064297122) ) +( (1.59893801565405, 0.77132731896787), (1.59993801565405, 0.77142731896787) ) +( (1.59894150631256, 0.771325573638618), (1.59994150631256, 0.771425573638618) ) +( (1.59894499697106, 0.771323828309366), (1.59994499697106, 0.771423828309366) ) +( (1.59894848762957, 0.771322082980114), (1.59994848762957, 0.7714220829801139) ) +( (1.59895197828807, 0.771320337650862), (1.5999519782880698, 0.771420337650862) ) +( (1.59895546894657, 0.77131859232161), (1.5999554689465698, 0.77141859232161) ) +( (3.61121537674092, -1.33598496521933), (3.6122153767409197, -1.33588496521933) ) +( (3.61121886739942, -1.33598321989008), (3.6122188673994198, -1.33588321989008) ) +( (3.61122235805792, -1.33598147456083), (3.61222235805792, -1.33588147456083) ) +( (3.61122584871643, -1.33597972923158), (3.61222584871643, -1.33587972923158) ) +( (3.61122933937493, -1.33597798390233), (3.61222933937493, -1.33587798390233) ) +( (3.61123283003344, -1.33597623857307), (3.61223283003344, -1.33587623857307) ) +( (3.61123632069194, -1.33597449324382), (3.61223632069194, -1.33587449324382) ) +( (3.61123981135044, -1.33597274791457), (3.61223981135044, -1.33587274791457) ) +( (3.61124330200895, -1.33597100258532), (3.6122433020089497, -1.33587100258532) ) +( (3.61124679266745, -1.33596925725607), (3.6122467926674497, -1.33586925725607) ) +( (3.61125028332595, -1.33596751192682), (3.6122502833259498, -1.33586751192682) ) +( (3.61125377398446, -1.33596576659756), (3.61225377398446, -1.33586576659756) ) +( (3.61125726464296, -1.33596402126831), (3.61225726464296, -1.33586402126831) ) +( (3.61126075530147, -1.33596227593906), (3.61226075530147, -1.33586227593906) ) +( (3.61126424595997, -1.33596053060981), (3.61226424595997, -1.33586053060981) ) +( (3.61126773661847, -1.33595878528056), (3.61226773661847, -1.33585878528056) ) +( (3.61127122727698, -1.3359570399513), (3.6122712272769797, -1.3358570399513001) ) +( (3.61127471793548, -1.33595529462205), (3.6122747179354797, -1.33585529462205) ) +( (3.61127820859399, -1.3359535492928), (3.61227820859399, -1.3358535492928) ) +\. + +CREATE OR REPLACE FUNCTION qnodes(q text) RETURNS text +LANGUAGE 'plpgsql' AS +$$ +DECLARE + exp TEXT; + mat TEXT[]; + ret TEXT[]; +BEGIN + FOR exp IN EXECUTE 'EXPLAIN ' || q + LOOP + --RAISE NOTICE 'EXP: %', exp; + mat := regexp_matches(exp, ' *(?:-> *)?(.*Scan on (test_boxes|test_boxes_brin_idx))'); + --RAISE NOTICE 'MAT: %', mat; + IF mat IS NOT NULL THEN + ret := array_append(ret, mat[1]); + END IF; + --RAISE NOTICE 'RET: %', ret; + END LOOP; + RETURN array_to_string(ret,','); +END; +$$; + +CREATE INDEX test_boxes_brin_idx ON test_boxes USING brin (b); + +SET enable_indexscan = OFF; +SET enable_bitmapscan = OFF; +SET enable_seqscan = ON; + +SELECT 'scan_seq', qnodes('SELECT * FROM test_boxes WHERE b <@ sbox ''( (10d,10d), (20d,20d) )'''); +SELECT * FROM test_boxes WHERE b <@ sbox '( (10d,10d), (20d,20d) )'; + +SELECT 'scan_seq', qnodes('SELECT * FROM test_boxes WHERE b && sbox ''( (10d,10d), (20d,20d) )'''); +SELECT * FROM test_boxes WHERE b && sbox '( (10d,10d), (20d,20d) )'; + +SET enable_indexscan = OFF; +SET enable_bitmapscan = ON; +SET enable_seqscan = OFF; + +SELECT 'scan_idx', qnodes('SELECT * FROM test_boxes WHERE b <@ sbox ''( (10d,10d), (20d,20d) )'''); +SELECT * FROM test_boxes WHERE b <@ sbox '( (10d,10d), (20d,20d) )'; + +SELECT 'scan_idx', qnodes('SELECT * FROM test_boxes WHERE b && sbox ''( (10d,10d), (20d,20d) )'''); +SELECT * FROM test_boxes WHERE b && sbox '( (10d,10d), (20d,20d) )'; + +---- cleanup +DROP INDEX test_boxes_brin_idx; +DROP TABLE test_boxes; +DROP FUNCTION qnodes(text); + +SET enable_indexscan = ON; +SET enable_bitmapscan = ON; +SET enable_seqscan = ON; diff --git a/sql/spoint_brin.sql b/sql/spoint_brin.sql new file mode 100644 index 0000000..4a37f37 --- /dev/null +++ b/sql/spoint_brin.sql @@ -0,0 +1,136 @@ +CREATE TABLE test_points ( + p spoint +); + +COPY test_points (p) FROM stdin; +(0.349065850398866 , 0.174532925199433) +(1.59875999207035 , 0.771416330759722) +(1.59876348272885 , 0.77141458543047) +(1.59876697338736 , 0.771412840101218) +(1.59877046404586 , 0.771411094771966) +(1.59877395470437 , 0.771409349442714) +(1.59877744536287 , 0.771407604113461) +(1.59878093602137 , 0.77140585878421) +(1.59878442667988 , 0.771404113454958) +(1.59878791733838 , 0.771402368125706) +(1.59879140799689 , 0.771400622796454) +(1.59879489865539 , 0.771398877467202) +(1.59879838931389 , 0.77139713213795) +(1.5988018799724 , 0.771395386808698) +(1.5988053706309 , 0.771393641479446) +(1.59880886128941 , 0.771391896150194) +(1.59881235194791 , 0.771390150820941) +(1.59881584260641 , 0.77138840549169) +(1.59881933326492 , 0.771386660162438) +(1.59882282392342 , 0.771384914833186) +(1.59882631458193 , 0.771383169503934) +(1.59882980524043 , 0.771381424174682) +(1.59883329589893 , 0.77137967884543) +(1.59883678655744 , 0.771377933516178) +(1.59884027721594 , 0.771376188186926) +(1.59884376787445 , 0.771374442857673) +(1.59884725853295 , 0.771372697528422) +(1.59885074919145 , 0.77137095219917) +(1.59885423984996 , 0.771369206869918) +(1.59885773050846 , 0.771367461540666) +(1.59886122116697 , 0.771365716211414) +(1.59886471182547 , 0.771363970882162) +(1.59886820248397 , 0.77136222555291) +(1.59887169314248 , 0.771360480223658) +(1.59887518380098 , 0.771358734894406) +(1.59887867445948 , 0.771356989565154) +(1.59888216511799 , 0.771355244235902) +(1.59888565577649 , 0.77135349890665) +(1.598889146435 , 0.771351753577398) +(1.5988926370935 , 0.771350008248146) +(1.59889612775201 , 0.771348262918894) +(1.59889961841051 , 0.771346517589642) +(1.59890310906901 , 0.77134477226039) +(1.59890659972752 , 0.771343026931138) +(1.59891009038602 , 0.771341281601886) +(1.59891358104452 , 0.771339536272634) +(1.59891707170303 , 0.771337790943382) +(1.59892056236153 , 0.77133604561413) +(1.59892405302004 , 0.771334300284878) +(1.59892754367854 , 0.771332554955626) +(1.59893103433705 , 0.771330809626374) +(1.59893452499555 , 0.771329064297122) +(1.59893801565405 , 0.77132731896787) +(1.59894150631256 , 0.771325573638618) +(1.59894499697106 , 0.771323828309366) +(1.59894848762957 , 0.771322082980114) +(1.59895197828807 , 0.771320337650862) +(1.59895546894657 , 0.77131859232161) +(3.61121537674092 , -1.33598496521933) +(3.61121886739942 , -1.33598321989008) +(3.61122235805792 , -1.33598147456083) +(3.61122584871643 , -1.33597972923158) +(3.61122933937493 , -1.33597798390233) +(3.61123283003344 , -1.33597623857307) +(3.61123632069194 , -1.33597449324382) +(3.61123981135044 , -1.33597274791457) +(3.61124330200895 , -1.33597100258532) +(3.61124679266745 , -1.33596925725607) +(3.61125028332595 , -1.33596751192682) +(3.61125377398446 , -1.33596576659756) +(3.61125726464296 , -1.33596402126831) +(3.61126075530147 , -1.33596227593906) +(3.61126424595997 , -1.33596053060981) +(3.61126773661847 , -1.33595878528056) +(3.61127122727698 , -1.3359570399513) +(3.61127471793548 , -1.33595529462205) +(3.61127820859399 , -1.3359535492928) +\. + +CREATE OR REPLACE FUNCTION qnodes(q text) RETURNS text +LANGUAGE 'plpgsql' AS +$$ +DECLARE + exp TEXT; + mat TEXT[]; + ret TEXT[]; +BEGIN + FOR exp IN EXECUTE 'EXPLAIN ' || q + LOOP + --RAISE NOTICE 'EXP: %', exp; + mat := regexp_matches(exp, ' *(?:-> *)?(.*Scan on (test_points|brin_spoint))'); + --RAISE NOTICE 'MAT: %', mat; + IF mat IS NOT NULL THEN + ret := array_append(ret, mat[1]); + END IF; + --RAISE NOTICE 'RET: %', ret; + END LOOP; + RETURN array_to_string(ret,','); +END; +$$; + +CREATE INDEX brin_spoint ON test_points USING brin (p) WITH (pages_per_range = 16); + +set enable_indexscan = off; +set enable_bitmapscan = off; +set enable_seqscan = on; + +SELECT 'scan_seq', qnodes('SELECT * FROM test_points WHERE p <@ sbox ''( (10d,10d), (20d,20d) )'''); +SELECT * FROM test_points WHERE p <@ sbox '( (10d,10d), (20d,20d) )'; + +SELECT 'scan_seq', qnodes('SELECT * FROM test_points WHERE p && sbox ''( (10d,10d), (20d,20d) )'''); +SELECT * FROM test_points WHERE p && sbox '( (10d,10d), (20d,20d) )'; + +set enable_indexscan = off; +set enable_bitmapscan = on; +set enable_seqscan = off; + +SELECT 'scan_idx', qnodes('SELECT * FROM test_points WHERE p <@ sbox ''( (10d,10d), (20d,20d) )'''); +SELECT * FROM test_points WHERE p <@ sbox '( (10d,10d), (20d,20d) )'; + +SELECT 'scan_idx', qnodes('SELECT * FROM test_points WHERE p && sbox ''( (10d,10d), (20d,20d) )'''); +SELECT * FROM test_points WHERE p && sbox '( (10d,10d), (20d,20d) )'; + +-- cleanup +DROP INDEX brin_spoint; +DROP TABLE test_points; +DROP FUNCTION qnodes(text); + +set enable_indexscan = on; +set enable_bitmapscan = on; +set enable_seqscan = on; diff --git a/src/brin.c b/src/brin.c new file mode 100644 index 0000000..1c5ae1b --- /dev/null +++ b/src/brin.c @@ -0,0 +1,352 @@ +/* + * BRIN SUPPORT for spheric objects: + * + * The stored type is the spherekey, as for GiST support, + * so include some already defined stuffs. We have to define + * then all the cross-type functions needed by the OpFamilies. + */ + +#include "brin.h" +#include "gist.h" +#include + +/* + * Functions needed to build a BRIN index + */ +PG_FUNCTION_INFO_V1(spoint_brin_inclusion_add_value); +PG_FUNCTION_INFO_V1(sbox_brin_inclusion_add_value); + +/* + * Functions needed to define supported operators + */ +PG_FUNCTION_INFO_V1(spoint_overlaps_spherekey); +PG_FUNCTION_INFO_V1(spoint_contains_spherekey); +PG_FUNCTION_INFO_V1(spoint_iscontained_spherekey); +PG_FUNCTION_INFO_V1(sbox_overlaps_spherekey); +PG_FUNCTION_INFO_V1(sbox_contains_spherekey); +PG_FUNCTION_INFO_V1(sbox_iscontained_spherekey); +PG_FUNCTION_INFO_V1(spherekey_overlaps_spherekey); +PG_FUNCTION_INFO_V1(spherekey_contains_spherekey); +PG_FUNCTION_INFO_V1(spherekey_iscontained_spherekey); +PG_FUNCTION_INFO_V1(spoint_overlaps_sbox); +PG_FUNCTION_INFO_V1(sbox_iscontained_spoint); + +Datum +spoint_brin_inclusion_add_value(PG_FUNCTION_ARGS) +{ + BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1); + SPoint *newval = (SPoint *) DatumGetPointer(PG_GETARG_DATUM(2)); + bool isnull = PG_GETARG_BOOL(3); + int32 spointkey[6]; + int32 *skey = (int32 *) column->bv_values[INCLUSION_UNION]; + + /* + * 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->bv_hasnulls) + PG_RETURN_BOOL(false); + + column->bv_hasnulls = true; + PG_RETURN_BOOL(true); + } + + spherepoint_gen_key(spointkey, newval); + + /* + * If spherekey pointer is NULL, we consider the spoint entry as 'empty'. + * + * The OpClass support empty entries: we need to set the "contains empty" + * flag in the element (unless already set). + */ + /* + if (spointkey == NULL) + { + if (!DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY])) + { + column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(true); + PG_RETURN_BOOL(true); + } + + PG_RETURN_BOOL(false); + } + */ + + /* if the recorded value is null, we just need to store the spherekey */ + if (column->bv_allnulls) + { + column->bv_values[INCLUSION_UNION] = datumCopy((Datum) spointkey, false, + (sizeof(int32) * 6)); + column->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(false); + column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(false); + column->bv_allnulls = false; + PG_RETURN_BOOL(true); + } + + /* + * Check if the stored spherekey already contains the key of the new value + */ + if (spherekey_interleave(skey, spointkey) == SCKEY_IN) + { + PG_RETURN_BOOL(false); + } + + /* + * Otherwise, we need to enlarge it to contains the current spoint + */ + spherekey_union_two(skey, spointkey); + + PG_RETURN_BOOL(true); +} + +Datum +sbox_brin_inclusion_add_value(PG_FUNCTION_ARGS) +{ + BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1); + SBOX *newval = (SBOX *) DatumGetPointer(PG_GETARG_DATUM(2)); + bool isnull = PG_GETARG_BOOL(3); + int32 sboxkey[6]; + int32 *skey = (int32 *) column->bv_values[INCLUSION_UNION]; + + /* + * 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->bv_hasnulls) + PG_RETURN_BOOL(false); + + column->bv_hasnulls = true; + PG_RETURN_BOOL(true); + } + + spherebox_gen_key(sboxkey, newval); + + /* + * If spherekey pointer is NULL, we consider the spoint entry as 'empty'. + * + * The OpClass support empty entries: we need to set the "contains empty" + * flag in the element (unless already set). + */ + /* + if (sboxkey == NULL) + { + if (!DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY])) + { + column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(true); + PG_RETURN_BOOL(true); + } + + PG_RETURN_BOOL(false); + } + */ + + /* if the recorded value is null, we just need to store the spherekey */ + if (column->bv_allnulls) + { + column->bv_values[INCLUSION_UNION] = datumCopy((Datum) sboxkey, false, + (sizeof(int32) * 6)); + column->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(false); + column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(false); + column->bv_allnulls = false; + PG_RETURN_BOOL(true); + } + + /* + * Check if the stored spherekey already contains the key of the new value + */ + if (spherekey_interleave(skey, sboxkey) == SCKEY_IN) + { + PG_RETURN_BOOL(false); + } + + /* + * Otherwise, we need to enlarge it to contains the current spoint + */ + spherekey_union_two(skey, sboxkey); + + PG_RETURN_BOOL(true); +} + +/* */ +/* Define operators procedures below */ +/* */ + +Datum +spoint_overlaps_spherekey(PG_FUNCTION_ARGS) +{ + int32 k1[6]; + SPoint *p1 = (SPoint *) PG_GETARG_POINTER(0); + int32 *k2 = (int32 *) PG_GETARG_POINTER(1); + + spherepoint_gen_key(k1, p1); + if (spherekey_interleave(k1, k2) == SCKEY_OVERLAP) + { + PG_RETURN_BOOL(true); + } + + PG_RETURN_BOOL(false); +} + +Datum +spoint_contains_spherekey(PG_FUNCTION_ARGS) +{ + int32 k1[6]; + SPoint *p1 = (SPoint *) PG_GETARG_POINTER(0); + int32 *k2 = (int32 *) PG_GETARG_POINTER(1); + + spherepoint_gen_key(k1, p1); + if (spherekey_interleave(k1, k2) == SCKEY_IN) + { + PG_RETURN_BOOL(true); + } + + PG_RETURN_BOOL(false); +} + +Datum +spoint_iscontained_spherekey(PG_FUNCTION_ARGS) +{ + int32 k1[6]; + SPoint *p1 = (SPoint *) PG_GETARG_POINTER(0); + int32 *k2 = (int32 *) PG_GETARG_POINTER(1); + + spherepoint_gen_key(k1, p1); + if (spherekey_interleave(k2, k1) == SCKEY_IN) + { + PG_RETURN_BOOL(true); + } + + PG_RETURN_BOOL(false); +} + +Datum +sbox_overlaps_spherekey(PG_FUNCTION_ARGS) +{ + int32 k1[6]; + SBOX *p1 = (SBOX *) PG_GETARG_POINTER(0); + int32 *k2 = (int32 *) PG_GETARG_POINTER(1); + + spherebox_gen_key(k1, p1); + if (spherekey_interleave(k1, k2) == SCKEY_OVERLAP) + { + PG_RETURN_BOOL(true); + } + + PG_RETURN_BOOL(false); +} + +Datum +sbox_contains_spherekey(PG_FUNCTION_ARGS) +{ + int32 k1[6]; + SBOX *p1 = (SBOX *) PG_GETARG_POINTER(0); + int32 *k2 = (int32 *) PG_GETARG_POINTER(1); + + spherebox_gen_key(k1, p1); + if (spherekey_interleave(k1, k2) == SCKEY_IN) + { + PG_RETURN_BOOL(true); + } + + PG_RETURN_BOOL(false); +} + +Datum +sbox_iscontained_spherekey(PG_FUNCTION_ARGS) +{ + int32 k1[6]; + SBOX *p1 = (SBOX *) PG_GETARG_POINTER(0); + int32 *k2 = (int32 *) PG_GETARG_POINTER(1); + + spherebox_gen_key(k1, p1); + if (spherekey_interleave(k2, k1) == SCKEY_IN) + { + PG_RETURN_BOOL(true); + } + + PG_RETURN_BOOL(false); +} + +Datum +spherekey_overlaps_spherekey(PG_FUNCTION_ARGS) +{ + int32 *k1 = (int32 *) PG_GETARG_POINTER(0); + int32 *k2 = (int32 *) PG_GETARG_POINTER(1); + + if (spherekey_interleave(k1, k2) == SCKEY_OVERLAP) + { + PG_RETURN_BOOL(true); + } + + PG_RETURN_BOOL(false); +} + +Datum +spherekey_contains_spherekey(PG_FUNCTION_ARGS) +{ + int32 *k1 = (int32 *) PG_GETARG_POINTER(0); + int32 *k2 = (int32 *) PG_GETARG_POINTER(1); + + if (spherekey_interleave(k1, k2) == SCKEY_IN) + { + PG_RETURN_BOOL(true); + } + + PG_RETURN_BOOL(false); +} + +Datum +spherekey_iscontained_spherekey(PG_FUNCTION_ARGS) +{ + int32 *k1 = (int32 *) PG_GETARG_POINTER(0); + int32 *k2 = (int32 *) PG_GETARG_POINTER(1); + + if (spherekey_interleave(k2, k1) == SCKEY_IN) + { + PG_RETURN_BOOL(true); + } + + PG_RETURN_BOOL(false); +} + +Datum +spoint_overlaps_sbox(PG_FUNCTION_ARGS) +{ + int32 k1[6]; + SPoint *p1 = (SPoint *) PG_GETARG_POINTER(0); + int32 k2[6]; + SBOX *p2 = (SBOX *) PG_GETARG_POINTER(1); + + spherepoint_gen_key(k1, p1); + spherebox_gen_key(k2, p2); + + if (spherekey_interleave(k1, k2) == SCKEY_OVERLAP) + { + PG_RETURN_BOOL(true); + } + + PG_RETURN_BOOL(false); +} + +Datum +sbox_iscontained_spoint(PG_FUNCTION_ARGS) +{ + int32 k1[6]; + SBOX *p1 = (SBOX *) PG_GETARG_POINTER(0); + int32 k2[6]; + SPoint *p2 = (SPoint *) PG_GETARG_POINTER(1); + + spherebox_gen_key(k1, p1); + spherepoint_gen_key(k2, p2); + + if (spherekey_interleave(k1, k2) == SCKEY_IN) + { + PG_RETURN_BOOL(true); + } + + PG_RETURN_BOOL(false); +} diff --git a/src/brin.h b/src/brin.h new file mode 100644 index 0000000..b1a1c2c --- /dev/null +++ b/src/brin.h @@ -0,0 +1,40 @@ +#ifndef __PGS_BRIN_H__ +#define __PGS_BRIN_H__ + +/* + * BRIN declarations + */ + +#include "postgres.h" +#include "fmgr.h" + +#include "key.h" + +#include +#include +#include +#include +#include "access/brin_tuple.h" +#include "utils/datum.h" + +#define INCLUSION_UNION 0 +#define INCLUSION_UNMERGEABLE 1 +#define INCLUSION_CONTAINS_EMPTY 2 + +Datum spoint_brin_inclusion_add_value(PG_FUNCTION_ARGS); +Datum sbox_brin_inclusion_add_value(PG_FUNCTION_ARGS); + +Datum spoint_overlaps_spherekey(PG_FUNCTION_ARGS); +Datum spoint_contains_spherekey(PG_FUNCTION_ARGS); +Datum spoint_iscontained_spherekey(PG_FUNCTION_ARGS); +Datum sbox_overlaps_spherekey(PG_FUNCTION_ARGS); +Datum sbox_contains_spherekey(PG_FUNCTION_ARGS); +Datum sbox_iscontained_spherekey(PG_FUNCTION_ARGS); +Datum spherekey_overlaps_spherekey(PG_FUNCTION_ARGS); +Datum spherekey_contains_spherekey(PG_FUNCTION_ARGS); +Datum spherekey_iscontained_spherekey(PG_FUNCTION_ARGS); + +Datum spoint_overlaps_sbox(PG_FUNCTION_ARGS); +Datum sbox_iscontained_spoint(PG_FUNCTION_ARGS); + +#endif