[postgis-tickets] r15700 - #3844, new btree behavior for = and < >

Paul Ramsey pramsey at cleverelephant.ca
Tue Sep 12 12:44:32 PDT 2017


Author: pramsey
Date: 2017-09-12 12:44:32 -0700 (Tue, 12 Sep 2017)
New Revision: 15700

Modified:
   trunk/liblwgeom/g_serialized.c
   trunk/liblwgeom/liblwgeom.h.in
   trunk/postgis/geography_btree.c
   trunk/postgis/lwgeom_btree.c
   trunk/regress/concave_hull.sql
   trunk/regress/operators.sql
   trunk/regress/operators_expected
   trunk/topology/test/regress/topojson_expected
Log:
#3844, new btree behavior for = and < > 


Modified: trunk/liblwgeom/g_serialized.c
===================================================================
--- trunk/liblwgeom/g_serialized.c	2017-09-12 16:04:46 UTC (rev 15699)
+++ trunk/liblwgeom/g_serialized.c	2017-09-12 19:44:32 UTC (rev 15700)
@@ -25,6 +25,7 @@
 
 #include "liblwgeom_internal.h"
 #include "lwgeom_log.h"
+#include "lwgeodetic.h"
 
 /***********************************************************************
 * GSERIALIZED metadata utility functions.
@@ -66,6 +67,16 @@
 	return sizeof(GSERIALIZED) + 8 * sizeof(float) + sizeof(int);
 }
 
+uint32_t gserialized_header_size(const GSERIALIZED *gser)
+{
+	uint32_t sz = 8; /* varsize (4) + srid(3) + flags (1) */
+
+	if (gserialized_has_bbox(gser)) 
+		sz += gbox_serialized_size(gser->flags);
+
+	return sz;
+}
+
 uint32_t gserialized_get_type(const GSERIALIZED *s)
 {
 	uint32_t *ptr;
@@ -169,6 +180,185 @@
 	return lwgeom_to_wkt(lwgeom_from_gserialized(g), WKT_ISO, 12, 0);
 }
 
