[postgis-tickets] r17298 - Use "support function" API in PgSQL 12+ to provide index support for ST_Intersects and company, in place of old SQL inlining method.

Paul Ramsey pramsey at cleverelephant.ca
Wed Mar 6 09:27:24 PST 2019


Author: pramsey
Date: 2019-03-06 09:27:24 -0800 (Wed, 06 Mar 2019)
New Revision: 17298

Modified:
   trunk/NEWS
   trunk/doc/reference_measure.xml
   trunk/postgis/Makefile.in
   trunk/postgis/geography.sql.in
   trunk/postgis/geography_measurement.c
   trunk/postgis/gserialized_gist_2d.c
   trunk/postgis/lwgeom_geos.c
   trunk/postgis/postgis.sql.in
   trunk/postgis/postgis_drop_after.sql
   trunk/regress/core/tickets.sql
   trunk/utils/create_undef.pl
Log:
Use "support function" API in PgSQL 12+ to provide index support for ST_Intersects and company, in place of old SQL inlining method.
Closes #4341


Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2019-03-06 15:50:34 UTC (rev 17297)
+++ trunk/NEWS	2019-03-06 17:27:24 UTC (rev 17298)
@@ -31,6 +31,8 @@
   - #4311, Introduce `--with-wagyu` as an option for MVT polygons (Raúl Marín)
 
 * Enhancements and fixes *
+  - #4341, Using "support function" API in PgSQL 12+ to replace SQL inlining
+           as the mechanism for providing index support under ST_Intersects, et al
   - #4322, Support for Proj 6+ API, bringing more accurate datum transforms
            and support for WKT projections
   - #4153, ST_Segmentize now splits segments proportionally (Darafei

Modified: trunk/doc/reference_measure.xml
===================================================================
--- trunk/doc/reference_measure.xml	2019-03-06 15:50:34 UTC (rev 17297)
+++ trunk/doc/reference_measure.xml	2019-03-06 17:27:24 UTC (rev 17298)
@@ -3082,20 +3082,8 @@
 
 				<paramdef><type>double precision </type>
 				<parameter>distance_meters</parameter></paramdef>
-		  </funcprototype>
 
-		  <funcprototype>
-				<funcdef>boolean <function>ST_DWithin</function></funcdef>
-				<paramdef><type>geography </type>
-				<parameter>gg1</parameter></paramdef>
-
-				<paramdef><type>geography </type>
-				<parameter>gg2</parameter></paramdef>
-
-				<paramdef><type>double precision </type>
-				<parameter>distance_meters</parameter></paramdef>
-
-				<paramdef><type>boolean </type>
+				<paramdef choice="opt"><type>boolean </type>
 				<parameter>use_spheroid</parameter></paramdef>
 		  </funcprototype>
 		</funcsynopsis>

Modified: trunk/postgis/Makefile.in
===================================================================
--- trunk/postgis/Makefile.in	2019-03-06 15:50:34 UTC (rev 17297)
+++ trunk/postgis/Makefile.in	2019-03-06 17:27:24 UTC (rev 17298)
@@ -106,6 +106,7 @@
 	gserialized_typmod.o \
 	gserialized_gist_2d.o \
 	gserialized_gist_nd.o \
+	gserialized_supportfn.o \
 	$(SPGIST_OBJ) \
 	brin_2d.o \
 	brin_nd.o \

Modified: trunk/postgis/geography.sql.in
===================================================================
--- trunk/postgis/geography.sql.in	2019-03-06 15:50:34 UTC (rev 17297)
+++ trunk/postgis/geography.sql.in	2019-03-06 17:27:24 UTC (rev 17298)
@@ -520,15 +520,7 @@
 	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
 	COST 100;
 
--- Stop calculation and return immediately once distance is less than tolerance
 -- Availability: 1.5.0
-CREATE OR REPLACE FUNCTION _ST_DWithin(geography, geography, float8, boolean)
-	RETURNS boolean
-	AS 'MODULE_PATHNAME','geography_dwithin'
-	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
-	COST 100;
-
--- Availability: 1.5.0
 CREATE OR REPLACE FUNCTION ST_Distance(geography, geography, boolean)
 	RETURNS float8
 	AS 'SELECT @extschema at ._ST_Distance($1, $2, 0.0, $3)'
@@ -555,26 +547,8 @@
 	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
 	COST 50;
 
--- Availability: 1.5.0
-CREATE OR REPLACE FUNCTION ST_DWithin(geography, geography, float8, boolean)
-	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .&&) @extschema at ._ST_Expand($2,$3) AND $2 OPERATOR(@extschema at .&&) @extschema at ._ST_Expand($1,$3) AND @extschema at ._ST_DWithin($1, $2, $3, $4)'
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
 
--- Currently defaulting to spheroid calculations
--- Availability: 1.5.0
-CREATE OR REPLACE FUNCTION ST_DWithin(geography, geography, float8)
-	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .&&) @extschema at ._ST_Expand($2,$3) AND $2 OPERATOR(@extschema at .&&) @extschema at ._ST_Expand($1,$3) AND @extschema at ._ST_DWithin($1, $2, $3, true)'
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
 
--- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
-CREATE OR REPLACE FUNCTION ST_DWithin(text, text, float8)
-	RETURNS boolean AS
-	$$ SELECT @extschema at .ST_DWithin($1::@extschema at .geometry, $2::@extschema at .geometry, $3);  $$
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
-
-
 -- ---------- ---------- ---------- ---------- ---------- ---------- ----------
 -- Distance/DWithin testing functions for cached operations.
 -- For developer/tester use only.
@@ -682,40 +656,6 @@
 	AS 'MODULE_PATHNAME','geography_point_outside'
 	LANGUAGE 'c' IMMUTABLE STRICT;
 
