]> granicus.if.org Git - postgis/commitdiff
index corruption and memory leak in BRIN support
authorRegina Obe <lr@pcorp.us>
Fri, 11 Nov 2016 19:42:31 +0000 (19:42 +0000)
committerRegina Obe <lr@pcorp.us>
Fri, 11 Nov 2016 19:42:31 +0000 (19:42 +0000)
Patch from Julien Rouhaud (Dalibo)
closes #3665 for PostGIS 2.3.1

git-svn-id: http://svn.osgeo.org/postgis/branches/2.3@15227 b70326c6-7e19-0410-871a-916f4a2858ee

12 files changed:
NEWS
doc/using_postgis_dataman.xml
libpgcommon/gserialized_gist.c
libpgcommon/gserialized_gist.h
postgis/brin_2d.c
postgis/brin_nd.c
postgis/gserialized_gist_2d.c
postgis/gserialized_gist_nd.c
regress/regress_brin_index.sql
regress/regress_brin_index_3d.sql
regress/regress_brin_index_3d_expected
regress/regress_brin_index_expected

diff --git a/NEWS b/NEWS
index 11cf5cc016034a651a034755736e4eff616d66b5..9d4992d5031faeef4fa7fc91ba5b5710dbeceafd 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,8 @@ PostGIS 2.3.1
   - #3644, Deadlock on interrupt
   - #3652, Crash on Collection(MultiCurve())
   - #3656, Fix upgrade of aggregates from 2.2 or lower version
+  - #3665, Index corruption and memory leak in BRIN indexes
+    patch from Julien Rouhaud (Dalibo)
   - #3667, geography ST_Segmentize bug
     patch from Hugo Mercier (Oslandia)
 
index ee91e6740d23d9bc4b70466fe3798f21e2b9a7f9..c9081630b3ac4efa34c3d478873647376f813075 100644 (file)
@@ -2184,7 +2184,7 @@ SELECT UPDATE_GEOMETRY_STATS([table_name], [column_name]);</programlisting></par
          <para>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
+         write performance. Its 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
@@ -2221,13 +2221,22 @@ SELECT UPDATE_GEOMETRY_STATS([table_name], [column_name]);</programlisting></par
          follows:</para>
 
          <para><programlisting>CREATE INDEX [indexname] ON [tablename] USING BRIN ( [geometryfield] ); </programlisting></para>
-         <para>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</para>
+         <para>The above syntax will always build a 2D-index.  To get a 3d-dimensional index, you can create one using this syntax</para>
          <programlisting>CREATE INDEX [indexname] ON [tablename] USING BRIN ([geometryfield] brin_geometry_inclusion_ops_3d);</programlisting>
-         <para>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</para>
-         <para><programlisting>CREATE INDEX [indexname] ON [tablename] USING BRIN ( [geometryfield] ) WITH (pages_per_range = [number]); </programlisting></para>
+      <para>You can also get a 4d-dimensional index using the 4d operator class</para>
+         <programlisting>CREATE INDEX [indexname] ON [tablename] USING BRIN ([geometryfield] brin_geometry_inclusion_ops_4d);</programlisting>
+      <para>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</para>
+      <para><programlisting>CREATE INDEX [indexname] ON [tablename] USING BRIN ( [geometryfield] ) WITH (pages_per_range = [number]); </programlisting></para>
+      <para>Also, keep in mind that a BRIN index will only store one index
+        value for a large number of rows.  If your table stores geometries with
+        a mixed number of dimensions, it's likely that the resulting index will
+        have poor performance.  You can avoid this drop of performance by
+        choosing the operator class whith the least number of dimensions of the
+        stored geometries
+      </para>
 
           <para>Also the "geography" datatype is supported for BRIN indexing. The
-          syntax for building a BRIN index on a "geometry" column is as follows:</para>
+          syntax for building a BRIN index on a "geography" column is as follows:</para>
 
           <para><programlisting>CREATE INDEX [indexname] ON [tablename] USING BRIN ( [geographyfield] ); </programlisting></para>
           <para>The above syntax will always build a 2D-index for geospatial objetcs on the spheroid. </para>
