[postgis-tickets] r15028 - Add support for BRIN indexes (2nd Quadrant, Giuseppe Broccolo, Julien Rouhaud)

Regina Obe lr at pcorp.us
Sat Jul 30 20:46:40 PDT 2016


Author: robe
Date: 2016-07-30 20:46:40 -0700 (Sat, 30 Jul 2016)
New Revision: 15028

Modified:
   trunk/NEWS
   trunk/configure.ac
   trunk/doc/reference_operator.xml
   trunk/doc/using_postgis_dataman.xml
   trunk/libpgcommon/gserialized_gist.c
   trunk/libpgcommon/gserialized_gist.h
   trunk/postgis/Makefile.in
   trunk/postgis/geography.sql.in
   trunk/postgis/gserialized_gist_2d.c
   trunk/postgis/gserialized_gist_nd.c
   trunk/postgis/postgis.sql.in
   trunk/regress/Makefile.in
   trunk/utils/postgis_proc_upgrade.pl
Log:
 Add support for BRIN indexes (2nd Quadrant, Giuseppe Broccolo, Julien Rouhaud)
Closes #3591
Closes https://github.com/postgis/postgis/pull/106

Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2016-07-30 17:39:39 UTC (rev 15027)
+++ trunk/NEWS	2016-07-31 03:46:40 UTC (rev 15028)
@@ -4,7 +4,7 @@
  * 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 @@
   - #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 *
 

Modified: trunk/configure.ac
===================================================================
--- trunk/configure.ac	2016-07-30 17:39:39 UTC (rev 15027)
+++ trunk/configure.ac	2016-07-31 03:46:40 UTC (rev 15028)
@@ -444,6 +444,11 @@
     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 @@
 
   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
 

Modified: trunk/doc/reference_operator.xml
===================================================================
--- trunk/doc/reference_operator.xml	2016-07-30 17:39:39 UTC (rev 15027)
+++ trunk/doc/reference_operator.xml	2016-07-31 03:46:40 UTC (rev 15028)
@@ -91,6 +91,204 @@
 		  </refsection>
 		</refentry>
 