--- Only implemented for polygon-over-point
--- Availability: 1.5.0
-CREATE OR REPLACE FUNCTION _ST_Covers(geography, geography)
-	RETURNS boolean
-	AS 'MODULE_PATHNAME','geography_covers'
-	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
-	COST 100;
-
--- Only implemented for polygon-over-point
--- Availability: 1.5.0
-CREATE OR REPLACE FUNCTION ST_Covers(geography, geography)
-	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .&&) $2 AND @extschema at ._ST_Covers($1, $2)'
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
-
--- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
-CREATE OR REPLACE FUNCTION ST_Covers(text, text)
-	RETURNS boolean AS
-	$$ SELECT @extschema at .ST_Covers($1::@extschema at .geometry, $2::@extschema at .geometry);  $$
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
-
--- Only implemented for polygon-over-point
--- Availability: 1.5.0
-CREATE OR REPLACE FUNCTION ST_CoveredBy(geography, geography)
-	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .&&) $2 AND @extschema at ._ST_Covers($2, $1)'
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
-
--- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
-CREATE OR REPLACE FUNCTION ST_CoveredBy(text, text)
-	RETURNS boolean AS
-	$$ SELECT @extschema at .ST_CoveredBy($1::@extschema at .geometry, $2::@extschema at .geometry);  $$
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
-
 -- Availability: 2.1.0
 CREATE OR REPLACE FUNCTION ST_Segmentize(geog geography, max_segment_length float8)
 	RETURNS geography
@@ -724,18 +664,6 @@
 	COST 100;
 
 -- Availability: 1.5.0
-CREATE OR REPLACE FUNCTION ST_Intersects(geography, geography)
-	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .&&) $2 AND @extschema at ._ST_Distance($1, $2, 0.0, false) < 0.00001'
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
-
--- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
-CREATE OR REPLACE FUNCTION ST_Intersects(text, text)
-	RETURNS boolean AS
-	$$ SELECT @extschema at .ST_Intersects($1::@extschema at .geometry, $2::@extschema at .geometry);  $$
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
-
--- Availability: 1.5.0
 CREATE OR REPLACE FUNCTION _ST_BestSRID(geography, geography)
 	RETURNS integer
 	AS 'MODULE_PATHNAME','geography_bestsrid'
@@ -863,3 +791,118 @@
 	LANGUAGE 'sql' IMMUTABLE STRICT _PARALLEL;
 
 -----------------------------------------------------------------------------
+
+-- Only implemented for polygon-over-point
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION _ST_Covers(geog1 geography, geog2 geography)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME','geography_covers'
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100;
+
+-- Stop calculation and return immediately once distance is less than tolerance
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION _ST_DWithin(geog1 geography, geog2 geography, tolerance float8, use_spheroid boolean DEFAULT true)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME','geography_dwithin'
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100;
+
+-- Only implemented for polygon-over-point
+-- Availability: 3.0.0
+CREATE OR REPLACE FUNCTION _ST_CoveredBy(geog1 geography, geog2 geography)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME','geography_coveredby'
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100;
+
+#if POSTGIS_PGSQL_VERSION >= 120
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_Covers(geog1 geography, geog2 geography)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME','geography_covers'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_DWithin(geog1 geography, geog2 geography, tolerance float8, use_spheroid boolean DEFAULT true)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME','geography_dwithin'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100;
+
+-- Availability: 3.0.0
+CREATE OR REPLACE FUNCTION ST_CoveredBy(geog1 geography, geog2 geography)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME','geography_coveredby'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_Intersects(geog1 geography, geog2 geography)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME','geography_intersects'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100;
+
+#else
+
+-- Only implemented for polygon-over-point
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_Covers(geog1 geography, geog2 geography)
+	RETURNS boolean
+	AS 'SELECT $1 OPERATOR(@extschema at .&&) $2 AND @extschema at ._ST_Covers($1, $2)'
+	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+
+-- Only implemented for polygon-over-point
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_CoveredBy(geog1 geography, geog2 geography)
+	RETURNS boolean
+	AS 'SELECT $1 OPERATOR(@extschema at .&&) $2 AND @extschema at ._ST_Covers($2, $1)'
+	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+
+-- Availability: 1.5.0
+CREATE OR REPLACE FUNCTION ST_DWithin(geog1 geography, geog2 geography, tolerance float8, use_spheroid boolean DEFAULT true)
+	RETURNS boolean
+	AS 'SELECT $1 OPERATOR(@extschema at .&&) @extschema at ._ST_Expand($2,$3) AND $2 OPERATOR(@extschema at .&&) @extschema at ._ST_Expand($1,$3) AND @extschema at ._ST_DWithin($1, $2, $3, $4)'
+	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+
+CREATE OR REPLACE FUNCTION ST_Intersects(geography, geography)
+	RETURNS boolean
+	AS 'SELECT $1 OPERATOR(@extschema at .&&) $2 AND @extschema at ._ST_Distance($1, $2, 0.0, false) < 0.00001'
+	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+
+#endif
+
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+CREATE OR REPLACE FUNCTION ST_Covers(text, text)
+	RETURNS boolean AS
+	$$ SELECT @extschema at .ST_Covers($1::@extschema at .geometry, $2::@extschema at .geometry);  $$
+	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+CREATE OR REPLACE FUNCTION ST_CoveredBy(text, text)
+	RETURNS boolean AS
+	$$ SELECT @extschema at .ST_CoveredBy($1::@extschema at .geometry, $2::@extschema at .geometry);  $$
+	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+CREATE OR REPLACE FUNCTION ST_DWithin(text, text, float8)
+	RETURNS boolean AS
+	$$ SELECT @extschema at .ST_DWithin($1::@extschema at .geometry, $2::@extschema at .geometry, $3);  $$
+	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+
+
+-- Availability: 1.5.0 - this is just a hack to prevent unknown from causing ambiguous name because of geography
+CREATE OR REPLACE FUNCTION ST_Intersects(text, text)
+	RETURNS boolean AS
+	$$ SELECT @extschema at .ST_Intersects($1::@extschema at .geometry, $2::@extschema at .geometry);  $$
+	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+
+-----------------------------------------------------------------------------
+

Modified: trunk/postgis/geography_measurement.c
===================================================================
--- trunk/postgis/geography_measurement.c	2019-03-06 15:50:34 UTC (rev 17297)
+++ trunk/postgis/geography_measurement.c	2019-03-06 17:27:24 UTC (rev 17298)
@@ -58,6 +58,7 @@
 Datum geography_expand(PG_FUNCTION_ARGS);
 Datum geography_point_outside(PG_FUNCTION_ARGS);
 Datum geography_covers(PG_FUNCTION_ARGS);