+/* Unfortunately including advanced instructions is something that
+only helps a small sliver of users who can build their own 
+knowing the target system they will be running on. Packagers
+have to aim for the lowest common demoninator. So this is 
+dead code for the forseeable future. */
+#define HAVE_PDEP 0
+#if HAVE_PDEP
+/* http://www.joshbarczak.com/blog/?p=454 */
+static uint64_t uint32_interleave_2(uint32_t u1, uint32_t u2)
+{
+    uint64_t x = u1;
+    uint64_t y = u2;
+    uint64_t x_mask = 0x5555555555555555;
+    uint64_t y_mask = 0xAAAAAAAAAAAAAAAA;
+    return _pdep_u64(x, x_mask) | _pdep_u64(y, y_mask);
+}
+
+static uint64_t uint32_interleave_3(uint32_t u1, uint32_t u2, uint32_t u3)
+{
+    /* only look at the first 21 bits */
+    uint64_t x = u1 & 0x1FFFFF;
+    uint64_t y = u2 & 0x1FFFFF;
+    uint64_t z = u3 & 0x1FFFFF;
+    uint64_t x_mask = 0x9249249249249249;
+    uint64_t y_mask = 0x2492492492492492;
+    uint64_t z_mask = 0x4924924924924924;
+    return _pdep_u64(x, x_mask) | _pdep_u64(y, y_mask) | _pdep_u64(z, z_mask);
+}
+
+#else
+static uint64_t uint32_interleave_2(uint32_t u1, uint32_t u2)
+{
+    uint64_t x = u1;
+    uint64_t y = u2;
+    int i;
+
+    static uint64_t B[5] = 
+    { 
+        0x5555555555555555, 
+        0x3333333333333333, 
+        0x0F0F0F0F0F0F0F0F, 
+        0x00FF00FF00FF00FF, 
+        0x0000FFFF0000FFFF 
+    };
+    static uint64_t S[5] = { 1, 2, 4, 8, 16 };
+
+    for ( i = 4; i >= 0; i-- )
+    {
+        x = (x | (x << S[i])) & B[i];
+        y = (y | (y << S[i])) & B[i];
+    }
+
+    return x | (y << 1);
+}
+#endif
+
+
+uint64_t gbox_get_sortable_hash(const GBOX *g)
+{
+	uint32_t ux, uy;
+	float fx, fy;
+
+	/* 
+	* Since in theory the bitwise representation of an IEEE
+	* float is sortable (exponents come before mantissa, etc)
+	* we just copy the bits directly into an int and then
+	* interleave those ints.
+	*/
+	if ( FLAGS_GET_GEODETIC(g->flags) )
+	{
+		GEOGRAPHIC_POINT gpt;
+		POINT3D p;
+		p.x = (g->xmax + g->xmin) / 2.0;
+		p.y = (g->ymax + g->ymin) / 2.0;
+		p.z = (g->zmax + g->zmin) / 2.0;
+		normalize(&p);
+		cart2geog(&p, &gpt);
+		fx = gpt.lon;
+		fy = gpt.lat;
+		memcpy(&ux, &fx, sizeof(uint32_t));
+		memcpy(&uy, &fy, sizeof(uint32_t));
+	}
+	else
+	{
+		fx = (g->xmax + g->xmin) / 2.0;
+		fy = (g->ymax + g->ymin) / 2.0;
+		memcpy(&ux, &fx, sizeof(uint32_t));
+		memcpy(&uy, &fy, sizeof(uint32_t));
+	}
+	return uint32_interleave_2(ux, uy);
+}
+
+int gserialized_cmp(const GSERIALIZED *g1, const GSERIALIZED *g2)
+{
+	int g1_is_empty, g2_is_empty, cmp;
+	GBOX box1, box2;
+	size_t sz1 = SIZE_GET(g1->size);
+	size_t sz2 = SIZE_GET(g2->size);
+	size_t hsz1 = gserialized_header_size(g1);
+	size_t hsz2 = gserialized_header_size(g2);
+
+	uint8_t *b1 = (uint8_t*)g1 + hsz1;
+	uint8_t *b2 = (uint8_t*)g2 + hsz2;
+	size_t bsz1 = sz1 - hsz1;
+	size_t bsz2 = sz2 - hsz2;
+	size_t bsz = bsz1 < bsz2 ? bsz1 : bsz2;
+	
+	uint64_t hash1, hash2;
+	int32_t srid1 = gserialized_get_srid(g1);
+	int32_t srid2 = gserialized_get_srid(g2);
+	
+	g1_is_empty = (gserialized_get_gbox_p(g1, &box1) == LW_FAILURE);
+	g2_is_empty = (gserialized_get_gbox_p(g2, &box2) == LW_FAILURE);
+	
+	/* Empty == Empty */
+	if (g1_is_empty && g2_is_empty)
+    {
+        /* POINT EMPTY == POINT EMPTY */
+        /* POINT EMPTY < LINESTRING EMPTY */
+        uint32_t t1 = gserialized_get_type(g1);
+        uint32_t t2 = gserialized_get_type(g2);
+		return t1 == t2 ? 0 : (t1 < t2 ? -1 : 1);
+    }
+	
+	/* Empty < Non-empty */
+	if (g1_is_empty)
+		return -1;
+	
+	/* Non-empty > Empty */
+	if (g2_is_empty)
+		return 1;
+
+	/* Return equality for perfect equality only */
+	cmp = memcmp(b1, b2, bsz);
+	if ( bsz1 == bsz2 && srid1 == srid2 && cmp == 0 )
+		return 0;
+	
+	/* using the centroids, and preferring the X axis */
+	hash1 = gbox_get_sortable_hash(&box1);
+	hash2 = gbox_get_sortable_hash(&box2);
+
+	if ( hash1 > hash2 )
+		return 1;
+	else if ( hash1 < hash2 ) 
+		return -1;
+	
+	/* What, the hashes are equal? OK... sort on the */
+	/* box minima */
+	if (box1.xmin < box2.xmin)
+		return -1;
+	else if (box1.xmin > box2.xmin)
+		return 1;
+
+	if (box1.ymin < box2.ymin)
+		return -1;
+	else if (box1.ymin > box2.ymin)
+		return 1;
+
+	/* Still equal? OK... sort on the box maxima */
+	if (box1.xmax < box2.xmax)
+		return -1;
+	else if (box1.xmax > box2.xmax)
+		return 1;
+
+	if (box1.ymax < box2.ymax)
+		return -1;
+	else if (box1.ymax > box2.ymax)
+		return 1;
+
+	/* How about object size? Sort on that... */
+	if (hsz1 < hsz2)
+		return -1;
+	else if (hsz1 > hsz2)
+		return 1;
+	
+	/* Well, they aren't memcmp equal, so we'll sort on the memcmp */
+	return cmp == 0 ? 0 : (cmp > 0 ? 1 : -1);
+}
+
 int gserialized_read_gbox_p(const GSERIALIZED *g, GBOX *gbox)
 {
 

Modified: trunk/liblwgeom/liblwgeom.h.in
===================================================================
--- trunk/liblwgeom/liblwgeom.h.in	2017-09-12 16:04:46 UTC (rev 15699)
+++ trunk/liblwgeom/liblwgeom.h.in	2017-09-12 19:44:32 UTC (rev 15700)
@@ -651,6 +651,12 @@
 extern uint32_t gserialized_max_header_size(void);
 
 /**
+* Returns the size in bytes of the header, from the start of the 
+* object up to the type number.
+*/
+extern uint32_t gserialized_header_size(const GSERIALIZED *gser);
+
+/**
 * Extract the SRID from the serialized form (it is packed into
 * three bytes so this is a handy function).
 */
@@ -701,6 +707,16 @@
 */
 extern int gserialized_ndims(const GSERIALIZED *gser);
 
+/**
+* Return -1 if g1 is "less than" g2, 1 if g1 is "greater than"
+* g2 and 0 if g1 and g2 are the "same". Equality is evaluated
+* with a memcmp and size check. So it is possible that two 
+* identical objects where one lacks a bounding box could be 
+* evaluated as non-equal initially. Greater and less than
+* are evaluated by calculating a sortable key from the center 
+* point of the object bounds.
+*/
+extern int gserialized_cmp(const GSERIALIZED *g1, const GSERIALIZED *g2);
 
 /**
 * Call this function to drop BBOX and SRID
@@ -1942,6 +1958,12 @@
 extern int gbox_is_valid(const GBOX *gbox);
 
 /**
+* Return a sortable key based on the center point of the
+* GBOX.
+*/
+extern uint64_t gbox_get_sortable_hash(const GBOX *g);
+
+/**
 * Utility function to get type number from string. For example, a string 'POINTZ'
 * would return type of 1 and z of 1 and m of 0. Valid
 */

Modified: trunk/postgis/geography_btree.c
===================================================================
--- trunk/postgis/geography_btree.c	2017-09-12 16:04:46 UTC (rev 15699)
+++ trunk/postgis/geography_btree.c	2017-09-12 19:44:32 UTC (rev 15700)
@@ -54,78 +54,6 @@
 	p->z = GIDX_GET_MIN(gidx, 2) + GIDX_GET_MAX(gidx, 2);
 }
 