+		<refentry id="overlaps_geometry_box2df">
+		  <refnamediv>
+			<refname>&&(geometry,box2df)</refname>
+
+			<refpurpose>Returns <varname>TRUE</varname> if a geometry's (cached) 2D bounding box intersects a 2D float precision bounding box (BOX2DF).</refpurpose>
+		  </refnamediv>
+
+		  <refsynopsisdiv>
+			<funcsynopsis>
+			  <funcprototype>
+				<funcdef>boolean <function>&&</function></funcdef>
+
+				<paramdef>
+				  <type>geometry </type>
+
+				  <parameter>A</parameter>
+				</paramdef>
+
+				<paramdef>
+				  <type>box2df</type>
+
+				  <parameter>B</parameter>
+				</paramdef>
+			  </funcprototype>
+			</funcsynopsis>
+		  </refsynopsisdiv>
+
+		  <refsection>
+			<title>Description</title>
+
+			<para>The <varname>&&</varname> operator returns <varname>TRUE</varname> 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)</para>
+
+			<note><para>This operand is intended to be used internally by BRIN indexes, more
+				than by users.</para></note>
+
+			<para>Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced.</para>
+			<para>&curve_support;</para>
+			<para>&P_support;</para>
+		  </refsection>
+
+		  <refsection>
+			<title>Examples</title>
+
+			<programlisting>SELECT ST_MakePoint(1,1) && ST_MakeBox2D(ST_MakePoint(0,0), ST_MakePoint(2,2)) AS overlaps;
+
+ overlaps
+----------
+ t
+(1 row)</programlisting>
+		  </refsection>
+
+		  <refsection>
+			<title>See Also</title>
+
+			<para>
+				<xref linkend="overlaps_box2df_geometry" />,
+				<xref linkend="overlaps_box2df_box2df" />,
+				<xref linkend="contains_geometry_box2df" />,
+				<xref linkend="contains_box2df_geometry" />,
+				<xref linkend="contains_box2df_box2df" />,
+				<xref linkend="is_contained_geometry_box2df" />,
+				<xref linkend="is_contained_box2df_geometry" />,
+				<xref linkend="is_contained_box2df_box2df" /></para>
+		  </refsection>
+		</refentry>
+
+		<refentry id="overlaps_box2df_geometry">
+		  <refnamediv>
+			<refname>&&(box2df,geometry)</refname>
+
+			<refpurpose>Returns <varname>TRUE</varname> if a 2D float precision bounding box (BOX2DF) intersects a geometry's (cached) 2D bounding box.</refpurpose>
+		  </refnamediv>
+
+		  <refsynopsisdiv>
+			<funcsynopsis>
+			  <funcprototype>
+				<funcdef>boolean <function>&&</function></funcdef>
+
+				<paramdef>
+				  <type>box2df </type>
+
+				  <parameter>A</parameter>
+				</paramdef>
+
+				<paramdef>
+				  <type>geometry </type>
+
+				  <parameter>B</parameter>
+				</paramdef>
+			  </funcprototype>
+			</funcsynopsis>
+		  </refsynopsisdiv>
+
+		  <refsection>
+			<title>Description</title>
+
+			<para>The <varname>&&</varname> operator returns <varname>TRUE</varname> 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)</para>
+
+			<note><para>This operand is intended to be used internally by BRIN indexes, more
+				than by users.</para></note>
+
+			<para>Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced.</para>
+			<para>&curve_support;</para>
+			<para>&P_support;</para>
+		  </refsection>
+
+		  <refsection>
+			<title>Examples</title>
+
+			<programlisting>SELECT ST_MakeBox2D(ST_MakePoint(0,0), ST_MakePoint(2,2)) && ST_MakePoint(1,1) AS overlaps;
+
+ overlaps
+----------
+ t
+(1 row)</programlisting>
+		  </refsection>
+
+		  <refsection>
+			<title>See Also</title>
+
+			<para>
+				<xref linkend="overlaps_geometry_box2df" />,
+				<xref linkend="overlaps_box2df_box2df" />,
+				<xref linkend="contains_geometry_box2df" />,
+				<xref linkend="contains_box2df_geometry" />,
+				<xref linkend="contains_box2df_box2df" />,
+				<xref linkend="is_contained_geometry_box2df" />,
+				<xref linkend="is_contained_box2df_geometry" />,
+				<xref linkend="is_contained_box2df_box2df" /></para>
+		  </refsection>
+		</refentry>
+
+		<refentry id="overlaps_box2df_box2df">
+		  <refnamediv>
+			<refname>&&(box2df,box2df)</refname>
+
+			<refpurpose>Returns <varname>TRUE</varname> if two 2D float precision bounding boxes (BOX2DF) intersect each other.</refpurpose>
+		  </refnamediv>
+
+		  <refsynopsisdiv>
+			<funcsynopsis>
+			  <funcprototype>
+				<funcdef>boolean <function>&&</function></funcdef>
+
+				<paramdef>
+				  <type>box2df </type>
+
+				  <parameter>A</parameter>
+				</paramdef>
+
+				<paramdef>
+				  <type>box2df </type>
+
+				  <parameter>B</parameter>
+				</paramdef>
+			  </funcprototype>
+			</funcsynopsis>
+		  </refsynopsisdiv>
+
+		  <refsection>
+			<title>Description</title>
+
+			<para>The <varname>&&</varname> operator returns <varname>TRUE</varname> 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)</para>
+
+			<note><para>This operator is intended to be used internally by BRIN indexes, more
+				than by users.</para></note>
+
+			<para>Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced.</para>
+			<para>&curve_support;</para>
+			<para>&P_support;</para>
+		  </refsection>
+
+		  <refsection>
+			<title>Examples</title>
+
+			<programlisting>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)</programlisting>
+		  </refsection>
+
+		  <refsection>
+			<title>See Also</title>
+
+			<para>
+				<xref linkend="overlaps_geometry_box2df" />,
+				<xref linkend="overlaps_box2df_geometry" />,
+				<xref linkend="contains_geometry_box2df" />,
+				<xref linkend="contains_box2df_geometry" />,
+				<xref linkend="contains_box2df_box2df" />,
+				<xref linkend="is_contained_geometry_box2df" />,
+				<xref linkend="is_contained_box2df_geometry" />,
+				<xref linkend="is_contained_box2df_box2df" /></para>
+		  </refsection>
+		</refentry>
+
 		<refentry id="geometry_overlaps_nd">
 		  <refnamediv>
 			<refname>&&&</refname>
