]> granicus.if.org Git - postgis/commitdiff
GiST and SP-GiST n-D indexes (based on GIDX) with overlaps, contains, within, and...
authorDarafei Praliaskouski <me@komzpa.net>
Sun, 11 Nov 2018 10:39:57 +0000 (10:39 +0000)
committerDarafei Praliaskouski <me@komzpa.net>
Sun, 11 Nov 2018 10:39:57 +0000 (10:39 +0000)
Patch by Esteban Zimányi and Arthur Lesuisse from Université Libre de Bruxelles (ULB)

Closes https://github.com/postgis/postgis/pull/327
Closes https://github.com/postgis/postgis/pull/293
Closes #4230

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

12 files changed:
.travis.yml
NEWS
configure.ac
libpgcommon/gserialized_gist.h
postgis/Makefile.in
postgis/gserialized_gist_nd.c
postgis/lwgeom_box3d.c
postgis/postgis.sql.in
postgis/postgis_spgist.sql.in
regress/core/Makefile.in
regress/core/operators.sql
regress/core/operators_expected

index 262c73c0eafee2156af3264bc1466cfa756e20c0..0cb00034b829e6a3da507ef7cbcf67b0544979ab 100644 (file)
@@ -9,8 +9,7 @@ env:
   - tag=pg11-geos37-gdal23-proj52
   - tag=pg10-geos36-gdal23-proj49
   - tag=pg96-geos36-gdal22-proj49
-  - tag=pg95-geos36-gdal22-proj49
-  - tag=pg94-geos35-gdal111-proj48
+  - tag=pg95-geos35-gdal111-proj48
 
 matrix:
   allow_failures:
diff --git a/NEWS b/NEWS
index 4d70a3ed35ee35748f2473dd1cbac1d8abb03a9c..79b676b0d2ea22ace24e6cd787f627964998c4e3 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,33 +2,39 @@ PostGIS 3.0.0
 2019/xx/xx
 * Breaking Changes *
   - #3888, Raster support now available as a separate extension
-    (Sandro Santilli)
+           (Sandro Santilli)
   - #3807, Extension library files no longer include the minor version.
-        Use New configure switch --with-library-minor-version
-        if you need the old behavior (Regina Obe)
+           Use New configure switch --with-library-minor-version
+           if you need the old behavior (Regina Obe)
+  - #4230, ND box operators (overlaps, contains, within, equals) now don't look on
+           dimentions that aren't present in both operands.
+           Please REINDEX your ND indexes after upgrade.
 
 * New Features *
   - #2902, postgis_geos_noop (Sandro Santilli)
   - #4128, ST_AsMVT support for Feature ID (Stepan Kuzmin)
+  - #4230, SP-GiST and GiST support for ND box operators overlaps, contains,
+           within, equals (Esteban Zimányi and Arthur Lesuisse from Université
+           Libre de Bruxelles (ULB), Darafei Praliaskouski)
 
 * Enhancements and fixes *
   - #4153, ST_Segmentize now splits segments proportionally (Darafei
-    Praliaskouski).
+           Praliaskouski).
   - #4162, ST_DWithin documentation examples for storing geometry and
-    radius in table (Darafei Praliaskouski, github user Boscop).
+           radius in table (Darafei Praliaskouski, github user Boscop).
   - #4161, MVT: Drop geometries smaller than the resolution (Raúl Marín)
   - #4176, ST_Intersects supports GEOMETRYCOLLECTION (Darafei Praliaskouski)
   - #4181, St_AsMVTGeom: Avoid type changes due to validation (Raúl Marín)
   - #4183, St_AsMVTGeom: Drop invalid geometries after simplification (Raúl Marín)
-  - #4188, Avoid division by zero in kmeans (Raúl Marín)
+  - #4188, Avoid division by zero in KMeans (Raúl Marín)
   - #4189, Fix undefined behaviour in SADFWrite (Raúl Marín)
   - #4191, Fix undefined behaviour in ptarray_clone_deep (Raúl Marín)
   - #4211, Fix ST_Subdivide for minimal exterior ring with minimal hole (Darafei
-    Praliaskouski)
+           Praliaskouski)
   - #3457, Fix raster envelope shortcut in ST_Clip (Sai-bot)
   - #4215, Use floating point compare in ST_DumpAsPolygons (Darafei Praliaskouski)
   - #4155, Support for GEOMETRYCOLLECTION, POLYGON, TIN, TRIANGLE in
-    ST_LocateBetween and ST_LocateBetweenElevations (Darafei Praliaskouski)
+           ST_LocateBetween and ST_LocateBetweenElevations (Darafei Praliaskouski)
   - #2767, Documentation for AddRasterConstraint optional parameters (Sunveer Singh)
 
 PostGIS 2.5.0
@@ -39,9 +45,9 @@ PostgreSQL 9.4 - PostgreSQL 12 (in development)
 GEOS >= 3.5
 
 * New Features *
-  - #1847, spgist 2d and 3d support for PG 11+
-    (Esteban Zimányi and Arthur Lesuisse from Université Libre de Bruxelles (ULB),
-      Darafei Praliaskouski)
+  - #1847, SP-GiST 2D and 3D support for PostgreSQL 11+ (Esteban Zimányi and
+           Arthur Lesuisse from Université Libre de Bruxelles (ULB), Darafei
+           Praliaskouski)
   - #4056, ST_FilterByM (Nicklas Avén)
   - #4050, ST_ChaikinSmoothing (Nicklas Avén)
   - #3989, ST_Buffer single sided option (Stephen Knox)
@@ -62,7 +68,7 @@ GEOS >= 3.5
 * Breaking Changes *
   - #4054, ST_SimplifyVW changed from > tolerance to >= tolerance
   - #3885, version number removed from address_standardize lib file
-          (Regina Obe)
+           (Regina Obe)
   - #3893, raster support functions can only be loaded in the same schema
            with core PostGIS functions. (Sandro Santilli)
   - #4035, remove dummy pgis_abs type from aggregate/collect routines.
index 2ef7eaeb1551c8ff7d0dc54b16d94a169913e27d..cdfa41800f1ba68c86bbd8278c5de214e30d4968 100644 (file)
@@ -483,9 +483,9 @@ if test "x$LIBLWGEOM_ONLY" = "xno"; then
   PGSQL_SHAREDIR=`"$PG_CONFIG" --sharedir`
 
   AC_MSG_RESULT([checking PostgreSQL version... $PGSQL_FULL_VERSION])
-  dnl Ensure that we are using PostgreSQL >= 9.4
-  if test $POSTGIS_PGSQL_VERSION -lt 94; then
-    AC_MSG_ERROR([PostGIS requires PostgreSQL >= 9.4])
+  dnl Ensure that we are using PostgreSQL >= 9.5
+  if test $POSTGIS_PGSQL_VERSION -lt 95; then
+    AC_MSG_ERROR([PostGIS requires PostgreSQL >= 9.5])
   fi
 
   HAVE_BRIN=no
index cfbced06784a2ca0050bd5e4f8dc3522fefe4138..0efba3c536a8884f8edac1ce52b9a2cf05aee067 100644 (file)
@@ -26,15 +26,15 @@ typedef struct
 #define GIDX_MAX_SIZE 36
 #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)) \
+       do \
+       { \
+               if ((Pointer)(ptrsrc) != (Pointer)(ptrori)) \
                        pfree(ptrsrc); \
        } while (0)
 
@@ -51,7 +51,6 @@ typedef struct
        float xmin, xmax, ymin, ymax;
 } BOX2DF;
 
-
 /*********************************************************************************
 ** GIDX support functions.
 **
@@ -61,7 +60,7 @@ typedef struct
 */
 
 /* allocate a new gidx object on the heap */
-GIDX* gidx_new(int ndims) ;
+GIDX *gidx_new(int ndims);
 
 /* Increase the size of a GIDX */
 void gidx_expand(GIDX *a, float d);
@@ -70,7 +69,7 @@ void gidx_expand(GIDX *a, float d);
 bool gidx_is_unknown(const GIDX *a);
 
 /* Generate human readable form for GIDX. */
-char* gidx_to_string(GIDX *a) ;
+char *gidx_to_string(GIDX *a);
 
 /* typedef to correct array-bounds checking for casts to GIDX - do not
    use this ANYWHERE except in the casts below */
@@ -79,24 +78,24 @@ typedef float _gidx_float_array[sizeof(float) * 2 * 4];
 /* Returns number of dimensions for this GIDX */
 #define GIDX_NDIMS(gidx) ((VARSIZE((gidx)) - VARHDRSZ) / (2 * sizeof(float)))
 /* Minimum accessor. */
-#define GIDX_GET_MIN(gidx, dimension) (*((_gidx_float_array *)(&(gidx)->c)))[2*(dimension)]
+#define GIDX_GET_MIN(gidx, dimension) (*((_gidx_float_array *)(&(gidx)->c)))[2 * (dimension)]
 /* Maximum accessor. */
-#define GIDX_GET_MAX(gidx, dimension) (*((_gidx_float_array *)(&(gidx)->c)))[2*(dimension)+1]
+#define GIDX_GET_MAX(gidx, dimension) (*((_gidx_float_array *)(&(gidx)->c)))[2 * (dimension) + 1]
 /* Minimum setter. */
-#define GIDX_SET_MIN(gidx, dimension, value) ((gidx)->c[2*(dimension)] = (value))
+#define GIDX_SET_MIN(gidx, dimension, value) ((gidx)->c[2 * (dimension)] = (value))
 /* Maximum setter. */
-#define GIDX_SET_MAX(gidx, dimension, value) ((gidx)->c[2*(dimension)+1] = (value))
+#define GIDX_SET_MAX(gidx, dimension, value) ((gidx)->c[2 * (dimension) + 1] = (value))
 /* Returns the size required to store a GIDX of requested dimension */
-#define GIDX_SIZE(dimensions) (sizeof(int32) + 2*(dimensions)*sizeof(float))
+#define GIDX_SIZE(dimensions) (sizeof(int32) + 2 * (dimensions) * sizeof(float))
 
 /* Allocate a copy of the box */
-BOX2DFbox2df_copy(BOX2DF *b);
+BOX2DF *box2df_copy(BOX2DF *b);
 
 /* Grow the first argument to contain the second */
 void box2df_merge(BOX2DF *b_union, BOX2DF *b_new);
 
 /* Allocate a copy of the box */
-GIDXgidx_copy(GIDX *b);
+GIDX *gidx_copy(GIDX *b);
 
 /* Grow the first argument to contain the second */
 void gidx_merge(GIDX **b_union, GIDX *b_new);
@@ -122,16 +121,14 @@ int gserialized_datum_get_gidx_p(Datum gserialized_datum, GIDX *gidx);
 /* Pull out the gidx bounding box from an already de-toasted geography */
 int gserialized_get_gidx_p(const GSERIALIZED *g, GIDX *gidx);
 /* Copy a new bounding box into an existing gserialized */
-GSERIALIZEDgserialized_set_gidx(GSERIALIZED *g, GIDX *gidx);
+GSERIALIZED *gserialized_set_gidx(GSERIALIZED *g, GIDX *gidx);
 
 /* Given two datums, do they overlap? Computed very fast using embedded boxes. */
 /* int gserialized_datum_overlaps(Datum gs1, Datum gs2); */
 /* Remove the box from a disk serialization */
-GSERIALIZEDgserialized_drop_gidx(GSERIALIZED *g);
+GSERIALIZED *gserialized_drop_gidx(GSERIALIZED *g);
 
 bool box2df_contains(const BOX2DF *a, const BOX2DF *b);
-
-
 void box2df_set_empty(BOX2DF *a);
 void box2df_set_finite(BOX2DF *a);
 void box2df_validate(BOX2DF *b);
@@ -146,7 +143,9 @@ bool box2df_below(const BOX2DF *a, const BOX2DF *b);
 bool box2df_above(const BOX2DF *a, const BOX2DF *b);
 bool box2df_overabove(const BOX2DF *a, const BOX2DF *b);
 
-
+void gidx_validate(GIDX *b);
+void gidx_set_unknown(GIDX *a);
+bool gidx_overlaps(GIDX *a, GIDX *b);
+bool gidx_equals(GIDX *a, GIDX *b);
 bool gidx_contains(GIDX *a, GIDX *b);
 int gserialized_datum_get_box2df_p(Datum gsdatum, BOX2DF *box2df);
-
index 49736eec3dae76879e297e956d2fda361d4310c2..f32fd9db050171b65135f71af696fc7f631552d9 100644 (file)
@@ -61,7 +61,7 @@ BRIN_OBJ= brin_2d.o brin_nd.o brin_common.o
 endif
 
 ifeq (@HAVE_SPGIST@,yes)
-SPGIST_OBJ= gserialized_spgist_2d.o gserialized_spgist_3d.o
+SPGIST_OBJ= gserialized_spgist_2d.o gserialized_spgist_3d.o gserialized_spgist_nd.o
 endif
 
 ifeq (@HAVE_PROTOBUF@,yes)
index a33dc0d693a902d00c9969b09db8710035d5318f..9916983deba553ca713fb95e3918a289111a12df 100644 (file)
@@ -23,7 +23,6 @@
  *
  **********************************************************************/
 
-
 /*
 ** R-Tree Bibliography
 **
 */
 
 #include "postgres.h"
-#include "access/gist.h"    /* For GiST */
+#include "access/gist.h" /* For GiST */
 #include "access/itup.h"
 #include "access/skey.h"
 
 #include "../postgis_config.h"
 
-/*#define POSTGIS_DEBUG_LEVEL 4*/
-
-#include "liblwgeom.h"         /* For standard geometry types. */
-#include "lwgeom_pg.h"       /* For debugging macros. */
-#include "gserialized_gist.h"       /* For utility functions. */
+#include "liblwgeom.h"        /* For standard geometry types. */
+#include "lwgeom_pg.h"        /* For debugging macros. */
+#include "gserialized_gist.h" /* For utility functions. */
 #include "geography.h"
 
 #include <assert.h>
 
-
 /* Fall back to older finite() if necessary */
 #ifndef HAVE_ISFINITE
-# ifdef HAVE_GNU_ISFINITE
-#  define _GNU_SOURCE
-# else
-#  define isfinite finite
-# endif
+#ifdef HAVE_GNU_ISFINITE
+#define _GNU_SOURCE
+#else
+#define isfinite finite
+#endif
 #endif
 
 /*
@@ -100,52 +96,49 @@ Datum gserialized_gist_geog_distance(PG_FUNCTION_ARGS);
 ** ND Operator prototypes
 */
 Datum gserialized_overlaps(PG_FUNCTION_ARGS);
+Datum gserialized_gidx_geom_overlaps(PG_FUNCTION_ARGS);
+Datum gserialized_gidx_gidx_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_same(PG_FUNCTION_ARGS);
 Datum gserialized_gidx_geom_same(PG_FUNCTION_ARGS);
 Datum gserialized_gidx_gidx_same(PG_FUNCTION_ARGS);
-#endif
+Datum gserialized_distance_nd(PG_FUNCTION_ARGS);
 
 /*
 ** GIDX true/false test function type
 */
 typedef bool (*gidx_predicate)(GIDX *a, GIDX *b);
 
-
 /* Allocate a new copy of GIDX */
-GIDX* gidx_copy(GIDX *b)
+GIDX *
+gidx_copy(GIDX *b)
 {
-       GIDX *c = (GIDX*)palloc(VARSIZE(b));
+       GIDX *c = (GIDX *)palloc(VARSIZE(b));
        POSTGIS_DEBUGF(5, "copied gidx (%p) to gidx (%p)", b, c);
-       memcpy((void*)c, (void*)b, VARSIZE(b));
+       memcpy((void *)c, (void *)b, VARSIZE(b));
        return c;
 }
 
-
 /* Ensure all minimums are below maximums. */