index 4a8d8c977871c1a9694a9e81d6be01bc46e8f25f..d379fb26ac393f46ed10c8ff622ac74449078e10 100644 (file)
@@ -290,12 +290,17 @@ gserialized_datum_get_gidx_p(Datum gsdatum, GIDX *gidx)
                {
                        POSTGIS_DEBUG(4, "could not calculate bbox, returning failure");
                        lwgeom_free(lwgeom);
+                       POSTGIS_FREE_IF_COPY_P(gpart, gsdatum);
+                       POSTGIS_FREE_IF_COPY_P(g, gsdatum);
                        return LW_FAILURE;
                }
                lwgeom_free(lwgeom);
+               POSTGIS_FREE_IF_COPY_P(g, gsdatum);
                result = gidx_from_gbox_p(gbox, gidx);
        }
-       
+
+       POSTGIS_FREE_IF_COPY_P(gpart, gsdatum);
+
        if ( result == LW_SUCCESS )
        {
                POSTGIS_DEBUGF(4, "got gidx %s", gidx_to_string(gidx));
index b6a3c49ab918a790011984ed2a2abb3a0a7163e8..292bb1e01c0f341de34b63a0fd1766e2f2f9df4d 100644 (file)
@@ -27,6 +27,17 @@ typedef struct
 #define GIDX_MAX_DIM 4
 
 
+/*
+ * This macro is based on PG_FREE_IF_COPY, except that it accepts two pointers.
+ * See PG_FREE_IF_COPY comment in src/include/fmgr.h in postgres source code
+ * for more details.
+ */
+#define POSTGIS_FREE_IF_COPY_P(ptrsrc, ptrori) \
+       do { \
+               if ((Pointer) (ptrsrc) != (Pointer) (ptrori)) \
+                       pfree(ptrsrc); \
+       } while (0)
+
 /**********************************************************************
 **  BOX2DF structure.
 **
@@ -95,6 +106,8 @@ GSERIALIZED* gserialized_set_gidx(GSERIALIZED *g, GIDX *gidx);
 /* Remove the box from a disk serialization */
 GSERIALIZED* gserialized_drop_gidx(GSERIALIZED *g);
 
+bool box2df_contains(const BOX2DF *a, const BOX2DF *b);
+bool gidx_contains(GIDX *a, GIDX *b);
 int gserialized_datum_get_box2df_p(Datum gsdatum, BOX2DF *box2df);
 
 
index f5fc2f53c5cde1744191f2169a95c13bbf05323a..148951db25164b2645f29a95641c8af7107c718d 100644 (file)
@@ -72,17 +72,20 @@ geom2d_brin_inclusion_add_value(PG_FUNCTION_ARGS)
                PG_RETURN_BOOL(true);
        }
 
+       box_key = (BOX2DF *) column->bv_values[INCLUSION_UNION];
+
+       /* Check if the stored bouding box already contains the geometry's one */
+       if (box2df_contains(box_key, &box_geom))
+                       PG_RETURN_BOOL(false);
+
        /*
         * Otherwise, we need to enlarge the stored box2df to make it contains the
         * current geometry
         */
-       box_key = (BOX2DF *) column->bv_values[INCLUSION_UNION];
-
-       /* enlarge box2df */
        box_key->xmin = Min(box_key->xmin, box_geom.xmin);
        box_key->xmax = Max(box_key->xmax, box_geom.xmax);
        box_key->ymin = Min(box_key->ymin, box_geom.ymin);
        box_key->ymax = Max(box_key->ymax, box_geom.ymax);
 
-       PG_RETURN_BOOL(false);
+       PG_RETURN_BOOL(true);
 }