@@ -177,6 +375,192 @@
 		  </refsection>
 		</refentry>
 
+		<refentry id="overlaps_nd_geometry_gidx">
+		  <refnamediv>
+			<refname>&&&(geometry,gidx)</refname>
+
+			<refpurpose>Returns <varname>TRUE</varname> if a geometry's (cached) n-D bounding box intersects a n-D float precision bounding box (GIDX).</refpurpose>
+		  </refnamediv>
+
+		  <refsynopsisdiv>
+			<funcsynopsis>
+			  <funcprototype>
+				<funcdef>boolean <function>&&&</function></funcdef>
+
+				<paramdef>
+				  <type>geometry </type>
+
+				  <parameter>A</parameter>
+				</paramdef>
+
+				<paramdef>
+				  <type>gidx </type>
+
+				  <parameter>B</parameter>
+				</paramdef>
+			  </funcprototype>
+			</funcsynopsis>
+		  </refsynopsisdiv>
+
+		  <refsection>
+			<title>Description</title>
+
+			<para>The <varname>&&&</varname> operator returns <varname>TRUE</varname> 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)</para>
+
+			<note><para>This operator is intended to be used internally by BRIN indexes, more
+				than by users.</para></note>
+
+			<para>Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced.</para>
+			<para>&curve_support;</para>
+			<para>&P_support;</para>
+			<para>&T_support;</para>
+			<para>&Z_support;</para>
+		  </refsection>
+
+		  <refsection>
+			<title>Examples</title>
+
+			<programlisting>SELECT ST_MakePoint(1,1,1) &&& ST_3DMakeBox(ST_MakePoint(0,0,0), ST_MakePoint(2,2,2)) AS overlaps;
+
+ overlaps
+----------
+ t
+(1 row)</programlisting>
+		  </refsection>
+
+		  <refsection>
+			<title>See Also</title>
+
+			<para>
+				<xref linkend="overlaps_nd_gidx_geometry" />,
+				<xref linkend="overlaps_nd_gidx_gidx" /></para>
+		  </refsection>
+		</refentry>
+
+		<refentry id="overlaps_nd_gidx_geometry">
+		  <refnamediv>
+			<refname>&&&(gidx,geometry)</refname>
+
+			<refpurpose>Returns <varname>TRUE</varname> if a n-D float precision bounding box (GIDX) intersects a geometry's (cached) n-D bounding box.</refpurpose>
+		  </refnamediv>
+
+		  <refsynopsisdiv>
+			<funcsynopsis>
+			  <funcprototype>
+				<funcdef>boolean <function>&&&</function></funcdef>
+
+				<paramdef>
+				  <type>gidx </type>
+
+				  <parameter>A</parameter>
+				</paramdef>
+
+				<paramdef>
+				  <type>geometry </type>
+
+				  <parameter>B</parameter>
+				</paramdef>
+			  </funcprototype>
+			</funcsynopsis>
+		  </refsynopsisdiv>
+
+		  <refsection>
+			<title>Description</title>
+
+			<para>The <varname>&&&</varname> operator returns <varname>TRUE</varname> 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)</para>
+
+			<note><para>This operator is intended to be used internally by BRIN indexes, more
+				than by users.</para></note>
+
+			<para>Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced.</para>
+			<para>&curve_support;</para>
+			<para>&P_support;</para>
+			<para>&T_support;</para>
+			<para>&Z_support;</para>
+		  </refsection>
+
+		  <refsection>
+			<title>Examples</title>
+
+			<programlisting>SELECT ST_3DMakeBox(ST_MakePoint(0,0,0), ST_MakePoint(2,2,2)) &&& ST_MakePoint(1,1,1) AS overlaps;
+
+ overlaps
+----------
+ t
+(1 row)</programlisting>
+		  </refsection>
+
+		  <refsection>
+			<title>See Also</title>
+
+			<para>
+				<xref linkend="overlaps_nd_geometry_gidx" />,
+				<xref linkend="overlaps_nd_gidx_gidx" /></para>
+		  </refsection>
+		</refentry>
+
+		<refentry id="overlaps_nd_gidx_gidx">
+		  <refnamediv>
+			<refname>&&&(gidx,gidx)</refname>
+
+			<refpurpose>Returns <varname>TRUE</varname> if two n-D float precision bounding boxes (GIDX) intersect each other.</refpurpose>
+		  </refnamediv>
+
+		  <refsynopsisdiv>
+			<funcsynopsis>
+			  <funcprototype>
+				<funcdef>boolean <function>&&&</function></funcdef>
+
+				<paramdef>
+				  <type>gidx </type>
+
+				  <parameter>A</parameter>
+				</paramdef>
+
+				<paramdef>
+				  <type>gidx </type>
+
+				  <parameter>B</parameter>
+				</paramdef>
+			  </funcprototype>
+			</funcsynopsis>
+		  </refsynopsisdiv>
+
+		  <refsection>
+			<title>Description</title>
+
+			<para>The <varname>&&&</varname> operator returns <varname>TRUE</varname> 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)</para>
+
+			<note><para>This operator is intended to be used internally by BRIN indexes, more
+				than by users.</para></note>
+
+			<para>Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced.</para>
+			<para>&curve_support;</para>
+			<para>&P_support;</para>
+			<para>&T_support;</para>
+			<para>&Z_support;</para>
+		  </refsection>
+
+		  <refsection>
+			<title>Examples</title>
+
+			<programlisting>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)</programlisting>
+		  </refsection>
+
+		  <refsection>
+			<title>See Also</title>
+
+			<para>
+                                <xref linkend="overlaps_nd_geometry_gidx" />,
+                                <xref linkend="overlaps_nd_gidx_geometry" /></para>
+		  </refsection>
+		</refentry>
+
 		<refentry id="ST_Geometry_Overleft">
 		  <refnamediv>
 			<refname>&<</refname>