+Datum geography_coveredby(PG_FUNCTION_ARGS);
 Datum geography_bestsrid(PG_FUNCTION_ARGS);
 Datum geography_perimeter(PG_FUNCTION_ARGS);
 Datum geography_project(PG_FUNCTION_ARGS);
@@ -267,33 +268,13 @@
 }
 
 
-/*
-** geography_dwithin(GSERIALIZED *g1, GSERIALIZED *g2, double tolerance, boolean use_spheroid)
-** returns double distance in meters
-*/
-PG_FUNCTION_INFO_V1(geography_dwithin);
-Datum geography_dwithin(PG_FUNCTION_ARGS)
+static bool
+geography_dwithin_impl(FunctionCallInfo fcinfo, GSERIALIZED *g1, GSERIALIZED *g2, double tolerance, bool use_spheroid)
 {
-	GSERIALIZED *g1 = NULL;
-	GSERIALIZED *g2 = NULL;
-	double tolerance = 0.0;
 	double distance;
-	bool use_spheroid = true;
 	SPHEROID s;
 	int dwithin = LW_FALSE;
 
-	/* Get our geometry objects loaded into memory. */
-	g1 = PG_GETARG_GSERIALIZED_P(0);
-	g2 = PG_GETARG_GSERIALIZED_P(1);
-
-	/* Read our tolerance value. */
-	if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
-		tolerance = PG_GETARG_FLOAT8(2);
-
-	/* Read our calculation type. */
-	if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
-		use_spheroid = PG_GETARG_BOOL(3);
-
 	error_if_srid_mismatch(gserialized_get_srid(g1), gserialized_get_srid(g2));
 
 	/* Initialize spheroid */
@@ -305,11 +286,7 @@
 
 	/* Return FALSE 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_BOOL(false);
-	}
+		return 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) )
@@ -325,14 +302,50 @@
 		lwgeom_free(lwgeom2);
 	}
 
-	/* Clean up */
+	return dwithin;
+}
+
+/*
+** geography_dwithin(GSERIALIZED *g1, GSERIALIZED *g2, double tolerance, boolean use_spheroid)
+** returns double distance in meters
+*/
+PG_FUNCTION_INFO_V1(geography_dwithin);
+Datum geography_dwithin(PG_FUNCTION_ARGS)
+{
+	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
+	GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
+	double tolerance = 0.0;
+	bool use_spheroid = true;
+	bool dwithin = false;
+
+	/* Read our tolerance value. */
+	if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
+		tolerance = PG_GETARG_FLOAT8(2);
+
+	/* Read our calculation type. */
+	if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
+		use_spheroid = PG_GETARG_BOOL(3);
+
+	dwithin = geography_dwithin_impl(fcinfo, g1, g2, tolerance, use_spheroid);
+
 	PG_FREE_IF_COPY(g1, 0);
 	PG_FREE_IF_COPY(g2, 1);
+	PG_RETURN_BOOL(dwithin);
+}
 
+PG_FUNCTION_INFO_V1(geography_intersects);
+Datum geography_intersects(PG_FUNCTION_ARGS)
+{
+	GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
+	GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
+	double tolerance = 0.0;
+	bool use_spheroid = true;
+	bool dwithin = geography_dwithin_impl(fcinfo, g1, g2, tolerance, use_spheroid);
+	PG_FREE_IF_COPY(g1, 0);
+	PG_FREE_IF_COPY(g2, 1);
 	PG_RETURN_BOOL(dwithin);
 }
 
-
 /*
 ** geography_distance_tree(GSERIALIZED *g1, GSERIALIZED *g2, double tolerance, boolean use_spheroid)
 ** returns double distance in meters
@@ -769,6 +782,48 @@
 	PG_RETURN_BOOL(result);
 }
 
+PG_FUNCTION_INFO_V1(geography_coveredby);
+Datum geography_coveredby(PG_FUNCTION_ARGS)
+{
+	LWGEOM *lwgeom1 = NULL;
+	LWGEOM *lwgeom2 = NULL;
+	GSERIALIZED *g1 = NULL;
+	GSERIALIZED *g2 = NULL;
+	int result = LW_FALSE;
+
+	/* Get our geometry objects loaded into memory. */
+	/* Pick them up in reverse order to covers */
+	g1 = PG_GETARG_GSERIALIZED_P(1);
+	g2 = PG_GETARG_GSERIALIZED_P(0);
+
+	/* Construct our working geometries */
+	lwgeom1 = lwgeom_from_gserialized(g1);
+	lwgeom2 = lwgeom_from_gserialized(g2);
+
+	error_if_srid_mismatch(lwgeom1->srid, lwgeom2->srid);
+
+	/* EMPTY never intersects with another geometry */
+	if ( lwgeom_is_empty(lwgeom1) || lwgeom_is_empty(lwgeom2) )
+	{
+		lwgeom_free(lwgeom1);
+		lwgeom_free(lwgeom2);
+		PG_FREE_IF_COPY(g1, 1);
+		PG_FREE_IF_COPY(g2, 0);
+		PG_RETURN_BOOL(false);
+	}
+
+	/* Calculate answer */
+	result = lwgeom_covers_lwgeom_sphere(lwgeom1, lwgeom2);
+
+	/* Clean up */
+	lwgeom_free(lwgeom1);
+	lwgeom_free(lwgeom2);
+	PG_FREE_IF_COPY(g1, 1);
+	PG_FREE_IF_COPY(g2, 0);
+
+	PG_RETURN_BOOL(result);
+}
+
 /*
 ** geography_bestsrid(GSERIALIZED *g, GSERIALIZED *g) returns int
 ** Utility function. Returns negative SRID numbers that match to the

Modified: trunk/postgis/gserialized_gist_2d.c
===================================================================
--- trunk/postgis/gserialized_gist_2d.c	2019-03-06 15:50:34 UTC (rev 17297)
+++ trunk/postgis/gserialized_gist_2d.c	2019-03-06 17:27:24 UTC (rev 17298)
@@ -383,8 +383,13 @@
 	if ( box2df_is_empty(a) && ! box2df_is_empty(b) )
 		return true;
 
-	POSTGIS_DEBUG(5, "entered function");
-	return box2df_contains(b,a);
+	if ( (a->xmin < b->xmin) || (a->xmax > b->xmax) ||
+	     (a->ymin < b->ymin) || (a->ymax > b->ymax) )
+	{
+		return false;
+	}
+
+	return true;
 }
 
 bool box2df_equals(const BOX2DF *a, const BOX2DF *b)
@@ -987,7 +992,7 @@
 		break;
 	case RTContainedByStrategyNumber:
 	case RTOldContainedByStrategyNumber:
-		retval = (bool) box2df_contains(query, key);
+		retval = (bool) box2df_within(key, query);
 		break;
 
 	/* To one side */