-static inline void gidx_validate(GIDX *b)
+void
+gidx_validate(GIDX *b)
 {
        uint32_t i;
        Assert(b);
-       POSTGIS_DEBUGF(5,"validating gidx (%s)", gidx_to_string(b));
-       for ( i = 0; i < GIDX_NDIMS(b); i++ )
+       POSTGIS_DEBUGF(5, "validating gidx (%s)", gidx_to_string(b));
+       for (i = 0; i < GIDX_NDIMS(b); i++)
        {
-               if ( GIDX_GET_MIN(b,i) > GIDX_GET_MAX(b,i) )
+               if (GIDX_GET_MIN(b, i) > GIDX_GET_MAX(b, i))
                {
                        float tmp;
-                       tmp = GIDX_GET_MIN(b,i);
-                       GIDX_SET_MIN(b,i,GIDX_GET_MAX(b,i));
-                       GIDX_SET_MAX(b,i,tmp);
+                       tmp = GIDX_GET_MIN(b, i);
+                       GIDX_SET_MIN(b, i, GIDX_GET_MAX(b, i));
+                       GIDX_SET_MAX(b, i, tmp);
                }
        }
        return;
@@ -154,23 +147,26 @@ static inline void gidx_validate(GIDX *b)
 /* An "unknown" GIDX is used to represent the bounds of an EMPTY
    geometry or other-wise unindexable geometry (like one with NaN
    or Inf bounds) */
-inline bool gidx_is_unknown(const GIDX *a)
+inline bool
+gidx_is_unknown(const GIDX *a)
 {
        size_t size = VARSIZE(a) - VARHDRSZ;
        /* "unknown" gidx objects have a too-small size of one float */
-       if ( size <= 0.0 )
+       if (size <= 0.0)
                return true;
        return false;
 }
 
-static inline void gidx_set_unknown(GIDX *a)
+void
+gidx_set_unknown(GIDX *a)
 {
        SET_VARSIZE(a, VARHDRSZ);
 }
 
 /* Enlarge b_union to contain b_new. If b_new contains more
    dimensions than b_union, expand b_union to contain those dimensions. */
-void gidx_merge(GIDX **b_union, GIDX *b_new)
+void
+gidx_merge(GIDX **b_union, GIDX *b_new)
 {
        int i, dims_union, dims_new;
        Assert(b_union);
@@ -178,11 +174,11 @@ void gidx_merge(GIDX **b_union, GIDX *b_new)
        Assert(b_new);
 
        /* Can't merge an unknown into any thing */
-       if( gidx_is_unknown(b_new) )
+       if (gidx_is_unknown(b_new))
                return;
 
        /* Merge of unknown and known is known */
-       if( gidx_is_unknown(*b_union) )
+       if (gidx_is_unknown(*b_union))
        {
                *b_union = b_new;
                return;
@@ -193,20 +189,20 @@ void gidx_merge(GIDX **b_union, GIDX *b_new)
 
        POSTGIS_DEBUGF(4, "merging gidx (%s) into gidx (%s)", gidx_to_string(b_new), gidx_to_string(*b_union));
 
-       if ( dims_new > dims_union )
+       if (dims_new > dims_union)
        {
                POSTGIS_DEBUGF(5, "reallocating b_union from %d dims to %d dims", dims_union, dims_new);
-               *b_union = (GIDX*)repalloc(*b_union, GIDX_SIZE(dims_new));
+               *b_union = (GIDX *)repalloc(*b_union, GIDX_SIZE(dims_new));
                SET_VARSIZE(*b_union, VARSIZE(b_new));
                dims_union = dims_new;
        }
 
-       for ( i = 0; i < dims_new; i++ )
+       for (i = 0; i < dims_new; i++)
        {
                /* Adjust minimums */
-               GIDX_SET_MIN(*b_union, i, Min(GIDX_GET_MIN(*b_union,i),GIDX_GET_MIN(b_new,i)));
+               GIDX_SET_MIN(*b_union, i, Min(GIDX_GET_MIN(*b_union, i), GIDX_GET_MIN(b_new, i)));
                /* Adjust maximums */
-               GIDX_SET_MAX(*b_union, i, Max(GIDX_GET_MAX(*b_union,i),GIDX_GET_MAX(b_new,i)));
+               GIDX_SET_MAX(*b_union, i, Max(GIDX_GET_MAX(*b_union, i), GIDX_GET_MAX(b_new, i)));
        }
 
        POSTGIS_DEBUGF(5, "merge complete (%s)", gidx_to_string(*b_union));
@@ -214,42 +210,40 @@ void gidx_merge(GIDX **b_union, GIDX *b_new)
 }
 
 /* Calculate the volume (in n-d units) of the GIDX */
-static float gidx_volume(GIDX *a)
+static float
+gidx_volume(GIDX *a)
 {
        float result;
        uint32_t i;
-       if ( a == NULL || gidx_is_unknown(a) )
-       {
-               /* elog(ERROR, "gidx_volume received a null argument"); */
+       if (!a || gidx_is_unknown(a))
                return 0.0;
-       }
-       result = GIDX_GET_MAX(a,0) - GIDX_GET_MIN(a,0);
-       for ( i = 1; i < GIDX_NDIMS(a); i++ )
-               result *= (GIDX_GET_MAX(a,i) - GIDX_GET_MIN(a,i));
+       result = GIDX_GET_MAX(a, 0) - GIDX_GET_MIN(a, 0);
+       for (i = 1; i < GIDX_NDIMS(a); i++)
+               result *= (GIDX_GET_MAX(a, i) - GIDX_GET_MIN(a, i));
        POSTGIS_DEBUGF(5, "calculated volume of %s as %.8g", gidx_to_string(a), result);
        return result;
 }
 
 /* Calculate the edge of the GIDX */
-static float gidx_edge(GIDX *a)
+static float
+gidx_edge(GIDX *a)
 {
        float result;
        uint32_t i;
-       if ( a == NULL || gidx_is_unknown(a) )
-       {
+       if (!a || gidx_is_unknown(a))
                return 0.0;
-       }
-       result = GIDX_GET_MAX(a,0) - GIDX_GET_MIN(a,0);
-       for ( i = 1; i < GIDX_NDIMS(a); i++ )
-               result += (GIDX_GET_MAX(a,i) - GIDX_GET_MIN(a,i));
+       result = GIDX_GET_MAX(a, 0) - GIDX_GET_MIN(a, 0);
+       for (i = 1; i < GIDX_NDIMS(a); i++)
+               result += (GIDX_GET_MAX(a, i) - GIDX_GET_MIN(a, i));
        POSTGIS_DEBUGF(5, "calculated edge of %s as %.8g", gidx_to_string(a), result);
        return result;
 }
 
 /* Ensure the first argument has the higher dimensionality. */
-static void gidx_dimensionality_check(GIDX **a, GIDX **b)
+static void
+gidx_dimensionality_check(GIDX **a, GIDX **b)
 {
-       if ( GIDX_NDIMS(*a) < GIDX_NDIMS(*b) )
+       if (GIDX_NDIMS(*a) < GIDX_NDIMS(*b))
        {
                GIDX *tmp = *b;
                *b = *a;
@@ -258,30 +252,29 @@ static void gidx_dimensionality_check(GIDX **a, GIDX **b)
 }
 
 /* Calculate the volume of the union of the boxes. Avoids creating an intermediate box. */
-static float gidx_union_volume(GIDX *a, GIDX *b)
+static float
+gidx_union_volume(GIDX *a, GIDX *b)
 {
        float result;
        int i;
        int ndims_a, ndims_b;
 
-       POSTGIS_DEBUG(5,"entered function");
+       POSTGIS_DEBUG(5, "entered function");
 
-       if ( a == NULL && b == NULL )
+       if (!a && !b)
        {
                elog(ERROR, "gidx_union_volume received two null arguments");
                return 0.0;
        }
 
-       if ( a == NULL || gidx_is_unknown(a) )
+       if (!a || gidx_is_unknown(a))
                return gidx_volume(b);
 
-       if ( b == NULL || gidx_is_unknown(b) )
+       if (!b || gidx_is_unknown(b))
                return gidx_volume(a);
 
-       if ( gidx_is_unknown(a) && gidx_is_unknown(b) )
-       {
+       if (gidx_is_unknown(a) && gidx_is_unknown(b))
                return 0.0;
-       }
 
        /* Ensure 'a' has the most dimensions. */
        gidx_dimensionality_check(&a, &b);
@@ -290,19 +283,15 @@ static float gidx_union_volume(GIDX *a, GIDX *b)
        ndims_b = GIDX_NDIMS(b);
 
        /* Initialize with maximal length of first dimension. */
-       result = Max(GIDX_GET_MAX(a,0),GIDX_GET_MAX(b,0)) - Min(GIDX_GET_MIN(a,0),GIDX_GET_MIN(b,0));
+       result = Max(GIDX_GET_MAX(a, 0), GIDX_GET_MAX(b, 0)) - Min(GIDX_GET_MIN(a, 0), GIDX_GET_MIN(b, 0));
 
        /* Multiply by maximal length of remaining dimensions. */
-       for ( i = 1; i < ndims_b; i++ )
-       {
-               result *= (Max(GIDX_GET_MAX(a,i),GIDX_GET_MAX(b,i)) - Min(GIDX_GET_MIN(a,i),GIDX_GET_MIN(b,i)));
-       }
+       for (i = 1; i < ndims_b; i++)
+               result *= (Max(GIDX_GET_MAX(a, i), GIDX_GET_MAX(b, i)) - Min(GIDX_GET_MIN(a, i), GIDX_GET_MIN(b, i)));
 
        /* Add in dimensions of higher dimensional box. */
-       for ( i = ndims_b; i < ndims_a; i++ )
-       {
-               result *= (GIDX_GET_MAX(a,i) - GIDX_GET_MIN(a,i));
-       }
+       for (i = ndims_b; i < ndims_a; i++)
+               result *= (GIDX_GET_MAX(a, i) - GIDX_GET_MIN(a, i));
 
        POSTGIS_DEBUGF(5, "volume( %s union %s ) = %.12g", gidx_to_string(a), gidx_to_string(b), result);
 
@@ -310,30 +299,29 @@ static float gidx_union_volume(GIDX *a, GIDX *b)
 }
 
 /* Calculate the edge of the union of the boxes. Avoids creating an intermediate box. */
-static float gidx_union_edge(GIDX *a, GIDX *b)
+static float
+gidx_union_edge(GIDX *a, GIDX *b)
 {
        float result;
        int i;
        int ndims_a, ndims_b;
 
-       POSTGIS_DEBUG(5,"entered function");
+       POSTGIS_DEBUG(5, "entered function");
 
-       if ( a == NULL && b == NULL )
+       if (!a && !b)
        {
                elog(ERROR, "gidx_union_edge received two null arguments");
                return 0.0;
        }
 
-       if ( a == NULL || gidx_is_unknown(a) )
+       if (!a || gidx_is_unknown(a))
                return gidx_volume(b);
 
-       if ( b == NULL || gidx_is_unknown(b) )
+       if (!b || gidx_is_unknown(b))
                return gidx_volume(a);
 
-       if ( gidx_is_unknown(a) && gidx_is_unknown(b) )
-       {
+       if (gidx_is_unknown(a) && gidx_is_unknown(b))
                return 0.0;
-       }
 
        /* Ensure 'a' has the most dimensions. */
        gidx_dimensionality_check(&a, &b);
@@ -342,19 +330,15 @@ static float gidx_union_edge(GIDX *a, GIDX *b)
        ndims_b = GIDX_NDIMS(b);
 
        /* Initialize with maximal length of first dimension. */
-       result = Max(GIDX_GET_MAX(a,0),GIDX_GET_MAX(b,0)) - Min(GIDX_GET_MIN(a,0),GIDX_GET_MIN(b,0));
+       result = Max(GIDX_GET_MAX(a, 0), GIDX_GET_MAX(b, 0)) - Min(GIDX_GET_MIN(a, 0), GIDX_GET_MIN(b, 0));
 
        /* Add maximal length of remaining dimensions. */
-       for ( i = 1; i < ndims_b; i++ )
-       {
-               result += (Max(GIDX_GET_MAX(a,i),GIDX_GET_MAX(b,i)) - Min(GIDX_GET_MIN(a,i),GIDX_GET_MIN(b,i)));
-       }
+       for (i = 1; i < ndims_b; i++)
+               result += (Max(GIDX_GET_MAX(a, i), GIDX_GET_MAX(b, i)) - Min(GIDX_GET_MIN(a, i), GIDX_GET_MIN(b, i)));
 
        /* Add in dimensions of higher dimensional box. */
-       for ( i = ndims_b; i < ndims_a; i++ )
-       {
-               result += (GIDX_GET_MAX(a,i) - GIDX_GET_MIN(a,i));
-       }
+       for (i = ndims_b; i < ndims_a; i++)
+               result += (GIDX_GET_MAX(a, i) - GIDX_GET_MIN(a, i));
 
        POSTGIS_DEBUGF(5, "edge( %s union %s ) = %.12g", gidx_to_string(a), gidx_to_string(b), result);
 
@@ -362,38 +346,39 @@ static float gidx_union_edge(GIDX *a, GIDX *b)
 }
 
 /* Calculate the volume of the intersection of the boxes. */
-static float gidx_inter_volume(GIDX *a, GIDX *b)
+static float
+gidx_inter_volume(GIDX *a, GIDX *b)
 {
        uint32_t i;
        float result;
 
-       POSTGIS_DEBUG(5,"entered function");
+       POSTGIS_DEBUG(5, "entered function");
 
-       if ( a == NULL || b == NULL )
+       if (!a || !b)
        {
                elog(ERROR, "gidx_inter_volume received a null argument");
                return 0.0;
        }
 
-       if ( gidx_is_unknown(a) || gidx_is_unknown(b) )
-       {
+       if (gidx_is_unknown(a) || gidx_is_unknown(b))
                return 0.0;
-       }
 
        /* Ensure 'a' has the most dimensions. */
        gidx_dimensionality_check(&a, &b);
 
        /* Initialize with minimal length of first dimension. */
-       result = Min(GIDX_GET_MAX(a,0),GIDX_GET_MAX(b,0)) - Max(GIDX_GET_MIN(a,0),GIDX_GET_MIN(b,0));
+       result = Min(GIDX_GET_MAX(a, 0), GIDX_GET_MAX(b, 0)) - Max(GIDX_GET_MIN(a, 0), GIDX_GET_MIN(b, 0));
 
        /* If they are disjoint (max < min) then return zero. */
-       if ( result < 0.0 ) return 0.0;
+       if (result < 0.0)
+               return 0.0;
 
        /* Continue for remaining dimensions. */
-       for ( i = 1; i < GIDX_NDIMS(b); i++ )
+       for (i = 1; i < GIDX_NDIMS(b); i++)
        {
-               float width = Min(GIDX_GET_MAX(a,i),GIDX_GET_MAX(b,i)) - Max(GIDX_GET_MIN(a,i),GIDX_GET_MIN(b,i));
-               if ( width < 0.0 ) return 0.0;
+               float width = Min(GIDX_GET_MAX(a, i), GIDX_GET_MAX(b, i)) - Max(GIDX_GET_MIN(a, i), GIDX_GET_MIN(b, i));
+               if (width < 0.0)
+                       return 0.0;
                /* Multiply by minimal length of remaining dimensions. */
                result *= width;
        }
@@ -414,29 +399,34 @@ static float gidx_inter_volume(GIDX *a, GIDX *b)
 **
 ** Empty boxes never overlap.
 */
-static bool gidx_overlaps(GIDX *a, GIDX *b)
+bool
+gidx_overlaps(GIDX *a, GIDX *b)
 {
-       int i;
-       int ndims_b;
-       POSTGIS_DEBUG(5, "entered function");
+       int i, dims_a, dims_b;
 
-       if ( (a == NULL) || (b == NULL) ) return false;
+       POSTGIS_DEBUG(5, "entered function");
 
-       if ( gidx_is_unknown(a) || gidx_is_unknown(b) )
+       if (!a || !b)
                return false;
 
-       /* Ensure 'a' has the most dimensions. */
-       gidx_dimensionality_check(&a, &b);
+       if (gidx_is_unknown(a) || gidx_is_unknown(b))
+               return false;
 
-       ndims_b = GIDX_NDIMS(b);
+       dims_a = GIDX_NDIMS(a);
+       dims_b = GIDX_NDIMS(b);
 
-       /* compare only up to dimensions of (b), missing dimensions always overlap */
-       for ( i = 0; i < ndims_b; i++ )
+       /* For all shared dimensions min(a) > max(b) and min(b) > max(a)
+          Unshared dimensions do not matter */
+       for (i = 0; i < Min(dims_a, dims_b); i++)
        {
-               if ( GIDX_GET_MIN(a,i) > GIDX_GET_MAX(b,i) )
-                       return false;
-               if ( GIDX_GET_MIN(b,i) > GIDX_GET_MAX(a,i) )
-                       return false;
+               /* If the missing dimension was not padded with -+FLT_MAX */
+               if (GIDX_GET_MAX(a, i) != FLT_MAX && GIDX_GET_MAX(b, i) != FLT_MAX)
+               {
+                       if (GIDX_GET_MIN(a, i) > GIDX_GET_MAX(b, i))
+                               return false;
+                       if (GIDX_GET_MIN(b, i) > GIDX_GET_MAX(a, i))
+                               return false;
+               }
        }
 
        return true;
@@ -447,44 +437,34 @@ 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)
 */
-bool gidx_contains(GIDX *a, GIDX *b)
+bool
+gidx_contains(GIDX *a, GIDX *b)
 {
-       int i, dims_a, dims_b;
+       uint32_t i, dims_a, dims_b;
 
-       POSTGIS_DEBUG(5, "entered function");
-
-       if ( (a == NULL) || (b == NULL) ) return false;
+       if (!a || !b)
+               return false;
 
-       if ( gidx_is_unknown(a) || gidx_is_unknown(b) )
+       if (gidx_is_unknown(a) || gidx_is_unknown(b))
                return false;
 
        dims_a = GIDX_NDIMS(a);
        dims_b = GIDX_NDIMS(b);
 
-       if ( dims_a < dims_b )
+       /* For all shared dimensions min(a) > min(b) and max(a) < max(b)
+          Unshared dimensions do not matter */
+       for (i = 0; i < Min(dims_a, dims_b); i++)
        {
-               /*
-               ** If (b) is of higher dimensionality than (a) it can only be contained
-               ** if those higher dimensions are zeroes.
-               */
-               for (i = dims_a; i < dims_b; i++)
+               /* If the missing dimension was not padded with -+FLT_MAX */
+               if (GIDX_GET_MAX(a, i) != FLT_MAX && GIDX_GET_MAX(b, i) != FLT_MAX)
                {
-                       if ( GIDX_GET_MIN(b,i) != 0 )
+                       if (GIDX_GET_MIN(a, i) > GIDX_GET_MIN(b, i))
                                return false;
-                       if ( GIDX_GET_MAX(b,i) != 0 )
+                       if (GIDX_GET_MAX(a, i) < GIDX_GET_MAX(b, i))
                                return false;
                }
        }
 
-       /* Excess dimensions of (a), don't matter, it just has to contain (b) in (b)'s dimensions */
-       for (i = 0; i < Min(dims_a, dims_b); i++)
-       {
-               if ( GIDX_GET_MIN(a,i) > GIDX_GET_MIN(b,i) )
-                       return false;
-               if ( GIDX_GET_MAX(a,i) < GIDX_GET_MAX(b,i) )
-                       return false;
-       }
-
        return true;
 }
 
@@ -493,63 +473,60 @@ bool gidx_contains(GIDX *a, GIDX *b)
 **
 ** Box(A) EQUALS Box(B) IFF (pt(A)LL == pt(B)LL) && (pt(A)UR == pt(B)UR)
 */
-static bool gidx_equals(GIDX *a, GIDX *b)
+bool
+gidx_equals(GIDX *a, GIDX *b)
 {
-       uint32_t i;
+       uint32_t i, dims_a, dims_b;
 
-       POSTGIS_DEBUG(5, "entered function");
-
-       if ( (a == NULL) && (b == NULL) ) return true;
-       if ( (a == NULL) || (b == NULL) ) return false;
+       if (!a && !b)
+               return true;
+       if (!a || !b)
+               return false;
 
-       if ( gidx_is_unknown(a) && gidx_is_unknown(b) )
+       if (gidx_is_unknown(a) && gidx_is_unknown(b))
                return true;
 
-       if ( gidx_is_unknown(a) || gidx_is_unknown(b) )
+       if (gidx_is_unknown(a) || gidx_is_unknown(b))
                return false;
 
-       /* Ensure 'a' has the most dimensions. */
-       gidx_dimensionality_check(&a, &b);
+       dims_a = GIDX_NDIMS(a);
+       dims_b = GIDX_NDIMS(b);
 
-       /* For all shared dimensions min(a) == min(b), max(a) == max(b) */
-       for (i = 0; i < GIDX_NDIMS(b); i++)
-       {
-               if ( GIDX_GET_MIN(a,i) != GIDX_GET_MIN(b,i) )
-                       return false;
-               if ( GIDX_GET_MAX(a,i) != GIDX_GET_MAX(b,i) )
-                       return false;
-       }
-       /* For all unshared dimensions min(a) == 0.0, max(a) == 0.0 */
-       for (i = GIDX_NDIMS(b); i < GIDX_NDIMS(a); i++)
+       /* For all shared dimensions min(a) == min(b), max(a) == max(b)
+          Unshared dimensions do not matter */
+       for (i = 0; i < Min(dims_a, dims_b); i++)
        {
-               if ( GIDX_GET_MIN(a,i) != 0.0 )
-                       return false;
-               if ( GIDX_GET_MAX(a,i) != 0.0 )
-                       return false;
+               /* If the missing dimension was not padded with -+FLT_MAX */
+               if (GIDX_GET_MAX(a, i) != FLT_MAX && GIDX_GET_MAX(b, i) != FLT_MAX)
+               {
+                       if (GIDX_GET_MIN(a, i) != GIDX_GET_MIN(b, i))
+                               return false;
+                       if (GIDX_GET_MAX(a, i) != GIDX_GET_MAX(b, i))
+                               return false;
+               }
        }
        return true;
 }
 
 /**
-* Support function. Based on two datums return true if
-* they satisfy the predicate and false otherwise.
-*/
+ * Support function. Based on two datums return true if
+ * they satisfy the predicate and false otherwise.
+ */
 static int
 gserialized_datum_predicate(Datum gs1, Datum gs2, gidx_predicate predicate)
 {
        /* Put aside some stack memory and use it for GIDX pointers. */
        char boxmem1[GIDX_MAX_SIZE];
        char boxmem2[GIDX_MAX_SIZE];
-       GIDX *gidx1 = (GIDX*)boxmem1;
-       GIDX *gidx2 = (GIDX*)boxmem2;
+       GIDX *gidx1 = (GIDX *)boxmem1;
+       GIDX *gidx2 = (GIDX *)boxmem2;
 
        POSTGIS_DEBUG(3, "entered function");
 
        /* Must be able to build box for each arguement (ie, not empty geometry)
           and predicate function to return true. */
-       if ( (gserialized_datum_get_gidx_p(gs1, gidx1) == LW_SUCCESS) &&
-            (gserialized_datum_get_gidx_p(gs2, gidx2) == LW_SUCCESS) &&
-             predicate(gidx1, gidx2) )
+       if ((gserialized_datum_get_gidx_p(gs1, gidx1) == LW_SUCCESS) &&
+           (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;
@@ -557,187 +534,98 @@ 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;
+       /* 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
+       /* 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");
 
-/**
-* Calculate the centroid->centroid distance between the boxes.
-*/
-#if POSTGIS_PGSQL_VERSION < 95
-static double gidx_distance_leaf_centroid(const GIDX *a, const GIDX *b)
-{
-  int ndims, i;
-  double sum = 0;
-
-  /* Base computation on least available dimensions */
-  ndims = Min(GIDX_NDIMS(b), GIDX_NDIMS(a));
-  for ( i = 0; i < ndims; ++i )
-  {
-    double ca, cb, d;
-    double amin = GIDX_GET_MIN(a,i);
-    double amax = GIDX_GET_MAX(a,i);
-    double bmin = GIDX_GET_MIN(b,i);
-    double bmax = GIDX_GET_MAX(b,i);
-    ca = amin + ( ( amax - amin ) / 2.0 );
-    cb = bmin + ( ( bmax - bmin ) / 2.0 );
-    d = ca - cb;
-    if ( ! isfinite(d) )
-    {
-      /* Can happen if a dimension was padded with FLT_MAX,
-       * effectively meaning "infinite range". In that case
-       * we take that dimension as adding 0 to the total
-       * distance.
-       */
-      continue;
-    }
-    sum += d * d;
-/*
-    POSTGIS_DEBUGF(3, " centroid of A for dimension %d is %g", i, ca);
-    POSTGIS_DEBUGF(3, " centroid of B for dimension %d is %g", i, cb);
-    POSTGIS_DEBUGF(3, " distance on dimension %d is %g, squared as %g, grows sum to %g", i, d, d*d, sum);
-*/
-  }
-  return sqrt(sum);
+       /* 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 box->box distance.
-*/
-static double gidx_distance(const GIDX *a, const GIDX *b, int m_is_time)
-{
-  int ndims, i;
-  double sum = 0;
-
-  /* Base computation on least available dimensions */
-  ndims = Min(GIDX_NDIMS(b), GIDX_NDIMS(a));
-  for ( i = 0; i < ndims; ++i )
-  {
-    double d;
-    double amin = GIDX_GET_MIN(a,i);
-    double amax = GIDX_GET_MAX(a,i);
-    double bmin = GIDX_GET_MIN(b,i);
-    double bmax = GIDX_GET_MAX(b,i);
-    POSTGIS_DEBUGF(3, "A %g - %g", amin, amax);
-    POSTGIS_DEBUGF(3, "B %g - %g", bmin, bmax);
-
-    if ( ( amin <= bmax && amax >= bmin ) )
-    {
-      /* overlaps */
-      d = 0;
-    }
-    else if ( i == 4 && m_is_time )
-    {
-      return FLT_MAX;
-    }
-    else if ( bmax < amin )
-    {
-      /* is "left" */
-      d = amin - bmax;
-    }
-    else
-    {
-      /* is "right" */
-      assert( bmin > amax );
-      d = bmin - amax;
-    }
-    if ( ! isfinite(d) )
-    {
-      /* Can happen if coordinates are corrupted/NaN */
-      continue;
-    }
-    sum += d * d;
-    POSTGIS_DEBUGF(3, "dist %g, squared %g, grows sum to %g", d, d*d, sum);
-  }
-  return sqrt(sum);
-}
-
-#if POSTGIS_PGSQL_VERSION < 95
-static double gidx_distance_node_centroid(const GIDX *node, const GIDX *query)
+ * Calculate the box->box distance.
+ */
+static double
+gidx_distance(const GIDX *a, const GIDX *b, int m_is_time)
 {
-       int i;
+       int ndims, i;
        double sum = 0;
 
        /* Base computation on least available dimensions */
-       int ndims = Min(GIDX_NDIMS(node), GIDX_NDIMS(query));
-
-       for ( i = 0; i < ndims; ++i )
+       ndims = Min(GIDX_NDIMS(b), GIDX_NDIMS(a));
+       for (i = 0; i < ndims; ++i)
        {
                double d;
-               double amin = GIDX_GET_MIN(query,i);
-               double amax = GIDX_GET_MAX(query,i);
-               double bmin = GIDX_GET_MIN(node,i);
-               double bmax = GIDX_GET_MAX(node,i);
-               double ca = amin + ( ( amax - amin ) / 2.0 );
-
-               if ( ( ca <= bmax && ca >= bmin ) )
+               double amin = GIDX_GET_MIN(a, i);
+               double amax = GIDX_GET_MAX(a, i);
+               double bmin = GIDX_GET_MIN(b, i);
+               double bmax = GIDX_GET_MAX(b, i);
+               POSTGIS_DEBUGF(3, "A %g - %g", amin, amax);
+               POSTGIS_DEBUGF(3, "B %g - %g", bmin, bmax);
+
+               if ((amin <= bmax && amax >= bmin))
                {
                        /* overlaps */
                        d = 0;
                }
-               else if ( bmax < ca )
+               else if (i == 4 && m_is_time)
+               {
+                       return FLT_MAX;
+               }
+               else if (bmax < amin)
                {
                        /* is "left" */
-                       d = ca - bmax;
+                       d = amin - bmax;
                }
                else
                {
                        /* is "right" */
-                       assert( bmin > ca );
-                       d = bmin - ca;
+                       assert(bmin > amax);
+                       d = bmin - amax;
                }
-               if ( ! isfinite(d) )
+               if (!isfinite(d))
                {
                        /* Can happen if coordinates are corrupted/NaN */
                        continue;
                }
                sum += d * d;
-               POSTGIS_DEBUGF(3, "dist %g, squared %g, grows sum to %g", d, d*d, sum);
+               POSTGIS_DEBUGF(3, "dist %g, squared %g, grows sum to %g", d, d * d, sum);
        }
        return sqrt(sum);
 }
-#else /* POSTGIS_PGSQL_VERSION >= 95 */
-static double gidx_distance_m(const GIDX *a, const GIDX *b)
+
+static double
+gidx_distance_m(const GIDX *a, const GIDX *b)
 {
        int mdim_a, mdim_b;
        double d, amin, amax, bmin, bmax;
@@ -746,48 +634,45 @@ static double gidx_distance_m(const GIDX *a, const GIDX *b)
        mdim_a = GIDX_NDIMS(a) - 1;
        mdim_b = GIDX_NDIMS(b) - 1;
 
-       amin = GIDX_GET_MIN(a,mdim_a);
-       amax = GIDX_GET_MAX(a,mdim_a);
-       bmin = GIDX_GET_MIN(b,mdim_b);
-       bmax = GIDX_GET_MAX(b,mdim_b);
-
-    if ( ( amin <= bmax && amax >= bmin ) )
-    {
-      /* overlaps */
-      d = 0;
-    }
-    else if ( bmax < amin )
-    {
-      /* is "left" */
-      d = amin - bmax;
-    }
-    else
-    {
-      /* is "right" */
-      assert( bmin > amax );
-      d = bmin - amax;
-    }
+       amin = GIDX_GET_MIN(a, mdim_a);
+       amax = GIDX_GET_MAX(a, mdim_a);
+       bmin = GIDX_GET_MIN(b, mdim_b);
+       bmax = GIDX_GET_MAX(b, mdim_b);
+
+       if ((amin <= bmax && amax >= bmin))
+       {
+               /* overlaps */
+               d = 0;
+       }
+       else if (bmax < amin)
+       {
+               /* is "left" */
+               d = amin - bmax;
+       }
+       else
+       {
+               /* is "right" */
+               assert(bmin > amax);
+               d = bmin - amax;
+       }
 
        return d;
 }
-#endif /* POSTGIS_PGSQL_VERSION >= 96 */
 
 /**
-* Return a #GSERIALIZED with an expanded bounding box.
-*/
-GSERIALIZED*
+ * Return a #GSERIALIZED with an expanded bounding box.
+ */
+GSERIALIZED *
 gserialized_expand(GSERIALIZED *g, double distance)
 {
        char boxmem[GIDX_MAX_SIZE];
-       GIDX *gidx = (GIDX*)boxmem;
+       GIDX *gidx = (GIDX *)boxmem;
        float fdistance = (float)distance;
 
        /* Get our bounding box out of the geography, return right away if
           input is an EMPTY geometry. */
-       if ( gserialized_get_gidx_p(g, gidx) == LW_FAILURE )
-       {
+       if (gserialized_get_gidx_p(g, gidx) == LW_FAILURE)
                return g;
-       }
 
        gidx_expand(gidx, fdistance);
 
@@ -795,39 +680,19 @@ gserialized_expand(GSERIALIZED *g, double distance)
 }
 
 /***********************************************************************
-* GiST N-D Index Operator Functions
-*/
+ * GiST N-D Index Operator Functions
+ */
 
 /*
-* Do centroid to centroid n-d distance if you don't have
-* re-check available (PgSQL 9.5+), do "real" n-d distance
-* if you do
-*/
+ * do "real" n-d distance
+ */
 PG_FUNCTION_INFO_V1(gserialized_distance_nd);
 Datum gserialized_distance_nd(PG_FUNCTION_ARGS)
 {
        char b1mem[GIDX_MAX_SIZE];
-       GIDX *b1 = (GIDX*)b1mem;
+       GIDX *b1 = (GIDX *)b1mem;
        char b2mem[GIDX_MAX_SIZE];
-       GIDX *b2 = (GIDX*)b2mem;
-
-#if POSTGIS_PGSQL_VERSION < 95
-
-       /* Centroid-to-centroid distance */
-       Datum gs1 = PG_GETARG_DATUM(0);
-       Datum gs2 = PG_GETARG_DATUM(1);
-       double box_distance = FLT_MAX;
-
-       /* Must be able to build box for each argument (ie, not empty geometry). */
-       if ( (gserialized_datum_get_gidx_p(gs1, b1) == LW_SUCCESS) &&
-            (gserialized_datum_get_gidx_p(gs2, b2) == LW_SUCCESS) )
-       {
-               box_distance = gidx_distance_leaf_centroid(b1, b2);
-               POSTGIS_DEBUGF(3, "got boxes %s and %s", gidx_to_string(b1), gidx_to_string(b2));
-       }
-       PG_RETURN_FLOAT8(box_distance);
-
-#else /* POSTGIS_PGSQL_VERSION >= 96 */
+       GIDX *b2 = (GIDX *)b2mem;
 
        /* Feature-to-feature distance */
        GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
@@ -837,9 +702,8 @@ Datum gserialized_distance_nd(PG_FUNCTION_ARGS)
        LWGEOM *closest;
        double distance;
 
-
        /* Find an exact shortest line w/ the dimensions we support */
-       if ( lwgeom_has_z(lw1) && lwgeom_has_z(lw2) )
+       if (lwgeom_has_z(lw1) && lwgeom_has_z(lw2))
        {
                closest = lwgeom_closest_line_3d(lw1, lw2);
                distance = lwgeom_length(closest);
@@ -850,235 +714,236 @@ Datum gserialized_distance_nd(PG_FUNCTION_ARGS)
                distance = lwgeom_length_2d(closest);
        }
 
-       /* Un-sqrt the distance so we can add extra terms */
-       distance = distance*distance;
-
        /* Can only add the M term if both objects have M */
-       if ( lwgeom_has_m(lw1) && lwgeom_has_m(lw2) )
+       if (lwgeom_has_m(lw1) && lwgeom_has_m(lw2))
        {
                double m1, m2;
                int usebox = false;
+               /* Un-sqrt the distance so we can add extra terms */
+               distance = distance * distance;
 
-               if ( lwgeom_get_type(lw1) == POINTTYPE )
+               if (lwgeom_get_type(lw1) == POINTTYPE)
                {
                        POINT4D p;
-                       lwpoint_getPoint4d_p((LWPOINT*)lw1, &p);
+                       lwpoint_getPoint4d_p((LWPOINT *)lw1, &p);
                        m1 = p.m;
                }
-               else if ( lwgeom_get_type(lw1) == LINETYPE )
+               else if (lwgeom_get_type(lw1) == LINETYPE)
                {
                        LWPOINT *lwp1 = lwline_get_lwpoint(lwgeom_as_lwline(closest), 0);
                        m1 = lwgeom_interpolate_point(lw1, lwp1);
                        lwpoint_free(lwp1);
                }
                else
-               {
                        usebox = true;
-               }
 
-               if ( lwgeom_get_type(lw2) == POINTTYPE )
+               if (lwgeom_get_type(lw2) == POINTTYPE)
                {
                        POINT4D p;
-                       lwpoint_getPoint4d_p((LWPOINT*)lw2, &p);
+                       lwpoint_getPoint4d_p((LWPOINT *)lw2, &p);
                        m2 = p.m;
                }
-               else if ( lwgeom_get_type(lw2) == LINETYPE )
+               else if (lwgeom_get_type(lw2) == LINETYPE)
                {
                        LWPOINT *lwp2 = lwline_get_lwpoint(lwgeom_as_lwline(closest), 1);
                        m2 = lwgeom_interpolate_point(lw2, lwp2);
                        lwpoint_free(lwp2);
                }
                else
-               {
                        usebox = true;
-               }
 
-               if ( usebox )
+               if (usebox)
                {
                        double d;
                        gserialized_get_gidx_p(geom1, b1);
                        gserialized_get_gidx_p(geom2, b2);
                        d = gidx_distance_m(b1, b2);
-                       distance += d*d;
+                       distance += d * d;
                }
                else
-               {
-                       distance += (m2-m1)*(m2-m1);
-               }
+                       distance += (m2 - m1) * (m2 - m1);
+
+               distance = sqrt(distance);
        }
 
        lwgeom_free(closest);
 
        PG_FREE_IF_COPY(geom1, 0);
        PG_FREE_IF_COPY(geom2, 1);
-       PG_RETURN_FLOAT8(sqrt(distance));
-#endif /* POSTGIS_PGSQL_VERSION >= 96 */
+       PG_RETURN_FLOAT8(distance);
 }
 
 /*
-** '~' and operator function. Based on two serialized return true if
+** '~~' and operator function. Based on two serialized return true if
 ** the first is contained by the second.
 */
 PG_FUNCTION_INFO_V1(gserialized_within);
 Datum gserialized_within(PG_FUNCTION_ARGS)
 {
-       if ( gserialized_datum_predicate(PG_GETARG_DATUM(1), PG_GETARG_DATUM(0), gidx_contains) == LW_TRUE )
-       {
+       if (gserialized_datum_predicate(PG_GETARG_DATUM(1), PG_GETARG_DATUM(0), gidx_contains))
                PG_RETURN_BOOL(true);
-       }
 
        PG_RETURN_BOOL(false);
 }
 
 #if POSTGIS_PGSQL_VERSION > 94
 /*
-** '~' and operator function. Based on a GIDX and a serialized return true if
+** '~~' 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);
+       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);
+       if (gserialized_datum_predicate_geom_gidx(PG_GETARG_DATUM(1), gidx, gidx_contains))
+               PG_RETURN_BOOL(true);
 
-   PG_RETURN_BOOL(false);
+       PG_RETURN_BOOL(false);
 }
 
 /*
-** '~' and operator function. Based on two GIDX return true if
+** '~~' 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);
+       if (gidx_contains((GIDX *)PG_GETARG_POINTER(1), (GIDX *)PG_GETARG_POINTER(0)))
+               PG_RETURN_BOOL(true);
 
-   PG_RETURN_BOOL(false);
+       PG_RETURN_BOOL(false);
 }
 #endif
 
 /*
-** '@' and operator function. Based on two serialized return true if
+** '@@' and operator function. Based on two serialized return true if
 ** the first contains the second.
 */
 PG_FUNCTION_INFO_V1(gserialized_contains);
 Datum gserialized_contains(PG_FUNCTION_ARGS)
 {
-       if ( gserialized_datum_predicate(PG_GETARG_DATUM(0),PG_GETARG_DATUM(1), gidx_contains) == LW_TRUE )
-       {
+       if (gserialized_datum_predicate(PG_GETARG_DATUM(0), PG_GETARG_DATUM(1), gidx_contains))
                PG_RETURN_BOOL(true);
-       }
 
        PG_RETURN_BOOL(false);
 }
 
-#if POSTGIS_PGSQL_VERSION > 94
 /*
-** '@' and operator function. Based on a GIDX and a serialized return true if
+** '@@' 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);
+       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);
+       if (gserialized_datum_predicate_gidx_geom(gidx, PG_GETARG_DATUM(1), gidx_contains))
+               PG_RETURN_BOOL(true);
 
-   PG_RETURN_BOOL(false);
+       PG_RETURN_BOOL(false);
 }
 
 /*
-** '@' and operator function. Based on two GIDX return true if
+** '@@' 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);
+       if (gidx_contains((GIDX *)PG_GETARG_POINTER(0), (GIDX *)PG_GETARG_POINTER(1)))
+               PG_RETURN_BOOL(true);
 
-   PG_RETURN_BOOL(false);
+       PG_RETURN_BOOL(false);
+}
+
+/*
+** '~=' and operator function. Based on two serialized return true if
+** the first equals the second.
+*/
+PG_FUNCTION_INFO_V1(gserialized_same);
+Datum gserialized_same(PG_FUNCTION_ARGS)
+{
+       if (gserialized_datum_predicate(PG_GETARG_DATUM(0), PG_GETARG_DATUM(1), gidx_equals))
+               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);
+       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);
+       if (gserialized_datum_predicate_gidx_geom(gidx, PG_GETARG_DATUM(1), gidx_equals))
+               PG_RETURN_BOOL(true);
 
-   PG_RETURN_BOOL(false);
+       PG_RETURN_BOOL(false);
 }
 
+/*
+** '~=' and operator function. Based on two GIDX return true if
+** the first equals the second.
+*/
 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);
+       if (gidx_equals((GIDX *)PG_GETARG_POINTER(0), (GIDX *)PG_GETARG_POINTER(1)))
+               PG_RETURN_BOOL(true);
 
-   PG_RETURN_BOOL(false);
+       PG_RETURN_BOOL(false);
 }
-#endif
 
 /*
-** '&&' operator function. Based on two serialized return true if
+** '&&&' operator function. Based on two serialized return true if
 ** they overlap and false otherwise.
 */
 PG_FUNCTION_INFO_V1(gserialized_overlaps);
 Datum gserialized_overlaps(PG_FUNCTION_ARGS)
 {
-       if ( gserialized_datum_predicate(PG_GETARG_DATUM(0),PG_GETARG_DATUM(1), gidx_overlaps) == LW_TRUE )
-       {
+       if (gserialized_datum_predicate(PG_GETARG_DATUM(0), PG_GETARG_DATUM(1), gidx_overlaps))
                PG_RETURN_BOOL(true);
-       }
 
        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);
+       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);
+       if (gserialized_datum_predicate_gidx_geom(gidx, PG_GETARG_DATUM(1), gidx_overlaps))
+               PG_RETURN_BOOL(true);
 
-   PG_RETURN_BOOL(false);
+       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);
+       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);
+       if (gserialized_datum_predicate_gidx_geom(gidx, PG_GETARG_DATUM(1), gidx_overlaps))
+               PG_RETURN_BOOL(true);
 
-   PG_RETURN_BOOL(false);
+       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);
+       if (gidx_overlaps((GIDX *)PG_GETARG_POINTER(0), (GIDX *)PG_GETARG_POINTER(1)))
+               PG_RETURN_BOOL(true);
 