-static int geography_cmp_internal(const GSERIALIZED *g1, const GSERIALIZED *g2)
-{
-	int cmp, have_box1, have_box2;
-	int g1_is_empty = gserialized_is_empty(g1);
-	int g2_is_empty = gserialized_is_empty(g2);
-	size_t sz1 = SIZE_GET(g1->size);
-	size_t sz2 = SIZE_GET(g2->size);
-	size_t sz = sz1 < sz2 ? sz1 : sz2;
-
-	/* Put aside some stack memory and use it for GIDX pointers. */
-	char gboxmem1[GIDX_MAX_SIZE];
-	char gboxmem2[GIDX_MAX_SIZE];
-	GIDX *gbox1 = (GIDX*)gboxmem1;
-	GIDX *gbox2 = (GIDX*)gboxmem2;
-	POINT3D p1, p2;
-
-	/* Empty == Empty */
-	if (g1_is_empty && g2_is_empty)
-    {
-        /* POINT EMPTY == POINT EMPTY */
-        /* POINT EMPTY < LINESTRING EMPTY */
-        uint32_t t1 = gserialized_get_type(g1);
-        uint32_t t2 = gserialized_get_type(g2);
-		return t1 == t2 ? 0 : (t1 < t2 ? -1 : 1);
-    }
-	
-	/* Empty < Non-empty */
-	if (g1_is_empty)
-		return -1;
-	
-	/* Non-empty > Empty */
-	if (g2_is_empty)
-		return 1;
-
-	/* Return equality for perfect equality only */
-	cmp = memcmp(g1, g2, sz);
-	if ( sz1 == sz2 && cmp == 0 )
-		return 0;
-	
-	/* Must be able to build box for each argument */
-	/* (ie, not empty geometry) */
-	have_box1 = gserialized_get_gidx_p(g1, gbox1);
-	have_box2 = gserialized_get_gidx_p(g2, gbox2);
-	if ( ! (have_box1 && have_box2) )
-	{
-		lwerror("%s [%d] unable to calculate boxes of geographies", __FILE__, __LINE__);
-	}
-
-	/* Order geographies more or less left-to-right */
-	/* using the centroids, and preferring the X axis */
-	geography_gidx_center(gbox1, &p1);
-	geography_gidx_center(gbox2, &p2);
-
-	if  ( ! FP_EQUALS(p1.x, p2.x) )
-		return p1.x < p2.x ? -1 : 1;
-
-	if  ( ! FP_EQUALS(p1.y, p2.y) )
-		return p1.y < p2.y ? -1 : 1;
-
-	if  ( ! FP_EQUALS(p1.z, p2.z) )
-		return p1.z < p2.z ? -1 : 1;
-
-	/* Geographies that are the "same in centroid" */
-	/* but didn't pass the exact equality test */
-	/* First order smallest-first */
-	if (sz1 != sz2)
-		return sz1 < sz2 ? -1 : 1;
-	/* Then just order on the memcmp return */
-	else
-		return cmp;
-}
-
 /*
 ** BTree support function. Based on two geographies return true if
 ** they are "less than" and false otherwise.
@@ -135,7 +63,7 @@
 {
 	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
 	GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
-	int cmp = geography_cmp_internal(g1, g2);
+	int cmp = gserialized_cmp(g1, g2);
 	if (cmp < 0)
 		PG_RETURN_BOOL(TRUE);
 	else
@@ -151,7 +79,7 @@
 {
 	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
 	GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
-	int cmp = geography_cmp_internal(g1, g2);
+	int cmp = gserialized_cmp(g1, g2);
 	if (cmp <= 0)
 		PG_RETURN_BOOL(TRUE);
 	else
@@ -167,7 +95,7 @@
 {
 	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
 	GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
-	int cmp = geography_cmp_internal(g1, g2);
+	int cmp = gserialized_cmp(g1, g2);
 	if (cmp > 0)
 		PG_RETURN_BOOL(TRUE);
 	else
@@ -183,7 +111,7 @@
 {
 	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
 	GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
-	int cmp = geography_cmp_internal(g1, g2);
+	int cmp = gserialized_cmp(g1, g2);
 	if (cmp >= 0)
 		PG_RETURN_BOOL(TRUE);
 	else
@@ -199,7 +127,7 @@
 {
 	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
 	GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
-	int cmp = geography_cmp_internal(g1, g2);
+	int cmp = gserialized_cmp(g1, g2);
 	if (cmp == 0)
 		PG_RETURN_BOOL(TRUE);
 	else
@@ -215,41 +143,5 @@
 {
 	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
 	GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
-	PG_RETURN_INT32(geography_cmp_internal(g1, g2));
+	PG_RETURN_INT32(gserialized_cmp(g1, g2));
 }
-
-
-#if 0
-/*
-** Calculate a hash code based on the geometry data alone
-*/
-static uint32 geography_hash(GSERIALIZED *g)
-{
-	return DatumGetUInt32(hash_any((void*)g, VARSIZE(g)));
-}
-/*
-** BTree support function. Based on two geographies return true if
-** they are "equal" and false otherwise. This version uses a hash
-** function to try and shoot for a more exact equality test.
-*/
-PG_FUNCTION_INFO_V1(geography_eq);
-Datum geography_eq(PG_FUNCTION_ARGS)
-{
-	/* Perfect equals test based on hash */
-	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
-	GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
-
-	uint32 h1 = geography_hash(g1);
-	uint32 h2 = geography_hash(g2);
-
-	PG_FREE_IF_COPY(g1,0);
-	PG_FREE_IF_COPY(g2,0);
-
-	if ( h1 == h2 )
-		PG_RETURN_BOOL(TRUE);
-
-	PG_RETURN_BOOL(FALSE);
-}
-#endif
-
-