Modified: trunk/postgis/lwgeom_geos.c
===================================================================
--- trunk/postgis/lwgeom_geos.c	2019-03-06 15:50:34 UTC (rev 17297)
+++ trunk/postgis/lwgeom_geos.c	2019-03-06 17:27:24 UTC (rev 17298)
@@ -73,6 +73,7 @@
 Datum ST_Intersects(PG_FUNCTION_ARGS);
 Datum crosses(PG_FUNCTION_ARGS);
 Datum contains(PG_FUNCTION_ARGS);
+Datum within(PG_FUNCTION_ARGS);
 Datum containsproperly(PG_FUNCTION_ARGS);
 Datum covers(PG_FUNCTION_ARGS);
 Datum overlaps(PG_FUNCTION_ARGS);
@@ -1610,26 +1611,20 @@
 	PG_RETURN_BOOL(result);
 }
 
-
-PG_FUNCTION_INFO_V1(contains);
-Datum contains(PG_FUNCTION_ARGS)
+static bool
+containsImpl(FunctionCallInfo fcinfo, GSERIALIZED *geom1, GSERIALIZED *geom2)
 {
-	GSERIALIZED *geom1;
-	GSERIALIZED *geom2;
 	GEOSGeometry *g1, *g2;
 	GBOX box1, box2;
 	int result;
 	PrepGeomCache *prep_cache;
 
-	geom1 = PG_GETARG_GSERIALIZED_P(0);
-	geom2 = PG_GETARG_GSERIALIZED_P(1);
-
 	errorIfGeometryCollection(geom1,geom2);
 	error_if_srid_mismatch(gserialized_get_srid(geom1), gserialized_get_srid(geom2));
 
 	/* A.Contains(Empty) == FALSE */
 	if ( gserialized_is_empty(geom1) || gserialized_is_empty(geom2) )
-		PG_RETURN_BOOL(false);
+		return false;
 
 	POSTGIS_DEBUG(3, "contains called.");
 
@@ -1637,10 +1632,11 @@
 	** short-circuit 1: if geom2 bounding box is not completely inside
 	** geom1 bounding box we can return FALSE.
 	*/
-	if ( gserialized_get_gbox_p(geom1, &box1) &&
-	        gserialized_get_gbox_p(geom2, &box2) )
+	if (gserialized_get_gbox_p(geom1, &box1) &&
+	    gserialized_get_gbox_p(geom2, &box2))
 	{
-		if (!gbox_contains_2d(&box1, &box2)) PG_RETURN_BOOL(false);
+		if (!gbox_contains_2d(&box1, &box2))
+			return false;
 	}
 
 	/*
@@ -1695,12 +1691,10 @@
 		{
 			/* Never get here */
 			elog(ERROR,"Type isn't point or multipoint!");
-			PG_RETURN_NULL();
+			return false;
 		}
 
-		PG_FREE_IF_COPY(geom1, 0);
-		PG_FREE_IF_COPY(geom2, 1);
-		PG_RETURN_BOOL(retval);
+		return retval > 0;
 	}
 	else
 	{
@@ -1739,13 +1733,32 @@
 
 	if (result == 2) HANDLE_GEOS_ERROR("GEOSContains");
 
-	PG_FREE_IF_COPY(geom1, 0);
-	PG_FREE_IF_COPY(geom2, 1);
+	return result > 0;
+}
 
+PG_FUNCTION_INFO_V1(contains);
+Datum contains(PG_FUNCTION_ARGS)
+{
+	GSERIALIZED *geom0 = PG_GETARG_GSERIALIZED_P(0);
+	GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(1);
+	bool result = containsImpl(fcinfo, geom0, geom1);
+	PG_FREE_IF_COPY(geom0, 0);
+	PG_FREE_IF_COPY(geom1, 1);
 	PG_RETURN_BOOL(result);
+}
 
+PG_FUNCTION_INFO_V1(within);
+Datum within(PG_FUNCTION_ARGS)
+{
+	GSERIALIZED *geom0 = PG_GETARG_GSERIALIZED_P(0);
+	GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(1);
+	bool result = containsImpl(fcinfo, geom1, geom0);
+	PG_FREE_IF_COPY(geom0, 0);
+	PG_FREE_IF_COPY(geom1, 1);
+	PG_RETURN_BOOL(result);
 }
 
