[postgis-tickets] [SCM] PostGIS branch master updated. 3.1.0alpha1-114-g10c9dc2

git at osgeo.org git at osgeo.org
Mon May 11 03:55:16 PDT 2020


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "PostGIS".

The branch, master has been updated
       via  10c9dc2ac242c194763a47edab2b2487b42eb3a6 (commit)
      from  5cea21d4ade82fa18a321a629892b0550f1ed398 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 10c9dc2ac242c194763a47edab2b2487b42eb3a6
Author: Raúl Marín <git at rmr.ninja>
Date:   Fri May 8 19:24:32 2020 +0200

    Share gserialized objects between different cache types
    
    Closes https://github.com/postgis/postgis/pull/564/
    Closes #4677

diff --git a/NEWS b/NEWS
index 44b4f23..ea49e53 100644
--- a/NEWS
+++ b/NEWS
@@ -21,12 +21,13 @@ Only tickets not included in 3.1.0alpha1
   - #4676, Avoid decompressing toasted geometries to read only the header (Raúl Marín)
            Optimize cast to Postgresql point type (Raúl Marín)
   - #4620, Update internal wagyu to 0.5.0 (Raúl Marín)
+  - #4623, Optimize varlena returning functions (Raúl Marín)
+  - #4677, Share gserialized objects between different cache types (Raúl Marín)
 
 * Bug fixes *
   - #4652, Fix several memory related bugs in ST_GeomFromGML (Raúl Marín)
   - #4661, Fix access to spatial_ref_sys with a non default schema (Raúl Marín)
   - #4670, ST_AddPoint: Fix bug when a positive position is requested (Raúl Marín)
-  - #4623, Optimize varlena returning functions (Raúl Marín)
 
 PostGIS 3.1.0alpha1
 2020/02/01
diff --git a/libpgcommon/Makefile.in b/libpgcommon/Makefile.in
index 05ce1c0..f1722a9 100644
--- a/libpgcommon/Makefile.in
+++ b/libpgcommon/Makefile.in
@@ -21,7 +21,8 @@ SA_OBJS = \
 	gserialized_gist.o \
 	lwgeom_transform.o \
 	lwgeom_cache.o \
-	lwgeom_pg.o
+	lwgeom_pg.o \
+	shared_gserialized.o
 
 
 SA_HEADERS = \
