From: Regina Obe Date: Sun, 31 Jul 2016 03:46:40 +0000 (+0000) Subject: Add support for BRIN indexes (2nd Quadrant, Giuseppe Broccolo, Julien Rouhaud) X-Git-Tag: 2.3.0beta1~29 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f49d42880f2aad1e23daaf5930fb66ec359a11a2;p=postgis Add support for BRIN indexes (2nd Quadrant, Giuseppe Broccolo, Julien Rouhaud) Closes #3591 Closes https://github.com/postgis/postgis/pull/106 git-svn-id: http://svn.osgeo.org/postgis/trunk@15028 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/NEWS b/NEWS index 89334b685..c988a6491 100644 --- a/NEWS +++ b/NEWS @@ -4,7 +4,7 @@ PostGIS 2.3.0 * Important / Breaking Changes * - #3466, Casting from box3d to geometry now returns a 3D - geometry (Julien Rouhaud) + geometry (2nd Quadrant, Julien Rouhaud) * Deprecated signatures * @@ -33,8 +33,9 @@ PostGIS 2.3.0 - #3465, ST_ClusterKMeans (Paul Ramsey) - #3469, ST_MakeLine with MULTIPOINTs (Paul Norman) - #3549, Support PgSQL 9.6 parallel query mode, as far as possible - (Paul Ramsey) + (Paul Ramsey, Regina Obe) - #3557, Geometry function costs based on query stats (Paul Norman) + - #3591, Add support for BRIN indexes (2nd Quadrant, Giuseppe Broccolo, Julien Rouhaud) * Performance Enhancements * diff --git a/configure.ac b/configure.ac index 370fd1ea0..ff00df607 100644 --- a/configure.ac +++ b/configure.ac @@ -444,6 +444,11 @@ if test "x$LIBLWGEOM_ONLY" = "xno"; then AC_MSG_ERROR([PostGIS requires PostgreSQL >= 9.1]) fi + HAVE_BRIN=no + if test $POSTGIS_PGSQL_VERSION -gt 94; then + HAVE_BRIN=yes + fi + dnl Note: We don't need the server-side LDFLAGS or CPPFLAGS because we get these from PGXS dnl Extract the linker and include flags for the frontend (for programs that use libpq) @@ -503,6 +508,7 @@ if test "x$LIBLWGEOM_ONLY" = "xno"; then AC_DEFINE_UNQUOTED([POSTGIS_PGSQL_VERSION], [$POSTGIS_PGSQL_VERSION], [PostgreSQL server version]) AC_SUBST([POSTGIS_PGSQL_VERSION]) + AC_SUBST([HAVE_BRIN]) fi dnl LIBLWGEOM_ONLY != no diff --git a/doc/reference_operator.xml b/doc/reference_operator.xml index daf42d26d..7937549bb 100644 --- a/doc/reference_operator.xml +++ b/doc/reference_operator.xml @@ -91,6 +91,204 @@ FROM ( VALUES + + + &&(geometry,box2df) + + Returns TRUE if a geometry's (cached) 2D bounding box intersects a 2D float precision bounding box (BOX2DF). + + + + + + boolean && + + + geometry + + A + + + + box2df + + B + + + + + + + Description + + The && operator returns TRUE if the cached 2D bounding box of geometry A intersects the 2D bounding box B, using float precision. This means that if B is a (double precision) box2d, it will be internally converted to a float precision 2D bounding box (BOX2DF) + + This operand is intended to be used internally by BRIN indexes, more + than by users. + + Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced. + &curve_support; + &P_support; + + + + Examples + + SELECT ST_MakePoint(1,1) && ST_MakeBox2D(ST_MakePoint(0,0), ST_MakePoint(2,2)) AS overlaps; + + overlaps +---------- + t +(1 row) + + + + See Also + + + , + , + , + , + , + , + , + + + + + + + &&(box2df,geometry) + + Returns TRUE if a 2D float precision bounding box (BOX2DF) intersects a geometry's (cached) 2D bounding box. + + + + + + boolean && + + + box2df + + A + + + + geometry + + B + + + + + + + Description + + The && operator returns TRUE if the 2D bounding box A intersects the cached 2D bounding box of geometry B, using float precision. This means that if A is a (double precision) box2d, it will be internally converted to a float precision 2D bounding box (BOX2DF) + + This operand is intended to be used internally by BRIN indexes, more + than by users. + + Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced. + &curve_support; + &P_support; + + + + Examples + + SELECT ST_MakeBox2D(ST_MakePoint(0,0), ST_MakePoint(2,2)) && ST_MakePoint(1,1) AS overlaps; + + overlaps +---------- + t +(1 row) + + + + See Also + + + , + , + , + , + , + , + , + + + + + + + &&(box2df,box2df) + + Returns TRUE if two 2D float precision bounding boxes (BOX2DF) intersect each other. + + + + + + boolean && + + + box2df + + A + + + + box2df + + B + + + + + + + Description + + The && operator returns TRUE if two 2D bounding boxes A and B intersect each other, using float precision. This means that if A (or B) is a (double precision) box2d, it will be internally converted to a float precision 2D bounding box (BOX2DF) + + This operator is intended to be used internally by BRIN indexes, more + than by users. + + Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced. + &curve_support; + &P_support; + + + + Examples + + SELECT ST_MakeBox2D(ST_MakePoint(0,0), ST_MakePoint(2,2)) && ST_MakeBox2D(ST_MakePoint(1,1), ST_MakePoint(3,3)) AS overlaps; + + overlaps +---------- + t +(1 row) + + + + See Also + + + , + , + , + , + , + , + , + + + + &&& @@ -177,6 +375,192 @@ FROM ( VALUES + + + &&&(geometry,gidx) + + Returns TRUE if a geometry's (cached) n-D bounding box intersects a n-D float precision bounding box (GIDX). + + + + + + boolean &&& + + + geometry + + A + + + + gidx + + B + + + + + + + Description + + The &&& operator returns TRUE if the cached n-D bounding box of geometry A intersects the n-D bounding box B, using float precision. This means that if B is a (double precision) box3d, it will be internally converted to a float precision 3D bounding box (GIDX) + + This operator is intended to be used internally by BRIN indexes, more + than by users. + + Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced. + &curve_support; + &P_support; + &T_support; + &Z_support; + + + + Examples + + SELECT ST_MakePoint(1,1,1) &&& ST_3DMakeBox(ST_MakePoint(0,0,0), ST_MakePoint(2,2,2)) AS overlaps; + + overlaps +---------- + t +(1 row) + + + + See Also + + + , + + + + + + + &&&(gidx,geometry) + + Returns TRUE if a n-D float precision bounding box (GIDX) intersects a geometry's (cached) n-D bounding box. + + + + + + boolean &&& + + + gidx + + A + + + + geometry + + B + + + + + + + Description + + The &&& operator returns TRUE if the n-D bounding box A intersects the cached n-D bounding box of geometry B, using float precision. This means that if A is a (double precision) box3d, it will be internally converted to a float precision 3D bounding box (GIDX) + + This operator is intended to be used internally by BRIN indexes, more + than by users. + + Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced. + &curve_support; + &P_support; + &T_support; + &Z_support; + + + + Examples + + SELECT ST_3DMakeBox(ST_MakePoint(0,0,0), ST_MakePoint(2,2,2)) &&& ST_MakePoint(1,1,1) AS overlaps; + + overlaps +---------- + t +(1 row) + + + + See Also + + + , + + + + + + + &&&(gidx,gidx) + + Returns TRUE if two n-D float precision bounding boxes (GIDX) intersect each other. + + + + + + boolean &&& + + + gidx + + A + + + + gidx + + B + + + + + + + Description + + The &&& operator returns TRUE if two n-D bounding boxes A and B intersect each other, using float precision. This means that if A (or B) is a (double precision) box3d, it will be internally converted to a float precision 3D bounding box (GIDX) + + This operator is intended to be used internally by BRIN indexes, more + than by users. + + Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced. + &curve_support; + &P_support; + &T_support; + &Z_support; + + + + Examples + + SELECT ST_3DMakeBox(ST_MakePoint(0,0,0), ST_MakePoint(2,2,2)) &&& ST_3DMakeBox(ST_MakePoint(1,1,1), ST_MakePoint(3,3,3)) AS overlaps; + + overlaps +---------- + t +(1 row) + + + + See Also + + + , + + + + &< @@ -591,82 +975,281 @@ FROM linkend="ST_Equals" /> - This operand will NOT make use of any indexes that may be available on the - geometries. + This operand will NOT make use of any indexes that may be available on the + geometries. + + &curve_support; + &P_support; + Changed: 2.0.0 , the bounding box of geometries was changed to use double precision instead of float4 precision of + prior. The side effect of this is that in particular points in prior versions that were a little different may have returned + true in prior versions and false in 2.0+ since their float4 boxes would be the same but there float8 (double precision), would be + different. + + + + + Examples + + SELECT 'LINESTRING(0 0, 0 1, 1 0)'::geometry = 'LINESTRING(1 1, 0 0)'::geometry; + ?column? +---------- + t +(1 row) + +SELECT ST_AsText(column1) +FROM ( VALUES + ('LINESTRING(0 0, 1 1)'::geometry), + ('LINESTRING(1 1, 0 0)'::geometry)) AS foo; + st_astext +--------------------- + LINESTRING(0 0,1 1) + LINESTRING(1 1,0 0) +(2 rows) + +-- Note: the GROUP BY uses the "=" to compare for geometry equivalency. +SELECT ST_AsText(column1) +FROM ( VALUES + ('LINESTRING(0 0, 1 1)'::geometry), + ('LINESTRING(1 1, 0 0)'::geometry)) AS foo +GROUP BY column1; + st_astext +--------------------- + LINESTRING(0 0,1 1) +(1 row) + +-- In versions prior to 2.0, this used to return true -- + SELECT ST_GeomFromText('POINT(1707296.37 4820536.77)') = + ST_GeomFromText('POINT(1707296.27 4820536.87)') As pt_intersect; + +--pt_intersect -- +f + + + + + See Also + + , + + + + + + + >> + + Returns TRUE if A's bounding box is strictly to the right of B's. + + + + + + + boolean >> + + + geometry + + A + + + + geometry + + B + + + + + + + Description + + The >> operator returns TRUE if the bounding box of geometry A + is strictly to the right of the bounding box of geometry B. + + This operand will make use of any indexes that may be available on the + geometries. + + + + Examples + + SELECT tbl1.column1, tbl2.column1, tbl1.column2 >> tbl2.column2 AS right +FROM + ( VALUES + (1, 'LINESTRING (2 3, 5 6)'::geometry)) AS tbl1, + ( VALUES + (2, 'LINESTRING (1 4, 1 7)'::geometry), + (3, 'LINESTRING (6 1, 6 5)'::geometry), + (4, 'LINESTRING (0 0, 4 3)'::geometry)) AS tbl2; + + column1 | column1 | right +---------+---------+------- + 1 | 2 | t + 1 | 3 | f + 1 | 4 | f +(3 rows) + + + + See Also + + , , + + + + + + @ + + Returns TRUE if A's bounding box is contained by B's. + + + + + + + boolean @ + + + geometry + + A + + + + geometry + + B + + + + + + + Description + + The @ operator returns TRUE if the bounding box of geometry A is completely + contained by the bounding box of geometry B. + + + This operand will make use of any indexes that may be available on the + geometries. + + + + + Examples + + SELECT tbl1.column1, tbl2.column1, tbl1.column2 @ tbl2.column2 AS contained +FROM + ( VALUES + (1, 'LINESTRING (1 1, 3 3)'::geometry)) AS tbl1, + ( VALUES + (2, 'LINESTRING (0 0, 4 4)'::geometry), + (3, 'LINESTRING (2 2, 4 4)'::geometry), + (4, 'LINESTRING (1 1, 3 3)'::geometry)) AS tbl2; + + column1 | column1 | contained +---------+---------+----------- + 1 | 2 | t + 1 | 3 | f + 1 | 4 | t +(3 rows) + + + + See Also + + , + + + + + + @(geometry,box2df) + + Returns TRUE if a geometry's 2D bounding box is contained into a 2D float precision bounding box (BOX2DF). + + + + + + boolean @ + + + geometry + + A + + + + box2df + + B + + + + + + + Description + + The @ operator returns TRUE if the A geometry's 2D bounding box is contained the 2D bounding box B, using float precision. This means that if B is a (double precision) box2d, it will be internally converted to a float precision 2D bounding box (BOX2DF) + This operand is intended to be used internally by BRIN indexes, more + than by users. + + Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced. &curve_support; &P_support; - Changed: 2.0.0 , the bounding box of geometries was changed to use double precision instead of float4 precision of - prior. The side effect of this is that in particular points in prior versions that were a little different may have returned - true in prior versions and false in 2.0+ since their float4 boxes would be the same but there float8 (double precision), would be - different. - Examples - SELECT 'LINESTRING(0 0, 0 1, 1 0)'::geometry = 'LINESTRING(1 1, 0 0)'::geometry; - ?column? ----------- - t -(1 row) - -SELECT ST_AsText(column1) -FROM ( VALUES - ('LINESTRING(0 0, 1 1)'::geometry), - ('LINESTRING(1 1, 0 0)'::geometry)) AS foo; - st_astext ---------------------- - LINESTRING(0 0,1 1) - LINESTRING(1 1,0 0) -(2 rows) - --- Note: the GROUP BY uses the "=" to compare for geometry equivalency. -SELECT ST_AsText(column1) -FROM ( VALUES - ('LINESTRING(0 0, 1 1)'::geometry), - ('LINESTRING(1 1, 0 0)'::geometry)) AS foo -GROUP BY column1; - st_astext ---------------------- - LINESTRING(0 0,1 1) -(1 row) - --- In versions prior to 2.0, this used to return true -- - SELECT ST_GeomFromText('POINT(1707296.37 4820536.77)') = - ST_GeomFromText('POINT(1707296.27 4820536.87)') As pt_intersect; + SELECT ST_Buffer(ST_GeomFromText('POINT(2 2)'), 1) @ ST_MakeBox2D(ST_MakePoint(0,0), ST_MakePoint(5,5)) AS is_contained; ---pt_intersect -- -f - + is_contained +-------------- + t +(1 row) See Also - , - + + , + , + , + , + , + , + , + - + - >> + @(box2df,geometry) - Returns TRUE if A's bounding box is strictly to the right of B's. + Returns TRUE if a 2D float precision bounding box (BOX2DF) is contained into a geometry's 2D bounding box. - - boolean >> + boolean @ - geometry + box2df A @@ -683,63 +1266,62 @@ f Description - The >> operator returns TRUE if the bounding box of geometry A - is strictly to the right of the bounding box of geometry B. + The @ operator returns TRUE if the 2D bounding box A is contained into the B geometry's 2D bounding box, using float precision. This means that if B is a (double precision) box2d, it will be internally converted to a float precision 2D bounding box (BOX2DF) - This operand will make use of any indexes that may be available on the - geometries. + This operand is intended to be used internally by BRIN indexes, more + than by users. + + Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced. + &curve_support; + &P_support; Examples - SELECT tbl1.column1, tbl2.column1, tbl1.column2 >> tbl2.column2 AS right -FROM - ( VALUES - (1, 'LINESTRING (2 3, 5 6)'::geometry)) AS tbl1, - ( VALUES - (2, 'LINESTRING (1 4, 1 7)'::geometry), - (3, 'LINESTRING (6 1, 6 5)'::geometry), - (4, 'LINESTRING (0 0, 4 3)'::geometry)) AS tbl2; + SELECT ST_MakeBox2D(ST_MakePoint(2,2), ST_MakePoint(3,3)) @ ST_Buffer(ST_GeomFromText('POINT(1 1)'), 10) AS is_contained; - column1 | column1 | right ----------+---------+------- - 1 | 2 | t - 1 | 3 | f - 1 | 4 | f -(3 rows) + is_contained +-------------- + t +(1 row) See Also - , , + + , + , + , + , + , + , + , + - + - @ + @(box2df,box2df) - Returns TRUE if A's bounding box is contained by B's. + Returns TRUE if a 2D float precision bounding box (BOX2DF) is contained into another 2D float precision bounding box. - boolean @ - geometry + box2df A - geometry + box2df B @@ -750,39 +1332,39 @@ FROM Description - The @ operator returns TRUE if the bounding box of geometry A is completely - contained by the bounding box of geometry B. + The @ operator returns TRUE if the 2D bounding box A is contained into the 2D bounding box B, using float precision. This means that if A (or B) is a (double precision) box2d, it will be internally converted to a float precision 2D bounding box (BOX2DF) - - This operand will make use of any indexes that may be available on the - geometries. - + This operand is intended to be used internally by BRIN indexes, more + than by users. + + Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced. + &curve_support; + &P_support; Examples - SELECT tbl1.column1, tbl2.column1, tbl1.column2 @ tbl2.column2 AS contained -FROM - ( VALUES - (1, 'LINESTRING (1 1, 3 3)'::geometry)) AS tbl1, - ( VALUES - (2, 'LINESTRING (0 0, 4 4)'::geometry), - (3, 'LINESTRING (2 2, 4 4)'::geometry), - (4, 'LINESTRING (1 1, 3 3)'::geometry)) AS tbl2; + SELECT ST_MakeBox2D(ST_MakePoint(2,2), ST_MakePoint(3,3)) @ ST_MakeBox2D(ST_MakePoint(0,0), ST_MakePoint(5,5)) AS is_contained; - column1 | column1 | contained ----------+---------+----------- - 1 | 2 | t - 1 | 3 | f - 1 | 4 | t -(3 rows) + is_contained +-------------- + t +(1 row) See Also - , + + , + , + , + , + , + , + , + @@ -992,6 +1574,204 @@ FROM + + + ~(geometry,box2df) + + Returns TRUE if a geometry's 2D bonding box contains a 2D float precision bounding box (GIDX). + + + + + + boolean ~ + + + geometry + + A + + + + box2df + + B + + + + + + + Description + + The ~ operator returns TRUE if the 2D bounding box of a geometry A contains the 2D bounding box B, using float precision. This means that if B is a (double precision) box2d, it will be internally converted to a float precision 2D bounding box (BOX2DF) + + This operand is intended to be used internally by BRIN indexes, more + than by users. + + Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced. + &curve_support; + &P_support; + + + + Examples + + SELECT ST_Buffer(ST_GeomFromText('POINT(1 1)'), 10) ~ ST_MakeBox2D(ST_MakePoint(0,0), ST_MakePoint(2,2)) AS contains; + + contains +---------- + t +(1 row) + + + + See Also + + + , + , + , + , + , + , + , + + + + + + + ~(box2df,geometry) + + Returns TRUE if a 2D float precision bounding box (BOX2DF) contains a geometry's 2D bonding box. + + + + + + boolean ~ + + + box2df + + A + + + + geometry + + B + + + + + + + Description + + The ~ operator returns TRUE if the 2D bounding box A contains the B geometry's bounding box, using float precision. This means that if A is a (double precision) box2d, it will be internally converted to a float precision 2D bounding box (BOX2DF) + + This operand is intended to be used internally by BRIN indexes, more + than by users. + + Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced. + &curve_support; + &P_support; + + + + Examples + + SELECT ST_MakeBox2D(ST_MakePoint(0,0), ST_MakePoint(5,5)) ~ ST_Buffer(ST_GeomFromText('POINT(2 2)'), 1) AS contains; + + contains +---------- + t +(1 row) + + + + See Also + + + , + , + , + , + , + , + , + + + + + + + ~(box2df,box2df) + + Returns TRUE if a 2D float precision bounding box (BOX2DF) contains another 2D float precision bounding box (BOX2DF). + + + + + + boolean ~ + + + box2df + + A + + + + box2df + + B + + + + + + + Description + + The ~ operator returns TRUE if the 2D bounding box A contains the 2D bounding box B, using float precision. This means that if A is a (double precision) box2d, it will be internally converted to a float precision 2D bounding box (BOX2DF) + + This operand is intended to be used internally by BRIN indexes, more + than by users. + + Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced. + &curve_support; + &P_support; + + + + Examples + + SELECT ST_MakeBox2D(ST_MakePoint(0,0), ST_MakePoint(5,5)) ~ ST_MakeBox2D(ST_MakePoint(2,2), ST_MakePoint(3,3)) AS contains; + + contains +---------- + t +(1 row) + + + + See Also + + + , + , + , + , + , + , + , + + + + ~= diff --git a/doc/using_postgis_dataman.xml b/doc/using_postgis_dataman.xml index f92b11934..ee91e6740 100644 --- a/doc/using_postgis_dataman.xml +++ b/doc/using_postgis_dataman.xml @@ -2178,6 +2178,72 @@ SELECT UPDATE_GEOMETRY_STATS([table_name], [column_name]); + + BRIN Indexes + + BRIN stands for "Block Range Index" and is a generic form of + indexing that has been introduced in PostgreSQL 9.5. BRIN is a lossy kind + of index, and its main usage is to provide a compromise for both read and + write performance. It's primary goal is to handle very large tables for + which some of the columns have some natural correlation with their + physical location within the table. In addition to GIS indexing, BRIN is + used to speed up searches on various kinds of regular or irregular data + structures (integer, arrays etc). + + Once a GIS data table exceeds a few thousand rows, you will want + to build an index to speed up spatial searches of the data (unless all + your searches are based on attributes, in which case you'll want to + build a normal index on the attribute fields). GiST indexes are really + performant as long as their size doesn't exceed the amount of RAM + available for the database, and as long as you can afford the storage + size, and the penalty in write workload. Otherwise, BRIN index can be + considered as an alternative. + + The idea of a BRIN index is to store only the bouding box englobing + all the geometries contained in all the rows in a set of table blocks, + called a range. Obviously, this indexing method will only be efficient + if the data is physically ordered in a way where the resulting bouding + boxes for block ranges will be mutually exclusive. The resulting index + will be really small, but will be less efficient than a GiST index in + many cases. + + Building a BRIN index is way less intensive than building a GiST + index. It's quite common to build a BRIN index in more than ten time less + than a GiST index would have required. As a BRIN index only store one + bouding box for one to many table blocks, it's pretty common to consume + up to a thousand time less disk space for this kind of indexes. + + You can choose the number of blocks to summarize in a range. If you + decrease this number, the index will be bigger but will probably help to + get better performance. + + The syntax for building a BRIN index on a "geometry" column is as + follows: + + CREATE INDEX [indexname] ON [tablename] USING BRIN ( [geometryfield] ); + The above syntax will always build a 2D-index. To get the 3d-dimensional index supported in PostGIS 2.0+ for the geometry type, you can create one using this syntax + CREATE INDEX [indexname] ON [tablename] USING BRIN ([geometryfield] brin_geometry_inclusion_ops_3d); + These above syntaxes will use the default number or block in a range, which is 128. To specify the number of blocks you want to summarise in a range, you can create one using this syntax + CREATE INDEX [indexname] ON [tablename] USING BRIN ( [geometryfield] ) WITH (pages_per_range = [number]); + + Also the "geography" datatype is supported for BRIN indexing. The + syntax for building a BRIN index on a "geometry" column is as follows: + + CREATE INDEX [indexname] ON [tablename] USING BRIN ( [geographyfield] ); + The above syntax will always build a 2D-index for geospatial objetcs on the spheroid. + + Currently, just the "inclusion support" is considered here, meaning + that just &&, ~ and + @ operators can be used for the 2D cases (both for + "geometry" and for "geography"), and just the &&& + operator can be used for the 3D geometries. There is no support + for kNN searches at the moment. + + VACUUM ANALYZE [table_name] [(column_name)]; +-- This is only needed for PostgreSQL 7.4 installations and below +SELECT UPDATE_GEOMETRY_STATS([table_name], [column_name]); + + Using Indexes diff --git a/libpgcommon/gserialized_gist.c b/libpgcommon/gserialized_gist.c index 9a277d933..4a8d8c977 100644 --- a/libpgcommon/gserialized_gist.c +++ b/libpgcommon/gserialized_gist.c @@ -374,6 +374,7 @@ GIDX* gidx_new(int ndims) { size_t size = GIDX_SIZE(ndims); GIDX *g = (GIDX*)palloc(size); + Assert( (ndims <= GIDX_MAX_DIM) && (size <= GIDX_MAX_SIZE) ); POSTGIS_DEBUGF(5,"created new gidx of %d dimensions, size %d", ndims, (int)size); SET_VARSIZE(g, size); return g; diff --git a/libpgcommon/gserialized_gist.h b/libpgcommon/gserialized_gist.h index 57177c7d7..b6a3c49ab 100644 --- a/libpgcommon/gserialized_gist.h +++ b/libpgcommon/gserialized_gist.h @@ -24,6 +24,7 @@ typedef struct ** 4 bytes varsize + 4 dimensions * 2 ordinates * 4 bytes float size = 36 bytes */ #define GIDX_MAX_SIZE 36 +#define GIDX_MAX_DIM 4 /********************************************************************** @@ -94,5 +95,6 @@ GSERIALIZED* gserialized_set_gidx(GSERIALIZED *g, GIDX *gidx); /* Remove the box from a disk serialization */ GSERIALIZED* gserialized_drop_gidx(GSERIALIZED *g); +int gserialized_datum_get_box2df_p(Datum gsdatum, BOX2DF *box2df); diff --git a/postgis/Makefile.in b/postgis/Makefile.in index 6a176a1e7..26dfe3289 100644 --- a/postgis/Makefile.in +++ b/postgis/Makefile.in @@ -46,6 +46,9 @@ DATA_built=$(SQL_built) SQL_OBJS=$(SQL_objs) endif +ifeq (@HAVE_BRIN@,yes) +BRIN_OBJ= brin_2d.o brin_nd.o brin_common.o +endif # SQL preprocessor @@ -87,6 +90,7 @@ PG_OBJS= \ gserialized_typmod.o \ gserialized_gist_2d.o \ gserialized_gist_nd.o \ + $(BRIN_OBJ) \ gserialized_estimate.o \ geography_inout.o \ geography_btree.o \ diff --git a/postgis/geography.sql.in b/postgis/geography.sql.in index 69ac907b3..f16e74c1a 100644 --- a/postgis/geography.sql.in +++ b/postgis/geography.sql.in @@ -286,6 +286,93 @@ CREATE OPERATOR CLASS gist_geography_ops FUNCTION 6 geography_gist_picksplit (internal, internal), FUNCTION 7 geography_gist_same (box2d, box2d, internal); +#if POSTGIS_PGSQL_VERSION > 94 +-------------------------------------------------------------------- +-- BRIN support for geographies -- +-------------------------------------------------------------------- + +-------------------------------- +-- the needed cross-operators -- +-------------------------------- + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION overlaps_geog(gidx, geography) +RETURNS boolean +AS 'MODULE_PATHNAME','gserialized_gidx_geog_overlaps' +LANGUAGE 'c' IMMUTABLE STRICT; + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION overlaps_geog(gidx, gidx) +RETURNS boolean +AS 'MODULE_PATHNAME','gserialized_gidx_gidx_overlaps' +LANGUAGE 'c' IMMUTABLE STRICT; + +-- Availability: 2.3.0 +CREATE OPERATOR && ( + LEFTARG = gidx, + RIGHTARG = geography, + PROCEDURE = overlaps_geog, + COMMUTATOR = && +); + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION overlaps_geog(geography, gidx) +RETURNS boolean +AS $$ + SELECT $2 && $1; +$$ LANGUAGE SQL IMMUTABLE STRICT; + +-- Availability: 2.3.0 +CREATE OPERATOR && ( + LEFTARG = geography, + RIGHTARG = gidx, + PROCEDURE = overlaps_geog, + COMMUTATOR = && +); + +-- Availability: 2.3.0 +CREATE OPERATOR && ( + LEFTARG = gidx, + RIGHTARG = gidx, + PROCEDURE = overlaps_geog, + COMMUTATOR = && +); + +-------------------------------- +-- the OpFamily -- +-------------------------------- + +-- Availability: 2.3.0 +CREATE OPERATOR FAMILY brin_geography_inclusion_ops USING brin; + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION geog_brin_inclusion_add_value(internal, internal, internal, internal) RETURNS boolean + AS 'MODULE_PATHNAME','geog_brin_inclusion_add_value' + LANGUAGE 'c'; + +-- Availability: 2.3.0 +CREATE OPERATOR CLASS brin_geography_inclusion_ops + DEFAULT FOR TYPE geography + USING brin + FAMILY brin_geography_inclusion_ops AS + OPERATOR 3 &&(geography, geography), + FUNCTION 1 brin_inclusion_opcinfo(internal) , + FUNCTION 2 geog_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 gidx; + +ALTER OPERATOR FAMILY brin_geography_inclusion_ops USING brin ADD + OPERATOR 3 &&(gidx, geography), + + OPERATOR 3 &&(geography, gidx), + + OPERATOR 3 &&(gidx, gidx); + +--------------------------------------------------------------- +-- END +--------------------------------------------------------------- +#endif -- ---------- ---------- ---------- ---------- ---------- ---------- ---------- -- B-Tree Functions diff --git a/postgis/gserialized_gist_2d.c b/postgis/gserialized_gist_2d.c index 06eaaeca2..dfd5b42c8 100644 --- a/postgis/gserialized_gist_2d.c +++ b/postgis/gserialized_gist_2d.c @@ -116,6 +116,15 @@ Datum gserialized_overbelow_2d(PG_FUNCTION_ARGS); Datum gserialized_distance_box_2d(PG_FUNCTION_ARGS); Datum gserialized_distance_centroid_2d(PG_FUNCTION_ARGS); +#if POSTGIS_PGSQL_VERSION > 94 +Datum gserialized_contains_box2df_geom_2d(PG_FUNCTION_ARGS); +Datum gserialized_contains_box2df_box2df_2d(PG_FUNCTION_ARGS); +Datum gserialized_within_box2df_geom_2d(PG_FUNCTION_ARGS); +Datum gserialized_within_box2df_box2df_2d(PG_FUNCTION_ARGS); +Datum gserialized_overlaps_box2df_geom_2d(PG_FUNCTION_ARGS); +Datum gserialized_overlaps_box2df_box2df_2d(PG_FUNCTION_ARGS); +#endif + /* ** true/false test function type */ @@ -541,7 +550,7 @@ static double box2df_distance(const BOX2DF *a, const BOX2DF *b) * full object and return the box based on that. If no box is available, * return #LW_FAILURE, otherwise #LW_SUCCESS. */ -static int +int gserialized_datum_get_box2df_p(Datum gsdatum, BOX2DF *box2df) { GSERIALIZED *gpart; @@ -621,8 +630,84 @@ gserialized_datum_predicate_2d(Datum gs1, Datum gs2, box2df_predicate predicate) return LW_FALSE; } +#if POSTGIS_PGSQL_VERSION > 94 +static int +gserialized_datum_predicate_box2df_geom_2d(const BOX2DF *br1, Datum gs2, box2df_predicate predicate) +{ + BOX2DF b2, *br2=NULL; + POSTGIS_DEBUG(3, "entered function"); + + if (gserialized_datum_get_box2df_p(gs2, &b2) == LW_SUCCESS) br2 = &b2; + + if ( predicate(br1, br2) ) + { + POSTGIS_DEBUGF(3, "got boxes %s and %s", br1 ? box2df_to_string(&b1) : "(null)", br2 ? box2df_to_string(&b2) : "(null)"); + return LW_TRUE; + } + return LW_FALSE; +} + +/*********************************************************************** +* BRIN 2-D Index Operator Functions +*/ + +PG_FUNCTION_INFO_V1(gserialized_contains_box2df_geom_2d); +Datum gserialized_contains_box2df_geom_2d(PG_FUNCTION_ARGS) +{ + POSTGIS_DEBUG(3, "entered function"); + if ( gserialized_datum_predicate_box2df_geom_2d((BOX2DF*)PG_GETARG_POINTER(0), PG_GETARG_DATUM(1), box2df_contains) == LW_TRUE ) + PG_RETURN_BOOL(TRUE); + + PG_RETURN_BOOL(FALSE); +} + +PG_FUNCTION_INFO_V1(gserialized_contains_box2df_box2df_2d); +Datum gserialized_contains_box2df_box2df_2d(PG_FUNCTION_ARGS) +{ + if ( box2df_contains((BOX2DF *)PG_GETARG_POINTER(0), (BOX2DF *)PG_GETARG_POINTER(1))) + PG_RETURN_BOOL(TRUE); + + PG_RETURN_BOOL(FALSE); +} + +PG_FUNCTION_INFO_V1(gserialized_within_box2df_geom_2d); +Datum gserialized_within_box2df_geom_2d(PG_FUNCTION_ARGS) +{ + POSTGIS_DEBUG(3, "entered function"); + if ( gserialized_datum_predicate_box2df_geom_2d((BOX2DF*)PG_GETARG_POINTER(0), PG_GETARG_DATUM(1), box2df_within) == LW_TRUE ) + PG_RETURN_BOOL(TRUE); + PG_RETURN_BOOL(FALSE); +} +PG_FUNCTION_INFO_V1(gserialized_within_box2df_box2df_2d); +Datum gserialized_within_box2df_box2df_2d(PG_FUNCTION_ARGS) +{ + if ( box2df_within((BOX2DF *)PG_GETARG_POINTER(0), (BOX2DF *)PG_GETARG_POINTER(1))) + PG_RETURN_BOOL(TRUE); + + PG_RETURN_BOOL(FALSE); +} + +PG_FUNCTION_INFO_V1(gserialized_overlaps_box2df_geom_2d); +Datum gserialized_overlaps_box2df_geom_2d(PG_FUNCTION_ARGS) +{ + POSTGIS_DEBUG(3, "entered function"); + if ( gserialized_datum_predicate_box2df_geom_2d((BOX2DF*)PG_GETARG_POINTER(0), PG_GETARG_DATUM(1), box2df_overlaps) == LW_TRUE ) + PG_RETURN_BOOL(TRUE); + + PG_RETURN_BOOL(FALSE); +} + +PG_FUNCTION_INFO_V1(gserialized_overlaps_box2df_box2df_2d); +Datum gserialized_overlaps_box2df_box2df_2d(PG_FUNCTION_ARGS) +{ + if ( box2df_overlaps((BOX2DF *)PG_GETARG_POINTER(0), (BOX2DF *)PG_GETARG_POINTER(1))) + PG_RETURN_BOOL(TRUE); + + PG_RETURN_BOOL(FALSE); +} +#endif /*********************************************************************** * GiST 2-D Index Operator Functions diff --git a/postgis/gserialized_gist_nd.c b/postgis/gserialized_gist_nd.c index fb281afd1..9be47be17 100644 --- a/postgis/gserialized_gist_nd.c +++ b/postgis/gserialized_gist_nd.c @@ -100,8 +100,20 @@ Datum gserialized_gist_geog_distance(PG_FUNCTION_ARGS); */ Datum gserialized_overlaps(PG_FUNCTION_ARGS); Datum gserialized_contains(PG_FUNCTION_ARGS); +#if POSTGIS_PGSQL_VERSION > 94 +Datum gserialized_gidx_geom_contains(PG_FUNCTION_ARGS); +Datum gserialized_gidx_gidx_contains(PG_FUNCTION_ARGS); +#endif Datum gserialized_within(PG_FUNCTION_ARGS); +#if POSTGIS_PGSQL_VERSION > 94 +Datum gserialized_gidx_geom_within(PG_FUNCTION_ARGS); +Datum gserialized_gidx_gidx_within(PG_FUNCTION_ARGS); +#endif Datum gserialized_distance_nd(PG_FUNCTION_ARGS); +#if POSTGIS_PGSQL_VERSION > 94 +Datum gserialized_gidx_geom_same(PG_FUNCTION_ARGS); +Datum gserialized_gidx_gidx_same(PG_FUNCTION_ARGS); +#endif /* ** GIDX true/false test function type @@ -476,6 +488,49 @@ gserialized_datum_predicate(Datum gs1, Datum gs2, gidx_predicate predicate) return LW_FALSE; } +#if POSTGIS_PGSQL_VERSION > 94 +static int +gserialized_datum_predicate_gidx_geom(GIDX *gidx1, Datum gs2, gidx_predicate predicate) +{ + /* Put aside some stack memory and use it for GIDX pointers. */ + char boxmem2[GIDX_MAX_SIZE]; + GIDX *gidx2 = (GIDX*)boxmem2; + + POSTGIS_DEBUG(3, "entered function"); + + /* Must be able to build box for gs2 arguement (ie, not empty geometry) + and predicate function to return true. */ + if ( (gserialized_datum_get_gidx_p(gs2, gidx2) == LW_SUCCESS) && + predicate(gidx1, gidx2) ) + { + POSTGIS_DEBUGF(3, "got boxes %s and %s", gidx_to_string(gidx1), gidx_to_string(gidx2)); + return LW_TRUE; + } + return LW_FALSE; +} + +static int +gserialized_datum_predicate_geom_gidx(Datum gs1, GIDX *gidx2, gidx_predicate predicate) +{ + /* Put aside some stack memory and use it for GIDX pointers. */ + char boxmem2[GIDX_MAX_SIZE]; + GIDX *gidx1 = (GIDX*)boxmem2; + + POSTGIS_DEBUG(3, "entered function"); + + /* Must be able to build box for gs2 arguement (ie, not empty geometry) + and predicate function to return true. */ + if ( (gserialized_datum_get_gidx_p(gs1, gidx1) == LW_SUCCESS) && + predicate(gidx1, gidx2) ) + { + POSTGIS_DEBUGF(3, "got boxes %s and %s", gidx_to_string(gidx1), gidx_to_string(gidx2)); + return LW_TRUE; + } + return LW_FALSE; +} +#endif + + /** * Calculate the centroid->centroid distance between the boxes. */ @@ -806,6 +861,36 @@ Datum gserialized_within(PG_FUNCTION_ARGS) PG_RETURN_BOOL(FALSE); } +#if POSTGIS_PGSQL_VERSION > 94 +/* +** '~' and operator function. Based on a GIDX and a serialized return true if +** the first is contained by the second. +*/ +PG_FUNCTION_INFO_V1(gserialized_gidx_geom_within); +Datum gserialized_gidx_geom_within(PG_FUNCTION_ARGS) +{ + GIDX *gidx = (GIDX *)PG_GETARG_POINTER(0); + + if ( gserialized_datum_predicate_geom_gidx(PG_GETARG_DATUM(1), gidx, gidx_contains) == LW_TRUE ) + PG_RETURN_BOOL(TRUE); + + PG_RETURN_BOOL(FALSE); +} + +/* +** '~' and operator function. Based on two GIDX return true if +** the first is contained by the second. +*/ +PG_FUNCTION_INFO_V1(gserialized_gidx_gidx_within); +Datum gserialized_gidx_gidx_within(PG_FUNCTION_ARGS) +{ + if ( gidx_contains((GIDX *)PG_GETARG_POINTER(1), (GIDX *)PG_GETARG_POINTER(0))) + PG_RETURN_BOOL(TRUE); + + PG_RETURN_BOOL(FALSE); +} +#endif + /* ** '@' and operator function. Based on two serialized return true if ** the first contains the second. @@ -821,6 +906,56 @@ Datum gserialized_contains(PG_FUNCTION_ARGS) PG_RETURN_BOOL(FALSE); } +#if POSTGIS_PGSQL_VERSION > 94 +/* +** '@' and operator function. Based on a GIDX and a serialized return true if +** the first contains the second. +*/ +PG_FUNCTION_INFO_V1(gserialized_gidx_geom_contains); +Datum gserialized_gidx_geom_contains(PG_FUNCTION_ARGS) +{ + GIDX *gidx = (GIDX *)PG_GETARG_POINTER(0); + + if ( gserialized_datum_predicate_gidx_geom(gidx, PG_GETARG_DATUM(1), gidx_contains) == LW_TRUE ) + PG_RETURN_BOOL(TRUE); + + PG_RETURN_BOOL(FALSE); +} + +/* +** '@' and operator function. Based on two GIDX return true if +** the first contains the second. +*/ +PG_FUNCTION_INFO_V1(gserialized_gidx_gidx_contains); +Datum gserialized_gidx_gidx_contains(PG_FUNCTION_ARGS) +{ + if ( gidx_contains((GIDX *)PG_GETARG_POINTER(0), (GIDX *)PG_GETARG_POINTER(1))) + PG_RETURN_BOOL(TRUE); + + PG_RETURN_BOOL(FALSE); +} + +PG_FUNCTION_INFO_V1(gserialized_gidx_geom_same); +Datum gserialized_gidx_geom_same(PG_FUNCTION_ARGS) +{ + GIDX *gidx = (GIDX *)PG_GETARG_POINTER(0); + + if ( gserialized_datum_predicate_gidx_geom(gidx, PG_GETARG_DATUM(1), gidx_equals) == LW_TRUE ) + PG_RETURN_BOOL(TRUE); + + PG_RETURN_BOOL(FALSE); +} + +PG_FUNCTION_INFO_V1(gserialized_gidx_gidx_same); +Datum gserialized_gidx_gidx_same(PG_FUNCTION_ARGS) +{ + if ( gidx_equals((GIDX *)PG_GETARG_POINTER(0), (GIDX *)PG_GETARG_POINTER(1)) ) + PG_RETURN_BOOL(TRUE); + + PG_RETURN_BOOL(FALSE); +} +#endif + /* ** '&&' operator function. Based on two serialized return true if ** they overlap and false otherwise. @@ -836,6 +971,42 @@ Datum gserialized_overlaps(PG_FUNCTION_ARGS) PG_RETURN_BOOL(FALSE); } +#if POSTGIS_PGSQL_VERSION > 94 +/* + * This is the cross-operator for the geographies + */ +PG_FUNCTION_INFO_V1(gserialized_gidx_geog_overlaps); +Datum gserialized_gidx_geog_overlaps(PG_FUNCTION_ARGS) +{ + GIDX *gidx = (GIDX *)PG_GETARG_POINTER(0); + + if ( gserialized_datum_predicate_gidx_geom(gidx, PG_GETARG_DATUM(1), gidx_overlaps) == LW_TRUE ) + PG_RETURN_BOOL(TRUE); + + PG_RETURN_BOOL(FALSE); +} + +PG_FUNCTION_INFO_V1(gserialized_gidx_geom_overlaps); +Datum gserialized_gidx_geom_overlaps(PG_FUNCTION_ARGS) +{ + GIDX *gidx = (GIDX *)PG_GETARG_POINTER(0); + + if ( gserialized_datum_predicate_gidx_geom(gidx, PG_GETARG_DATUM(1), gidx_overlaps) == LW_TRUE ) + PG_RETURN_BOOL(TRUE); + + PG_RETURN_BOOL(FALSE); +} + +PG_FUNCTION_INFO_V1(gserialized_gidx_gidx_overlaps); +Datum gserialized_gidx_gidx_overlaps(PG_FUNCTION_ARGS) +{ + if ( gidx_overlaps((GIDX *)PG_GETARG_POINTER(0), (GIDX *)PG_GETARG_POINTER(1)) ) + PG_RETURN_BOOL(TRUE); + + PG_RETURN_BOOL(FALSE); +} +#endif + /*********************************************************************** * GiST Index Support Functions */ diff --git a/postgis/postgis.sql.in b/postgis/postgis.sql.in index 59b3d177c..235d688bc 100644 --- a/postgis/postgis.sql.in +++ b/postgis/postgis.sql.in @@ -746,7 +746,6 @@ CREATE OPERATOR CLASS gist_geometry_ops_2d FUNCTION 6 geometry_gist_picksplit_2d (internal, internal), FUNCTION 7 geometry_gist_same_2d (geom1 geometry, geom2 geometry, internal); - ----------------------------------------------------------------------------- -- GiST ND GEOMETRY-over-GSERIALIZED ----------------------------------------------------------------------------- @@ -5546,10 +5545,300 @@ CREATE OR REPLACE FUNCTION ST_InterpolatePoint(Line geometry, Point geometry) AS 'MODULE_PATHNAME', 'ST_InterpolatePoint' LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL; +#if POSTGIS_PGSQL_VERSION > 94 +-------------------------------------------------------------------- +-- BRIN support -- +-------------------------------------------------------------------- + +--------------------------------- +-- 2d operators -- +--------------------------------- + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION contains_2d(box2df, geometry) +RETURNS boolean +AS 'MODULE_PATHNAME','gserialized_contains_box2df_geom_2d' +LANGUAGE 'c' IMMUTABLE STRICT; + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION is_contained_2d(box2df, geometry) +RETURNS boolean +AS 'MODULE_PATHNAME','gserialized_within_box2df_geom_2d' +LANGUAGE 'c' IMMUTABLE STRICT; + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION overlaps_2d(box2df, geometry) +RETURNS boolean +AS 'MODULE_PATHNAME','gserialized_overlaps_box2df_geom_2d' +LANGUAGE 'c' IMMUTABLE STRICT; + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION overlaps_2d(box2df, box2df) +RETURNS boolean +AS 'MODULE_PATHNAME','gserialized_contains_box2df_box2df_2d' +LANGUAGE 'c' IMMUTABLE STRICT; + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION contains_2d(box2df, box2df) +RETURNS boolean +AS 'MODULE_PATHNAME','gserialized_contains_box2df_box2df_2d' +LANGUAGE 'c' IMMUTABLE STRICT; + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION is_contained_2d(box2df, box2df) +RETURNS boolean +AS 'MODULE_PATHNAME','gserialized_contains_box2df_box2df_2d' +LANGUAGE 'c' IMMUTABLE STRICT; + +-- Availability: 2.3.0 +CREATE OPERATOR ~ ( + LEFTARG = box2df, + RIGHTARG = geometry, + PROCEDURE = contains_2d, + COMMUTATOR = @ +); + +-- Availability: 2.3.0 +CREATE OPERATOR @ ( + LEFTARG = box2df, + RIGHTARG = geometry, + PROCEDURE = is_contained_2d, + COMMUTATOR = ~ +); + +-- Availability: 2.3.0 +CREATE OPERATOR && ( + LEFTARG = box2df, + RIGHTARG = geometry, + PROCEDURE = overlaps_2d, + COMMUTATOR = && +); + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION contains_2d(geometry, box2df) +RETURNS boolean +AS $$ + SELECT $2 @ $1; +$$ LANGUAGE SQL IMMUTABLE STRICT; + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION is_contained_2d(geometry, box2df) +RETURNS boolean +AS $$ + SELECT $2 ~ $1; +$$ LANGUAGE SQL IMMUTABLE STRICT; + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION overlaps_2d(geometry, box2df) +RETURNS boolean +AS $$ + SELECT $2 && $1; +$$ LANGUAGE SQL IMMUTABLE STRICT; + +-- Availability: 2.3.0 +CREATE OPERATOR ~ ( + LEFTARG = geometry, + RIGHTARG = box2df, + COMMUTATOR = @, + PROCEDURE = contains_2d +); + +-- Availability: 2.3.0 +CREATE OPERATOR @ ( + LEFTARG = geometry, + RIGHTARG = box2df, + COMMUTATOR = ~, + PROCEDURE = is_contained_2d +); + +-- Availability: 2.3.0 +CREATE OPERATOR && ( + LEFTARG = geometry, + RIGHTARG = box2df, + PROCEDURE = overlaps_2d, + COMMUTATOR = && +); + +-- Availability: 2.3.0 +CREATE OPERATOR && ( + LEFTARG = box2df, + RIGHTARG = box2df, + PROCEDURE = overlaps_2d, + COMMUTATOR = && +); + +-- Availability: 2.3.0 +CREATE OPERATOR @ ( + LEFTARG = box2df, + RIGHTARG = box2df, + PROCEDURE = is_contained_2d, + COMMUTATOR = ~ +); + +-- Availability: 2.3.0 +CREATE OPERATOR ~ ( + LEFTARG = box2df, + RIGHTARG = box2df, + PROCEDURE = contains_2d, + COMMUTATOR = @ +); + +---------------------------- +-- nd operators -- +---------------------------- + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION overlaps_nd(gidx, geometry) +RETURNS boolean +AS 'MODULE_PATHNAME','gserialized_gidx_geom_overlaps' +LANGUAGE 'c' IMMUTABLE STRICT; + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION overlaps_nd(gidx, gidx) +RETURNS boolean +AS 'MODULE_PATHNAME','gserialized_gidx_gidx_overlaps' +LANGUAGE 'c' IMMUTABLE STRICT; + +-- Availability: 2.3.0 +CREATE OPERATOR &&& ( + LEFTARG = gidx, + RIGHTARG = geometry, + PROCEDURE = overlaps_nd, + COMMUTATOR = &&& +); + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION overlaps_nd(geometry, gidx) +RETURNS boolean +AS $$ + SELECT $2 &&& $1; +$$ LANGUAGE SQL IMMUTABLE STRICT; + +-- Availability: 2.3.0 +CREATE OPERATOR &&& ( + LEFTARG = geometry, + RIGHTARG = gidx, + PROCEDURE = overlaps_nd, + COMMUTATOR = &&& +); + +-- Availability: 2.3.0 +CREATE OPERATOR &&& ( + LEFTARG = gidx, + RIGHTARG = gidx, + PROCEDURE = overlaps_nd, + COMMUTATOR = &&& +); + +------------------------------ +-- Create operator families -- +------------------------------ + +------------- +-- 2D case -- +------------- + +-- Availability: 2.3.0 +CREATE OPERATOR FAMILY brin_geometry_inclusion_ops_2d USING brin; + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION geom2d_brin_inclusion_add_value(internal, internal, internal, internal) RETURNS boolean + AS 'MODULE_PATHNAME','geom2d_brin_inclusion_add_value' + LANGUAGE 'c'; + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION geom3d_brin_inclusion_add_value(internal, internal, internal, internal) RETURNS boolean + AS 'MODULE_PATHNAME','geom3d_brin_inclusion_add_value' + LANGUAGE 'c'; + +-- Availability: 2.3.0 +CREATE OR REPLACE FUNCTION geom4d_brin_inclusion_add_value(internal, internal, internal, internal) RETURNS boolean + AS 'MODULE_PATHNAME','geom4d_brin_inclusion_add_value' + LANGUAGE 'c'; + +-- Availability: 2.3.0 +CREATE OPERATOR CLASS brin_geometry_inclusion_ops_2d + DEFAULT FOR TYPE geometry + USING brin + FAMILY brin_geometry_inclusion_ops_2d AS + OPERATOR 3 &&(geometry, geometry), + OPERATOR 7 ~(geometry, geometry), + OPERATOR 8 @(geometry, geometry), + FUNCTION 1 brin_inclusion_opcinfo(internal) , + FUNCTION 2 geom2d_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 box2df; + +ALTER OPERATOR FAMILY brin_geometry_inclusion_ops_2d USING brin ADD + OPERATOR 3 &&(box2df, geometry), + OPERATOR 7 ~(box2df, geometry), + OPERATOR 8 @(box2df, geometry), + + OPERATOR 3 &&(geometry, box2df), + OPERATOR 7 ~(geometry, box2df), + OPERATOR 8 @(geometry, box2df), + + OPERATOR 3 &&(box2df, box2df), + OPERATOR 7 ~(box2df, box2df), + OPERATOR 8 @(box2df, box2df); + +------------- +-- 3D case -- +------------- + +-- Availability: 2.3.0 +CREATE OPERATOR FAMILY brin_geometry_inclusion_ops_3d USING brin; + +-- Availability: 2.3.0 +CREATE OPERATOR CLASS brin_geometry_inclusion_ops_3d + FOR TYPE geometry + USING brin + FAMILY brin_geometry_inclusion_ops_3d AS + OPERATOR 3 &&&(geometry, geometry), + FUNCTION 1 brin_inclusion_opcinfo(internal) , + FUNCTION 2 geom3d_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 gidx; + +ALTER OPERATOR FAMILY brin_geometry_inclusion_ops_3d USING brin ADD + OPERATOR 3 &&&(gidx, geometry), + + OPERATOR 3 &&&(geometry, gidx), + + OPERATOR 3 &&&(gidx, gidx); + +------------- +-- 4D case -- +------------- + +-- Availability: 2.3.0 +CREATE OPERATOR FAMILY brin_geometry_inclusion_ops_4d USING brin; + +-- Availability: 2.3.0 +CREATE OPERATOR CLASS brin_geometry_inclusion_ops_4d + FOR TYPE geometry + USING brin + FAMILY brin_geometry_inclusion_ops_4d AS + OPERATOR 3 &&&(geometry, geometry), + FUNCTION 1 brin_inclusion_opcinfo(internal) , + FUNCTION 2 geom4d_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 gidx; + +ALTER OPERATOR FAMILY brin_geometry_inclusion_ops_4d USING brin ADD + OPERATOR 3 &&&(gidx, geometry), + + OPERATOR 3 &&&(geometry, gidx), + + OPERATOR 3 &&&(gidx, gidx); + --------------------------------------------------------------- -- END --------------------------------------------------------------- - +#endif --------------------------------------------------------------- -- USER CONTRIBUTED diff --git a/regress/Makefile.in b/regress/Makefile.in index d8a2ad6ae..5b7946aa7 100644 --- a/regress/Makefile.in +++ b/regress/Makefile.in @@ -23,6 +23,7 @@ POSTGIS_MAJOR_VERSION=@POSTGIS_MAJOR_VERSION@ POSTGIS_MINOR_VERSION=@POSTGIS_MINOR_VERSION@ HAVE_JSON=@HAVE_JSON@ HAVE_SFCGAL=@HAVE_SFCGAL@ +HAVE_BRIN=@HAVE_BRIN@ MINGWBUILD=@MINGWBUILD@ INTERRUPTTESTS=@INTERRUPTTESTS@ @@ -231,6 +232,13 @@ ifeq ($(HAVE_JSON),yes) in_geojson endif +ifeq ($(HAVE_BRIN),yes) + TESTS += \ + regress_brin_index \ + regress_brin_index_3d \ + regress_brin_index_geography +endif + ifeq ($(HAVE_SFCGAL),yes) # SFCGAL additionnal backend TESTS += \ diff --git a/utils/postgis_proc_upgrade.pl b/utils/postgis_proc_upgrade.pl index 9298b652a..0425b0168 100755 --- a/utils/postgis_proc_upgrade.pl +++ b/utils/postgis_proc_upgrade.pl @@ -390,6 +390,37 @@ EOF } } + # This code handles operator family by creating them if we are doing a major upgrade + if ( /^create operator family\s+(\w+)\s+USING\s+(\w+)\s*/i ) + { + my $opfname = $1; + my $amname = $2; + my $def = $_; + my $opfsig = $opfname . " " . $amname; + while() + { + $def .= $_; + last if /\);/; + } + + my $last_updated = parse_last_updated($comment); + if ( ! $last_updated ) { + print STDERR "WARNING: no last updated info for operator family '${opfname}'\n"; + $last_updated = find_last_updated("opfamilies", $opfsig); + } + print "-- Operator family ${opfsig} -- LastUpdated: ${last_updated}\n"; + print <<"EOF"; +DO LANGUAGE 'plpgsql' +\$postgis_proc_upgrade\$ +BEGIN + IF $last_updated > version_from_num FROM _postgis_upgrade_info THEN + EXECUTE \$postgis_proc_upgrade_parsed_def\$ $def \$postgis_proc_upgrade_parsed_def\$; + END IF; +END +\$postgis_proc_upgrade\$; +EOF + } + # This code handles operator classes by creating them if we are doing a major upgrade if ( /^create operator class\s+(\w+)\s*/i ) {