+
 PG_FUNCTION_INFO_V1(containsproperly);
 Datum containsproperly(PG_FUNCTION_ARGS)
 {

Modified: trunk/postgis/postgis.sql.in
===================================================================
--- trunk/postgis/postgis.sql.in	2019-03-06 15:50:34 UTC (rev 17297)
+++ trunk/postgis/postgis.sql.in	2019-03-06 17:27:24 UTC (rev 17298)
@@ -221,7 +221,7 @@
 	AS 'MODULE_PATHNAME','LWGEOM_m_point'
 	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL;
 
--------------------------------------------
+
 -------------------------------------------------------------------
 
 CREATE OR REPLACE FUNCTION box3d_in(cstring)
@@ -537,6 +537,7 @@
 	AS 'MODULE_PATHNAME', 'gserialized_gist_joinsel_nd'
 	LANGUAGE 'c' _PARALLEL;
 
+
 -----------------------------------------------------------------------------
 -- GEOMETRY Operators
 -----------------------------------------------------------------------------
@@ -3508,20 +3509,6 @@
 	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
 	COST 1; -- reset cost, see #3675
 
--- Only accepts LINESTRING as parameters.
--- Availability: 1.4.0
-CREATE OR REPLACE FUNCTION _ST_LineCrossingDirection(geom1 geometry, geom2 geometry)
-	RETURNS integer
-	AS 'MODULE_PATHNAME', 'ST_LineCrossingDirection'
-	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
-	COST 100; -- Guessed cost
-
--- Availability: 1.4.0
-CREATE OR REPLACE FUNCTION ST_LineCrossingDirection(geom1 geometry, geom2 geometry)
-	RETURNS integer AS
-	$$ SELECT CASE WHEN NOT $1 OPERATOR(@extschema at .&&) $2 THEN 0 ELSE @extschema at ._ST_LineCrossingDirection($1,$2) END $$
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
-
 -- Availability: 1.3.3
 CREATE OR REPLACE FUNCTION ST_SimplifyPreserveTopology(geometry, float8)
 	RETURNS geometry
@@ -4160,20 +4147,16 @@
 	AS 'MODULE_PATHNAME','disjoint'
 	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL;
 
--- PostGIS equivalent function: touches(geom1 geometry, geom2 geometry)
-CREATE OR REPLACE FUNCTION _ST_Touches(geom1 geometry, geom2 geometry)
-	RETURNS boolean
-	AS 'MODULE_PATHNAME','touches'
+-----------------------------------------------------------------------------
+-- Non-indexed functions (see above for public indexed variants)
+
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION _ST_LineCrossingDirection(line1 geometry, line2 geometry)
+	RETURNS integer
+	AS 'MODULE_PATHNAME', 'ST_LineCrossingDirection'
 	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
-	COST 100; -- Guessed cost
+	COST 100;
 
--- Availability: 1.2.2
--- Inlines index magic
-CREATE OR REPLACE FUNCTION ST_Touches(geom1 geometry, geom2 geometry)
-	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .&&) $2 AND @extschema at ._ST_Touches($1,$2)'
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
-
 -- Availability: 1.3.4
 CREATE OR REPLACE FUNCTION _ST_DWithin(geom1 geometry, geom2 geometry,float8)
 	RETURNS boolean
@@ -4182,12 +4165,13 @@
 	COST 100; -- Guessed cost
 
 -- Availability: 1.2.2
-CREATE OR REPLACE FUNCTION ST_DWithin(geom1 geometry, geom2 geometry, float8)
+CREATE OR REPLACE FUNCTION _ST_Touches(geom1 geometry, geom2 geometry)
 	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .&&) @extschema at .ST_Expand($2,$3) AND $2 OPERATOR(@extschema at .&&) @extschema at .ST_Expand($1,$3) AND @extschema at ._ST_DWithin($1, $2, $3)'
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+	AS 'MODULE_PATHNAME','touches'
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100; -- Guessed cost
 
--- PostGIS equivalent function: intersects(geom1 geometry, geom2 geometry)
+-- Availability: 1.2.2
 CREATE OR REPLACE FUNCTION _ST_Intersects(geom1 geometry, geom2 geometry)
 	RETURNS boolean
 	AS 'MODULE_PATHNAME','ST_Intersects'
@@ -4195,13 +4179,6 @@
 	COST 100; -- Guessed cost
 
 -- Availability: 1.2.2
--- Inlines index magic
-CREATE OR REPLACE FUNCTION ST_Intersects(geom1 geometry, geom2 geometry)
-	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .&&) $2 AND @extschema at ._ST_Intersects($1,$2)'
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
-
--- PostGIS equivalent function: crosses(geom1 geometry, geom2 geometry)
 CREATE OR REPLACE FUNCTION _ST_Crosses(geom1 geometry, geom2 geometry)
 	RETURNS boolean
 	AS 'MODULE_PATHNAME','crosses'
@@ -4209,13 +4186,6 @@
 	COST 100; -- Guessed cost
 
 -- Availability: 1.2.2
--- Inlines index magic
-CREATE OR REPLACE FUNCTION ST_Crosses(geom1 geometry, geom2 geometry)
-	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .&&) $2 AND @extschema at ._ST_Crosses($1,$2)'
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
-
--- PostGIS equivalent function: contains(geom1 geometry, geom2 geometry)
 CREATE OR REPLACE FUNCTION _ST_Contains(geom1 geometry, geom2 geometry)
 	RETURNS boolean
 	AS 'MODULE_PATHNAME','contains'
@@ -4222,12 +4192,19 @@
 	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
 	COST 100; -- Guessed cost
 
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION _ST_ContainsProperly(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME','containsproperly'
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100; -- Guessed cost
+
 -- Availability: 1.2.2
--- Inlines index magic
-CREATE OR REPLACE FUNCTION ST_Contains(geom1 geometry, geom2 geometry)
+CREATE OR REPLACE FUNCTION _ST_Covers(geom1 geometry, geom2 geometry)
 	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .~) $2 AND @extschema at ._ST_Contains($1,$2)'
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+	AS 'MODULE_PATHNAME', 'covers'
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100; -- Guessed cost
 
 -- Availability: 1.2.2
 CREATE OR REPLACE FUNCTION _ST_CoveredBy(geom1 geometry, geom2 geometry)
@@ -4237,54 +4214,229 @@
 	COST 100; -- Guessed cost
 
 -- Availability: 1.2.2
-CREATE OR REPLACE FUNCTION ST_CoveredBy(geom1 geometry, geom2 geometry)
+CREATE OR REPLACE FUNCTION _ST_Within(geom1 geometry, geom2 geometry)
 	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .@) $2 AND @extschema at ._ST_CoveredBy($1,$2)'
+	AS 'SELECT @extschema at ._ST_Contains($2,$1)'
 	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
 
 -- Availability: 1.2.2
-CREATE OR REPLACE FUNCTION _ST_Covers(geom1 geometry, geom2 geometry)
+CREATE OR REPLACE FUNCTION _ST_Overlaps(geom1 geometry, geom2 geometry)
 	RETURNS boolean