diff --git a/libpgcommon/lwgeom_cache.c b/libpgcommon/lwgeom_cache.c
index 6ca313b..74609ee 100644
--- a/libpgcommon/lwgeom_cache.c
+++ b/libpgcommon/lwgeom_cache.c
@@ -133,21 +133,20 @@ GetPROJSRSCache(FunctionCallInfo fcinfo)
 GeomCache *
 GetGeomCache(FunctionCallInfo fcinfo,
 	     const GeomCacheMethods *cache_methods,
-	     const GSERIALIZED *g1,
-	     const GSERIALIZED *g2)
+	     SHARED_GSERIALIZED *g1,
+	     SHARED_GSERIALIZED *g2)
 {
 	GeomCache* cache;
 	int cache_hit = 0;
 	MemoryContext old_context;
 	const GSERIALIZED *geom;
 	GenericCacheCollection* generic_cache = GetGenericCacheCollection(fcinfo);
-	int entry_number = cache_methods->entry_number;
+	uint32_t entry_number = cache_methods->entry_number;
 
 	Assert(entry_number >= 0);
 	Assert(entry_number < NUM_CACHE_ENTRIES);
 
 	cache = (GeomCache*)(generic_cache->entry[entry_number]);
-
 	if ( ! cache )
 	{
 		old_context = MemoryContextSwitchTo(PostgisCacheContext(fcinfo));
@@ -160,25 +159,16 @@ GetGeomCache(FunctionCallInfo fcinfo,
 	}
 
 	/* Cache hit on the first argument */
-	if ( g1 &&
-	     cache->argnum != 2 && (
-	     (g1 == cache->geom1) ||
-	     (cache->geom1_size == VARSIZE(g1) && memcmp(cache->geom1, g1, cache->geom1_size) == 0)
-	     ))
+	if (g1 && cache->geom1 && cache->argnum != 2 && shared_gserialized_equal(g1, cache->geom1))
 	{
 		cache_hit = 1;
-		geom = cache->geom1;
-
+		geom = shared_gserialized_get(cache->geom1);
 	}
 	/* Cache hit on second argument */
-	else if ( g2 &&
-	          cache->argnum != 1 && (
-	          (g2 == cache->geom2) ||
-	          (cache->geom2_size == VARSIZE(g2) && memcmp(cache->geom2, g2, cache->geom2_size) == 0)
-	          ))
+	else if (g2 && cache->geom2 && cache->argnum != 1 && shared_gserialized_equal(g2, cache->geom2))
 	{
 		cache_hit = 2;
-		geom = cache->geom2;
+		geom = shared_gserialized_get(cache->geom2);
 	}
 	/* No cache hit. If we have a tree, free it. */
 	else
@@ -189,16 +179,6 @@ GetGeomCache(FunctionCallInfo fcinfo,
 			cache_methods->GeomIndexFreer(cache);
 			cache->argnum = 0;
 		}
-		if ( cache->lwgeom1 )
-		{
-			lwgeom_free(cache->lwgeom1);
-			cache->lwgeom1 = 0;
-		}
-		if ( cache->lwgeom2 )
-		{
-			lwgeom_free(cache->lwgeom2);
-			cache->lwgeom2 = 0;
-		}
 	}
 
 	/* Cache hit, but no tree built yet, build it! */
@@ -237,18 +217,17 @@ GetGeomCache(FunctionCallInfo fcinfo,
 	/* Argument one didn't match, so copy the new value in. */
 	if ( g1 && cache_hit != 1 )
 	{
-		if ( cache->geom1 ) pfree(cache->geom1);
-		cache->geom1_size = VARSIZE(g1);
-		cache->geom1 = MemoryContextAlloc(PostgisCacheContext(fcinfo), cache->geom1_size);
-		memcpy(cache->geom1, g1, cache->geom1_size);
+		if (cache->geom1)
+			shared_gserialized_unref(fcinfo, cache->geom1);
+		cache->geom1 = shared_gserialized_ref(fcinfo, g1);
 	}
+
 	/* Argument two didn't match, so copy the new value in. */
 	if ( g2 && cache_hit != 2 )
 	{
-		if ( cache->geom2 ) pfree(cache->geom2);
-		cache->geom2_size = VARSIZE(g2);
-		cache->geom2 = MemoryContextAlloc(PostgisCacheContext(fcinfo), cache->geom2_size);
-		memcpy(cache->geom2, g2, cache->geom2_size);
+		if (cache->geom2)
+			shared_gserialized_unref(fcinfo, cache->geom2);
+		cache->geom2 = shared_gserialized_ref(fcinfo, g2);
 	}
 
 	return NULL;
@@ -271,7 +250,7 @@ ToastCacheGet(FunctionCallInfo fcinfo)
 	return cache;
 }
 
-GSERIALIZED*
+SHARED_GSERIALIZED *
 ToastCacheGetGeometry(FunctionCallInfo fcinfo, uint32_t argnum)
 {
 	Assert(argnum < ToastCacheSize);
@@ -292,7 +271,7 @@ ToastCacheGetGeometry(FunctionCallInfo fcinfo, uint32_t argnum)
 	* https://www.postgresql.org/message-id/8196.1585870220@sss.pgh.pa.us
 	*/
 	if (!VARATT_IS_EXTERNAL_ONDISK(attr))
-		return (GSERIALIZED*)PG_DETOAST_DATUM(datum);
+		return shared_gserialized_new_nocache(datum);
 
 	/* Retrieve the unique keys for this object */
 	struct varatt_external ve;
@@ -303,13 +282,6 @@ ToastCacheGetGeometry(FunctionCallInfo fcinfo, uint32_t argnum)
 	/* We've seen this object before? */
 	if (arg->valueid == valueid && arg->toastrelid == toastrelid)
 	{
-		if (arg->geom)
-			return arg->geom;
-
-		/* Take a copy into the upper context */
-		MemoryContext old_context = MemoryContextSwitchTo(PostgisCacheContext(fcinfo));
-		arg->geom = (GSERIALIZED*)PG_DETOAST_DATUM_COPY(datum);
-		MemoryContextSwitchTo(old_context);
 		return arg->geom;
 	}
 	/* New object, clear our old copies and see if it */
@@ -317,11 +289,11 @@ ToastCacheGetGeometry(FunctionCallInfo fcinfo, uint32_t argnum)
 	else
 	{
 		if (arg->geom)
-			pfree(arg->geom);
+			shared_gserialized_unref(fcinfo, arg->geom);
 		arg->valueid = valueid;
 		arg->toastrelid = toastrelid;
-		arg->geom = NULL;
-		return (GSERIALIZED*)PG_DETOAST_DATUM(datum);
+		arg->geom = shared_gserialized_new_cached(fcinfo, datum);
+		return arg->geom;
 	}
 }
 
diff --git a/libpgcommon/lwgeom_cache.h b/libpgcommon/lwgeom_cache.h
index 825701e..113abe0 100644
--- a/libpgcommon/lwgeom_cache.h
+++ b/libpgcommon/lwgeom_cache.h
@@ -35,6 +35,18 @@
 /* Returns the MemoryContext used to store the caches */
 MemoryContext PostgisCacheContext(FunctionCallInfo fcinfo);
 
+typedef struct {
+	GSERIALIZED *geom;
+	uint32_t count;
+} SHARED_GSERIALIZED;
+
+SHARED_GSERIALIZED *shared_gserialized_new_nocache(Datum d);
+SHARED_GSERIALIZED *shared_gserialized_new_cached(FunctionCallInfo fcinfo, Datum d);
+SHARED_GSERIALIZED *shared_gserialized_ref(FunctionCallInfo fcinfo, SHARED_GSERIALIZED *ref);
+void shared_gserialized_unref(FunctionCallInfo fcinfo, SHARED_GSERIALIZED *ref);
+bool shared_gserialized_equal(SHARED_GSERIALIZED *r1, SHARED_GSERIALIZED *r2);
+const GSERIALIZED *shared_gserialized_get(SHARED_GSERIALIZED *s);
+
 /*
 * A generic GeomCache just needs space for the cache type,
 * the cache keys (GSERIALIZED geometries), the key sizes,
@@ -42,14 +54,10 @@ MemoryContext PostgisCacheContext(FunctionCallInfo fcinfo);
 * to refer to.
 */
 typedef struct {
-	int                         type;
-	GSERIALIZED*                geom1;
-	GSERIALIZED*                geom2;
-	size_t                      geom1_size;
-	size_t                      geom2_size;
-	LWGEOM*                     lwgeom1;
-	LWGEOM*                     lwgeom2;
-	int32                       argnum;
+	uint32_t type;
+	uint32 argnum;
+	SHARED_GSERIALIZED *geom1;
+	SHARED_GSERIALIZED *geom2;
 } GeomCache;
 
 /*
@@ -100,7 +108,7 @@ PROJPortalCache;
 */
 typedef struct
 {
-	int entry_number; /* What kind of structure is this? */
+	uint32_t entry_number; /* What kind of structure is this? */
 	int (*GeomIndexBuilder)(const LWGEOM* lwgeom, GeomCache* cache); /* Build an index/tree and add it to your cache */
 	int (*GeomIndexFreer)(GeomCache* cache); /* Free the index/tree in your cache */
 	GeomCache* (*GeomCacheAllocator)(void); /* Allocate the kind of cache object you use (GeomCache+some extra space) */
@@ -112,8 +120,8 @@ typedef struct
 PROJPortalCache *GetPROJSRSCache(FunctionCallInfo fcinfo);
 GeomCache *GetGeomCache(FunctionCallInfo fcinfo,
 			const GeomCacheMethods *cache_methods,
-			const GSERIALIZED *g1,
-			const GSERIALIZED *g2);
+			SHARED_GSERIALIZED *g1,
+			SHARED_GSERIALIZED *g2);
 
 /******************************************************************************/
 
@@ -123,7 +131,7 @@ typedef struct
 {
 	Oid valueid;
 	Oid toastrelid;
-	GSERIALIZED *geom;
+	SHARED_GSERIALIZED *geom;
 } ToastCacheArgument;
 
 typedef struct
@@ -132,7 +140,7 @@ typedef struct
 	ToastCacheArgument arg[ToastCacheSize];
 } ToastCache;
 