-   PG_RETURN_BOOL(false);
+       PG_RETURN_BOOL(false);
 }
-#endif
 
 /***********************************************************************
-* GiST Index  Support Functions
-*/
+ * GiST Index  Support Functions
+ */
 
 /*
 ** GiST support function. Given a geography, return a "compressed"
@@ -1089,10 +954,10 @@ Datum gserialized_gidx_gidx_overlaps(PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1(gserialized_gist_compress);
 Datum gserialized_gist_compress(PG_FUNCTION_ARGS)
 {
-       GISTENTRY *entry_in = (GISTENTRY*)PG_GETARG_POINTER(0);
+       GISTENTRY *entry_in = (GISTENTRY *)PG_GETARG_POINTER(0);
        GISTENTRY *entry_out = NULL;
        char gidxmem[GIDX_MAX_SIZE];
-       GIDX *bbox_out = (GIDX*)gidxmem;
+       GIDX *bbox_out = (GIDX *)gidxmem;
        int result = LW_SUCCESS;
        uint32_t i;
 
@@ -1102,7 +967,7 @@ Datum gserialized_gist_compress(PG_FUNCTION_ARGS)
        ** Not a leaf key? There's nothing to do.
        ** Return the input unchanged.
        */
-       if ( ! entry_in->leafkey )
+       if (!entry_in->leafkey)
        {
                POSTGIS_DEBUG(4, "[GIST] non-leafkey entry, returning input unaltered");
                PG_RETURN_POINTER(entry_in);
@@ -1115,11 +980,10 @@ Datum gserialized_gist_compress(PG_FUNCTION_ARGS)
        ** Null key? Make a copy of the input entry and
        ** return.
        */
-       if ( DatumGetPointer(entry_in->key) == NULL )
+       if (!DatumGetPointer(entry_in->key))
        {
                POSTGIS_DEBUG(4, "[GIST] leafkey is null");
-               gistentryinit(*entry_out, (Datum) 0, entry_in->rel,
-                             entry_in->page, entry_in->offset, false);
+               gistentryinit(*entry_out, (Datum)0, entry_in->rel, entry_in->page, entry_in->offset, false);
                POSTGIS_DEBUG(4, "[GIST] returning copy of input");
                PG_RETURN_POINTER(entry_out);
        }
@@ -1129,40 +993,45 @@ Datum gserialized_gist_compress(PG_FUNCTION_ARGS)
 
        /* Is the bounding box valid (non-empty, non-infinite) ?
         * If not, use the "unknown" GIDX. */
-       if ( result == LW_FAILURE )
+       if (result == LW_FAILURE)
        {
                POSTGIS_DEBUG(4, "[GIST] empty geometry!");
                gidx_set_unknown(bbox_out);
-               gistentryinit(*entry_out, PointerGetDatum(gidx_copy(bbox_out)),
-                             entry_in->rel, entry_in->page,
-                             entry_in->offset, false);
+               gistentryinit(*entry_out,
+                             PointerGetDatum(gidx_copy(bbox_out)),
+                             entry_in->rel,
+                             entry_in->page,
+                             entry_in->offset,
+                             false);
                PG_RETURN_POINTER(entry_out);
        }
 
        POSTGIS_DEBUGF(4, "[GIST] got entry_in->key: %s", gidx_to_string(bbox_out));
 
+       /* ORIGINAL VERSION */
        /* Check all the dimensions for finite values.
         * If not, use the "unknown" GIDX as a key */
-       for ( i = 0; i < GIDX_NDIMS(bbox_out); i++ )
+       for (i = 0; i < GIDX_NDIMS(bbox_out); i++)
        {
-               if ( ! isfinite(GIDX_GET_MAX(bbox_out, i))
-                    || ! isfinite(GIDX_GET_MIN(bbox_out, i)) )
+               if (!isfinite(GIDX_GET_MAX(bbox_out, i)) || !isfinite(GIDX_GET_MIN(bbox_out, i)))
                {
                        gidx_set_unknown(bbox_out);
                        gistentryinit(*entry_out,
-                                     PointerGetDatum(gidx_copy(bbox_out)),
-                                     entry_in->rel, entry_in->page,
-                                     entry_in->offset, false);
+                                     PointerGetDatum(gidx_copy(bbox_out)),
+                                     entry_in->rel,
+                                     entry_in->page,
+                                     entry_in->offset,
+                                     false);
                        PG_RETURN_POINTER(entry_out);
                }
        }
 
