[postgis-tickets] r16059 - Equality test failed on points with same coordinates

Paul Ramsey pramsey at cleverelephant.ca
Wed Oct 25 06:26:11 PDT 2017


Author: pramsey
Date: 2017-10-25 06:26:11 -0700 (Wed, 25 Oct 2017)
New Revision: 16059

Modified:
   trunk/liblwgeom/g_serialized.c
   trunk/postgis/lwgeom_btree.c
   trunk/regress/tickets.sql
   trunk/regress/tickets_expected
Log:
Equality test failed on points with same coordinates
and differing SRIDs, resulting in incorrect hashing. 
Amazingly, this problem existed in *both* the btree
function and the new hash machinery (and it was the
btree machinery that was actually called for the 
UNION operation).
References #1014


Modified: trunk/liblwgeom/g_serialized.c
===================================================================
--- trunk/liblwgeom/g_serialized.c	2017-10-24 21:25:45 UTC (rev 16058)
+++ trunk/liblwgeom/g_serialized.c	2017-10-25 13:26:11 UTC (rev 16059)
@@ -305,10 +305,10 @@
 	if (
 		sz1 > 16 && // 16 is size of EMPTY, if it's larger - it has coordinates
 		sz2 > 16 &&
-		*(uint32_t*)(g1 + 2 * sizeof(uint32_t)) == POINTTYPE &&
-		*(uint32_t*)(g2 + 2 * sizeof(uint32_t)) == POINTTYPE &&
 		!FLAGS_GET_BBOX(g1->flags) &&
-		!FLAGS_GET_BBOX(g2->flags)
+		!FLAGS_GET_BBOX(g2->flags) &&
+		*(uint32_t*)(g1->data) == POINTTYPE &&
+		*(uint32_t*)(g2->data) == POINTTYPE
 	)
 	{
 		double *dptr = (double*)(g1->data + sizeof(double));
@@ -321,12 +321,18 @@
 		y.f = 2.0 * dptr[1];
 		hash2 = uint32_interleave_2(x.u, y.u);
 
-		if ( hash1 > hash2 )
-			return 1;
-		if ( hash1 < hash2 )
-			return -1;
+		/* If the SRIDs are the same, we can use hash inequality */
+		/* to jump us out of this function early. Otherwise we still */
+		/* have to do the full calculation */
+		if ( gserialized_cmp_srid(g1, g2) == 0 )
+		{
+			if ( hash1 > hash2 )
+				return 1;
+			if ( hash1 < hash2 )
+				return -1;
+		}
 
-		// if hashes happen to be the same, go to full compare.
+		/* if hashes happen to be the same, go to full compare. */
 	}
 
 	size_t hsz1 = gserialized_header_size(g1);
@@ -401,7 +407,7 @@
 		else if (bsz1 > bsz2)
  			return 1;
 	}
-	return cmp == 0 ? 0 : (cmp > 0 ? 1 : -1);
+	return cmp > 0 ? 1 : -1;
 }
 
 int gserialized_read_gbox_p(const GSERIALIZED *g, GBOX *gbox)

Modified: trunk/postgis/lwgeom_btree.c
===================================================================
--- trunk/postgis/lwgeom_btree.c	2017-10-24 21:25:45 UTC (rev 16058)
+++ trunk/postgis/lwgeom_btree.c	2017-10-25 13:26:11 UTC (rev 16059)
@@ -132,11 +132,23 @@
 Datum lwgeom_hash(PG_FUNCTION_ARGS)
 {
 	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
-	size_t sz1 = VARSIZE(g1);
+	/* Point to just the type/coordinate part of buffer */
 	size_t hsz1 = gserialized_header_size(g1);
 	uint8_t *b1 = (uint8_t*)g1 + hsz1;
+	/* Calculate size of type/coordinate buffer */
+	size_t sz1 = VARSIZE(g1);
 	size_t bsz1 = sz1 - hsz1;
-	Datum hval = hash_any(b1, bsz1);
+	/* Calculate size of srid/type/coordinate buffer */
+	int srid = gserialized_get_srid(g1);
+	size_t bsz2 = bsz1 + sizeof(int);
+	uint8_t *b2 = palloc(bsz2);
+	/* Copy srid into front of combined buffer */
+	memcpy(b2, &srid, sizeof(int));
+	/* Copy type/coordinates into rest of combined buffer */
+	memcpy(b2+sizeof(int), b1, bsz1);
+	/* Hash combined buffer */
+	Datum hval = hash_any(b2, bsz2);
+	pfree(b2);
 	PG_FREE_IF_COPY(g1, 0);
 	PG_RETURN_DATUM(hval);
 }

Modified: trunk/regress/tickets.sql
===================================================================
--- trunk/regress/tickets.sql	2017-10-24 21:25:45 UTC (rev 16058)
+++ trunk/regress/tickets.sql	2017-10-25 13:26:11 UTC (rev 16059)
@@ -1048,6 +1048,11 @@
     WHERE ST_Y(path.g) = ST_X(rec.g)
 )
 SELECT '#1014c', id, st_astext(g) FROM path;
+SELECT '#1014d', ST_AsEWKT(g) FROM (
+	SELECT 'SRID=1;POINT(0 1)'::geometry AS g
+	UNION
+	SELECT 'SRID=2;POINT(0 1)'::geometry AS g
+) a;
 DROP TABLE IF EXISTS rec;
 
 

Modified: trunk/regress/tickets_expected
===================================================================
--- trunk/regress/tickets_expected	2017-10-24 21:25:45 UTC (rev 16058)
+++ trunk/regress/tickets_expected	2017-10-25 13:26:11 UTC (rev 16059)
@@ -312,3 +312,5 @@
 #1014c|1|POINT(0 1)
 #1014c|2|POINT(1 2)
 #1014c|3|POINT(2 3)
+#1014d|SRID=1;POINT(0 1)
+#1014d|SRID=2;POINT(0 1)



More information about the postgis-tickets mailing list