@@ -786,6 +1170,204 @@
 		  </refsection>
 		</refentry>
 
+		<refentry id="is_contained_geometry_box2df">
+		  <refnamediv>
+			<refname>@(geometry,box2df)</refname>
+
+			<refpurpose>Returns <varname>TRUE</varname> if a geometry's 2D bounding box is contained into a 2D float precision bounding box (BOX2DF).</refpurpose>
+		  </refnamediv>
+
+		  <refsynopsisdiv>
+			<funcsynopsis>
+			  <funcprototype>
+				<funcdef>boolean <function>@</function></funcdef>
+
+				<paramdef>
+				  <type>geometry </type>
+
+				  <parameter>A</parameter>
+				</paramdef>
+
+				<paramdef>
+				  <type>box2df </type>
+
+				  <parameter>B</parameter>
+				</paramdef>
+			  </funcprototype>
+			</funcsynopsis>
+		  </refsynopsisdiv>
+
+		  <refsection>
+			<title>Description</title>
+
+			<para>The <varname>@</varname> operator returns <varname>TRUE</varname> 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)</para>
+
+			<note><para>This operand is intended to be used internally by BRIN indexes, more
+				than by users.</para></note>
+
+			<para>Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced.</para>
+			<para>&curve_support;</para>
+			<para>&P_support;</para>
+		  </refsection>
+
+		  <refsection>
+			<title>Examples</title>
+
+			<programlisting>SELECT ST_Buffer(ST_GeomFromText('POINT(2 2)'), 1) @ ST_MakeBox2D(ST_MakePoint(0,0), ST_MakePoint(5,5)) AS is_contained;
+
+ is_contained
+--------------
+ t
+(1 row)</programlisting>
+		  </refsection>
+
+		  <refsection>
+			<title>See Also</title>
+
+			<para>
+				<xref linkend="overlaps_geometry_box2df" />,
+				<xref linkend="overlaps_box2df_geometry" />,
+				<xref linkend="overlaps_box2df_box2df" />,
+				<xref linkend="contains_geometry_box2df" />,
+				<xref linkend="contains_box2df_geometry" />,
+				<xref linkend="contains_box2df_box2df" />,
+				<xref linkend="is_contained_box2df_geometry" />,
+				<xref linkend="is_contained_box2df_box2df" /></para>
+		  </refsection>
+		</refentry>
+
+		<refentry id="is_contained_box2df_geometry">
+		  <refnamediv>
+			<refname>@(box2df,geometry)</refname>
+
+			<refpurpose>Returns <varname>TRUE</varname> if a 2D float precision bounding box (BOX2DF) is contained into a geometry's 2D bounding box.</refpurpose>
+		  </refnamediv>
+
+		  <refsynopsisdiv>
+			<funcsynopsis>
+			  <funcprototype>
+				<funcdef>boolean <function>@</function></funcdef>
+
+				<paramdef>
+				  <type>box2df </type>
+
+				  <parameter>A</parameter>
+				</paramdef>
+
+				<paramdef>
+				  <type>geometry </type>
+
+				  <parameter>B</parameter>
+				</paramdef>
+			  </funcprototype>
+			</funcsynopsis>
+		  </refsynopsisdiv>
+
+		  <refsection>
+			<title>Description</title>
+
+			<para>The <varname>@</varname> operator returns <varname>TRUE</varname> 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)</para>
+
+			<note><para>This operand is intended to be used internally by BRIN indexes, more
+				than by users.</para></note>
+
+			<para>Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced.</para>
+			<para>&curve_support;</para>
+			<para>&P_support;</para>
+		  </refsection>
+
+		  <refsection>
+			<title>Examples</title>
+
+			<programlisting>SELECT ST_MakeBox2D(ST_MakePoint(2,2), ST_MakePoint(3,3)) @ ST_Buffer(ST_GeomFromText('POINT(1 1)'), 10) AS is_contained;
+
+ is_contained
+--------------
+ t
+(1 row)</programlisting>
+		  </refsection>
+
+		  <refsection>
+			<title>See Also</title>
+
+			<para>
+				<xref linkend="overlaps_geometry_box2df" />,
+				<xref linkend="overlaps_box2df_geometry" />,
+				<xref linkend="overlaps_box2df_box2df" />,
+				<xref linkend="contains_geometry_box2df" />,
+				<xref linkend="contains_box2df_geometry" />,
+				<xref linkend="contains_box2df_box2df" />,
+				<xref linkend="is_contained_geometry_box2df" />,
+				<xref linkend="is_contained_box2df_box2df" /></para>
+		  </refsection>
+		</refentry>
+
+		<refentry id="is_contained_box2df_box2df">
+		  <refnamediv>
+			<refname>@(box2df,box2df)</refname>
+
+			<refpurpose>Returns <varname>TRUE</varname> if a 2D float precision bounding box (BOX2DF) is contained into another 2D float precision bounding box.</refpurpose>
+		  </refnamediv>
+
+		  <refsynopsisdiv>
+			<funcsynopsis>
+			  <funcprototype>
+				<funcdef>boolean <function>@</function></funcdef>
+
+				<paramdef>
+				  <type>box2df </type>
+
+				  <parameter>A</parameter>
+				</paramdef>
+
+				<paramdef>
+				  <type>box2df </type>
+
+				  <parameter>B</parameter>
+				</paramdef>
+			  </funcprototype>
+			</funcsynopsis>
+		  </refsynopsisdiv>
+
+		  <refsection>
+			<title>Description</title>
+
+			<para>The <varname>@</varname> operator returns <varname>TRUE</varname> 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)</para>
+
+			<note><para>This operand is intended to be used internally by BRIN indexes, more
+				than by users.</para></note>
+
+			<para>Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced.</para>
+			<para>&curve_support;</para>
+			<para>&P_support;</para>
+		  </refsection>
+
+		  <refsection>
+			<title>Examples</title>
+
+			<programlisting>SELECT ST_MakeBox2D(ST_MakePoint(2,2), ST_MakePoint(3,3)) @ ST_MakeBox2D(ST_MakePoint(0,0), ST_MakePoint(5,5)) AS is_contained;
+
+ is_contained
+--------------
+ t
+(1 row)</programlisting>
+		  </refsection>
+
+		  <refsection>
+			<title>See Also</title>
+
+			<para>
+				<xref linkend="overlaps_geometry_box2df" />,
+				<xref linkend="overlaps_box2df_geometry" />,
+				<xref linkend="overlaps_box2df_box2df" />,
+				<xref linkend="contains_geometry_box2df" />,
+				<xref linkend="contains_box2df_geometry" />,
+				<xref linkend="contains_box2df_box2df" />,
+				<xref linkend="is_contained_geometry_box2df" />,
+				<xref linkend="is_contained_box2df_geometry" /></para>
+		  </refsection>
+		</refentry>
+
 		<refentry id="ST_Geometry_Overabove">
 		  <refnamediv>
 			<refname>|&></refname>