Modified: trunk/postgis/lwgeom_btree.c
===================================================================
--- trunk/postgis/lwgeom_btree.c	2017-09-12 16:04:46 UTC (rev 15699)
+++ trunk/postgis/lwgeom_btree.c	2017-09-12 19:44:32 UTC (rev 15700)
@@ -49,354 +49,68 @@
 PG_FUNCTION_INFO_V1(lwgeom_lt);
 Datum lwgeom_lt(PG_FUNCTION_ARGS)
 {
-	GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
-	GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
-	GBOX box1;
-	GBOX box2;
-	bool empty1, empty2;
-
-	POSTGIS_DEBUG(2, "lwgeom_lt called");
-
-	error_if_srid_mismatch(gserialized_get_srid(geom1), gserialized_get_srid(geom2));
-
-	POSTGIS_DEBUG(3, "lwgeom_lt passed getSRID test");
-
-	empty1 = ( gserialized_get_gbox_p(geom1, &box1) == LW_FAILURE );
-	empty2 = ( gserialized_get_gbox_p(geom2, &box2) == LW_FAILURE );
-
-	PG_FREE_IF_COPY(geom1, 0);
-	PG_FREE_IF_COPY(geom2, 1);
-
-	POSTGIS_DEBUG(3, "lwgeom_lt getbox2d_p passed");
-
-	if  ( empty1 != empty2 )
-	{
-		PG_RETURN_BOOL(FALSE);
-	}
-
-	if  ( ! FPeq(box1.xmin , box2.xmin) )
-	{
-		if  (box1.xmin < box2.xmin)
-			PG_RETURN_BOOL(TRUE);
-	}
-
-	if  ( ! FPeq(box1.ymin , box2.ymin) )
-	{
-		if  (box1.ymin < box2.ymin)
-			PG_RETURN_BOOL(TRUE);
-	}
-
-	if  ( ! FPeq(box1.xmax , box2.xmax) )
-	{
-		if  (box1.xmax < box2.xmax)
-			PG_RETURN_BOOL(TRUE);
-	}
-
-	if  ( ! FPeq(box1.ymax , box2.ymax) )
-	{
-		if  (box1.ymax < box2.ymax)
-			PG_RETURN_BOOL(TRUE);
-	}
-
-	PG_RETURN_BOOL(FALSE);
+	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
+	GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
+	int cmp = gserialized_cmp(g1, g2);
+	if (cmp < 0)
+		PG_RETURN_BOOL(TRUE);
+	else
+		PG_RETURN_BOOL(FALSE);	
 }
 
 PG_FUNCTION_INFO_V1(lwgeom_le);
 Datum lwgeom_le(PG_FUNCTION_ARGS)
 {
-	GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
-	GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
-	GBOX box1;
-	GBOX box2;
-	bool empty1, empty2;
-
-	POSTGIS_DEBUG(2, "lwgeom_le called");
-
-	error_if_srid_mismatch(gserialized_get_srid(geom1), gserialized_get_srid(geom2));
-
-	empty1 = ( gserialized_get_gbox_p(geom1, &box1) == LW_FAILURE );
-	empty2 = ( gserialized_get_gbox_p(geom2, &box2) == LW_FAILURE );
-
-	PG_FREE_IF_COPY(geom1, 0);
-	PG_FREE_IF_COPY(geom2, 1);
-
-	if  ( empty1 != empty2 )
-	{
-		PG_RETURN_BOOL(FALSE);
-	}
-
-	if  ( ! FPeq(box1.xmin , box2.xmin) )
-	{
-		if  (box1.xmin < box2.xmin)
-		{
-			PG_RETURN_BOOL(TRUE);
-		}
-		PG_RETURN_BOOL(FALSE);
-	}
-
-	if  ( ! FPeq(box1.ymin , box2.ymin) )
-	{
-		if  (box1.ymin < box2.ymin)
-		{
-			PG_RETURN_BOOL(TRUE);
-		}
-		PG_RETURN_BOOL(FALSE);
-	}
-
-	if  ( ! FPeq(box1.xmax , box2.xmax) )
-	{
-		if  (box1.xmax < box2.xmax)
-		{
-			PG_RETURN_BOOL(TRUE);
-		}
-		PG_RETURN_BOOL(FALSE);
-	}
-
-	if  ( ! FPeq(box1.ymax , box2.ymax) )
-	{
-		if  (box1.ymax < box2.ymax)
-		{
-			PG_RETURN_BOOL(TRUE);
-		}
-		PG_RETURN_BOOL(FALSE);
-	}
-
-	PG_RETURN_BOOL(TRUE);
+	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
+	GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
+	int cmp = gserialized_cmp(g1, g2);
+	if (cmp == 0)
+		PG_RETURN_BOOL(TRUE);
+	else
+		PG_RETURN_BOOL(FALSE);	
 }
 
 PG_FUNCTION_INFO_V1(lwgeom_eq);
 Datum lwgeom_eq(PG_FUNCTION_ARGS)
 {
-	GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
-	GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
-	GBOX box1;
-	GBOX box2;
-  bool empty1, empty2;
-	bool result;
-
-	POSTGIS_DEBUG(2, "lwgeom_eq called");
-
-	error_if_srid_mismatch(gserialized_get_srid(geom1), gserialized_get_srid(geom2));
-
-	gbox_init(&box1);
-	gbox_init(&box2);
-
-	empty1 = ( gserialized_get_gbox_p(geom1, &box1) == LW_FAILURE );
-	empty2 = ( gserialized_get_gbox_p(geom2, &box2) == LW_FAILURE );
-
-	PG_FREE_IF_COPY(geom1, 0);
-	PG_FREE_IF_COPY(geom2, 1);
-
-	if  ( empty1 != empty2 )
-	{
-    result = FALSE;
-	}
-  else if  ( ! (FPeq(box1.xmin, box2.xmin) && FPeq(box1.ymin, box2.ymin) &&
-	         FPeq(box1.xmax, box2.xmax) && FPeq(box1.ymax, box2.ymax)) )
-	{
-		result = FALSE;
-	}
+	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
+	GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
+	int cmp = gserialized_cmp(g1, g2);
+	if (cmp == 0)
+		PG_RETURN_BOOL(TRUE);
 	else
-	{
-		result = TRUE;
-	}
-
-	PG_RETURN_BOOL(result);
+		PG_RETURN_BOOL(FALSE);	
 }
 
 PG_FUNCTION_INFO_V1(lwgeom_ge);
 Datum lwgeom_ge(PG_FUNCTION_ARGS)
 {
-	GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
-	GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
-	GBOX box1;
-	GBOX box2;
-	bool empty1, empty2;
-
-	POSTGIS_DEBUG(2, "lwgeom_ge called");
-
-	error_if_srid_mismatch(gserialized_get_srid(geom1), gserialized_get_srid(geom2));
-
-	empty1 = ( gserialized_get_gbox_p(geom1, &box1) == LW_FAILURE );
-	empty2 = ( gserialized_get_gbox_p(geom2, &box2) == LW_FAILURE );
-
-	PG_FREE_IF_COPY(geom1, 0);
-	PG_FREE_IF_COPY(geom2, 1);
-
-	if  ( empty1 != empty2 )
-	{
-		PG_RETURN_BOOL(FALSE);
-	}
-
-	if  ( ! FPeq(box1.xmin , box2.xmin) )
-	{
-		if  (box1.xmin > box2.xmin)
-		{
-			PG_RETURN_BOOL(TRUE);
-		}
-		PG_RETURN_BOOL(FALSE);
-	}
-
-	if  ( ! FPeq(box1.ymin , box2.ymin) )
-	{
-		if  (box1.ymin > box2.ymin)
-		{
-			PG_RETURN_BOOL(TRUE);
-		}
-		PG_RETURN_BOOL(FALSE);
-	}
-
-	if  ( ! FPeq(box1.xmax , box2.xmax) )
-	{
-		if  (box1.xmax > box2.xmax)
-		{
-			PG_RETURN_BOOL(TRUE);
-		}
-		PG_RETURN_BOOL(FALSE);
-	}
-
-	if  ( ! FPeq(box1.ymax , box2.ymax) )
-	{
-		if  (box1.ymax > box2.ymax)
-		{
-			PG_RETURN_BOOL(TRUE);
-		}
-		PG_RETURN_BOOL(FALSE);
-	}
-
-	PG_RETURN_BOOL(TRUE);
+	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
+	GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
+	int cmp = gserialized_cmp(g1, g2);
+	if (cmp >= 0)
+		PG_RETURN_BOOL(TRUE);
+	else
+		PG_RETURN_BOOL(FALSE);	
 }
 
 PG_FUNCTION_INFO_V1(lwgeom_gt);
 Datum lwgeom_gt(PG_FUNCTION_ARGS)
 {
-	GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
-	GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
-	GBOX box1;
-	GBOX box2;
-	bool empty1, empty2;
-
-	POSTGIS_DEBUG(2, "lwgeom_gt called");
-
-	error_if_srid_mismatch(gserialized_get_srid(geom1), gserialized_get_srid(geom2));
-
-	empty1 = ( gserialized_get_gbox_p(geom1, &box1) == LW_FAILURE );
-	empty2 = ( gserialized_get_gbox_p(geom2, &box2) == LW_FAILURE );
-
-	PG_FREE_IF_COPY(geom1, 0);
-	PG_FREE_IF_COPY(geom2, 1);
-
-	if  ( empty1 != empty2 )
-	{
-		PG_RETURN_BOOL(FALSE);
-	}
-
-	if  ( ! FPeq(box1.xmin , box2.xmin) )
-	{
-		if  (box1.xmin > box2.xmin)
-		{
-			PG_RETURN_BOOL(TRUE);
-		}
-	}
-
-	if  ( ! FPeq(box1.ymin , box2.ymin) )
-	{
-		if  (box1.ymin > box2.ymin)
-		{
-			PG_RETURN_BOOL(TRUE);
-		}
-	}
-
-	if  ( ! FPeq(box1.xmax , box2.xmax) )
-	{
-		if  (box1.xmax > box2.xmax)
-		{
-			PG_RETURN_BOOL(TRUE);
-		}
-	}
-
-	if  ( ! FPeq(box1.ymax , box2.ymax) )
-	{
-		if  (box1.ymax > box2.ymax)
-		{
-			PG_RETURN_BOOL(TRUE);
-		}
-	}
-
-	PG_RETURN_BOOL(FALSE);
+	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
+	GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
+	int cmp = gserialized_cmp(g1, g2);
+	if (cmp > 0)
+		PG_RETURN_BOOL(TRUE);
+	else
+		PG_RETURN_BOOL(FALSE);	
 }
 
 PG_FUNCTION_INFO_V1(lwgeom_cmp);
 Datum lwgeom_cmp(PG_FUNCTION_ARGS)
 {
-	GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
-	GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
-	GBOX box1;
-	GBOX box2;
-	bool empty1, empty2;
-
-	POSTGIS_DEBUG(2, "lwgeom_cmp called");
-
-	error_if_srid_mismatch(gserialized_get_srid(geom1), gserialized_get_srid(geom2));
-
-	empty1 = ( gserialized_get_gbox_p(geom1, &box1) == LW_FAILURE );
-	empty2 = ( gserialized_get_gbox_p(geom2, &box2) == LW_FAILURE );
-
-	PG_FREE_IF_COPY(geom1, 0);
-	PG_FREE_IF_COPY(geom2, 1);
-
-	if  ( empty1 || empty2 )
-	{
-		if  ( empty1 && empty2 )
-		{
-			PG_RETURN_INT32(1);
-		}
-		else if ( empty1 )
-		{
-			PG_RETURN_INT32(-1);
-		}
-		else
-		{
-			PG_RETURN_INT32(1);
-		}
-	}
-
-	if  ( ! FPeq(box1.xmin , box2.xmin) )
-	{
-		if  (box1.xmin < box2.xmin)
-		{
-			PG_RETURN_INT32(-1);
-		}
-		PG_RETURN_INT32(1);
-	}
-
-	if  ( ! FPeq(box1.ymin , box2.ymin) )
-	{
-		if  (box1.ymin < box2.ymin)
-		{
-			PG_RETURN_INT32(-1);
-		}
-		PG_RETURN_INT32(1);
-	}
-
-	if  ( ! FPeq(box1.xmax , box2.xmax) )
-	{
-		if  (box1.xmax < box2.xmax)
-		{
-			PG_RETURN_INT32(-1);
-		}
-		PG_RETURN_INT32(1);
-	}
-
-	if  ( ! FPeq(box1.ymax , box2.ymax) )
-	{
-		if  (box1.ymax < box2.ymax)
-		{
-			PG_RETURN_INT32(-1);
-		}
-		PG_RETURN_INT32(1);
-	}
-
-	PG_RETURN_INT32(0);
+	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
+	GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
+    PG_RETURN_INT32(gserialized_cmp(g1, g2));
 }
 