-       /* Enure bounding box has minimums below maximums. */
+       /* Ensure bounding box has minimums below maximums. */
        gidx_validate(bbox_out);
 
        /* Prepare GISTENTRY for return. */
-       gistentryinit(*entry_out, PointerGetDatum(gidx_copy(bbox_out)),
-                     entry_in->rel, entry_in->page, entry_in->offset, false);
+       gistentryinit(
+           *entry_out, PointerGetDatum(gidx_copy(bbox_out)), entry_in->rel, entry_in->page, entry_in->offset, false);
 
        /* Return GISTENTRY. */
        POSTGIS_DEBUG(4, "[GIST] 'compress' function complete");
@@ -1184,28 +1053,28 @@ Datum gserialized_gist_decompress(PG_FUNCTION_ARGS)
 /*
 ** GiST support function. Called from gserialized_gist_consistent below.
 */
-static inline bool gserialized_gist_consistent_leaf(GIDX *key, GIDX *query, StrategyNumber strategy)
+static inline bool
+gserialized_gist_consistent_leaf(GIDX *key, GIDX *query, StrategyNumber strategy)
 {
        bool retval;
 
-       POSTGIS_DEBUGF(4, "[GIST] leaf consistent, strategy [%d], count[%i]",
-                      strategy, geog_counter_leaf++);
+       POSTGIS_DEBUGF(4, "[GIST] leaf consistent, strategy [%d], count[%i]", strategy, geog_counter_leaf++);
 
        switch (strategy)
        {
        case RTOverlapStrategyNumber:
-               retval = (bool) gidx_overlaps(key, query);
+               retval = (bool)gidx_overlaps(key, query);
                break;
        case RTSameStrategyNumber:
-               retval = (bool) gidx_equals(key, query);
+               retval = (bool)gidx_equals(key, query);
                break;
        case RTContainsStrategyNumber:
        case RTOldContainsStrategyNumber:
-               retval = (bool) gidx_contains(key, query);
+               retval = (bool)gidx_contains(key, query);
                break;
        case RTContainedByStrategyNumber:
        case RTOldContainedByStrategyNumber:
-               retval = (bool) gidx_contains(query, key);
+               retval = (bool)gidx_contains(query, key);
                break;
        default:
                retval = false;
@@ -1217,26 +1086,29 @@ static inline bool gserialized_gist_consistent_leaf(GIDX *key, GIDX *query, Stra
 /*
 ** GiST support function. Called from gserialized_gist_consistent below.
 */
-static inline bool gserialized_gist_consistent_internal(GIDX *key, GIDX *query, StrategyNumber strategy)
+static inline bool
+gserialized_gist_consistent_internal(GIDX *key, GIDX *query, StrategyNumber strategy)
 {
-       bool            retval;
+       bool retval;
 
-       POSTGIS_DEBUGF(4, "[GIST] internal consistent, strategy [%d], count[%i], query[%s], key[%s]",
-                      strategy, geog_counter_internal++, gidx_to_string(query), gidx_to_string(key) );
+       POSTGIS_DEBUGF(4,
+                      "[GIST] internal consistent, strategy [%d], count[%i], query[%s], key[%s]",
+                      strategy,
+                      geog_counter_internal++,
+                      gidx_to_string(query),
+                      gidx_to_string(key));
 
        switch (strategy)
        {
        case RTOverlapStrategyNumber:
-               retval = (bool) gidx_overlaps(key, query);
+       case RTContainedByStrategyNumber:
+       case RTOldContainedByStrategyNumber:
+               retval = (bool)gidx_overlaps(key, query);
                break;
        case RTSameStrategyNumber:
        case RTContainsStrategyNumber:
        case RTOldContainsStrategyNumber:
-               retval = (bool) gidx_contains(key, query);
-               break;
-       case RTContainedByStrategyNumber:
-       case RTOldContainedByStrategyNumber:
-               retval = (bool) gidx_overlaps(key, query);
+               retval = (bool)gidx_contains(key, query);
                break;
        default:
                retval = false;
@@ -1252,15 +1124,15 @@ static inline bool gserialized_gist_consistent_internal(GIDX *key, GIDX *query,
 PG_FUNCTION_INFO_V1(gserialized_gist_consistent);
 Datum gserialized_gist_consistent(PG_FUNCTION_ARGS)
 {
-       GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0);
-       StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+       GISTENTRY *entry = (GISTENTRY *)PG_GETARG_POINTER(0);
+       StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
        bool result;
        char gidxmem[GIDX_MAX_SIZE];
-       GIDX *query_gbox_index = (GIDX*)gidxmem;
+       GIDX *query_gbox_index = (GIDX *)gidxmem;
 
        /* PostgreSQL 8.4 and later require the RECHECK flag to be set here,
           rather than being supplied as part of the operator class definition */
-       bool *recheck = (bool *) PG_GETARG_POINTER(4);
+       bool *recheck = (bool *)PG_GETARG_POINTER(4);
 
        /* We set recheck to false to avoid repeatedly pulling every "possibly matched" geometry
           out during index scans. For cases when the geometries are large, rechecking
@@ -1270,21 +1142,21 @@ Datum gserialized_gist_consistent(PG_FUNCTION_ARGS)
        POSTGIS_DEBUG(4, "[GIST] 'consistent' function called");
 
        /* Quick sanity check on query argument. */
-       if ( DatumGetPointer(PG_GETARG_DATUM(1)) == NULL )
+       if (!DatumGetPointer(PG_GETARG_DATUM(1)))
        {
                POSTGIS_DEBUG(4, "[GIST] null query pointer (!?!), returning false");
                PG_RETURN_BOOL(false); /* NULL query! This is screwy! */
        }
 
        /* Quick sanity check on entry key. */
-       if ( DatumGetPointer(entry->key) == NULL )
+       if (!DatumGetPointer(entry->key))
        {
                POSTGIS_DEBUG(4, "[GIST] null index entry, returning false");
                PG_RETURN_BOOL(false); /* NULL entry! */
        }
 
        /* Null box should never make this far. */
-       if ( gserialized_datum_get_gidx_p(PG_GETARG_DATUM(1), query_gbox_index) == LW_FAILURE )
+       if (gserialized_datum_get_gidx_p(PG_GETARG_DATUM(1), query_gbox_index) == LW_FAILURE)
        {
                POSTGIS_DEBUG(4, "[GIST] null query_gbox_index!");
                PG_RETURN_BOOL(false);
@@ -1293,15 +1165,13 @@ Datum gserialized_gist_consistent(PG_FUNCTION_ARGS)
        /* Treat leaf node tests different from internal nodes */
        if (GIST_LEAF(entry))
        {
-               result = gserialized_gist_consistent_leaf(
-                            (GIDX*)DatumGetPointer(entry->key),
-                            query_gbox_index, strategy);
+               result =
+                   gserialized_gist_consistent_leaf((GIDX *)DatumGetPointer(entry->key), query_gbox_index, strategy);
        }
        else
        {
                result = gserialized_gist_consistent_internal(
-                            (GIDX*)DatumGetPointer(entry->key),
-                            query_gbox_index, strategy);
+                   (GIDX *)DatumGetPointer(entry->key), query_gbox_index, strategy);
        }
 
        PG_RETURN_BOOL(result);
@@ -1320,19 +1190,26 @@ Datum gserialized_gist_consistent(PG_FUNCTION_ARGS)
 ** greater than float b, integer A with same bit representation as a is greater
 ** than integer B with same bits as b.
 */
-static float pack_float(const float value, const int realm)
+static float
+pack_float(const float value, const int realm)
 {
-  union {
-    float f;
-    struct { unsigned value:31, sign:1; } vbits;
-    struct { unsigned value:29, realm:2, sign:1; } rbits;
-  } a;
+       union {
+               float f;
+               struct
+               {
+                       unsigned value : 31, sign : 1;
+               } vbits;
+               struct
+               {
+                       unsigned value : 29, realm : 2, sign : 1;
+               } rbits;
+       } a;
 
-  a.f = value;
-  a.rbits.value = a.vbits.value >> 2;
-  a.rbits.realm = realm;
+       a.f = value;
+       a.rbits.value = a.vbits.value >> 2;
+       a.rbits.realm = realm;
 
-  return a.f;
+       return a.f;
 }
 
 /*
@@ -1342,19 +1219,19 @@ static float pack_float(const float value, const int realm)
 PG_FUNCTION_INFO_V1(gserialized_gist_penalty);
 Datum gserialized_gist_penalty(PG_FUNCTION_ARGS)
 {
-       GISTENTRY *origentry = (GISTENTRY*) PG_GETARG_POINTER(0);
-       GISTENTRY *newentry = (GISTENTRY*) PG_GETARG_POINTER(1);
-       float *result = (float*) PG_GETARG_POINTER(2);
+       GISTENTRY *origentry = (GISTENTRY *)PG_GETARG_POINTER(0);
+       GISTENTRY *newentry = (GISTENTRY *)PG_GETARG_POINTER(1);
+       float *result = (float *)PG_GETARG_POINTER(2);
        GIDX *gbox_index_orig, *gbox_index_new;
        float size_union, size_orig, edge_union, edge_orig;
 
        POSTGIS_DEBUG(4, "[GIST] 'penalty' function called");
 
-       gbox_index_orig = (GIDX*)DatumGetPointer(origentry->key);
-       gbox_index_new = (GIDX*)DatumGetPointer(newentry->key);
+       gbox_index_orig = (GIDX *)DatumGetPointer(origentry->key);
+       gbox_index_new = (GIDX *)DatumGetPointer(newentry->key);
 
        /* Drop out if we're dealing with null inputs. Shouldn't happen. */
-       if ( (gbox_index_orig == NULL) && (gbox_index_new == NULL) )
+       if (!gbox_index_orig && !gbox_index_new)
        {
                POSTGIS_DEBUG(4, "[GIST] both inputs NULL! returning penalty of zero");
                *result = 0.0;
@@ -1367,37 +1244,30 @@ Datum gserialized_gist_penalty(PG_FUNCTION_ARGS)
        *result = size_union - size_orig;
 
        /* REALM 0: No extension is required, volume is zero, return edge */
-       /* REALM 1: No extension is required, return nonzero area */
-       /* REALM 2: Area extension is zero, return nonzero edge extension */
-       /* REALM 3: Area extension is nonzero, return it */
+       /* REALM 1: No extension is required, return nonzero area */
+       /* REALM 2: Area extension is zero, return nonzero edge extension */
+       /* REALM 3: Area extension is nonzero, return it */
 
-       if( *result == 0 )
-       {
+       if (*result == 0)
+       {
                if (size_orig > 0)
-               {
                        *result = pack_float(size_orig, 1); /* REALM 1 */
-               }
                else
                {
                        edge_union = gidx_union_edge(gbox_index_orig, gbox_index_new);
                        edge_orig = gidx_edge(gbox_index_orig);
-                       *result = edge_union - edge_orig;
-                       if( *result == 0 )
-                       {
-                               *result = pack_float(edge_orig, 0); /* REALM 0 */
-                       }
-                       else
-                       {
-                               *result = pack_float(*result, 2); /* REALM 2 */
-                       }
+                       *result = edge_union - edge_orig;
+                       if (*result == 0)
+                               *result = pack_float(edge_orig, 0); /* REALM 0 */
+                       else
+                               *result = pack_float(*result, 2); /* REALM 2 */
                }
-       }
-       else
-       {
-               *result = pack_float(*result, 3); /* REALM 3 */
-       }
+       }
+       else
+               *result = pack_float(*result, 3); /* REALM 3 */
 
-       POSTGIS_DEBUGF(4, "[GIST] union size (%.12f), original size (%.12f), penalty (%.12f)", size_union, size_orig, *result);
+       POSTGIS_DEBUGF(
+           4, "[GIST] union size (%.12f), original size (%.12f), penalty (%.12f)", size_union, size_orig, *result);
 
        PG_RETURN_POINTER(result);
 }
@@ -1408,22 +1278,22 @@ Datum gserialized_gist_penalty(PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1(gserialized_gist_union);
 Datum gserialized_gist_union(PG_FUNCTION_ARGS)
 {
-       GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
-       int *sizep = (int *) PG_GETARG_POINTER(1); /* Size of the return value */
-       int     numranges, i;
+       GistEntryVector *entryvec = (GistEntryVector *)PG_GETARG_POINTER(0);
+       int *sizep = (int *)PG_GETARG_POINTER(1); /* Size of the return value */
+       int numranges, i;
        GIDX *box_cur, *box_union;
 
        POSTGIS_DEBUG(4, "[GIST] 'union' function called");
 
        numranges = entryvec->n;
 
-       box_cur = (GIDX*) DatumGetPointer(entryvec->vector[0].key);
+       box_cur = (GIDX *)DatumGetPointer(entryvec->vector[0].key);
 
        box_union = gidx_copy(box_cur);
 
-       for ( i = 1; i < numranges; i++ )
+       for (i = 1; i < numranges; i++)
        {
-               box_cur = (GIDX*) DatumGetPointer(entryvec->vector[i].key);
+               box_cur = (GIDX *)DatumGetPointer(entryvec->vector[i].key);
                gidx_merge(&box_union, box_cur);
        }
 
@@ -1432,7 +1302,6 @@ Datum gserialized_gist_union(PG_FUNCTION_ARGS)
        POSTGIS_DEBUGF(4, "[GIST] union called, numranges(%i), pageunion %s", numranges, gidx_to_string(box_union));
 
        PG_RETURN_POINTER(box_union);
-
 }
 
 /*
@@ -1441,9 +1310,9 @@ Datum gserialized_gist_union(PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1(gserialized_gist_same);
 Datum gserialized_gist_same(PG_FUNCTION_ARGS)
 {
-       GIDX *b1 = (GIDX*)PG_GETARG_POINTER(0);
-       GIDX *b2 = (GIDX*)PG_GETARG_POINTER(1);
-       bool *result = (bool*)PG_GETARG_POINTER(2);
+       GIDX *b1 = (GIDX *)PG_GETARG_POINTER(0);
+       GIDX *b2 = (GIDX *)PG_GETARG_POINTER(1);
+       bool *result = (bool *)PG_GETARG_POINTER(2);
 
        POSTGIS_DEBUG(4, "[GIST] 'same' function called");
 
@@ -1452,49 +1321,40 @@ Datum gserialized_gist_same(PG_FUNCTION_ARGS)
        PG_RETURN_POINTER(result);
 }
 
-
-
-
 PG_FUNCTION_INFO_V1(gserialized_gist_geog_distance);
 Datum gserialized_gist_geog_distance(PG_FUNCTION_ARGS)
 {
-       GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0);
+       GISTENTRY *entry = (GISTENTRY *)PG_GETARG_POINTER(0);
        Datum query_datum = PG_GETARG_DATUM(1);
-       StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
-#if POSTGIS_PGSQL_VERSION >= 95
-       bool *recheck = (bool *) PG_GETARG_POINTER(4);
-#endif
+       StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
+       bool *recheck = (bool *)PG_GETARG_POINTER(4);
        char query_box_mem[GIDX_MAX_SIZE];
-       GIDX *query_box = (GIDX*)query_box_mem;
+       GIDX *query_box = (GIDX *)query_box_mem;
        GIDX *entry_box;
        double distance;
 
        POSTGIS_DEBUGF(3, "[GIST] '%s' function called", __func__);
 
        /* We are using '13' as the gist geography distance <-> strategy number */
-       if ( strategy != 13  )
+       if (strategy != 13)
        {
                elog(ERROR, "unrecognized strategy number: %d", strategy);
                PG_RETURN_FLOAT8(FLT_MAX);
        }
 
        /* Null box should never make this far. */
-       if ( gserialized_datum_get_gidx_p(query_datum, query_box) == LW_FAILURE )
+       if (gserialized_datum_get_gidx_p(query_datum, query_box) == LW_FAILURE)
        {
                POSTGIS_DEBUG(2, "[GIST] null query_gbox_index!");
                PG_RETURN_FLOAT8(FLT_MAX);
        }
 
-#if POSTGIS_PGSQL_VERSION >= 95
        /* When we hit leaf nodes, it's time to turn on recheck */
        if (GIST_LEAF(entry))
-       {
                *recheck = true;
-       }
-#endif
 
        /* Get the entry box */
-       entry_box = (GIDX*)DatumGetPointer(entry->key);
+       entry_box = (GIDX *)DatumGetPointer(entry->key);
 
        /* Return distances from key-based tests should always be */
        /* the minimum possible distance, box-to-box */
@@ -1507,7 +1367,6 @@ Datum gserialized_gist_geog_distance(PG_FUNCTION_ARGS)
        PG_RETURN_FLOAT8(distance);
 }
 
-
 /*
 ** GiST support function.
 ** Take in a query and an entry and return the "distance" between them.
@@ -1527,14 +1386,12 @@ Datum gserialized_gist_geog_distance(PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1(gserialized_gist_distance);
 Datum gserialized_gist_distance(PG_FUNCTION_ARGS)
 {
-       GISTENTRY *entry = (GISTENTRY*) PG_GETARG_POINTER(0);
-       StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+       GISTENTRY *entry = (GISTENTRY *)PG_GETARG_POINTER(0);
+       StrategyNumber strategy = (StrategyNumber)PG_GETARG_UINT16(2);
        char query_box_mem[GIDX_MAX_SIZE];
-       GIDX *query_box = (GIDX*)query_box_mem;
+       GIDX *query_box = (GIDX *)query_box_mem;
        GIDX *entry_box;
-#if POSTGIS_PGSQL_VERSION >= 95
-       bool *recheck = (bool *) PG_GETARG_POINTER(4);
-#endif
+       bool *recheck = (bool *)PG_GETARG_POINTER(4);
 
        double distance;
 
@@ -1542,22 +1399,21 @@ Datum gserialized_gist_distance(PG_FUNCTION_ARGS)
 
        /* Strategy 13 is <<->> */
        /* Strategy 20 is |=| */
-       if ( strategy != 13 && strategy != 20 ) {
+       if (strategy != 13 && strategy != 20)
+       {
                elog(ERROR, "unrecognized strategy number: %d", strategy);
                PG_RETURN_FLOAT8(FLT_MAX);
        }
 
        /* Null box should never make this far. */
-       if ( gserialized_datum_get_gidx_p(PG_GETARG_DATUM(1), query_box) == LW_FAILURE )
+       if (gserialized_datum_get_gidx_p(PG_GETARG_DATUM(1), query_box) == LW_FAILURE)
        {
                POSTGIS_DEBUG(4, "[GIST] null query_gbox_index!");
                PG_RETURN_FLOAT8(FLT_MAX);
        }
 
        /* Get the entry box */
-       entry_box = (GIDX*)DatumGetPointer(entry->key);
-
-#if POSTGIS_PGSQL_VERSION >= 95
+       entry_box = (GIDX *)DatumGetPointer(entry->key);
 
        /* Strategy 20 is |=| */
        distance = gidx_distance(entry_box, query_box, strategy == 20);
@@ -1565,40 +1421,21 @@ Datum gserialized_gist_distance(PG_FUNCTION_ARGS)
        /* Treat leaf node tests different from internal nodes */
        if (GIST_LEAF(entry))
                *recheck = true;
-#else
 
-       if ( strategy == 20 )
-       {
-               elog(ERROR, "You need PostgreSQL 9.5.0 or higher in order to use |=| with index");
-               PG_RETURN_FLOAT8(FLT_MAX);
-       }
-
-       /* Treat leaf node tests different from internal nodes */
-       if (GIST_LEAF(entry))
-       {
-               /* Calculate distance to leaves */
-               distance = (double)gidx_distance_leaf_centroid(entry_box, query_box);
-       }
-       else
-       {
-               /* Calculate distance for internal nodes */
-               distance = (double)gidx_distance_node_centroid(entry_box, query_box);
-       }
-#endif
        PG_RETURN_FLOAT8(distance);
 }
 
-
 /*
 ** Utility function to add entries to the axis partition lists in the
 ** picksplit function.
 */
-static void gserialized_gist_picksplit_addlist(OffsetNumber *list, GIDX **box_union, GIDX *box_current, int *pos, int num)
+static void
+gserialized_gist_picksplit_addlist(OffsetNumber *list, GIDX **box_union, GIDX *box_current, int *pos, int num)
 {
-       if ( *pos )
-               gidx_merge(box_union,  box_current);
+       if (*pos)
+               gidx_merge(box_union, box_current);
        else
-               memcpy((void*)(*box_union), (void*)box_current, VARSIZE(box_current));
+               memcpy((void *)(*box_union), (void *)box_current, VARSIZE(box_current));
        list[*pos] = num;
        (*pos)++;
 }
@@ -1607,33 +1444,34 @@ static void gserialized_gist_picksplit_addlist(OffsetNumber *list, GIDX **box_un
 ** Utility function check whether the number of entries two halves of the
 ** space constitute a "bad ratio" (poor balance).
 */
-static int gserialized_gist_picksplit_badratio(int x, int y)
+static int
+gserialized_gist_picksplit_badratio(int x, int y)
 {
        POSTGIS_DEBUGF(4, "[GIST] checking split ratio (%d, %d)", x, y);
-       if ( (y == 0) || (((float)x / (float)y) < LIMIT_RATIO) ||
-            (x == 0) || (((float)y / (float)x) < LIMIT_RATIO) )
+       if ((y == 0) || (((float)x / (float)y) < LIMIT_RATIO) || (x == 0) || (((float)y / (float)x) < LIMIT_RATIO))
                return true;
 
        return false;
 }
 
-static bool gserialized_gist_picksplit_badratios(int *pos, int dims)
+static bool
+gserialized_gist_picksplit_badratios(int *pos, int dims)
 {
        int i;
-       for ( i = 0; i < dims; i++ )
+       for (i = 0; i < dims; i++)
        {
-               if ( gserialized_gist_picksplit_badratio(pos[2*i],pos[2*i+1]) == false )
+               if (gserialized_gist_picksplit_badratio(pos[2 * i], pos[2 * i + 1]) == false)
                        return false;
        }
        return true;
 }
 
-
 /*
 ** Where the picksplit algorithm cannot find any basis for splitting one way
 ** or another, we simply split the overflowing node in half.
 */
-static void gserialized_gist_picksplit_fallback(GistEntryVector *entryvec, GIST_SPLITVEC *v)
+static void
+gserialized_gist_picksplit_fallback(GistEntryVector *entryvec, GIST_SPLITVEC *v)
 {
        OffsetNumber i, maxoff;
        GIDX *unionL = NULL;
@@ -1645,59 +1483,56 @@ static void gserialized_gist_picksplit_fallback(GistEntryVector *entryvec, GIST_
        maxoff = entryvec->n - 1;
 
        nbytes = (maxoff + 2) * sizeof(OffsetNumber);
-       v->spl_left = (OffsetNumber*) palloc(nbytes);
-       v->spl_right = (OffsetNumber*) palloc(nbytes);
+       v->spl_left = (OffsetNumber *)palloc(nbytes);
+       v->spl_right = (OffsetNumber *)palloc(nbytes);
        v->spl_nleft = v->spl_nright = 0;
 
        for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
        {
-               GIDX *cur = (GIDX*)DatumGetPointer(entryvec->vector[i].key);
+               GIDX *cur = (GIDX *)DatumGetPointer(entryvec->vector[i].key);
 
                if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
                {
                        v->spl_left[v->spl_nleft] = i;
-                       if (unionL == NULL)
-                       {
+                       if (!unionL)
                                unionL = gidx_copy(cur);
-                       }
                        else
-                       {
                                gidx_merge(&unionL, cur);
-                       }
                        v->spl_nleft++;
                }
                else
                {
                        v->spl_right[v->spl_nright] = i;
-                       if (unionR == NULL)
-                       {
+                       if (!unionR)
                                unionR = gidx_copy(cur);
-                       }
                        else
-                       {
                                gidx_merge(&unionR, cur);
-                       }
                        v->spl_nright++;
                }
        }
 
        if (v->spl_ldatum_exists)
-               gidx_merge(&unionL, (GIDX*)DatumGetPointer(v->spl_ldatum));
+               gidx_merge(&unionL, (GIDX *)DatumGetPointer(v->spl_ldatum));
 
        v->spl_ldatum = PointerGetDatum(unionL);
 
        if (v->spl_rdatum_exists)
-               gidx_merge(&unionR, (GIDX*)DatumGetPointer(v->spl_rdatum));
+               gidx_merge(&unionR, (GIDX *)DatumGetPointer(v->spl_rdatum));
 
        v->spl_rdatum = PointerGetDatum(unionR);
        v->spl_ldatum_exists = v->spl_rdatum_exists = false;
 }
 
-
-
-static void gserialized_gist_picksplit_constructsplit(GIST_SPLITVEC *v, OffsetNumber *list1, int nlist1, GIDX **union1, OffsetNumber *list2, int nlist2, GIDX **union2)
+static void
+gserialized_gist_picksplit_constructsplit(GIST_SPLITVEC *v,
+                                         OffsetNumber *list1,
+                                         int nlist1,
+                                         GIDX **union1,
+                                         OffsetNumber *list2,
+                                         int nlist2,
+                                         GIDX **union2)
 {
-       bool            firstToLeft = true;
+       bool firstToLeft = true;
 
        POSTGIS_DEBUG(4, "[GIST] picksplit in constructsplit function");
 
@@ -1711,32 +1546,41 @@ static void gserialized_gist_picksplit_constructsplit(GIST_SPLITVEC *v, OffsetNu
                        GIDX *RLr = gidx_copy(*union1);
                        double sizeLR, sizeRL;
 
-                       gidx_merge(&LRl, (GIDX*)DatumGetPointer(v->spl_ldatum));
-                       gidx_merge(&LRr, (GIDX*)DatumGetPointer(v->spl_rdatum));
-                       gidx_merge(&RLl, (GIDX*)DatumGetPointer(v->spl_ldatum));
-                       gidx_merge(&RLr, (GIDX*)DatumGetPointer(v->spl_rdatum));
+                       gidx_merge(&LRl, (GIDX *)DatumGetPointer(v->spl_ldatum));
+                       gidx_merge(&LRr, (GIDX *)DatumGetPointer(v->spl_rdatum));
+                       gidx_merge(&RLl, (GIDX *)DatumGetPointer(v->spl_ldatum));
+                       gidx_merge(&RLr, (GIDX *)DatumGetPointer(v->spl_rdatum));
 
-                       sizeLR = gidx_inter_volume(LRl,LRr);
-                       sizeRL = gidx_inter_volume(RLl,RLr);
+                       sizeLR = gidx_inter_volume(LRl, LRr);
+                       sizeRL = gidx_inter_volume(RLl, RLr);
 
                        POSTGIS_DEBUGF(4, "[GIST] sizeLR / sizeRL == %.12g / %.12g", sizeLR, sizeRL);
 
                        if (sizeLR > sizeRL)
                                firstToLeft = false;
-
                }
                else
                {
                        float p1, p2;
-                       GISTENTRY oldUnion,     addon;
+                       GISTENTRY oldUnion, addon;
 
-                       gistentryinit(oldUnion, (v->spl_ldatum_exists) ? v->spl_ldatum : v->spl_rdatum,
-                                     NULL, NULL, InvalidOffsetNumber, false);
+                       gistentryinit(oldUnion,
+                                     (v->spl_ldatum_exists) ? v->spl_ldatum : v->spl_rdatum,
+                                     NULL,
+                                     NULL,
+                                     InvalidOffsetNumber,
+                                     false);
 
                        gistentryinit(addon, PointerGetDatum(*union1), NULL, NULL, InvalidOffsetNumber, false);
-                       DirectFunctionCall3(gserialized_gist_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&addon), PointerGetDatum(&p1));
+                       DirectFunctionCall3(gserialized_gist_penalty,
+                                           PointerGetDatum(&oldUnion),
+                                           PointerGetDatum(&addon),
+                                           PointerGetDatum(&p1));
                        gistentryinit(addon, PointerGetDatum(*union2), NULL, NULL, InvalidOffsetNumber, false);
-                       DirectFunctionCall3(gserialized_gist_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&addon), PointerGetDatum(&p2));
+                       DirectFunctionCall3(gserialized_gist_penalty,
+                                           PointerGetDatum(&oldUnion),
+                                           PointerGetDatum(&addon),
+                                           PointerGetDatum(&p2));
 
                        POSTGIS_DEBUGF(4, "[GIST] p1 / p2 == %.12g / %.12g", p1, p2);
 
@@ -1754,10 +1598,10 @@ static void gserialized_gist_picksplit_constructsplit(GIST_SPLITVEC *v, OffsetNu
                v->spl_nleft = nlist1;
                v->spl_nright = nlist2;
                if (v->spl_ldatum_exists)
-                       gidx_merge(union1, (GIDX*)DatumGetPointer(v->spl_ldatum));
+                       gidx_merge(union1, (GIDX *)DatumGetPointer(v->spl_ldatum));
                v->spl_ldatum = PointerGetDatum(*union1);
                if (v->spl_rdatum_exists)
-                       gidx_merge(union2, (GIDX*)DatumGetPointer(v->spl_rdatum));
+                       gidx_merge(union2, (GIDX *)DatumGetPointer(v->spl_rdatum));
                v->spl_rdatum = PointerGetDatum(*union2);
        }
        else
@@ -1767,19 +1611,18 @@ static void gserialized_gist_picksplit_constructsplit(GIST_SPLITVEC *v, OffsetNu
                v->spl_nleft = nlist2;
                v->spl_nright = nlist1;
                if (v->spl_ldatum_exists)
-                       gidx_merge(union2, (GIDX*)DatumGetPointer(v->spl_ldatum));
+                       gidx_merge(union2, (GIDX *)DatumGetPointer(v->spl_ldatum));
                v->spl_ldatum = PointerGetDatum(*union2);
                if (v->spl_rdatum_exists)
-                       gidx_merge(union1, (GIDX*)DatumGetPointer(v->spl_rdatum));
+                       gidx_merge(union1, (GIDX *)DatumGetPointer(v->spl_rdatum));
                v->spl_rdatum = PointerGetDatum(*union1);
        }
 
        v->spl_ldatum_exists = v->spl_rdatum_exists = false;
 }
 
-
-#define BELOW(d) (2*(d))
-#define ABOVE(d) ((2*(d))+1)
+#define BELOW(d) (2 * (d))
+#define ABOVE(d) ((2 * (d)) + 1)
 
 /*
 ** GiST support function. Split an overflowing node into two new nodes.
@@ -1792,9 +1635,9 @@ PG_FUNCTION_INFO_V1(gserialized_gist_picksplit);
 Datum gserialized_gist_picksplit(PG_FUNCTION_ARGS)
 {
 
-       GistEntryVector *entryvec = (GistEntryVector*) PG_GETARG_POINTER(0);
+       GistEntryVector *entryvec = (GistEntryVector *)PG_GETARG_POINTER(0);
 
-       GIST_SPLITVEC *v = (GIST_SPLITVEC*) PG_GETARG_POINTER(1);
+       GIST_SPLITVEC *v = (GIST_SPLITVEC *)PG_GETARG_POINTER(1);
        OffsetNumber i;
        /* One union box for each half of the space. */
        GIDX **box_union;
@@ -1817,24 +1660,24 @@ Datum gserialized_gist_picksplit(PG_FUNCTION_ARGS)
        */
 
        max_offset = entryvec->n - 1;
-       box_current = (GIDX*) DatumGetPointer(entryvec->vector[FirstOffsetNumber].key);
+       box_current = (GIDX *)DatumGetPointer(entryvec->vector[FirstOffsetNumber].key);
        box_pageunion = gidx_copy(box_current);
 
        /* Calculate the containing box (box_pageunion) for the whole page we are going to split. */
-       for ( i = OffsetNumberNext(FirstOffsetNumber); i <= max_offset; i = OffsetNumberNext(i) )
+       for (i = OffsetNumberNext(FirstOffsetNumber); i <= max_offset; i = OffsetNumberNext(i))
        {
-               box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key);
+               box_current = (GIDX *)DatumGetPointer(entryvec->vector[i].key);
 
-               if ( all_entries_equal == true && ! gidx_equals (box_pageunion, box_current) )
+               if (all_entries_equal && !gidx_equals(box_pageunion, box_current))
                        all_entries_equal = false;
 
-               gidx_merge( &box_pageunion, box_current );
+               gidx_merge(&box_pageunion, box_current);
        }
 
        POSTGIS_DEBUGF(3, "[GIST] box_pageunion: %s", gidx_to_string(box_pageunion));
 
        /* Every box in the page is the same! So, we split and just put half the boxes in each child. */
-       if ( all_entries_equal )
+       if (all_entries_equal)
        {
                POSTGIS_DEBUG(4, "[GIST] picksplit finds all entries equal!");
                gserialized_gist_picksplit_fallback(entryvec, v);
@@ -1845,13 +1688,13 @@ Datum gserialized_gist_picksplit(PG_FUNCTION_ARGS)
        nbytes = (max_offset + 2) * sizeof(OffsetNumber);
        ndims_pageunion = GIDX_NDIMS(box_pageunion);
        POSTGIS_DEBUGF(4, "[GIST] ndims_pageunion == %d", ndims_pageunion);
-       pos = palloc(2*ndims_pageunion * sizeof(int));
-       list = palloc(2*ndims_pageunion * sizeof(OffsetNumber*));
-       box_union = palloc(2*ndims_pageunion * sizeof(GIDX*));
-       for ( d = 0; d < ndims_pageunion; d++ )
+       pos = palloc(2 * ndims_pageunion * sizeof(int));
+       list = palloc(2 * ndims_pageunion * sizeof(OffsetNumber *));
+       box_union = palloc(2 * ndims_pageunion * sizeof(GIDX *));
+       for (d = 0; d < ndims_pageunion; d++)
        {
-               list[BELOW(d)] = (OffsetNumber*) palloc(nbytes);
-               list[ABOVE(d)] = (OffsetNumber*) palloc(nbytes);
+               list[BELOW(d)] = (OffsetNumber *)palloc(nbytes);
+               list[ABOVE(d)] = (OffsetNumber *)palloc(nbytes);
                box_union[BELOW(d)] = gidx_new(ndims_pageunion);
                box_union[ABOVE(d)] = gidx_new(ndims_pageunion);
                pos[BELOW(d)] = 0;
@@ -1864,23 +1707,20 @@ Datum gserialized_gist_picksplit(PG_FUNCTION_ARGS)
        ** Each entry thereby ends up in three of the six partitions.
        */
        POSTGIS_DEBUG(4, "[GIST] 'picksplit' calculating best split axis");
-       for ( i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i) )
+       for (i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i))
        {
-               box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key);
+               box_current = (GIDX *)DatumGetPointer(entryvec->vector[i].key);
 
-               for ( d = 0; d < ndims_pageunion; d++ )
+               for (d = 0; d < ndims_pageunion; d++)
                {
-                       if ( GIDX_GET_MIN(box_current,d)-GIDX_GET_MIN(box_pageunion,d) < GIDX_GET_MAX(box_pageunion,d)-GIDX_GET_MAX(box_current,d) )
-                       {
-                               gserialized_gist_picksplit_addlist(list[BELOW(d)], &(box_union[BELOW(d)]), box_current, &(pos[BELOW(d)]), i);
-                       }
+                       if (GIDX_GET_MIN(box_current, d) - GIDX_GET_MIN(box_pageunion, d) <
+                           GIDX_GET_MAX(box_pageunion, d) - GIDX_GET_MAX(box_current, d))
+                               gserialized_gist_picksplit_addlist(
+                                   list[BELOW(d)], &(box_union[BELOW(d)]), box_current, &(pos[BELOW(d)]), i);
                        else
-                       {
-                               gserialized_gist_picksplit_addlist(list[ABOVE(d)], &(box_union[ABOVE(d)]), box_current, &(pos[ABOVE(d)]), i);
-                       }
-
+                               gserialized_gist_picksplit_addlist(
+                                   list[ABOVE(d)], &(box_union[ABOVE(d)]), box_current, &(pos[ABOVE(d)]), i);
                }
-
        }
 
        /*
@@ -1890,7 +1730,7 @@ Datum gserialized_gist_picksplit(PG_FUNCTION_ARGS)
        ** sides of the page union box can occasionally all end up in one place, leading
        ** to this condition.
        */
-       if ( gserialized_gist_picksplit_badratios(pos,ndims_pageunion) == true )
+       if (gserialized_gist_picksplit_badratios(pos, ndims_pageunion) == true)
        {
                /*
                ** Instead we split on center points and see if we do better.
@@ -1898,22 +1738,18 @@ Datum gserialized_gist_picksplit(PG_FUNCTION_ARGS)
                */
                double *avgCenter = palloc(ndims_pageunion * sizeof(double));
 
-               for ( d = 0; d < ndims_pageunion; d++ )
-               {
+               for (d = 0; d < ndims_pageunion; d++)
                        avgCenter[d] = 0.0;
-               }
 
                POSTGIS_DEBUG(4, "[GIST] picksplit can't find good split axis, trying center point method");
 
-               for ( i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i) )
+               for (i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i))
                {
-                       box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key);
-                       for ( d = 0; d < ndims_pageunion; d++ )
-                       {
-                               avgCenter[d] += (GIDX_GET_MAX(box_current,d) + GIDX_GET_MIN(box_current,d)) / 2.0;
-                       }
+                       box_current = (GIDX *)DatumGetPointer(entryvec->vector[i].key);
+                       for (d = 0; d < ndims_pageunion; d++)
+                               avgCenter[d] += (GIDX_GET_MAX(box_current, d) + GIDX_GET_MIN(box_current, d)) / 2.0;
                }
-               for ( d = 0; d < ndims_pageunion; d++ )
+               for (d = 0; d < ndims_pageunion; d++)
                {
                        avgCenter[d] /= max_offset;
                        pos[BELOW(d)] = pos[ABOVE(d)] = 0; /* Re-initialize our counters. */
@@ -1921,35 +1757,44 @@ Datum gserialized_gist_picksplit(PG_FUNCTION_ARGS)
                }
 
                /* For each of our entries... */
-               for ( i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i) )
+               for (i = FirstOffsetNumber; i <= max_offset; i = OffsetNumberNext(i))
                {
                        double center;
-                       box_current = (GIDX*) DatumGetPointer(entryvec->vector[i].key);
+                       box_current = (GIDX *)DatumGetPointer(entryvec->vector[i].key);
 
-                       for ( d = 0; d < ndims_pageunion; d++ )
+                       for (d = 0; d < ndims_pageunion; d++)
                        {
-                               center = (GIDX_GET_MIN(box_current,d)+GIDX_GET_MAX(box_current,d))/2.0;
-                               if ( center < avgCenter[d] )
-                                       gserialized_gist_picksplit_addlist(list[BELOW(d)], &(box_union[BELOW(d)]), box_current, &(pos[BELOW(d)]), i);
-                               else if ( FPeq(center, avgCenter[d]) )
-                                       if ( pos[BELOW(d)] > pos[ABOVE(d)] )
-                                               gserialized_gist_picksplit_addlist(list[ABOVE(d)], &(box_union[ABOVE(d)]), box_current, &(pos[ABOVE(d)]), i);
+                               center = (GIDX_GET_MIN(box_current, d) + GIDX_GET_MAX(box_current, d)) / 2.0;
+                               if (center < avgCenter[d])
+                                       gserialized_gist_picksplit_addlist(
+                                           list[BELOW(d)], &(box_union[BELOW(d)]), box_current, &(pos[BELOW(d)]), i);
+                               else if (FPeq(center, avgCenter[d]))
+                                       if (pos[BELOW(d)] > pos[ABOVE(d)])
+                                               gserialized_gist_picksplit_addlist(list[ABOVE(d)],
+                                                                                  &(box_union[ABOVE(d)]),
+                                                                                  box_current,
+                                                                                  &(pos[ABOVE(d)]),
+                                                                                  i);
                                        else
-                                               gserialized_gist_picksplit_addlist(list[BELOW(d)], &(box_union[BELOW(d)]), box_current, &(pos[BELOW(d)]), i);
+                                               gserialized_gist_picksplit_addlist(list[BELOW(d)],
+                                                                                  &(box_union[BELOW(d)]),
+                                                                                  box_current,
+                                                                                  &(pos[BELOW(d)]),
+                                                                                  i);
                                else
-                                       gserialized_gist_picksplit_addlist(list[ABOVE(d)], &(box_union[ABOVE(d)]), box_current, &(pos[ABOVE(d)]), i);
+                                       gserialized_gist_picksplit_addlist(
+                                           list[ABOVE(d)], &(box_union[ABOVE(d)]), box_current, &(pos[ABOVE(d)]), i);
                        }
-
                }
 
                /* Do we have a good disposition now? If not, screw it, just cut the node in half. */
-               if ( gserialized_gist_picksplit_badratios(pos,ndims_pageunion) == true )
+               if (gserialized_gist_picksplit_badratios(pos, ndims_pageunion))
                {
-                       POSTGIS_DEBUG(4, "[GIST] picksplit still cannot find a good split! just cutting the node in half");
+                       POSTGIS_DEBUG(4,
+                                     "[GIST] picksplit still cannot find a good split! just cutting the node in half");
                        gserialized_gist_picksplit_fallback(entryvec, v);
                        PG_RETURN_POINTER(v);
                }
-
        }
 
        /*
@@ -1959,41 +1804,43 @@ Datum gserialized_gist_picksplit(PG_FUNCTION_ARGS)
        ** number of entries in its regions is the most evenly distributed.
        ** TODO: what if the distributions are equal in two or more axes?
        */
-       for ( d = 0; d < ndims_pageunion; d++ )
+       for (d = 0; d < ndims_pageunion; d++)
        {
-               int posd = Max(pos[ABOVE(d)],pos[BELOW(d)]);
-               if ( posd < posmin )
+               int posd = Max(pos[ABOVE(d)], pos[BELOW(d)]);
+               if (posd < posmin)
                {
                        direction = d;
                        posmin = posd;
                }
        }
-       if ( direction == -1 || posmin == entryvec->n )
-       {
-               /* ERROR OUT HERE */
+       if (direction == -1 || posmin == entryvec->n)
                elog(ERROR, "Error in building split, unable to determine split direction.");
-       }
 
        POSTGIS_DEBUGF(3, "[GIST] 'picksplit' splitting on axis %d", direction);
 
-       gserialized_gist_picksplit_constructsplit(v, list[BELOW(direction)],
-                                               pos[BELOW(direction)],
-                                               &(box_union[BELOW(direction)]),
-                                               list[ABOVE(direction)],
-                                               pos[ABOVE(direction)],
-                                               &(box_union[ABOVE(direction)]) );
-
-       POSTGIS_DEBUGF(4, "[GIST] spl_ldatum: %s", gidx_to_string((GIDX*)v->spl_ldatum));
-       POSTGIS_DEBUGF(4, "[GIST] spl_rdatum: %s", gidx_to_string((GIDX*)v->spl_rdatum));
-
-       POSTGIS_DEBUGF(4, "[GIST] axis %d: parent range (%.12g, %.12g) left range (%.12g, %.12g), right range (%.12g, %.12g)",
-                      direction,
-                      GIDX_GET_MIN(box_pageunion, direction), GIDX_GET_MAX(box_pageunion, direction),
-                      GIDX_GET_MIN((GIDX*)v->spl_ldatum, direction), GIDX_GET_MAX((GIDX*)v->spl_ldatum, direction),
-                      GIDX_GET_MIN((GIDX*)v->spl_rdatum, direction), GIDX_GET_MAX((GIDX*)v->spl_rdatum, direction) );
+       gserialized_gist_picksplit_constructsplit(v,
+                                                 list[BELOW(direction)],
+                                                 pos[BELOW(direction)],
+                                                 &(box_union[BELOW(direction)]),
+                                                 list[ABOVE(direction)],
+                                                 pos[ABOVE(direction)],
+                                                 &(box_union[ABOVE(direction)]));
+
+       POSTGIS_DEBUGF(4, "[GIST] spl_ldatum: %s", gidx_to_string((GIDX *)v->spl_ldatum));
+       POSTGIS_DEBUGF(4, "[GIST] spl_rdatum: %s", gidx_to_string((GIDX *)v->spl_rdatum));
+
+       POSTGIS_DEBUGF(
+           4,
+           "[GIST] axis %d: parent range (%.12g, %.12g) left range (%.12g, %.12g), right range (%.12g, %.12g)",
+           direction,
+           GIDX_GET_MIN(box_pageunion, direction),
+           GIDX_GET_MAX(box_pageunion, direction),
+           GIDX_GET_MIN((GIDX *)v->spl_ldatum, direction),
+           GIDX_GET_MAX((GIDX *)v->spl_ldatum, direction),
+           GIDX_GET_MIN((GIDX *)v->spl_rdatum, direction),
+           GIDX_GET_MAX((GIDX *)v->spl_rdatum, direction));
 
        PG_RETURN_POINTER(v);
-
 }
 
 /*
@@ -2003,15 +1850,14 @@ Datum gserialized_gist_picksplit(PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1(gidx_in);
 Datum gidx_in(PG_FUNCTION_ARGS)
 {
-       ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                      errmsg("function gidx_in not implemented")));
+       ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function gidx_in not implemented")));
        PG_RETURN_POINTER(NULL);
 }
 
 PG_FUNCTION_INFO_V1(gidx_out);
 Datum gidx_out(PG_FUNCTION_ARGS)
 {
-  GIDX *box = (GIDX *) PG_GETARG_POINTER(0);
-  char *result = gidx_to_string(box);
-  PG_RETURN_CSTRING(result);
+       GIDX *box = (GIDX *)PG_GETARG_POINTER(0);
+       char *result = gidx_to_string(box);
+       PG_RETURN_CSTRING(result);
 }
index 236a51e1d27ef147dc595b8cc87ff5a432414ad0..dfd23d051a2ecc6668367085edd6bd2afcbaf4fc 100644 (file)
@@ -28,6 +28,7 @@
 #include "fmgr.h"
 #include "utils/elog.h"
 #include "utils/geo_decls.h"
+#include "gserialized_spgist_3d.h"
 
 #include "../postgis_config.h"
 #include "lwgeom_pg.h"
index 848a2ae61e6c30b8f1c8b04c532c595783a2e063..285350c306248836d174f4baa1bc1dcba41b3261 100644 (file)
@@ -824,6 +824,48 @@ CREATE OPERATOR &&& (
        JOIN = gserialized_gist_joinsel_nd
 );
 
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION geometry_contains_nd(geometry, geometry)
+       RETURNS boolean
+       AS 'MODULE_PATHNAME' ,'gserialized_contains'
+       LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL;
+
+-- Availability: 2.5.0
+CREATE OPERATOR ~~ (
+       LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_contains_nd,
+       COMMUTATOR = '@@',
+       RESTRICT = gserialized_gist_sel_nd,
+       JOIN = gserialized_gist_joinsel_nd
+);
+
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION geometry_within_nd(geometry, geometry)
+       RETURNS boolean
+       AS 'MODULE_PATHNAME' ,'gserialized_within'
+       LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL;
+
+-- Availability: 2.5.0
+CREATE OPERATOR @@ (
+       LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_within_nd,
+       COMMUTATOR = '~~',
+       RESTRICT = gserialized_gist_sel_nd,
+       JOIN = gserialized_gist_joinsel_nd
+);
+
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION geometry_same_nd(geometry, geometry)
+       RETURNS boolean
+       AS 'MODULE_PATHNAME' ,'gserialized_same'
+       LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL;
+
+-- Availability: 2.5.0
+CREATE OPERATOR ~~= (
+       LEFTARG = geometry, RIGHTARG = geometry, PROCEDURE = geometry_same_nd,
+       COMMUTATOR = '~~=',
+       RESTRICT = gserialized_gist_sel_nd,
+       JOIN = gserialized_gist_joinsel_nd
+);
+
 -- Availability: 2.2.0
 CREATE OR REPLACE FUNCTION geometry_distance_centroid_nd(geometry,geometry)
        RETURNS float8
@@ -866,9 +908,12 @@ CREATE OPERATOR CLASS gist_geometry_ops_nd
        FOR TYPE geometry USING GIST AS
        STORAGE         gidx,
        OPERATOR        3        &&&    ,
---     OPERATOR        6        ~=     ,
---     OPERATOR        7        ~      ,
---     OPERATOR        8        @      ,
+       -- Availability: 2.5.0
+       OPERATOR        6        ~~=    ,
+       -- Availability: 2.5.0
+       OPERATOR        7        ~~     ,
+       -- Availability: 2.5.0
+       OPERATOR        8        @@     ,
        -- Availability: 2.2.0
        OPERATOR        13       <<->> FOR ORDER BY pg_catalog.float_ops,
 #if POSTGIS_PGSQL_VERSION >= 95
index bcde4ea38576bc5d77ec2d88feada9c5ce58c594..3fd2424e4904e064859439994c5207714afeb95a 100644 (file)
@@ -163,4 +163,107 @@ CREATE OPERATOR CLASS spgist_geometry_ops_3d
        FUNCTION        4       geometry_spgist_inner_consistent_3d(internal, internal),
        FUNCTION        5       geometry_spgist_leaf_consistent_3d(internal, internal),
        FUNCTION        6       geometry_spgist_compress_3d(internal);
+
+-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
+-- SP-GiST ND Support Functions
+-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
+
+-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
+-- Geometry
+-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
+
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION geometry_spgist_config_nd(internal, internal)
+       RETURNS void
+       AS 'MODULE_PATHNAME' ,'gserialized_spgist_config_nd'
+       LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION geometry_spgist_choose_nd(internal, internal)
+       RETURNS void
+       AS 'MODULE_PATHNAME' ,'gserialized_spgist_choose_nd'
+       LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION geometry_spgist_picksplit_nd(internal, internal)
+       RETURNS void
+       AS 'MODULE_PATHNAME' ,'gserialized_spgist_picksplit_nd'
+       LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION geometry_spgist_inner_consistent_nd(internal, internal)
+       RETURNS void
+       AS 'MODULE_PATHNAME' ,'gserialized_spgist_inner_consistent_nd'
+       LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION geometry_spgist_leaf_consistent_nd(internal, internal)
+       RETURNS bool
+       AS 'MODULE_PATHNAME' ,'gserialized_spgist_leaf_consistent_nd'
+       LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION geometry_spgist_compress_nd(internal)
+       RETURNS internal
+       AS 'MODULE_PATHNAME' ,'gserialized_spgist_compress_nd'
+       LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+-- Availability: 2.5.0
+CREATE OPERATOR CLASS spgist_geometry_ops_nd
+       FOR TYPE geometry USING SPGIST AS
+       OPERATOR        3        &&& ,
+       OPERATOR        6        ~~=    ,
+       OPERATOR        7        ~~     ,
+       OPERATOR        8       @@      ,
+       FUNCTION                1               geometry_spgist_config_nd(internal, internal),
+       FUNCTION                2               geometry_spgist_choose_nd(internal, internal),
+       FUNCTION                3               geometry_spgist_picksplit_nd(internal, internal),
+       FUNCTION                4               geometry_spgist_inner_consistent_nd(internal, internal),
+       FUNCTION                5               geometry_spgist_leaf_consistent_nd(internal, internal),
+       FUNCTION                6               geometry_spgist_compress_nd(internal);
+
+-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
+-- Geography
+-- ---------- ---------- ---------- ---------- ---------- ---------- ----------
+
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION geography_spgist_config_nd(internal, internal)
+       RETURNS void
+       AS 'MODULE_PATHNAME' ,'gserialized_spgist_config_nd'
+       LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION geography_spgist_choose_nd(internal, internal)
+       RETURNS void
+       AS 'MODULE_PATHNAME' ,'gserialized_spgist_choose_nd'
+       LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION geography_spgist_picksplit_nd(internal, internal)
+       RETURNS void
+       AS 'MODULE_PATHNAME' ,'gserialized_spgist_picksplit_nd'
+       LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION geography_spgist_inner_consistent_nd(internal, internal)
+       RETURNS void
+       AS 'MODULE_PATHNAME' ,'gserialized_spgist_inner_consistent_nd'
+       LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION geography_spgist_leaf_consistent_nd(internal, internal)
+       RETURNS bool
+       AS 'MODULE_PATHNAME' ,'gserialized_spgist_leaf_consistent_nd'
+       LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+-- Availability: 2.5.0
+CREATE OR REPLACE FUNCTION geography_spgist_compress_nd(internal)
+       RETURNS internal
+       AS 'MODULE_PATHNAME' ,'gserialized_spgist_compress_nd'
+       LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+-- Availability: 2.5.0
+CREATE OPERATOR CLASS spgist_geography_ops_nd
+       DEFAULT FOR TYPE geography USING SPGIST AS
+       OPERATOR        3        && ,
+--     OPERATOR        6        ~=     ,
+--     OPERATOR        7        ~      ,
+--     OPERATOR        8        @      ,
+       FUNCTION                1               geography_spgist_config_nd(internal, internal),
+       FUNCTION                2               geography_spgist_choose_nd(internal, internal),
+       FUNCTION                3               geography_spgist_picksplit_nd(internal, internal),
+       FUNCTION                4               geography_spgist_inner_consistent_nd(internal, internal),
+       FUNCTION                5               geography_spgist_leaf_consistent_nd(internal, internal),
+       FUNCTION                6               geography_spgist_compress_nd(internal);
+
 #endif
index f5eb6bc502c15286f5773fdfc99f3a6829be4706..045b7667f8b80e15f103de67bea8b31b9d5386cc 100644 (file)
@@ -233,7 +233,9 @@ endif
 ifeq ($(HAVE_SPGIST),yes)
        TESTS += \
        regress_spgist_index_2d \
-       regress_spgist_index_3d
+       regress_spgist_index_3d \
+       regress_spgist_index_nd #\
+#      regress_gist_index_nd
 endif
 
 ifeq ($(HAVE_PROTOBUF),yes)
index 206fd88dd9a4af1b9834ecf17e51d2660640eb3e..0b8a44e3b22167adf8595c66c13828cb51d3d006 100644 (file)
@@ -115,30 +115,121 @@ select 'ndov7', 'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry &&&
 -- &&& with mixed dimensions
 
 WITH v(i,g) AS ( VALUES
- (1,'POINT(0 0)'::geometry), -- true, infinite M range
- (2,'POINTZ(0 0 1)'),        -- true, infinite M range
- (3,'POINTZ(0 0 0)'),        -- true, infinite M range
- (4,'POINTM(0 0 1)'),        -- true, fully defined overlap
- (5,'POINTZM(0 0 0 1)'),     -- true, fully defined overlap
- (6,'POINTZM(0 0 1 0)'),     -- false, M out of range
- (7,'LINESTRINGM(-1 0 2,1 0 3)'), -- false, M out of range
- (8,'LINESTRINGZ(-1 0 2,1 0 3)')  -- true, infinite M range
+ (1,'POINT(0 0)'::geometry),                   -- true for {1,2,3,4,5,6,7,8,9}
+ (2,'POINTZ(0 0 1)'),                                  -- true for {1,2,4,6,7}
+ (3,'POINTZ(0 0 0)'),                                  -- true for {1,3,4,5,7}
+ (4,'POINTM(0 0 1)'),                                  -- true for {1,2,3,4,5,8}
+ (5,'POINTZM(0 0 0 1)'),                               -- true for {1,3,4,5}
+ (6,'POINTZM(0 0 1 0)'),                                       -- true for {1,2,6}
+ (7,'LINESTRINGM(-1 0 2,1 0 3)'),              -- true for {1,2,3,7,8,9}
+ (8,'LINESTRINGZ(-1 0 2,1 0 3)'),              -- true for {1,4,7,8,9}
+ (9,'LINESTRINGZM(-1 0 2 2,1 0 3 3)')  -- true for {1,7,8,9}
  )
-SELECT 'ndovm1', array_agg(i) FROM v WHERE g &&& 'POINTM(0 0 1)'::geometry
-ORDER BY 1;
+SELECT 'ndovm', v1.i, array_agg(v2.i) FROM v v1, v v2 WHERE v1.g &&& v2.g
+group by v1.i
+ORDER BY 2;
+
+-- nd contains             ~~
+
+select 'ndcont1', 'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry ~~
+                'POINT(3 3 3 5)'::geometry; -- f
+select 'ndcont2', 'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry ~~
+                'POINT(3 3 5 3)'::geometry; -- f
+select 'ndcont3', 'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry ~~
+                'POINT(3 5 3 3)'::geometry; -- f
+select 'ndcont4', 'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry ~~
+                'POINT(5 3 3 3)'::geometry; -- f
+select 'ndcont5', 'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry ~~
+                'POINT(3 3 3 3)'::geometry; -- t
+select 'ndcont6', 'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry ~~
+                'POINT(2 4 2 4)'::geometry; -- t
+select 'ndcont7', 'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry ~~
+                'POINT(4 2 4 2)'::geometry; -- t
+
+-- ~~ with mixed dimensions
+
+WITH v(i,g) AS ( VALUES
+ (1,'POINT(0 0)'::geometry),
+ (2,'POINTZ(0 0 1)'),
+ (3,'POINTZ(0 0 0)'),
+ (4,'POINTM(0 0 1)'),
+ (5,'POINTZM(0 0 0 1)'),
+ (6,'POINTZM(0 0 1 0)'),
+ (7,'LINESTRINGM(-1 0 2,1 0 3)'),
+ (8,'LINESTRINGZ(-1 0 2,1 0 3)'),
+ (9,'LINESTRINGZM(-1 0 2 2,1 0 3 3)')
+ )
+SELECT 'ndcontm', v1.i, array_agg(v2.i) FROM v v1, v v2 WHERE v1.g ~~ v2.g
+group by v1.i
+ORDER BY 2;
+
+-- nd within             @@
+
+select 'ndwithin1', 'POINT(3 3 3 5)'::geometry @@
+                'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry; -- f
+select 'ndwithin2', 'POINT(3 3 5 3)'::geometry @@
+                'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry; -- f
+select 'ndwithin3', 'POINT(3 5 3 3)'::geometry @@
+                'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry; -- f
+select 'ndwithin4', 'POINT(5 3 3 3)'::geometry @@
+                'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry; -- f
+select 'ndwithin5', 'POINT(3 3 3 3)'::geometry @@
+                'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry; -- t
+select 'ndwithin6', 'POINT(2 4 2 4)'::geometry @@
+                'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry; -- t
+select 'ndwithin7', 'POINT(4 2 4 2)'::geometry @@
+                'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry; -- t
+
+-- @@ with mixed dimensions
+
+WITH v(i,g) AS ( VALUES
+ (1,'POINT(0 0)'::geometry),
+ (2,'POINTZ(0 0 1)'),
+ (3,'POINTZ(0 0 0)'),
+ (4,'POINTM(0 0 1)'),
+ (5,'POINTZM(0 0 0 1)'),
+ (6,'POINTZM(0 0 1 0)'),
+ (7,'LINESTRINGM(-1 0 2,1 0 3)'),
+ (8,'LINESTRINGZ(-1 0 2,1 0 3)'),
+ (9,'LINESTRINGZM(-1 0 2 2,1 0 3 3)')
+ )
+SELECT 'ndwithinm', v1.i, array_agg(v2.i) FROM v v1, v v2 WHERE v1.g @@ v2.g
+group by v1.i
+ORDER BY 2;
+
+-- nd same             ~~=
+
+select 'ndsame1', 'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry ~~=
+                'POINT(3 3 3 3)'::geometry; -- f
+select 'ndsame2', 'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry ~~=
+                'LINESTRING(2 2 2 2, 4 4 4 5)'::geometry; -- f
+select 'ndsame3', 'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry ~~=
+                'LINESTRING(2 2 2 2, 4 4 5 4)'::geometry; -- f
+select 'ndsame4', 'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry ~~=
+                'LINESTRING(2 2 2 2, 4 5 4 4)'::geometry; -- f
+select 'ndsame5', 'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry ~~=
+                'LINESTRING(2 2 2 2, 5 4 4 4)'::geometry; -- f
+select 'ndsame6', 'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry ~~=
+                'LINESTRING(4 4 4 4, 2 2 2 2)'::geometry; -- t
+select 'ndsame7', 'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry ~~=
+                'LINESTRING(2 2 2 4, 2 2 4 2, 2 4 2 2, 4 2 2 2)'::geometry; -- t
+
+-- ~~= with mixed dimensions
 
 WITH v(i,g) AS ( VALUES
- (1,'POINT(0 0)'::geometry), -- true, infinite Z range
- (2,'POINTZ(0 0 1)'),        -- true, fully defined overlap
- (3,'POINTZ(0 0 0)'),        -- false, Z out of range
- (4,'POINTM(0 0 0)'),        -- true, infinite Z range
- (5,'POINTZM(0 0 0 1)'),     -- false, Z out of range
- (6,'POINTZM(0 0 1 0)'),     -- true, fully defined overlap
- (7,'LINESTRINGM(-1 0 2,1 0 3)'), -- true, infinite Z range
- (8,'LINESTRINGZ(-1 0 2,1 0 3)')  -- false, Z out of range
+ (1,'POINT(0 0)'::geometry),
+ (2,'POINTZ(0 0 1)'),
+ (3,'POINTZ(0 0 0)'),
+ (4,'POINTM(0 0 1)'),
+ (5,'POINTZM(0 0 0 1)'),
+ (6,'POINTZM(0 0 1 0)'),
+ (7,'LINESTRINGM(-1 0 2,1 0 3)'),
+ (8,'LINESTRINGZ(-1 0 2,1 0 3)'),
+ (9,'LINESTRINGZM(-1 0 2 2,1 0 3 3)')
  )
-SELECT 'ndovm2', array_agg(i) FROM v WHERE g &&& 'POINTZ(0 0 1)'::geometry
-ORDER BY 1;
+SELECT 'ndsamem', v1.i, array_agg(v2.i) FROM v v1, v v2 WHERE v1.g ~~= v2.g
+group by v1.i
+ORDER BY 2;
 
 -- GROUP BY on empty
 SELECT '#3777', ST_AsText(geom), count(*)
index b5018c50913dc2f50718d6f11b7054a00c559454..801e8bfecdc9aa5ccfa493be394721dd76fc7db2 100644 (file)
@@ -54,8 +54,63 @@ ndov4|f
 ndov5|t
 ndov6|t
 ndov7|t
-ndovm1|{1,2,3,4,5,8}
-ndovm2|{1,2,4,6,7}
+ndovm|1|{1,2,3,4,5,6,7,8,9}
+ndovm|2|{1,2,4,6,7}
+ndovm|3|{1,3,4,5,7}
+ndovm|4|{1,2,3,4,5,8}
+ndovm|5|{1,3,4,5}
+ndovm|6|{1,2,6}
+ndovm|7|{1,2,3,7,8,9}
+ndovm|8|{1,4,7,8,9}
+ndovm|9|{1,7,8,9}
+ndcont1|f
+ndcont2|f
+ndcont3|f
+ndcont4|f
+ndcont5|t
+ndcont6|t
+ndcont7|t
+ndcontm|1|{1,2,3,4,5,6}
+ndcontm|2|{1,2,4,6}
+ndcontm|3|{1,3,4,5}
+ndcontm|4|{1,2,3,4,5}
+ndcontm|5|{1,3,4,5}
+ndcontm|6|{1,2,6}
+ndcontm|7|{1,2,3,7,8,9}
+ndcontm|8|{1,4,7,8,9}
+ndcontm|9|{1,7,8,9}
+ndwithin1|f
+ndwithin2|f
+ndwithin3|f
+ndwithin4|f
+ndwithin5|t
+ndwithin6|t
+ndwithin7|t
+ndwithinm|1|{1,2,3,4,5,6,7,8,9}
+ndwithinm|2|{1,2,4,6,7}
+ndwithinm|3|{1,3,4,5,7}
+ndwithinm|4|{1,2,3,4,5,8}
+ndwithinm|5|{1,3,4,5}
+ndwithinm|6|{1,2,6}
+ndwithinm|7|{7,8,9}
+ndwithinm|8|{7,8,9}
+ndwithinm|9|{7,8,9}
+ndsame1|f
+ndsame2|f
+ndsame3|f
+ndsame4|f
+ndsame5|f
+ndsame6|t
+ndsame7|t
+ndsamem|1|{1,2,3,4,5,6}
+ndsamem|2|{1,2,4,6}
+ndsamem|3|{1,3,4,5}
+ndsamem|4|{1,2,3,4,5}
+ndsamem|5|{1,3,4,5}
+ndsamem|6|{1,2,6}
+ndsamem|7|{7,8,9}
+ndsamem|8|{7,8,9}
+ndsamem|9|{7,8,9}
 #3777|GEOMETRYCOLLECTION EMPTY|1
 #3777|LINESTRING(0 0,0 1)|1
 #3777|POINT EMPTY|1