-	AS 'MODULE_PATHNAME', 'covers'
+	AS 'MODULE_PATHNAME','overlaps'
 	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
 	COST 100; -- Guessed cost
 
--- Availability: 1.2.2
--- Inlines index magic
-CREATE OR REPLACE FUNCTION ST_Covers(geom1 geometry, geom2 geometry)
+CREATE OR REPLACE FUNCTION _ST_DFullyWithin(geom1 geometry, geom2 geometry,float8)
 	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .~) $2 AND @extschema at ._ST_Covers($1,$2)'
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+	AS 'MODULE_PATHNAME', 'LWGEOM_dfullywithin'
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL;
 
+CREATE OR REPLACE FUNCTION _ST_3DDWithin(geom1 geometry, geom2 geometry,float8)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME', 'LWGEOM_dwithin3d'
+	LANGUAGE 'c' IMMUTABLE STRICT  _PARALLEL
+	COST 100;
+
+CREATE OR REPLACE FUNCTION _ST_3DDFullyWithin(geom1 geometry, geom2 geometry,float8)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME', 'LWGEOM_dfullywithin3d'
+	LANGUAGE 'c' IMMUTABLE STRICT  _PARALLEL
+	COST 100;
+
+CREATE OR REPLACE FUNCTION _ST_3DIntersects(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME', 'ST_3DIntersects'
+	LANGUAGE 'c' IMMUTABLE STRICT  _PARALLEL
+	COST 100;
+
+-----------------------------------------------------------------------------
+
+
+#if POSTGIS_PGSQL_VERSION >= 120
+
+-----------------------------------------------------------------------------
+-- Planner Support Functions
+-----------------------------------------------------------------------------
+-- Availability 3.0.0
+CREATE OR REPLACE FUNCTION postgis_index_supportfn (internal)
+	RETURNS internal
+	AS 'MODULE_PATHNAME', 'postgis_index_supportfn'
+	LANGUAGE 'c';
+
+-----------------------------------------------------------------------------
+
 -- Availability: 1.4.0
-CREATE OR REPLACE FUNCTION _ST_ContainsProperly(geom1 geometry, geom2 geometry)
-	RETURNS boolean
-	AS 'MODULE_PATHNAME','containsproperly'
+CREATE OR REPLACE FUNCTION ST_LineCrossingDirection(geom1 geometry, geom2 geometry)
+	RETURNS integer
+	AS 'MODULE_PATHNAME', 'ST_LineCrossingDirection'
+	SUPPORT postgis_index_supportfn
 	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
 	COST 100; -- Guessed cost
 
+-- Availability: 1.3.4
+CREATE OR REPLACE FUNCTION ST_DWithin(geom1 geometry, geom2 geometry,float8)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME', 'LWGEOM_dwithin'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Touches(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME','touches'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Intersects(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME','ST_Intersects'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Crosses(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME','crosses'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Contains(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME','contains'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100;
+
 -- Availability: 1.4.0
--- Inlines index magic
 CREATE OR REPLACE FUNCTION ST_ContainsProperly(geom1 geometry, geom2 geometry)
 	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .~) $2 AND @extschema at ._ST_ContainsProperly($1,$2)'
-	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+	AS 'MODULE_PATHNAME','containsproperly'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100;
 
--- PostGIS equivalent function: overlaps(geom1 geometry, geom2 geometry)
-CREATE OR REPLACE FUNCTION _ST_Overlaps(geom1 geometry, geom2 geometry)
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Within(geom1 geometry, geom2 geometry)
 	RETURNS boolean
+	AS 'MODULE_PATHNAME','within'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Covers(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME', 'covers'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_CoveredBy(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME', 'coveredby'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
+	COST 100;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Overlaps(geom1 geometry, geom2 geometry)
+	RETURNS boolean
 	AS 'MODULE_PATHNAME','overlaps'
+	SUPPORT postgis_index_supportfn
 	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL
-	COST 100; -- Guessed cost
+	COST 100;
 
--- PostGIS equivalent function: within(geom1 geometry, geom2 geometry)
-CREATE OR REPLACE FUNCTION _ST_Within(geom1 geometry, geom2 geometry)
+CREATE OR REPLACE FUNCTION ST_DFullyWithin(geom1 geometry, geom2 geometry,float8)
 	RETURNS boolean
-	AS 'SELECT @extschema at ._ST_Contains($2,$1)'
+	AS 'MODULE_PATHNAME', 'LWGEOM_dfullywithin'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL;
+
+CREATE OR REPLACE FUNCTION ST_3DDWithin(geom1 geometry, geom2 geometry,float8)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME', 'LWGEOM_dwithin3d'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT  _PARALLEL
+	COST 100;
+
+CREATE OR REPLACE FUNCTION ST_3DDFullyWithin(geom1 geometry, geom2 geometry,float8)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME', 'LWGEOM_dfullywithin3d'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT  _PARALLEL
+	COST 100;
+
+CREATE OR REPLACE FUNCTION ST_3DIntersects(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'MODULE_PATHNAME', 'ST_3DIntersects'
+	SUPPORT postgis_index_supportfn
+	LANGUAGE 'c' IMMUTABLE STRICT  _PARALLEL
+	COST 100;
+
+#else
+
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION ST_LineCrossingDirection(line1 geometry, line2 geometry)
+	RETURNS integer AS
+	$$ SELECT CASE WHEN NOT $1 OPERATOR(@extschema at .&&) $2 THEN 0 ELSE @extschema at ._ST_LineCrossingDirection($1,$2) END $$
 	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
 
 -- Availability: 1.2.2
--- Inlines index magic
+CREATE OR REPLACE FUNCTION ST_DWithin(geom1 geometry, geom2 geometry, float8)
+	RETURNS boolean
+	AS 'SELECT $1 OPERATOR(@extschema at .&&) @extschema at .ST_Expand($2,$3) AND $2 OPERATOR(@extschema at .&&) @extschema at .ST_Expand($1,$3) AND @extschema at ._ST_DWithin($1, $2, $3)'
+	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Touches(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'SELECT $1 OPERATOR(@extschema at .&&) $2 AND @extschema at ._ST_Touches($1,$2)'
+	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Intersects(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'SELECT $1 OPERATOR(@extschema at .&&) $2 AND @extschema at ._ST_Intersects($1,$2)'
+	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Crosses(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'SELECT $1 OPERATOR(@extschema at .&&) $2 AND @extschema at ._ST_Crosses($1,$2)'
+	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Contains(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'SELECT $1 OPERATOR(@extschema at .~) $2 AND @extschema at ._ST_Contains($1,$2)'
+	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_CoveredBy(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'SELECT $1 OPERATOR(@extschema at .@) $2 AND @extschema at ._ST_CoveredBy($1,$2)'
+	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+
+-- Availability: 1.2.2
+CREATE OR REPLACE FUNCTION ST_Covers(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'SELECT $1 OPERATOR(@extschema at .~) $2 AND @extschema at ._ST_Covers($1,$2)'
+	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+
+-- Availability: 1.4.0
+CREATE OR REPLACE FUNCTION ST_ContainsProperly(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'SELECT $1 OPERATOR(@extschema at .~) $2 AND @extschema at ._ST_ContainsProperly($1,$2)'
+	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
+
+-- Availability: 1.2.2
 CREATE OR REPLACE FUNCTION ST_Within(geom1 geometry, geom2 geometry)
 	RETURNS boolean
 	AS 'SELECT $2 OPERATOR(@extschema at .~) $1 AND @extschema at ._ST_Contains($2,$1)'
@@ -4291,12 +4443,38 @@
 	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
 
 -- Availability: 1.2.2
--- Inlines index magic
 CREATE OR REPLACE FUNCTION ST_Overlaps(geom1 geometry, geom2 geometry)
 	RETURNS boolean
 	AS 'SELECT $1 OPERATOR(@extschema at .&&) $2 AND @extschema at ._ST_Overlaps($1,$2)'
 	LANGUAGE 'sql' IMMUTABLE _PARALLEL;
 
+CREATE OR REPLACE FUNCTION ST_DFullyWithin(geom1 geometry, geom2 geometry, float8)
+	RETURNS boolean
+	AS 'SELECT $1 OPERATOR(@extschema at .&&) @extschema at .ST_Expand($2,$3) AND $2 OPERATOR(@extschema at .&&) @extschema at .ST_Expand($1,$3) AND @extschema at ._ST_DFullyWithin(@extschema at .ST_ConvexHull($1), @extschema at .ST_ConvexHull($2), $3)'
+	LANGUAGE 'sql' IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION ST_3DDWithin(geom1 geometry, geom2 geometry,float8)
+	RETURNS boolean
+	AS 'SELECT $1 OPERATOR(@extschema at .&&) @extschema at .ST_Expand($2,$3) AND $2 OPERATOR(@extschema at .&&) @extschema at .ST_Expand($1,$3) AND @extschema at ._ST_3DDWithin($1, $2, $3)'
+	LANGUAGE 'sql' IMMUTABLE  _PARALLEL
+	COST 100;
+
+CREATE OR REPLACE FUNCTION ST_3DDFullyWithin(geom1 geometry, geom2 geometry,float8)
+	RETURNS boolean
+	AS 'SELECT $1 OPERATOR(@extschema at .&&) @extschema at .ST_Expand($2,$3) AND $2 OPERATOR(@extschema at .&&) @extschema at .ST_Expand($1,$3) AND @extschema at ._ST_3DDFullyWithin($1, $2, $3)'
+	LANGUAGE 'sql' IMMUTABLE  _PARALLEL
+	COST 100;
+
+CREATE OR REPLACE FUNCTION ST_3DIntersects(geom1 geometry, geom2 geometry)
+	RETURNS boolean
+	AS 'SELECT $1 OPERATOR(@extschema at .&&) $2 AND @extschema at ._ST_3DIntersects($1, $2)'
+	LANGUAGE 'sql' IMMUTABLE  _PARALLEL
+	COST 100;
+
+#endif
+
+-----------------------------------------------------------------------------
+
 -- PostGIS equivalent function: IsValid(geometry)
 -- TODO: change null returns to true
 CREATE OR REPLACE FUNCTION ST_IsValid(geometry)
@@ -5433,16 +5611,6 @@
 	AS 'SELECT @extschema at ._ST_LongestLine(@extschema at .ST_ConvexHull($1), @extschema at .ST_ConvexHull($2))'
 	LANGUAGE 'sql' IMMUTABLE STRICT _PARALLEL;
 
-CREATE OR REPLACE FUNCTION _ST_DFullyWithin(geom1 geometry, geom2 geometry,float8)
-	RETURNS boolean
-	AS 'MODULE_PATHNAME', 'LWGEOM_dfullywithin'
-	LANGUAGE 'c' IMMUTABLE STRICT _PARALLEL;
-
-CREATE OR REPLACE FUNCTION ST_DFullyWithin(geom1 geometry, geom2 geometry, float8)
-	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .&&) @extschema at .ST_Expand($2,$3) AND $2 OPERATOR(@extschema at .&&) @extschema at .ST_Expand($1,$3) AND @extschema at ._ST_DFullyWithin(@extschema at .ST_ConvexHull($1), @extschema at .ST_ConvexHull($2), $3)'
-	LANGUAGE 'sql' IMMUTABLE;
-
 -- Availability: 2.2.0
 CREATE OR REPLACE FUNCTION ST_SwapOrdinates(geom geometry, ords cstring)
 	RETURNS geometry
@@ -5813,42 +5981,7 @@
 	LANGUAGE 'c' IMMUTABLE STRICT  _PARALLEL
 	COST 1; -- reset cost, see #3675
 
-CREATE OR REPLACE FUNCTION _ST_3DDWithin(geom1 geometry, geom2 geometry,float8)
-	RETURNS boolean
-	AS 'MODULE_PATHNAME', 'LWGEOM_dwithin3d'
-	LANGUAGE 'c' IMMUTABLE STRICT  _PARALLEL
-	COST 100;
 
-CREATE OR REPLACE FUNCTION ST_3DDWithin(geom1 geometry, geom2 geometry,float8)
-	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .&&) @extschema at .ST_Expand($2,$3) AND $2 OPERATOR(@extschema at .&&) @extschema at .ST_Expand($1,$3) AND @extschema at ._ST_3DDWithin($1, $2, $3)'
-	LANGUAGE 'sql' IMMUTABLE  _PARALLEL
-	COST 100;
-
-CREATE OR REPLACE FUNCTION _ST_3DDFullyWithin(geom1 geometry, geom2 geometry,float8)
-	RETURNS boolean
-	AS 'MODULE_PATHNAME', 'LWGEOM_dfullywithin3d'
-	LANGUAGE 'c' IMMUTABLE STRICT  _PARALLEL
-	COST 100;
-
-CREATE OR REPLACE FUNCTION ST_3DDFullyWithin(geom1 geometry, geom2 geometry,float8)
-	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .&&) @extschema at .ST_Expand($2,$3) AND $2 OPERATOR(@extschema at .&&) @extschema at .ST_Expand($1,$3) AND @extschema at ._ST_3DDFullyWithin($1, $2, $3)'
-	LANGUAGE 'sql' IMMUTABLE  _PARALLEL
-	COST 100;
-
-CREATE OR REPLACE FUNCTION _ST_3DIntersects(geom1 geometry, geom2 geometry)
-	RETURNS boolean
-	AS 'MODULE_PATHNAME', 'ST_3DIntersects'
-	LANGUAGE 'c' IMMUTABLE STRICT  _PARALLEL
-	COST 100;
-
-CREATE OR REPLACE FUNCTION ST_3DIntersects(geom1 geometry, geom2 geometry)
-	RETURNS boolean
-	AS 'SELECT $1 OPERATOR(@extschema at .&&) $2 AND @extschema at ._ST_3DIntersects($1, $2)'
-	LANGUAGE 'sql' IMMUTABLE  _PARALLEL
-	COST 100;
-
 ---------------------------------------------------------------
 -- SQL-MM
 ---------------------------------------------------------------

Modified: trunk/postgis/postgis_drop_after.sql
===================================================================
--- trunk/postgis/postgis_drop_after.sql	2019-03-06 15:50:34 UTC (rev 17297)
+++ trunk/postgis/postgis_drop_after.sql	2019-03-06 17:27:24 UTC (rev 17298)
@@ -104,6 +104,7 @@
 DROP FUNCTION IF EXISTS st_box3d(geometry);
 DROP FUNCTION IF EXISTS st_box(geometry);
 DROP FUNCTION IF EXISTS ST_ConcaveHull(geometry,float); -- this one changed to use default parameters
+DROP FUNCTION IF EXISTS ST_DWithin(geography, geography, float8); -- this one changed to use default parameters
 DROP FUNCTION IF EXISTS st_text(geometry);
 DROP FUNCTION IF EXISTS st_geometry(box2d);
 DROP FUNCTION IF EXISTS st_geometry(box3d);
@@ -177,6 +178,7 @@
 DROP FUNCTION IF EXISTS _ST_DistanceRectTreeCached(g1 geometry, g2 geometry);
 
 
+
 -- pgis_abs type was increased from 8 bytes in 2.1 to 16 bytes in 2.2
 -- See #3460
 UPDATE pg_type SET typlen=16 WHERE typname='pgis_abs' AND typlen=8;

Modified: trunk/regress/core/tickets.sql
===================================================================
--- trunk/regress/core/tickets.sql	2019-03-06 15:50:34 UTC (rev 17297)
+++ trunk/regress/core/tickets.sql	2019-03-06 17:27:24 UTC (rev 17298)
@@ -597,7 +597,7 @@
  select ST_Collect('POLYGON EMPTY', 'POLYGON EMPTY') as mp,
         'POINT(0 0)'::geometry as p
 )
-select '#1578', _st_within(p, mp), _st_intersects(p, mp) FROM inp;
+select '#1578', st_within(p, mp), st_intersects(p, mp) FROM inp;
 
 -- #1580
 select '#1580.1', ST_Summary(ST_Transform('SRID=4326;POINT(0 0)'::geometry, 3395));

Modified: trunk/utils/create_undef.pl
===================================================================
--- trunk/utils/create_undef.pl	2019-03-06 15:50:34 UTC (rev 17297)
+++ trunk/utils/create_undef.pl	2019-03-06 17:27:24 UTC (rev 17298)
@@ -37,7 +37,8 @@
 my @funcs = ();
 my @types = ();
 my %type_funcs = ();
-my @type_funcs= (); # function to drop _after_ type drop
+my @type_funcs = (); # function to drop _after_ type drop
+my @supp_funcs = ();
 my @ops = ();
 my @opcs = ();
 my @views = ();
@@ -82,11 +83,16 @@
 while( my $line = <INPUT>)
 {
 	if ($line =~ /^create (or replace )?function/i) {
+		my $supp = 0;
 		my $defn = $line;
 		while( not $defn =~ /\)/ ) {
 			$defn .= <INPUT>;
 		}
-		push (@funcs, $defn)
+		if ($defn =~ /_supportfn /) {
+			$supp = 1;
+		}
+		push (@funcs, $defn) if ! $supp;
+		push (@supp_funcs, $defn) if $supp;
 	}
 	elsif ($line =~ /^create or replace view\s*(\w+)/i) {
 		push (@views, $1);
@@ -283,6 +289,24 @@
 
 }
 
+print "-- Drop all support functions.\n";
+foreach my $fn (@supp_funcs)
+{
+	if ($fn =~ /.* function ([^(]+)\((.*)\)/i )
+	{
+		my $fn_nm = $1;
+		my $fn_arg = $2;
+
+		$fn_arg =~ s/DEFAULT [\w']+//ig;
+
+		print "DROP FUNCTION IF EXISTS $fn_nm ($fn_arg);\n";
+	}
+	else
+	{
+		die "Couldn't parse line: $fn\n";
+	}
+}
+
 print "-- Drop all functions needed for types definition.\n";
 foreach my $fn (@type_funcs)
 {



More information about the postgis-tickets mailing list