Modified: trunk/regress/concave_hull.sql
===================================================================
--- trunk/regress/concave_hull.sql	2017-09-12 16:04:46 UTC (rev 15699)
+++ trunk/regress/concave_hull.sql	2017-09-12 19:44:32 UTC (rev 15700)
@@ -11,8 +11,8 @@
 		) As geom;
 		
 SELECT
-	'ST_ConcaveHull Lines 0.80', ST_Intersection(geom,ST_ConcaveHull(
-		geom, 0.80) ) = geom As encloses_geom,
+	'ST_ConcaveHull Lines 0.80', ST_Within(geom,ST_ConcaveHull(
+		geom, 0.80) ) As encloses_geom,
 		(ST_Area(ST_ConvexHull(geom))
 		- ST_Area(ST_ConcaveHull(geom, 0.80))) < (0.80 * ST_Area(ST_ConvexHull(geom) ) ) As reached_target
 
@@ -27,8 +27,8 @@
 
 -- test holes vs. no holes - holes should still enclose but have smaller area than no holes --
 SELECT
-	'ST_ConcaveHull Lines 0.80 holes', ST_Intersection(geom,ST_ConcaveHull(
-		geom, 0.80, true) ) = geom As encloses_geom,
+	'ST_ConcaveHull Lines 0.80 holes', ST_Within(geom,ST_ConcaveHull(
+		geom, 0.80, true) ) As encloses_geom,
 		ST_Area(ST_ConcaveHull(geom, 0.80, true)) < ST_Area(ST_ConcaveHull(geom, 0.80)) As reached_target
 
 FROM ST_GeomFromText('MULTILINESTRING((106 164,30 112,74 70,82 112,130 94,

Modified: trunk/regress/operators.sql
===================================================================
--- trunk/regress/operators.sql	2017-09-12 16:04:46 UTC (rev 15699)
+++ trunk/regress/operators.sql	2017-09-12 19:44:32 UTC (rev 15700)
@@ -141,23 +141,26 @@
 ORDER BY 1;
 
 -- GROUP BY on empty
-SELECT '#3777', ST_AsText(geom), count(*) FROM (
-SELECT 'POINT(0 0)'::geometry geom UNION ALL
-SELECT 'POINT(0 0)'::geometry UNION ALL
-SELECT 'POINT(0 0)'::geometry UNION ALL
-SELECT 'POINT(0 1)'::geometry UNION ALL
-SELECT 'LINESTRING(0 0,0 1)'::geometry UNION ALL
-SELECT 'GEOMETRYCOLLECTION EMPTY'::geometry UNION ALL
-SELECT 'POINT EMPTY'::geometry
-) foo
+SELECT '#3777', ST_AsText(geom), count(*) 
+FROM (VALUES 
+    ('POINT(0 0)'::geometry),
+    ('POINT(0 0)'::geometry),
+    ('POINT(0 0)'::geometry),
+    ('POINT(0 1)'::geometry),
+    ('LINESTRING(0 0,0 1)'::geometry),
+    ('GEOMETRYCOLLECTION EMPTY'::geometry),
+    ('POINT EMPTY'::geometry)
+) AS f(geom)
 GROUP BY geom ORDER BY 2;
-SELECT '#3777.1', ST_AsText(geom), count(*) FROM (
-SELECT 'POINT(0 0)'::geometry geom UNION ALL
-SELECT 'POINT(0 0)'::geometry UNION ALL
-SELECT 'POINT EMPTY'::geometry UNION ALL
-SELECT 'POINT(0 0)'::geometry UNION ALL
-SELECT 'POINT(0 1)'::geometry UNION ALL
-SELECT 'LINESTRING(0 0,0 1)'::geometry UNION ALL
-SELECT 'GEOMETRYCOLLECTION EMPTY'::geometry geom
-) foo
+
+SELECT '#3777.1', ST_AsText(geom), count(*) 
+FROM (VALUES
+    ('POINT(0 0)'::geometry),
+    ('POINT(0 0)'::geometry),
+    ('POINT EMPTY'::geometry),
+    ('POINT(0 0)'::geometry),
+    ('POINT(0 1)'::geometry),
+    ('LINESTRING(0 0,0 1)'::geometry),
+    ('GEOMETRYCOLLECTION EMPTY'::geometry)
+) AS f(geom)
 GROUP BY geom ORDER BY 2;

Modified: trunk/regress/operators_expected
===================================================================
--- trunk/regress/operators_expected	2017-09-12 16:04:46 UTC (rev 15699)
+++ trunk/regress/operators_expected	2017-09-12 19:44:32 UTC (rev 15700)
@@ -42,7 +42,7 @@
 ab2|f
 ab3|t
 eq1|t
-eq2|t
+eq2|f
 eq3|f
 cd1|4
 bd1|0
@@ -56,11 +56,13 @@
 ndov7|t
 ndovm1|{1,2,3,4,5,8}
 ndovm2|{1,2,4,6,7}
-#3777|GEOMETRYCOLLECTION EMPTY|2
+#3777|GEOMETRYCOLLECTION EMPTY|1
 #3777|LINESTRING(0 0,0 1)|1
+#3777|POINT EMPTY|1
 #3777|POINT(0 0)|3
 #3777|POINT(0 1)|1
-#3777.1|GEOMETRYCOLLECTION EMPTY|2
+#3777.1|GEOMETRYCOLLECTION EMPTY|1
 #3777.1|LINESTRING(0 0,0 1)|1
+#3777.1|POINT EMPTY|1
 #3777.1|POINT(0 0)|3
 #3777.1|POINT(0 1)|1

Modified: trunk/topology/test/regress/topojson_expected
===================================================================
--- trunk/topology/test/regress/topojson_expected	2017-09-12 16:04:46 UTC (rev 15699)
+++ trunk/topology/test/regress/topojson_expected	2017-09-12 19:44:32 UTC (rev 15700)
@@ -24,30 +24,30 @@
 L1-vanilla|R4|{ "type": "MultiLineString", "arcs": [[3]]}
 L2-vanilla|R1R2|{ "type": "MultiLineString", "arcs": [[9,-11],[4,-6]]}
 L2-vanilla|R4|{ "type": "MultiLineString", "arcs": [[3]]}
-A1-vanilla|P1|{ "type": "MultiPolygon", "arcs": [[[20,5,-19,-20,-12,21]]]}
-A1-vanilla|P2|{ "type": "MultiPolygon", "arcs": [[[18,6,-17,-18,-13,19]]]}
-A1-vanilla|P3|{ "type": "MultiPolygon", "arcs": [[[16,7,-15,-16,-14,17]]]}
+A1-vanilla|P1|{ "type": "MultiPolygon", "arcs": [[[21,20,5,-19,-20,-12]]]}
+A1-vanilla|P2|{ "type": "MultiPolygon", "arcs": [[[19,18,6,-17,-18,-13]]]}
+A1-vanilla|P3|{ "type": "MultiPolygon", "arcs": [[[17,16,7,-15,-16,-14]]]}
 A1-vanilla|P4|{ "type": "MultiPolygon", "arcs": [[[-2]]]}
-A1-vanilla|P5|{ "type": "MultiPolygon", "arcs": [[[-1],[25]]]}
-A2-vanilla|P1P2|{ "type": "MultiPolygon", "arcs": [[[20,5,6,-17,-18,-13,-12,21]]]}
-A2-vanilla|P3P4|{ "type": "MultiPolygon", "arcs": [[[-2]],[[16,7,-15,-16,-14,17]]]}
+A1-vanilla|P5|{ "type": "MultiPolygon", "arcs": [[[25],[-1]]]}
+A2-vanilla|P1P2|{ "type": "MultiPolygon", "arcs": [[[21,20,5,6,-17,-18,-13,-12]]]}
+A2-vanilla|P3P4|{ "type": "MultiPolygon", "arcs": [[[17,16,7,-15,-16,-14]],[[-2]]]}
 L1-edgemap|R1|{ "type": "MultiLineString", "arcs": [[0,-2]]}
 L1-edgemap|R2|{ "type": "MultiLineString", "arcs": [[2,-4]]}
 L1-edgemap|R3|{ "type": "MultiLineString", "arcs": [[4]]}
 L1-edgemap|R4|{ "type": "MultiLineString", "arcs": [[5]]}
 L2-edgemap|R1R2|{ "type": "MultiLineString", "arcs": [[0,-2],[2,-4]]}
 L2-edgemap|R4|{ "type": "MultiLineString", "arcs": [[4]]}
-A1-edgemap|P1|{ "type": "MultiPolygon", "arcs": [[[5,4,-4,-3,-2,0]]]}
-A1-edgemap|P2|{ "type": "MultiPolygon", "arcs": [[[3,9,-9,-8,-7,2]]]}
-A1-edgemap|P3|{ "type": "MultiPolygon", "arcs": [[[8,13,-13,-12,-11,7]]]}
+A1-edgemap|P1|{ "type": "MultiPolygon", "arcs": [[[5,4,3,-3,-2,-1]]]}
+A1-edgemap|P2|{ "type": "MultiPolygon", "arcs": [[[1,2,9,-9,-8,-7]]]}
+A1-edgemap|P3|{ "type": "MultiPolygon", "arcs": [[[7,8,13,-13,-12,-11]]]}
 A1-edgemap|P4|{ "type": "MultiPolygon", "arcs": [[[-15]]]}
-A1-edgemap|P5|{ "type": "MultiPolygon", "arcs": [[[-16],[16]]]}
-A2-edgemap|P1P2|{ "type": "MultiPolygon", "arcs": [[[7,6,5,-5,-4,-3,-2,0]]]}
-A2-edgemap|P3P4|{ "type": "MultiPolygon", "arcs": [[[-9]],[[4,12,-12,-11,-10,3]]]}
+A1-edgemap|P5|{ "type": "MultiPolygon", "arcs": [[[15],[-17]]]}
+A2-edgemap|P1P2|{ "type": "MultiPolygon", "arcs": [[[7,6,5,4,-4,-3,-2,-1]]]}
+A2-edgemap|P3P4|{ "type": "MultiPolygon", "arcs": [[[2,3,11,-11,-10,-9]],[[-13]]]}
 E32
 E33
 E34
 E35
-A3-vanilla|P6|{ "type": "MultiPolygon", "arcs": [[[-33],[30,25],[1]],[[-34],[34]]]}
+A3-vanilla|P6|{ "type": "MultiPolygon", "arcs": [[[30,25],[-33],[1]],[[34],[-34]]]}
 P1-vanilla|S2|{"type":"MultiPoint","coordinates":[[35,14]]}
 Topology 'city_data' dropped



More information about the postgis-tickets mailing list