@@ -992,6 +1574,204 @@
 		  </refsection>
 		</refentry>
 
+		<refentry id="contains_geometry_box2df">
+		  <refnamediv>
+			<refname>~(geometry,box2df)</refname>
+
+			<refpurpose>Returns <varname>TRUE</varname> if a geometry's 2D bonding box contains a 2D float precision bounding box (GIDX).</refpurpose>
+		  </refnamediv>
+
+		  <refsynopsisdiv>
+			<funcsynopsis>
+			  <funcprototype>
+				<funcdef>boolean <function>~</function></funcdef>
+
+				<paramdef>
+				  <type>geometry </type>
+
+				  <parameter>A</parameter>
+				</paramdef>
+
+				<paramdef>
+				  <type>box2df </type>
+
+				  <parameter>B</parameter>
+				</paramdef>
+			  </funcprototype>
+			</funcsynopsis>
+		  </refsynopsisdiv>
+
+		  <refsection>
+			<title>Description</title>
+
+			<para>The <varname>~</varname> operator returns <varname>TRUE</varname> 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)</para>
+
+			<note><para>This operand is intended to be used internally by BRIN indexes, more
+				than by users.</para></note>
+
+			<para>Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced.</para>
+			<para>&curve_support;</para>
+			<para>&P_support;</para>
+		  </refsection>
+
+		  <refsection>
+			<title>Examples</title>
+
+			<programlisting>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)</programlisting>
+		  </refsection>
+
+		  <refsection>
+			<title>See Also</title>
+
+			<para>
+				<xref linkend="overlaps_geometry_box2df" />,
+				<xref linkend="overlaps_box2df_geometry" />,
+				<xref linkend="overlaps_box2df_box2df" />,
+				<xref linkend="contains_box2df_geometry" />,
+				<xref linkend="contains_box2df_box2df" />,
+				<xref linkend="is_contained_geometry_box2df" />,
+				<xref linkend="is_contained_box2df_geometry" />,
+				<xref linkend="is_contained_box2df_box2df" /></para>
+		  </refsection>
+		</refentry>
+
+		<refentry id="contains_box2df_geometry">
+		  <refnamediv>
+			<refname>~(box2df,geometry)</refname>
+
+			<refpurpose>Returns <varname>TRUE</varname> if a 2D float precision bounding box (BOX2DF) contains a geometry's 2D bonding box.</refpurpose>
+		  </refnamediv>
+
+		  <refsynopsisdiv>
+			<funcsynopsis>
+			  <funcprototype>
+				<funcdef>boolean <function>~</function></funcdef>
+
+				<paramdef>
+				  <type>box2df </type>
+
+				  <parameter>A</parameter>
+				</paramdef>
+
+				<paramdef>
+				  <type>geometry </type>
+
+				  <parameter>B</parameter>
+				</paramdef>
+			  </funcprototype>
+			</funcsynopsis>
+		  </refsynopsisdiv>
+
+		  <refsection>
+			<title>Description</title>
+
+			<para>The <varname>~</varname> operator returns <varname>TRUE</varname> 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)</para>
+
+			<note><para>This operand is intended to be used internally by BRIN indexes, more
+				than by users.</para></note>
+
+			<para>Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced.</para>
+			<para>&curve_support;</para>
+			<para>&P_support;</para>
+		  </refsection>
+
+		  <refsection>
+			<title>Examples</title>
+
+			<programlisting>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)</programlisting>
+		  </refsection>
+
+		  <refsection>
+			<title>See Also</title>
+
+			<para>
+				<xref linkend="overlaps_geometry_box2df" />,
+				<xref linkend="overlaps_box2df_geometry" />,
+				<xref linkend="overlaps_box2df_box2df" />,
+				<xref linkend="contains_geometry_box2df" />,
+				<xref linkend="contains_box2df_box2df" />,
+				<xref linkend="is_contained_geometry_box2df" />,
+				<xref linkend="is_contained_box2df_geometry" />,
+				<xref linkend="is_contained_box2df_box2df" /></para>
+		  </refsection>
+		</refentry>
+
+		<refentry id="contains_box2df_box2df">
+		  <refnamediv>
+			<refname>~(box2df,box2df)</refname>
+
+			<refpurpose>Returns <varname>TRUE</varname> if a 2D float precision bounding box (BOX2DF) contains another 2D float precision bounding box (BOX2DF).</refpurpose>
+		  </refnamediv>
+
+		  <refsynopsisdiv>
+			<funcsynopsis>
+			  <funcprototype>
+				<funcdef>boolean <function>~</function></funcdef>
+
+				<paramdef>
+				  <type>box2df </type>
+
+				  <parameter>A</parameter>
+				</paramdef>
+
+				<paramdef>
+				  <type>box2df </type>
+
+				  <parameter>B</parameter>
+				</paramdef>
+			  </funcprototype>
+			</funcsynopsis>
+		  </refsynopsisdiv>
+
+		  <refsection>
+			<title>Description</title>
+
+			<para>The <varname>~</varname> operator returns <varname>TRUE</varname> 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)</para>
+
+			<note><para>This operand is intended to be used internally by BRIN indexes, more
+				than by users.</para></note>
+
+			<para>Availability: 2.3.0 support for Block Range INdexes (BRIN) was introduced.</para>
+			<para>&curve_support;</para>
+			<para>&P_support;</para>
+		  </refsection>
+
+		  <refsection>
+			<title>Examples</title>
+
+			<programlisting>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)</programlisting>
+		  </refsection>
+
+		  <refsection>
+			<title>See Also</title>
+
+			<para>
+				<xref linkend="overlaps_geometry_box2df" />,
+				<xref linkend="overlaps_box2df_geometry" />,
+				<xref linkend="overlaps_box2df_box2df" />,
+				<xref linkend="contains_geometry_box2df" />,
+				<xref linkend="contains_box2df_geometry" />,
+				<xref linkend="is_contained_geometry_box2df" />,
+				<xref linkend="is_contained_box2df_geometry" />,
+				<xref linkend="is_contained_box2df_box2df" /></para>
+		  </refsection>
+		</refentry>
+
 		<refentry id="ST_Geometry_Same">
 		  <refnamediv>
 			<refname>~=</refname>