index db8a8714999d47efcf9fdf278b06b481916656be..ad1470d93ad27d091b802636a14b56b5c0e22cde 100644 (file)
@@ -12,7 +12,7 @@
  */
 
 Datum gidx_brin_inclusion_add_value(BrinDesc *bdesc, BrinValues *column, Datum
-               newval, bool isnull, int dims_wanted);
+               newval, bool isnull, int max_dims);
 
 /*
  * As for the GiST case, geographies are converted into GIDX before
@@ -60,13 +60,13 @@ geom4d_brin_inclusion_add_value(PG_FUNCTION_ARGS)
 
 Datum
 gidx_brin_inclusion_add_value(BrinDesc *bdesc, BrinValues *column, Datum newval,
-               bool isnull, int dims_wanted)
+               bool isnull, int max_dims)
 {
        char gboxmem[GIDX_MAX_SIZE];
        GIDX *gidx_geom, *gidx_key;
-       int dims_geom, i;
+       int dims_geom, dims_key, i;
 
-       Assert(dims_wanted <= GIDX_MAX_DIM);
+       Assert(max_dims <= GIDX_MAX_DIM);
 
        /*
         * If the new value is null, we record that we saw it if it's the first
@@ -81,6 +81,14 @@ gidx_brin_inclusion_add_value(BrinDesc *bdesc, BrinValues *column, Datum newval,
                PG_RETURN_BOOL(true);
        }
 
+       /*
+        * No need for further processing if the block range is already initialized
+        * and is marked as containing unmergeable values.
+        */
+       if (!column->bv_allnulls &&
+                       DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE]))
+               PG_RETURN_BOOL(false);
+
        /* create a new GIDX in stack memory, maximum dimensions */
        gidx_geom = (GIDX *) gboxmem;
 
@@ -120,28 +128,24 @@ gidx_brin_inclusion_add_value(BrinDesc *bdesc, BrinValues *column, Datum newval,
        if (column->bv_allnulls)
        {
                /*
-                * We have to make sure we store a GIDX of wanted dimension. If the
-                * original geometry has less dimensions, we zero them in the GIDX. If
-                * the original geometry has more, we ignore them.
+                * It's not safe to summarize geometries of different number of
+                * dimensions in the same range.  We therefore fix the number of
+                * dimension for this range by storing the bounding box of the first
+                * geometry found as is, being careful not to store more dimension than
+                * defined in the opclass.
                 */
-               if (dims_geom != dims_wanted)
+               if (dims_geom > max_dims)
                {
                        /*
-                        * This is safe to either enlarge or diminush the varsize because
-                        * the GIDX was created with the maximum number of dimension a GIDX
-                        * can contain
+                        * Diminush the varsize to only store the maximum number of
+                        * dimensions allowed by the opclass
                         */
-                       SET_VARSIZE(gidx_geom, VARHDRSZ + dims_wanted * 2 * sizeof(float));
-               }
-               /* zero the extra dimensions if we enlarged the GIDX */
-               for (i = dims_geom; i < dims_wanted; i++)
-               {
-                       GIDX_SET_MIN(gidx_geom, i, 0);
-                       GIDX_SET_MAX(gidx_geom, i, 0);
+                       SET_VARSIZE(gidx_geom, VARHDRSZ + max_dims * 2 * sizeof(float));
+                       dims_geom = max_dims;
                }
 
                column->bv_values[INCLUSION_UNION] = datumCopy((Datum) gidx_geom, false,
-                               GIDX_SIZE(dims_wanted));
+                               GIDX_SIZE(dims_geom));
                column->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(false);
                column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(false);
                column->bv_allnulls = false;
@@ -149,12 +153,28 @@ gidx_brin_inclusion_add_value(BrinDesc *bdesc, BrinValues *column, Datum newval,
        }
 
        gidx_key = (GIDX *) column->bv_values[INCLUSION_UNION];
+       dims_key = GIDX_NDIMS(gidx_key);
+
+       /*
+        * Mark the datum as unmergeable if its number of dimension is not the same
+        * as the one stored in the key of the current range
+        */
+       if (dims_key != dims_geom)
+       {
+               column->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(true);
+               PG_RETURN_BOOL(true);
+       }
+
+       /* Check if the stored bounding box already contains the geometry's one */
+       if (gidx_contains(gidx_key, gidx_geom))
+                       PG_RETURN_BOOL(false);
 
        /*
-        * As we always store a GIDX of the wanted number of dimensions, we just
-        * need adjust min and max
+        * Otherwise, we need to enlarge the stored GIDX to make it contains the
+        * current geometry.  As we store a GIDX with a fixed number of dimensions,
+        * we just need adjust min and max
         */
-       for ( i = 0; i < dims_wanted; i++ )
+       for ( i = 0; i < dims_key; i++ )
        {
                /* Adjust minimums */
                GIDX_SET_MIN(gidx_key, i,
@@ -164,5 +184,5 @@ gidx_brin_inclusion_add_value(BrinDesc *bdesc, BrinValues *column, Datum newval,
                                Max(GIDX_GET_MAX(gidx_key,i),GIDX_GET_MAX(gidx_geom,i)));
        }
 
-       PG_RETURN_BOOL(false);
+       PG_RETURN_BOOL(true);
 }
index 70ba6d0dc5eff07204cc479687839e3a66af5775..6c382495821123d7ecbee5555be9b6e3b735962c 100644 (file)
@@ -291,7 +291,7 @@ static bool box2df_overlaps(const BOX2DF *a, const BOX2DF *b)
        return TRUE;
 }
 