-GSERIALIZED* ToastCacheGetGeometry(FunctionCallInfo fcinfo, uint32_t argnum);
+SHARED_GSERIALIZED *ToastCacheGetGeometry(FunctionCallInfo fcinfo, uint32_t argnum);
 
 /******************************************************************************/
 
diff --git a/libpgcommon/shared_gserialized.c b/libpgcommon/shared_gserialized.c
new file mode 100644
index 0000000..4b088a9
--- /dev/null
+++ b/libpgcommon/shared_gserialized.c
@@ -0,0 +1,98 @@
+/**********************************************************************
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * http://postgis.net
+ *
+ * PostGIS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * PostGIS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with PostGIS.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ **********************************************************************
+ *
+ * Copyright 2020 Raúl Marín
+ *
+ **********************************************************************/
+
+#include "lwgeom_cache.h"
+
+SHARED_GSERIALIZED *
+shared_gserialized_new_nocache(Datum d)
+{
+	SHARED_GSERIALIZED *s = palloc(sizeof(SHARED_GSERIALIZED));
+	s->count = 0;
+	s->geom = (GSERIALIZED *)PG_DETOAST_DATUM(d);
+	return s;
+}
+
+SHARED_GSERIALIZED *
+shared_gserialized_new_cached(FunctionCallInfo fcinfo, Datum d)
+{
+	SHARED_GSERIALIZED *s = MemoryContextAlloc(PostgisCacheContext(fcinfo), sizeof(SHARED_GSERIALIZED));
+	MemoryContext old_context = MemoryContextSwitchTo(PostgisCacheContext(fcinfo));
+	s->geom = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(d);
+	MemoryContextSwitchTo(old_context);
+	s->count = 1;
+	return s;
+}
+
+SHARED_GSERIALIZED *
+shared_gserialized_ref(FunctionCallInfo fcinfo, SHARED_GSERIALIZED *ref)
+{
+	if (MemoryContextContains(PostgisCacheContext(fcinfo), ref))
+	{
+		ref->count++;
+		return ref;
+	}
+	else
+	{
+		SHARED_GSERIALIZED *sg = MemoryContextAlloc(PostgisCacheContext(fcinfo), sizeof(SHARED_GSERIALIZED));
+		sg->count = 1;
+		sg->geom = MemoryContextAlloc(PostgisCacheContext(fcinfo), VARSIZE(ref->geom));
+		memcpy(sg->geom, ref->geom, VARSIZE(ref->geom));
+		return sg;
+	}
+}
+
+void
+shared_gserialized_unref(FunctionCallInfo fcinfo, SHARED_GSERIALIZED *ref)
+{
+	if (MemoryContextContains(PostgisCacheContext(fcinfo), ref))
+	{
+		ref->count--;
+		if (!ref->count)
+		{
+			pfree(ref->geom);
+			pfree(ref);
+		}
+	}
+	else
+	{
+		pfree(ref->geom);
+		pfree(ref);
+	}
+}
+
+bool
+shared_gserialized_equal(SHARED_GSERIALIZED *r1, SHARED_GSERIALIZED *r2)
+{
+	if (r1->geom == r2->geom)
+		return true;
+	if (VARSIZE(r1->geom) != VARSIZE(r2->geom))
+		return false;
+	return memcmp(r1->geom, r2->geom, VARSIZE(r1->geom)) == 0;
+}
+
+const GSERIALIZED *
+shared_gserialized_get(SHARED_GSERIALIZED *s)
+{
+	return s->geom;
+}
\ No newline at end of file
diff --git a/postgis/geography_measurement.c b/postgis/geography_measurement.c
index 851eda0..79a231b 100644
--- a/postgis/geography_measurement.c
+++ b/postgis/geography_measurement.c
@@ -205,15 +205,14 @@ Datum geography_distance_uncached(PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1(geography_distance);
 Datum geography_distance(PG_FUNCTION_ARGS)
 {
-	GSERIALIZED* g1 = NULL;
-	GSERIALIZED* g2 = NULL;
+	SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
+	SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
+	const GSERIALIZED *g1 = shared_gserialized_get(shared_geom1);
+	const GSERIALIZED *g2 = shared_gserialized_get(shared_geom2);
 	double distance;
 	bool use_spheroid = true;
 	SPHEROID s;
 
-	/* Get our geometry objects loaded into memory. */
-	g1 = ToastCacheGetGeometry(fcinfo, 0);
-	g2 = ToastCacheGetGeometry(fcinfo, 1);
 
 	if (PG_NARGS() > 2)
 		use_spheroid = PG_GETARG_BOOL(2);
@@ -234,7 +233,7 @@ Datum geography_distance(PG_FUNCTION_ARGS)
 	}
 
 	/* Do the brute force calculation if the cached calculation doesn't tick over */
-	if ( LW_FAILURE == geography_distance_cache(fcinfo, g1, g2, &s, &distance) )
+	if (LW_FAILURE == geography_distance_cache(fcinfo, shared_geom1, shared_geom2, &s, &distance))
 	{
 		/* default to using tree-based distance calculation at all times */
 		/* in standard distance call. */
@@ -268,8 +267,10 @@ Datum geography_distance(PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1(geography_dwithin);
 Datum geography_dwithin(PG_FUNCTION_ARGS)
 {
-	GSERIALIZED *g1 = ToastCacheGetGeometry(fcinfo, 0);
-	GSERIALIZED *g2 = ToastCacheGetGeometry(fcinfo, 1);
+	SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
+	SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
+	const GSERIALIZED *g1 = shared_gserialized_get(shared_geom1);
+	const GSERIALIZED *g2 = shared_gserialized_get(shared_geom2);
 	SPHEROID s;
 	double tolerance = 0.0;
 	bool use_spheroid = true;
@@ -298,7 +299,7 @@ Datum geography_dwithin(PG_FUNCTION_ARGS)
 		PG_RETURN_BOOL(false);
 
 	/* Do the brute force calculation if the cached calculation doesn't tick over */
-	if ( LW_FAILURE == geography_dwithin_cache(fcinfo, g1, g2, &s, tolerance, &dwithin) )
+	if (LW_FAILURE == geography_dwithin_cache(fcinfo, shared_geom1, shared_geom2, &s, tolerance, &dwithin))
 	{
 		LWGEOM* lwgeom1 = lwgeom_from_gserialized(g1);
 		LWGEOM* lwgeom2 = lwgeom_from_gserialized(g2);
diff --git a/postgis/geography_measurement_trees.c b/postgis/geography_measurement_trees.c
index e932b94..ed0cef9 100644
--- a/postgis/geography_measurement_trees.c
+++ b/postgis/geography_measurement_trees.c
@@ -90,7 +90,7 @@ static GeomCacheMethods CircTreeCacheMethods =
 };
 
 static CircTreeGeomCache *
-GetCircTreeGeomCache(FunctionCallInfo fcinfo, const GSERIALIZED *g1, const GSERIALIZED *g2)
+GetCircTreeGeomCache(FunctionCallInfo fcinfo, SHARED_GSERIALIZED *g1, SHARED_GSERIALIZED *g2)
 {
 	return (CircTreeGeomCache*)GetGeomCache(fcinfo, &CircTreeCacheMethods, g1, g2);
 }
@@ -155,12 +155,14 @@ CircTreePIP(const CIRC_NODE* tree1, const GSERIALIZED* g1, const POINT4D* in_poi
 
 static int
 geography_distance_cache_tolerance(FunctionCallInfo fcinfo,
-				   const GSERIALIZED *g1,
-				   const GSERIALIZED *g2,
+				   SHARED_GSERIALIZED *shared_g1,
+				   SHARED_GSERIALIZED *shared_g2,
 				   const SPHEROID *s,
 				   double tolerance,
 				   double *distance)
 {
+	const GSERIALIZED *g1 = shared_gserialized_get(shared_g1);
+	const GSERIALIZED *g2 = shared_gserialized_get(shared_g2);
 	CircTreeGeomCache* tree_cache = NULL;
 
 	int type1 = gserialized_get_type(g1);
@@ -173,7 +175,7 @@ geography_distance_cache_tolerance(FunctionCallInfo fcinfo,
 		return LW_FAILURE;
 
 	/* Fetch/build our cache, if appropriate, etc... */
-	tree_cache = GetCircTreeGeomCache(fcinfo, g1, g2);
+	tree_cache = GetCircTreeGeomCache(fcinfo, shared_g1, shared_g2);
 
 	/* OK, we have an index at the ready! Use it for the one tree argument and */
 	/* fill in the other tree argument */
@@ -250,8 +252,8 @@ geography_distance_cache_tolerance(FunctionCallInfo fcinfo,
 
 int
 geography_distance_cache(FunctionCallInfo fcinfo,
-			 const GSERIALIZED *g1,
-			 const GSERIALIZED *g2,
+			 SHARED_GSERIALIZED *g1,
+			 SHARED_GSERIALIZED *g2,
 			 const SPHEROID *s,
 			 double *distance)
 {
@@ -260,8 +262,8 @@ geography_distance_cache(FunctionCallInfo fcinfo,
 
 int
 geography_dwithin_cache(FunctionCallInfo fcinfo,
-			const GSERIALIZED *g1,
-			const GSERIALIZED *g2,
+			SHARED_GSERIALIZED *g1,
+			SHARED_GSERIALIZED *g2,
 			const SPHEROID *s,
 			double tolerance,
 			int *dwithin)
diff --git a/postgis/geography_measurement_trees.h b/postgis/geography_measurement_trees.h
index fac792e..501a2c6 100644
--- a/postgis/geography_measurement_trees.h
+++ b/postgis/geography_measurement_trees.h
@@ -27,14 +27,14 @@
 #include "lwgeom_cache.h"
 
 int geography_dwithin_cache(FunctionCallInfo fcinfo,
-			    const GSERIALIZED *g1,
-			    const GSERIALIZED *g2,
+			    SHARED_GSERIALIZED *g1,
+			    SHARED_GSERIALIZED *g2,
 			    const SPHEROID *s,
 			    double tolerance,
 			    int *dwithin);
 int geography_distance_cache(FunctionCallInfo fcinfo,
-			     const GSERIALIZED *g1,
-			     const GSERIALIZED *g2,
+			     SHARED_GSERIALIZED *g1,
+			     SHARED_GSERIALIZED *g2,
 			     const SPHEROID *s,
 			     double *distance);
 int geography_tree_distance(const GSERIALIZED* g1, const GSERIALIZED* g2, const SPHEROID* s, double tolerance, double* distance);
diff --git a/postgis/lwgeom_geos.c b/postgis/lwgeom_geos.c
index 6f7b2fb..922fefa 100644
--- a/postgis/lwgeom_geos.c
+++ b/postgis/lwgeom_geos.c
@@ -141,7 +141,7 @@ is_point(const GSERIALIZED* g)
  * Serialized poly may be a multipart.
  */
 static int
-pip_short_circuit(RTREE_POLY_CACHE* poly_cache, LWPOINT* point, GSERIALIZED* gpoly)
+pip_short_circuit(RTREE_POLY_CACHE *poly_cache, LWPOINT *point, const GSERIALIZED *gpoly)
 {
 	int result;
 
@@ -1783,8 +1783,10 @@ Datum overlaps(PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1(contains);
 Datum contains(PG_FUNCTION_ARGS)
 {
-	GSERIALIZED *geom1 = ToastCacheGetGeometry(fcinfo, 0);
-	GSERIALIZED *geom2 = ToastCacheGetGeometry(fcinfo, 1);
+	SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
+	SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
+	const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
+	const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
 	int result;
 	GEOSGeometry *g1, *g2;
 	GBOX box1, box2;
@@ -1814,9 +1816,11 @@ Datum contains(PG_FUNCTION_ARGS)
 	*/
 	if (is_poly(geom1) && is_point(geom2))
 	{
-		GSERIALIZED* gpoly  = is_poly(geom1) ? geom1 : geom2;
-		GSERIALIZED* gpoint = is_point(geom1) ? geom1 : geom2;
-		RTREE_POLY_CACHE* cache = GetRtreeCache(fcinfo, gpoly);
+		SHARED_GSERIALIZED *shared_gpoly = is_poly(geom1) ? shared_geom1 : shared_geom2;
+		SHARED_GSERIALIZED *shared_gpoint = is_point(geom1) ? shared_geom1 : shared_geom2;
+		const GSERIALIZED *gpoly = shared_gserialized_get(shared_gpoly);
+		const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint);
+		RTREE_POLY_CACHE *cache = GetRtreeCache(fcinfo, shared_gpoly);
 		int retval;
 
 		POSTGIS_DEBUG(3, "Point in Polygon test requested...short-circuiting.");
@@ -1872,7 +1876,7 @@ Datum contains(PG_FUNCTION_ARGS)
 
 	initGEOS(lwpgnotice, lwgeom_geos_error);
 
-	prep_cache = GetPrepGeomCache( fcinfo, geom1, 0 );
+	prep_cache = GetPrepGeomCache(fcinfo, shared_geom1, NULL);
 
 	if ( prep_cache && prep_cache->prepared_geom && prep_cache->gcache.argnum == 1 )
 	{
@@ -1918,14 +1922,14 @@ Datum within(PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1(containsproperly);
 Datum containsproperly(PG_FUNCTION_ARGS)
 {
-	GSERIALIZED *				geom1;
-	GSERIALIZED *				geom2;
+	SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
+	SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
+	const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
+	const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
 	char 					result;
 	GBOX 			box1, box2;
 	PrepGeomCache *	prep_cache;
 
-	geom1 = ToastCacheGetGeometry(fcinfo, 0);
-	geom2 = ToastCacheGetGeometry(fcinfo, 1);
 	gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
 
 	/* A.ContainsProperly(Empty) == FALSE */
@@ -1945,7 +1949,7 @@ Datum containsproperly(PG_FUNCTION_ARGS)
 
 	initGEOS(lwpgnotice, lwgeom_geos_error);
 
-	prep_cache = GetPrepGeomCache( fcinfo, geom1, 0 );
+	prep_cache = GetPrepGeomCache(fcinfo, shared_geom1, 0);
 
 	if ( prep_cache && prep_cache->prepared_geom && prep_cache->gcache.argnum == 1 )
 	{
@@ -1984,14 +1988,14 @@ Datum containsproperly(PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1(covers);
 Datum covers(PG_FUNCTION_ARGS)
 {
-	GSERIALIZED *geom1;
-	GSERIALIZED *geom2;
+	SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
+	SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
+	const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
+	const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
 	int result;
 	GBOX box1, box2;
 	PrepGeomCache *prep_cache;
 
-	geom1 = ToastCacheGetGeometry(fcinfo, 0);
-	geom2 = ToastCacheGetGeometry(fcinfo, 1);
 
 	/* A.Covers(Empty) == FALSE */
 	if ( gserialized_is_empty(geom1) || gserialized_is_empty(geom2) )
@@ -2017,9 +2021,11 @@ Datum covers(PG_FUNCTION_ARGS)
 	 */
 	if (is_poly(geom1) && is_point(geom2))
 	{
-		GSERIALIZED* gpoly  = is_poly(geom1) ? geom1 : geom2;
-		GSERIALIZED* gpoint = is_point(geom1) ? geom1 : geom2;
-		RTREE_POLY_CACHE* cache = GetRtreeCache(fcinfo, gpoly);
+		SHARED_GSERIALIZED *shared_gpoly = is_poly(geom1) ? shared_geom1 : shared_geom2;
+		SHARED_GSERIALIZED *shared_gpoint = is_point(geom1) ? shared_geom1 : shared_geom2;
+		const GSERIALIZED *gpoly = shared_gserialized_get(shared_gpoly);
+		const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint);
+		RTREE_POLY_CACHE *cache = GetRtreeCache(fcinfo, shared_gpoly);
 		int retval;
 
 		POSTGIS_DEBUG(3, "Point in Polygon test requested...short-circuiting.");
@@ -2065,7 +2071,7 @@ Datum covers(PG_FUNCTION_ARGS)
 
 	initGEOS(lwpgnotice, lwgeom_geos_error);
 
-	prep_cache = GetPrepGeomCache( fcinfo, geom1, 0 );
+	prep_cache = GetPrepGeomCache(fcinfo, shared_geom1, 0);
 
 	if ( prep_cache && prep_cache->prepared_geom && prep_cache->gcache.argnum == 1 )
 	{
@@ -2112,15 +2118,15 @@ Datum within(PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1(coveredby);
 Datum coveredby(PG_FUNCTION_ARGS)
 {
-	GSERIALIZED *geom1;
-	GSERIALIZED *geom2;
+	SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
+	SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
+	const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
+	const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
 	GEOSGeometry *g1, *g2;
 	int result;
 	GBOX box1, box2;
 	char *patt = "**F**F***";
 
-	geom1 = ToastCacheGetGeometry(fcinfo, 0);
-	geom2 = ToastCacheGetGeometry(fcinfo, 1);
 	gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
 
 	/* A.CoveredBy(Empty) == FALSE */
@@ -2147,9 +2153,11 @@ Datum coveredby(PG_FUNCTION_ARGS)
 	 */
 	if (is_point(geom1) && is_poly(geom2))
 	{
-		GSERIALIZED* gpoly  = is_poly(geom1) ? geom1 : geom2;
-		GSERIALIZED* gpoint = is_point(geom1) ? geom1 : geom2;
-		RTREE_POLY_CACHE* cache = GetRtreeCache(fcinfo, gpoly);
+		SHARED_GSERIALIZED *shared_gpoly = is_poly(geom1) ? shared_geom1 : shared_geom2;
+		SHARED_GSERIALIZED *shared_gpoint = is_point(geom1) ? shared_geom1 : shared_geom2;
+		const GSERIALIZED *gpoly = shared_gserialized_get(shared_gpoly);
+		const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint);
+		RTREE_POLY_CACHE *cache = GetRtreeCache(fcinfo, shared_gpoly);
 		int retval;
 
 		POSTGIS_DEBUG(3, "Point in Polygon test requested...short-circuiting.");
@@ -2277,14 +2285,14 @@ Datum crosses(PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1(ST_Intersects);
 Datum ST_Intersects(PG_FUNCTION_ARGS)
 {
-	GSERIALIZED *geom1;
-	GSERIALIZED *geom2;
+	SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
+	SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
+	const GSERIALIZED *geom1 = shared_gserialized_get(shared_geom1);
+	const GSERIALIZED *geom2 = shared_gserialized_get(shared_geom2);
 	int result;
 	GBOX box1, box2;
 	PrepGeomCache *prep_cache;
 
-	geom1 = ToastCacheGetGeometry(fcinfo, 0);
-	geom2 = ToastCacheGetGeometry(fcinfo, 1);
 	gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
 
 	/* A.Intersects(Empty) == FALSE */
@@ -2308,9 +2316,11 @@ Datum ST_Intersects(PG_FUNCTION_ARGS)
 	 */
 	if ((is_point(geom1) && is_poly(geom2)) || (is_poly(geom1) && is_point(geom2)))
 	{
-		GSERIALIZED* gpoly  = is_poly(geom1) ? geom1 : geom2;
-		GSERIALIZED* gpoint = is_point(geom1) ? geom1 : geom2;
-		RTREE_POLY_CACHE* cache = GetRtreeCache(fcinfo, gpoly);
+		SHARED_GSERIALIZED *shared_gpoly = is_poly(geom1) ? shared_geom1 : shared_geom2;
+		SHARED_GSERIALIZED *shared_gpoint = is_point(geom1) ? shared_geom1 : shared_geom2;
+		const GSERIALIZED *gpoly = shared_gserialized_get(shared_gpoly);
+		const GSERIALIZED *gpoint = shared_gserialized_get(shared_gpoint);
+		RTREE_POLY_CACHE *cache = GetRtreeCache(fcinfo, shared_gpoly);
 		int retval;
 
 		POSTGIS_DEBUG(3, "Point in Polygon test requested...short-circuiting.");
@@ -2351,7 +2361,7 @@ Datum ST_Intersects(PG_FUNCTION_ARGS)
 	}
 
 	initGEOS(lwpgnotice, lwgeom_geos_error);
-	prep_cache = GetPrepGeomCache( fcinfo, geom1, geom2 );
+	prep_cache = GetPrepGeomCache(fcinfo, shared_geom1, shared_geom2);
 
 	if ( prep_cache && prep_cache->prepared_geom )
 	{
@@ -2766,9 +2776,8 @@ GEOS2POSTGIS(GEOSGeom geom, char want3d)
 
 /*-----=POSTGIS2GEOS= */
 
-
 GEOSGeometry *
-POSTGIS2GEOS(GSERIALIZED *pglwgeom)
+POSTGIS2GEOS(const GSERIALIZED *pglwgeom)
 {
 	GEOSGeometry *ret;
 	LWGEOM *lwgeom = lwgeom_from_gserialized(pglwgeom);
diff --git a/postgis/lwgeom_geos.h b/postgis/lwgeom_geos.h
index 1bdb1fb..1a834c4 100644
--- a/postgis/lwgeom_geos.h
+++ b/postgis/lwgeom_geos.h
@@ -35,7 +35,7 @@
 */
 
 GSERIALIZED *GEOS2POSTGIS(GEOSGeom geom, char want3d);
-GEOSGeometry * POSTGIS2GEOS(GSERIALIZED *g);
+GEOSGeometry *POSTGIS2GEOS(const GSERIALIZED *g);
 GEOSGeometry** ARRAY2GEOS(ArrayType* array, uint32_t nelems, int* is3d, int* srid);
 LWGEOM** ARRAY2LWGEOM(ArrayType* array, uint32_t nelems, int* is3d, int* srid);
 
diff --git a/postgis/lwgeom_geos_prepared.c b/postgis/lwgeom_geos_prepared.c
index 136b461..436b7fa 100644
--- a/postgis/lwgeom_geos_prepared.c
+++ b/postgis/lwgeom_geos_prepared.c
@@ -366,7 +366,7 @@ static GeomCacheMethods PrepGeomCacheMethods =
 * we need for this particular caching strategy.
 */
 PrepGeomCache *
-GetPrepGeomCache(FunctionCallInfo fcinfo, GSERIALIZED *g1, GSERIALIZED *g2)
+GetPrepGeomCache(FunctionCallInfo fcinfo, SHARED_GSERIALIZED *g1, SHARED_GSERIALIZED *g2)
 {
 	return (PrepGeomCache*)GetGeomCache(fcinfo, &PrepGeomCacheMethods, g1, g2);
 }
diff --git a/postgis/lwgeom_geos_prepared.h b/postgis/lwgeom_geos_prepared.h
index 6c8f8d8..5f3417b 100644
--- a/postgis/lwgeom_geos_prepared.h
+++ b/postgis/lwgeom_geos_prepared.h
@@ -70,6 +70,6 @@ typedef struct {
 ** If you are only caching one argument (e.g., in contains) supply 0 as the
 ** value for pg_geom2.
 */
-PrepGeomCache *GetPrepGeomCache(FunctionCallInfo fcinfo, GSERIALIZED *pg_geom1, GSERIALIZED *pg_geom2);
+PrepGeomCache *GetPrepGeomCache(FunctionCallInfo fcinfo, SHARED_GSERIALIZED *pg_geom1, SHARED_GSERIALIZED *pg_geom2);
 
 #endif /* LWGEOM_GEOS_PREPARED_H_ */
diff --git a/postgis/lwgeom_rectree.c b/postgis/lwgeom_rectree.c
index 17a774a..4927750 100644
--- a/postgis/lwgeom_rectree.c
+++ b/postgis/lwgeom_rectree.c
@@ -106,7 +106,7 @@ static GeomCacheMethods RectTreeCacheMethods =
 };
 
 static RectTreeGeomCache *
-GetRectTreeGeomCache(FunctionCallInfo fcinfo, const GSERIALIZED *g1, const GSERIALIZED *g2)
+GetRectTreeGeomCache(FunctionCallInfo fcinfo, SHARED_GSERIALIZED *g1, SHARED_GSERIALIZED *g2)
 {
 	return (RectTreeGeomCache*)GetGeomCache(fcinfo, &RectTreeCacheMethods, g1, g2);
 }
@@ -149,27 +149,27 @@ PG_FUNCTION_INFO_V1(ST_DistanceRectTreeCached);
 Datum ST_DistanceRectTreeCached(PG_FUNCTION_ARGS)
 {
 	RectTreeGeomCache *tree_cache = NULL;
-	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
-	GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
-	LWGEOM *lwg1, *lwg2;
+	SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
+	SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
+	const GSERIALIZED *g1 = shared_gserialized_get(shared_geom1);
+	const GSERIALIZED *g2 = shared_gserialized_get(shared_geom2);
 
 	/* Return NULL on empty arguments. */
 	if (gserialized_is_empty(g1) || gserialized_is_empty(g2))
 	{
-		PG_FREE_IF_COPY(g1, 0);
-		PG_FREE_IF_COPY(g2, 1);
 		PG_RETURN_NULL();
 	}
 
-	lwg1 = lwgeom_from_gserialized(g1);
-	lwg2 = lwgeom_from_gserialized(g2);
-
 	/* Two points? Get outa here... */
-	if (lwg1->type == POINTTYPE && lwg2->type == POINTTYPE)
+	if (gserialized_get_type(g1) == POINTTYPE && gserialized_get_type(g2) == POINTTYPE)
+	{
+		LWGEOM *lwg1 = lwgeom_from_gserialized(g1);
+		LWGEOM *lwg2 = lwgeom_from_gserialized(g2);
 		PG_RETURN_FLOAT8(lwgeom_mindistance2d(lwg1, lwg2));
+	}
 
 	/* Fetch/build our cache, if appropriate, etc... */
-	tree_cache = GetRectTreeGeomCache(fcinfo, g1, g2);
+	tree_cache = GetRectTreeGeomCache(fcinfo, shared_geom1, shared_geom2);
 
 	if (tree_cache && tree_cache->gcache.argnum)
 	{
@@ -177,10 +177,12 @@ Datum ST_DistanceRectTreeCached(PG_FUNCTION_ARGS)
 		RECT_NODE *n_cached = tree_cache->index;;
 		if (tree_cache->gcache.argnum == 1)
 		{
+			LWGEOM *lwg2 = lwgeom_from_gserialized(g2);
 			n = rect_tree_from_lwgeom(lwg2);
 		}
 		else if (tree_cache->gcache.argnum == 2)
 		{
+			LWGEOM *lwg1 = lwgeom_from_gserialized(g1);
 			n = rect_tree_from_lwgeom(lwg1);
 		}
 		else
@@ -191,6 +193,8 @@ Datum ST_DistanceRectTreeCached(PG_FUNCTION_ARGS)
 	}
 	else
 	{
+		LWGEOM *lwg1 = lwgeom_from_gserialized(g1);
+		LWGEOM *lwg2 = lwgeom_from_gserialized(g2);
 		PG_RETURN_FLOAT8(lwgeom_mindistance2d(lwg1, lwg2));
 	}
 
diff --git a/postgis/lwgeom_rtree.c b/postgis/lwgeom_rtree.c
index 27b71d5..f743b92 100644
--- a/postgis/lwgeom_rtree.c
+++ b/postgis/lwgeom_rtree.c
@@ -429,7 +429,7 @@ static GeomCacheMethods RTreeCacheMethods =
 };
 
 RTREE_POLY_CACHE *
-GetRtreeCache(FunctionCallInfo fcinfo, GSERIALIZED *g1)
+GetRtreeCache(FunctionCallInfo fcinfo, SHARED_GSERIALIZED *g1)
 {
 	RTreeGeomCache* cache = (RTreeGeomCache*)GetGeomCache(fcinfo, &RTreeCacheMethods, g1, NULL);
 	RTREE_POLY_CACHE* index = NULL;
diff --git a/postgis/lwgeom_rtree.h b/postgis/lwgeom_rtree.h
index 484ed81..84efc07 100644
--- a/postgis/lwgeom_rtree.h
+++ b/postgis/lwgeom_rtree.h
@@ -80,6 +80,6 @@ LWMLINE *RTreeFindLineSegments(RTREE_NODE *root, double value);
 * a pre-built index structure (RTREE_POLY_CACHE) if one exists. Otherwise
 * builds a new one and returns that.
 */
-RTREE_POLY_CACHE *GetRtreeCache(FunctionCallInfo fcinfo, GSERIALIZED *g1);
+RTREE_POLY_CACHE *GetRtreeCache(FunctionCallInfo fcinfo, SHARED_GSERIALIZED *g1);
 
 #endif /* !defined _LWGEOM_RTREE_H */

-----------------------------------------------------------------------

Summary of changes:
 NEWS                                  |  3 +-
 libpgcommon/Makefile.in               |  3 +-
 libpgcommon/lwgeom_cache.c            | 66 +++++++----------------
 libpgcommon/lwgeom_cache.h            | 34 +++++++-----
 libpgcommon/shared_gserialized.c      | 98 +++++++++++++++++++++++++++++++++++
 postgis/geography_measurement.c       | 19 +++----
 postgis/geography_measurement_trees.c | 18 ++++---
 postgis/geography_measurement_trees.h |  8 +--
 postgis/lwgeom_geos.c                 | 83 ++++++++++++++++-------------
 postgis/lwgeom_geos.h                 |  2 +-
 postgis/lwgeom_geos_prepared.c        |  2 +-
 postgis/lwgeom_geos_prepared.h        |  2 +-
 postgis/lwgeom_rectree.c              | 26 ++++++----
 postgis/lwgeom_rtree.c                |  2 +-
 postgis/lwgeom_rtree.h                |  2 +-
 15 files changed, 232 insertions(+), 136 deletions(-)
 create mode 100644 libpgcommon/shared_gserialized.c


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list