Modified: trunk/doc/using_postgis_dataman.xml
===================================================================
--- trunk/doc/using_postgis_dataman.xml	2016-07-30 17:39:39 UTC (rev 15027)
+++ trunk/doc/using_postgis_dataman.xml	2016-07-31 03:46:40 UTC (rev 15028)
@@ -2178,6 +2178,72 @@
 	  built.</para>
 	</sect2>
 
+	<sect2 id="brin_indexes">
+	  <title>BRIN Indexes</title>
+
+	  <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
+	  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).</para>
+
+	  <para>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. </para>
+
+      <para>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.</para>
+
+	  <para>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.</para>
+
+      <para>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.</para>
+
+	  <para>The syntax for building a BRIN index on a "geometry" column is as
+	  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>
+	  <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>Also the "geography" datatype is supported for BRIN indexing. The
+          syntax for building a BRIN index on a "geometry" 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>
+
+          <para>Currently, just the "inclusion support" is considered here, meaning
+          that just <varname>&&</varname>, <varname>~</varname> and
+          <varname>@</varname> operators can be used for the 2D cases (both for
+          "geometry" and for "geography"), and just the <varname>&&&</varname>
+          operator can be used for the 3D geometries. There is no support
+          for kNN searches at the moment.</para>
+
+	  <para><programlisting>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]);</programlisting></para>
+	</sect2>
+
 	<sect2>
 	  <title>Using Indexes</title>
 