-static bool box2df_contains(const BOX2DF *a, const BOX2DF *b)
+bool box2df_contains(const BOX2DF *a, const BOX2DF *b)
 {
        if ( ! a || ! b ) return FALSE; /* TODO: might be smarter for EMPTY */
 
@@ -595,11 +595,16 @@ gserialized_datum_get_box2df_p(Datum gsdatum, BOX2DF *box2df)
                if (gserialized_get_gbox_p(g, &gbox) == LW_FAILURE)
                {
                        POSTGIS_DEBUG(4, "could not calculate bbox, returning failure");
+                       POSTGIS_FREE_IF_COPY_P(gpart, gsdatum);
+                       POSTGIS_FREE_IF_COPY_P(g, gsdatum);
                        return LW_FAILURE;
                }
+               POSTGIS_FREE_IF_COPY_P(g, gsdatum);
                result = box2df_from_gbox_p(&gbox, box2df);
        }
 
+       POSTGIS_FREE_IF_COPY_P(gpart, gsdatum);
+
        if ( result == LW_SUCCESS )
        {
                POSTGIS_DEBUGF(4, "got box2df %s", box2df_to_string(box2df));
index 9be47be17d6d1ec6832122f3230bf0eb204afceb..4fc5fa476b12b581f8e3d4e18e2d11ec029c15be 100644 (file)
@@ -378,7 +378,7 @@ static bool gidx_overlaps(GIDX *a, GIDX *b)
 **
 ** Box(A) CONTAINS Box(B) IFF (pt(A)LL < pt(B)LL) && (pt(A)UR > pt(B)UR)
 */
-static bool gidx_contains(GIDX *a, GIDX *b)
+bool gidx_contains(GIDX *a, GIDX *b)
 {
        int i, dims_a, dims_b;
 
index 089523cbed62aaeb0044fe6e896a09677a8abe35..e0aaf5633fdc98629019aab37ca01e63c7756c07 100644 (file)
@@ -1,7 +1,7 @@
 --- build a larger database
 \i regress_lots_of_points.sql
 
---- test some of the searching capabilities
+--- Test the various BRIN opclass with dataset containing 2D geometries
 
 CREATE OR REPLACE FUNCTION qnodes(q text) RETURNS text
 LANGUAGE 'plpgsql' AS
@@ -96,6 +96,81 @@ SELECT 'scan_idx', qnodes('select * from test where the_geom &&& ST_MakePoint(0,
 
 DROP INDEX brin_4d;
 
+-- test adding rows and unsummarized ranges
+--
+
+-- 2D
+TRUNCATE TABLE test;
+INSERT INTO test select 1, st_makepoint(1, 1);
+CREATE INDEX brin_2d on test using brin (the_geom) WITH (pages_per_range = 1);
+INSERT INTO test select i, st_makepoint(i, i) FROM generate_series(2, 3) i;
+
+set enable_indexscan = off;
+set enable_bitmapscan = on;
+set enable_seqscan = off;
+
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom && ''BOX(2.1 2.1, 3.1 3.1)''::box2d');
+ select '2d', count(*) from test where the_geom && 'BOX(2.1 2.1, 3.1 3.1)'::box2d;
+
+INSERT INTO test select i, st_makepoint(i, i) FROM generate_series(4, 1000) i;
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom && ''BOX(900.1 900.1, 920.1 920.1)''::box2d');
+ select '2d', count(*) from test where the_geom && 'BOX(900.1 900.1, 920.1 920.1)'::box2d;
+
+SELECT 'summarize 2d', brin_summarize_new_values('brin_2d');
+
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom && ''BOX(900.1 900.1, 920.1 920.1)''::box2d');
+ select '2d', count(*) from test where the_geom && 'BOX(900.1 900.1, 920.1 920.1)'::box2d;
+
+DROP INDEX brin_2d;
+
+-- 3D
+TRUNCATE TABLE test;
+INSERT INTO test select 1, st_makepoint(1, 1);
+CREATE INDEX brin_3d on test using brin (the_geom brin_geometry_inclusion_ops_3d) WITH (pages_per_range = 1);
+INSERT INTO test select i, st_makepoint(i, i) FROM generate_series(2, 3) i;
+
+set enable_indexscan = off;
+set enable_bitmapscan = on;
+set enable_seqscan = off;
+
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom &&& ''BOX3D(2.1 2.1 2.1, 3.1 3.1 3.1)''::box3d');
+ select '3d', count(*) from test where the_geom &&& 'BOX3D(2.1 2.1 2.1, 3.1 3.1 3.1)'::box3d;
+
+INSERT INTO test select i, st_makepoint(i, i) FROM generate_series(4, 1000) i;
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom &&& ''BOX3D(900.1 900.1 900.1, 920.1 920.1 920.1)''::box3d');
+ select '3d', count(*) from test where the_geom &&& 'BOX3D(900.1 900.1 900.1, 920.1 920.1 920.1)'::box3d;
+
+SELECT 'summarize 3d', brin_summarize_new_values('brin_3d');
+
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom &&& ''BOX3D(900.1 900.1 900.1, 920.1 920.1 920.1)''::box3d');
+ select '3d', count(*) from test where the_geom &&& 'BOX3D(900.1 900.1 900.1, 920.1 920.1 920.1)'::box3d;
+
+DROP INDEX brin_3d;
+
+-- 4D
+TRUNCATE TABLE test;
+INSERT INTO test select 1, st_makepoint(1, 1);
+CREATE INDEX brin_4d on test using brin (the_geom brin_geometry_inclusion_ops_4d) WITH (pages_per_range = 1);
+INSERT INTO test select i, st_makepoint(i, i) FROM generate_series(2, 3) i;
+
+set enable_indexscan = off;
+set enable_bitmapscan = on;
+set enable_seqscan = off;
+
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom &&& ''BOX3D(2.1 2.1 2.1, 3.1 3.1 3.1)''::box3d');
+ select '4d', count(*) from test where the_geom &&& 'BOX3D(2.1 2.1 2.1, 3.1 3.1 3.1)'::box3d;
+
+INSERT INTO test select i, st_makepoint(i, i) FROM generate_series(4, 1000) i;
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom &&& ''BOX3D(900.1 900.1 900.1, 920.1 920.1 920.1)''::box3d');
+ select '4d', count(*) from test where the_geom &&& 'BOX3D(900.1 900.1 900.1, 920.1 920.1 920.1)'::box3d;
+
+SELECT 'summarize 4d', brin_summarize_new_values('brin_4d');
+
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom &&& ''BOX3D(900.1 900.1 900.1, 920.1 920.1 920.1)''::box3d');
+ select '4d', count(*) from test where the_geom &&& 'BOX3D(900.1 900.1 900.1, 920.1 920.1 920.1)'::box3d;
+
+DROP INDEX brin_4d;
+
 -- cleanup
 DROP TABLE test;
 DROP FUNCTION qnodes(text);
index 07c50da45957af471e04ec1628751666f323be96..4fef2a07c55a704d4dbeef73c19464b69234cd86 100644 (file)
@@ -1,7 +1,8 @@
 --- build a larger database
 \i regress_lots_of_3dpoints.sql
 
---- test some of the searching capabilities
+--- Test the various BRIN opclass with dataset containing 3D geometries, or
+-- geometries of different number of dimensions
 
 CREATE OR REPLACE FUNCTION qnodes(q text) RETURNS text
 LANGUAGE 'plpgsql' AS
@@ -114,6 +115,137 @@ SELECT 'scan_idx', qnodes('SELECT * FROM test WHERE the_geom IS NULL');
 
 DROP INDEX brin_4d;
 
+-- test adding rows and unsummarized ranges
+--
+
+-- 2D
+TRUNCATE TABLE test;
+INSERT INTO test select 1, st_makepoint(1, 1, 1);
+CREATE INDEX brin_2d on test using brin (the_geom) WITH (pages_per_range = 1);
+INSERT INTO test select i, st_makepoint(i, i, i) FROM generate_series(2, 3) i;
+
+set enable_indexscan = off;
+set enable_bitmapscan = on;
+set enable_seqscan = off;
+
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom && ''BOX(2.1 2.1, 3.1 3.1)''::box2d');
+ select '2d', count(*) from test where the_geom && 'BOX(2.1 2.1, 3.1 3.1)'::box2d;
+
+INSERT INTO test select i, st_makepoint(i, i) FROM generate_series(4, 1000) i;
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom && ''BOX(900.1 900.1, 920.1 920.1)''::box2d');
+ select '2d', count(*) from test where the_geom && 'BOX(900.1 900.1, 920.1 920.1)'::box2d;
+
+SELECT 'summarize 2d', brin_summarize_new_values('brin_2d');
+
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom && ''BOX(900.1 900.1, 920.1 920.1)''::box2d');
+ select '2d', count(*) from test where the_geom && 'BOX(900.1 900.1, 920.1 920.1)'::box2d;
+
+DROP INDEX brin_2d;
+
+-- 3D
+TRUNCATE TABLE test;
+INSERT INTO test select 1, st_makepoint(1, 1, 1);
+CREATE INDEX brin_3d on test using brin (the_geom brin_geometry_inclusion_ops_3d) WITH (pages_per_range = 1);
+INSERT INTO test select i, st_makepoint(i, i, i) FROM generate_series(2, 3) i;
+
+set enable_indexscan = off;
+set enable_bitmapscan = on;
+set enable_seqscan = off;
+
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom &&& ''BOX3D(2.1 2.1 2.1, 3.1 3.1 3.1)''::box3d');
+ select '3d', count(*) from test where the_geom &&& 'BOX3D(2.1 2.1 2.1, 3.1 3.1 3.1)'::box3d;
+
+INSERT INTO test select i, st_makepoint(i, i) FROM generate_series(4, 1000) i;
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom &&& ''BOX3D(900.1 900.1 900.1, 920.1 920.1 920.1)''::box3d');
+ select '3d', count(*) from test where the_geom &&& 'BOX3D(900.1 900.1 900.1, 920.1 920.1 920.1)'::box3d;
+
+SELECT 'summarize 3d', brin_summarize_new_values('brin_3d');
+
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom &&& ''BOX3D(900.1 900.1 900.1, 920.1 920.1 920.1)''::box3d');
+ select '3d', count(*) from test where the_geom &&& 'BOX3D(900.1 900.1 900.1, 920.1 920.1 920.1)'::box3d;
+
+DROP INDEX brin_3d;
+
+-- 4D
+TRUNCATE TABLE test;
+INSERT INTO test select 1, st_makepoint(1, 1, 1);
+CREATE INDEX brin_4d on test using brin (the_geom brin_geometry_inclusion_ops_4d) WITH (pages_per_range = 1);
+INSERT INTO test select i, st_makepoint(i, i, i) FROM generate_series(2, 3) i;
+
+set enable_indexscan = off;
+set enable_bitmapscan = on;
+set enable_seqscan = off;
+
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom &&& ''BOX3D(2.1 2.1 2.1, 3.1 3.1 3.1)''::box3d');
+ select '4d', count(*) from test where the_geom &&& 'BOX3D(2.1 2.1 2.1, 3.1 3.1 3.1)'::box3d;
+
+INSERT INTO test select i, st_makepoint(i, i) FROM generate_series(4, 1000) i;
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom &&& ''BOX3D(900.1 900.1 900.1, 920.1 920.1 920.1)''::box3d');
+ select '4d', count(*) from test where the_geom &&& 'BOX3D(900.1 900.1 900.1, 920.1 920.1 920.1)'::box3d;
+
+SELECT 'summarize 4d', brin_summarize_new_values('brin_4d');
+
+SELECT 'scan_idx', qnodes('select count(*) from test where the_geom &&& ''BOX3D(900.1 900.1 900.1, 920.1 920.1 920.1)''::box3d');
+ select '4d', count(*) from test where the_geom &&& 'BOX3D(900.1 900.1 900.1, 920.1 920.1 920.1)'::box3d;
+
+DROP INDEX brin_4d;
+
+-- test mix of dimensions, NULL and empty geomertries
+TRUNCATE TABLE test;
+INSERT INTO test SELECT i,
+    CASE i%5
+        WHEN 0 THEN ST_MakePoint(i, i)
+        WHEN 1 THEN ST_MakePoint(i, i, 2)
+        WHEN 2 THEN ST_MakePoint(i, i, 2, 3)
+        WHEN 3 THEN NULL
+        ELSE 'POINTZ EMPTY'::geometry
+    END
+    FROM generate_series(1, 5) i;
+
+-- seq scan
+set enable_indexscan = off;
+set enable_bitmapscan = off;
+set enable_seqscan = on;
+SELECT 'scan_seq', qnodes('select * from test where the_geom && ''BOX(1 1, 5 5)''::box2d');
+ select 'mix_seq_box2d', num,ST_astext(the_geom) from test where the_geom && 'BOX(1 1, 5 5)'::box2d order by num;
+ select 'mix_seq_box3d', num,ST_astext(the_geom) from test where the_geom &&& 'BOX3D(1 1 0, 5 5 0)'::box3d order by num;
+
+-- 2D
+CREATE INDEX brin_2d on test using brin (the_geom) WITH (pages_per_range = 1);
+set enable_indexscan = off;
+set enable_bitmapscan = on;
+set enable_seqscan = off;
+
+SELECT 'scan_idx', qnodes('select * from test where the_geom && ''BOX(1 1, 5 5)''::box2d');
+ select 'mix_2d_box2d', num,ST_astext(the_geom) from test where the_geom && 'BOX(1 1, 5 5)'::box2d order by num;
+ select 'mix_2d_box3d', num,ST_astext(the_geom) from test where the_geom &&& 'BOX3D(1 1 0, 5 5 0)'::box3d order by num;
+
+DROP INDEX brin_2d;
+
+-- 3D
+CREATE INDEX brin_3d on test using brin (the_geom brin_geometry_inclusion_ops_3d);
+set enable_indexscan = off;
+set enable_bitmapscan = on;
+set enable_seqscan = off;
+
+SELECT 'scan_idx', qnodes('select * from test where the_geom && ''BOX(1 1, 5 5)''::box2d');
+ select 'mix_3d_box2d', num,ST_astext(the_geom) from test where the_geom && 'BOX(1 1, 5 5)'::box2d order by num;
+ select 'mix_3d_box3d', num,ST_astext(the_geom) from test where the_geom &&& 'BOX3D(1 1 0, 5 5 0)'::box3d order by num;
+
+DROP INDEX brin_3d;
+
+-- 4D
+CREATE INDEX brin_4d on test using brin (the_geom brin_geometry_inclusion_ops_4d);
+set enable_indexscan = off;
+set enable_bitmapscan = on;
+set enable_seqscan = off;
+
+SELECT 'scan_idx', qnodes('select * from test where the_geom && ''BOX(1 1, 5 5)''::box2d');
+ select 'mix_4d_box2d', num,ST_astext(the_geom) from test where the_geom && 'BOX(1 1, 5 5)'::box2d order by num;
+ select 'mix_4d_box3d', num,ST_astext(the_geom) from test where the_geom &&& 'BOX3D(1 1 0, 5 5 0)'::box3d order by num;
+
+DROP INDEX brin_4d;
+
 -- cleanup
 DROP TABLE test;
 DROP FUNCTION qnodes(text);
index 0c05fc68944cf41dfbced71be328d04329efc1a1..6cbaf089402eb7cb530b0e380322f8f01eca916c 100644 (file)
@@ -130,3 +130,44 @@ scan_idx|Bitmap Heap Scan,Bitmap Index Scan
 1260|POINT Z (126 126 126)
 scan_idx|Bitmap Heap Scan,Bitmap Index Scan
 20
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+2d|1
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+2d|20
+summarize 2d|8
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+2d|20
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+3d|1
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+3d|20
+summarize 3d|8
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+3d|20
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+4d|1
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+4d|20
+summarize 4d|8
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+4d|20
+scan_seq|Seq Scan
+mix_seq_box2d|1|POINT Z (1 1 2)
+mix_seq_box2d|2|POINT ZM (2 2 2 3)
+mix_seq_box2d|5|POINT(5 5)
+mix_seq_box3d|5|POINT(5 5)
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+mix_2d_box2d|1|POINT Z (1 1 2)
+mix_2d_box2d|2|POINT ZM (2 2 2 3)
+mix_2d_box2d|5|POINT(5 5)
+mix_2d_box3d|5|POINT(5 5)
+scan_idx|Seq Scan
+mix_3d_box2d|1|POINT Z (1 1 2)
+mix_3d_box2d|2|POINT ZM (2 2 2 3)
+mix_3d_box2d|5|POINT(5 5)
+mix_3d_box3d|5|POINT(5 5)
+scan_idx|Seq Scan
+mix_4d_box2d|1|POINT Z (1 1 2)
+mix_4d_box2d|2|POINT ZM (2 2 2 3)
+mix_4d_box2d|5|POINT(5 5)
+mix_4d_box3d|5|POINT(5 5)
index 009a0ae7d4fc1122231bd1335101d5cf0252cdec..7322b2930edb0c96ec45c6a0d546ab265eb01598 100644 (file)
@@ -38,3 +38,24 @@ scan_idx|Bitmap Heap Scan,Bitmap Index Scan
 2594|POINT(130.504303 126.53112)
 3618|POINT(130.447205 131.655289)
 7245|POINT(128.10466 130.94133)
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+2d|1
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+2d|20
+summarize 2d|8
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+2d|20
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+3d|1
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+3d|20
+summarize 3d|8
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+3d|20
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+4d|1
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+4d|20
+summarize 4d|8
+scan_idx|Bitmap Heap Scan,Bitmap Index Scan
+4d|20