Modified: trunk/libpgcommon/gserialized_gist.c
===================================================================
--- trunk/libpgcommon/gserialized_gist.c	2016-07-30 17:39:39 UTC (rev 15027)
+++ trunk/libpgcommon/gserialized_gist.c	2016-07-31 03:46:40 UTC (rev 15028)
@@ -374,6 +374,7 @@
 {
 	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;

Modified: trunk/libpgcommon/gserialized_gist.h
===================================================================
--- trunk/libpgcommon/gserialized_gist.h	2016-07-30 17:39:39 UTC (rev 15027)
+++ trunk/libpgcommon/gserialized_gist.h	2016-07-31 03:46:40 UTC (rev 15028)
@@ -24,6 +24,7 @@
 ** 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 @@
 /* Remove the box from a disk serialization */
 GSERIALIZED* gserialized_drop_gidx(GSERIALIZED *g);
 
+int gserialized_datum_get_box2df_p(Datum gsdatum, BOX2DF *box2df);
 
 

Modified: trunk/postgis/Makefile.in
===================================================================
--- trunk/postgis/Makefile.in	2016-07-30 17:39:39 UTC (rev 15027)
+++ trunk/postgis/Makefile.in	2016-07-31 03:46:40 UTC (rev 15028)
@@ -46,6 +46,9 @@
 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 @@
 	gserialized_typmod.o \
 	gserialized_gist_2d.o \
 	gserialized_gist_nd.o \
+	$(BRIN_OBJ) \
 	gserialized_estimate.o \
 	geography_inout.o \
 	geography_btree.o \

Modified: trunk/postgis/geography.sql.in
===================================================================
--- trunk/postgis/geography.sql.in	2016-07-30 17:39:39 UTC (rev 15027)
+++ trunk/postgis/geography.sql.in	2016-07-31 03:46:40 UTC (rev 15028)
@@ -286,7 +286,94 @@
 	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
 -- For sorting and grouping

Modified: trunk/postgis/gserialized_gist_2d.c
===================================================================
--- trunk/postgis/gserialized_gist_2d.c	2016-07-30 17:39:39 UTC (rev 15027)
+++ trunk/postgis/gserialized_gist_2d.c	2016-07-31 03:46:40 UTC (rev 15028)
@@ -116,6 +116,15 @@
 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 @@
 * 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,10 +630,86 @@
 	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
 */
 

Modified: trunk/postgis/gserialized_gist_nd.c
===================================================================
--- trunk/postgis/gserialized_gist_nd.c	2016-07-30 17:39:39 UTC (rev 15027)
+++ trunk/postgis/gserialized_gist_nd.c	2016-07-31 03:46:40 UTC (rev 15028)
@@ -100,8 +100,20 @@
 */
 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 @@
 	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,7 +861,37 @@
 	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,7 +906,57 @@
 	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 @@
 	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
 */

Modified: trunk/postgis/postgis.sql.in
===================================================================
--- trunk/postgis/postgis.sql.in	2016-07-30 17:39:39 UTC (rev 15027)
+++ trunk/postgis/postgis.sql.in	2016-07-31 03:46:40 UTC (rev 15028)
@@ -746,7 +746,6 @@
 	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,11 +5545,301 @@
 	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
 ---------------------------------------------------------------

Modified: trunk/regress/Makefile.in
===================================================================
--- trunk/regress/Makefile.in	2016-07-30 17:39:39 UTC (rev 15027)
+++ trunk/regress/Makefile.in	2016-07-31 03:46:40 UTC (rev 15028)
@@ -23,6 +23,7 @@
 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 @@
 		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 += \

Modified: trunk/utils/postgis_proc_upgrade.pl
===================================================================
--- trunk/utils/postgis_proc_upgrade.pl	2016-07-30 17:39:39 UTC (rev 15027)
+++ trunk/utils/postgis_proc_upgrade.pl	2016-07-31 03:46:40 UTC (rev 15028)
@@ -390,6 +390,37 @@
 		}
 	}
 
+	# 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(<INPUT>)
+		{
+			$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 )
 	{



More information about the postgis-tickets mailing list