[SCM] PostGIS branch stable-3.5 updated. 3.5.7-66-g2dec9daa4
git at osgeo.org
git at osgeo.org
Sun Jul 19 08:59:19 PDT 2026
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, stable-3.5 has been updated
via 2dec9daa4d5d4676f256a7d5c1fb085dca1f1758 (commit)
via 48fcce28eb28eda328cb71eedce8c2ea7c412997 (commit)
via d1751e881e4f9e18cff6849fcafacfa85fe9ceb7 (commit)
via 62c24a2c44963458aa232e50b26064f9c6d6ceb2 (commit)
from a40c5b03f73f50cdc22e2522a3d58d8217c03a6d (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 2dec9daa4d5d4676f256a7d5c1fb085dca1f1758
Merge: a40c5b03f 48fcce28e
Author: Darafei Praliaskouski <komzpa at gmail.com>
Date: Sun Jul 19 08:59:18 2026 -0700
Merge pull request 'Backport GEOS 3.15 compatibility fixes to stable 3.5' (!445) from Komzpa/postgis:fix/geos315-stable-3.5 into stable-3.5
Reviewed-on: https://gitea.osgeo.org/postgis/postgis/pulls/445
commit 48fcce28eb28eda328cb71eedce8c2ea7c412997
Author: Darafei Praliaskouski <me at komzpa.net>
Date: Thu Jul 9 11:33:15 2026 +0400
Fix GEOS version parser in wrapx regression
A stray ']' made the regexp never match, so the GEOS >= 3.15
expected outputs were never selected.
(cherry picked from commit 9c931e6fcdcf78a5d605a0d445b4a51564f78ff5)
diff --git a/regress/core/wrapx.sql b/regress/core/wrapx.sql
index 321958d52..b35504961 100644
--- a/regress/core/wrapx.sql
+++ b/regress/core/wrapx.sql
@@ -15,7 +15,7 @@ $$ LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION geos_version()
RETURNS integer AS $$
SELECT (matches[1]::integer * 100) + matches[2]::integer
- FROM regexp_match(postgis_geos_version(), E'^([0-9]+)]\\.([0-9]+)') AS matches;
+ FROM regexp_match(postgis_geos_version(), E'^([0-9]+)\\.([0-9]+)') AS matches;
$$ LANGUAGE 'sql' IMMUTABLE;
commit d1751e881e4f9e18cff6849fcafacfa85fe9ceb7
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date: Wed Jul 8 14:10:37 2026 -0700
Fix non-topology regression tests for GEOS >= 3.15
(cherry picked from commit 63de00830dc7afb6102a095cb1a41514e9064c1f)
diff --git a/liblwgeom/cunit/cu_wrapx.c b/liblwgeom/cunit/cu_wrapx.c
index a5ca09a28..79e707238 100644
--- a/liblwgeom/cunit/cu_wrapx.c
+++ b/liblwgeom/cunit/cu_wrapx.c
@@ -83,9 +83,11 @@ static void test_lwgeom_wrapx(void)
lwgeom_free(tmp);
CU_ASSERT_FATAL(ret != NULL);
obt_wkt = lwgeom_to_ewkt(ret);
- tmp = lwgeom_from_wkt(
- "MULTILINESTRING((0 0,8 0),(-2 0,0 0))",
- LW_PARSER_CHECK_NONE);
+#if POSTGIS_GEOS_VERSION < 31500
+ tmp = lwgeom_from_wkt("MULTILINESTRING((0 0,8 0),(-2 0,0 0))",LW_PARSER_CHECK_NONE);
+#else
+ tmp = lwgeom_from_wkt("LINESTRING(-2 0,0 0,8 0)",LW_PARSER_CHECK_NONE);
+#endif
tmp2 = lwgeom_normalize(tmp);
lwgeom_free(tmp);
exp_wkt = lwgeom_to_ewkt(tmp2);
diff --git a/regress/core/fixedoverlay.sql b/regress/core/fixedoverlay.sql
index 45d3b8979..2377f5667 100644
--- a/regress/core/fixedoverlay.sql
+++ b/regress/core/fixedoverlay.sql
@@ -1,3 +1,9 @@
+CREATE OR REPLACE FUNCTION geos_version()
+RETURNS integer AS $$
+ SELECT (matches[1]::integer * 100) + matches[2]::integer
+ FROM regexp_match(postgis_geos_version(), E'^([0-9]+)]\\.([0-9]+)') AS matches;
+$$ LANGUAGE 'sql' IMMUTABLE;
+
SELECT 'intersection', ST_AsText(ST_Intersection(
'LINESTRING(0 0, 9 0)'::geometry,
'LINESTRING(7 0, 13.2 0)'::geometry,
@@ -13,14 +19,7 @@ SELECT 'symdifference', ST_AsText(ST_SymDifference(
'LINESTRING(7 0, 13.2 0)'::geometry,
2));
-SELECT 'union', ST_AsText(ST_Union(
- 'LINESTRING(0.5 0, 9 0)'::geometry,
- 'LINESTRING(7 0, 13.2 0)'::geometry,
- 2));
-SELECT 'unaryunion', ST_AsText(ST_UnaryUnion(
- 'GEOMETRYCOLLECTION(LINESTRING(0.5 0, 9 0), LINESTRING(7 0, 13.2 0))'::geometry,
-2));
WITH n AS (SELECT geom
FROM ST_Subdivide(
@@ -28,3 +27,6 @@ FROM ST_Subdivide(
6, 1) AS geom)
SELECT 'subdivide', count(geom), ST_AsText(ST_Normalize(ST_Union(geom)))
FROM n;
+
+
+DROP FUNCTION geos_version();
diff --git a/regress/core/fixedoverlay_expected b/regress/core/fixedoverlay_expected
index 4f03bb27b..835d8b92c 100644
--- a/regress/core/fixedoverlay_expected
+++ b/regress/core/fixedoverlay_expected
@@ -1,6 +1,4 @@
intersection|LINESTRING(8 0,10 0)
difference|LINESTRING(0 0,8 0)
symdifference|MULTILINESTRING((0 0,8 0),(10 0,14 0))
-union|MULTILINESTRING((0 0,8 0),(8 0,10 0),(10 0,14 0))
-unaryunion|MULTILINESTRING((0 0,8 0),(8 0,10 0),(10 0,14 0))
subdivide|3|MULTIPOLYGON(((0 0,0 10,10 10,10 6,100 5,10 5,10 0,0 0)),((100 0,100 5,100 10,110 10,110 0,100 0)))
diff --git a/regress/core/wrapx.sql b/regress/core/wrapx.sql
index d08dc9c9c..321958d52 100644
--- a/regress/core/wrapx.sql
+++ b/regress/core/wrapx.sql
@@ -1,94 +1,112 @@
-CREATE FUNCTION test(geom geometry, wrap float8, amount float8, exp geometry)
+CREATE FUNCTION test_wrapx(geom geometry, wrap float8, amount float8, exp geometry)
RETURNS text AS $$
DECLARE
- obt geometry;
+ obt geometry;
BEGIN
- obt = ST_Normalize(ST_WrapX(geom, wrap, amount));
- IF ST_OrderingEquals(obt, exp) THEN
- RETURN 'OK';
- ELSE
- RETURN 'KO:' || ST_AsEWKT(obt) || ' != ' || ST_AsEWKT(exp);
- END IF;
+ obt = ST_Normalize(ST_WrapX(geom, wrap, amount));
+ IF ST_OrderingEquals(obt, exp) THEN
+ RETURN 'OK';
+ ELSE
+ RETURN 'KO:' || ST_AsEWKT(obt) || ' != ' || ST_AsEWKT(exp);
+ END IF;
END
-$$ LANGUAGE plpgsql;
+$$ LANGUAGE 'plpgsql';
-SELECT 'P1', test(
- 'POINT(0 0)', 2, 10,
- 'POINT(10 0)');
+CREATE OR REPLACE FUNCTION geos_version()
+RETURNS integer AS $$
+ SELECT (matches[1]::integer * 100) + matches[2]::integer
+ FROM regexp_match(postgis_geos_version(), E'^([0-9]+)]\\.([0-9]+)') AS matches;
+$$ LANGUAGE 'sql' IMMUTABLE;
-SELECT 'P2', test(
- 'POINT(0 0)', 2, -10,
- 'POINT(0 0)');
-SELECT 'P3', test(
- 'POINT(0 0)', -2, -10,
- 'POINT(-10 0)');
+SELECT 'P1', test_wrapx(
+ 'POINT(0 0)', 2, 10,
+ 'POINT(10 0)');
-SELECT 'L1', test(
- 'LINESTRING(0 0,10 0)', 2, 10,
- --'LINESTRING(2 0,12 0)');
- 'MULTILINESTRING((10 0,12 0),(2 0,10 0))');
+SELECT 'P2', test_wrapx(
+ 'POINT(0 0)', 2, -10,
+ 'POINT(0 0)');
-SELECT 'L2', test(
- 'LINESTRING(0 0,10 0)', 8, -10,
- 'MULTILINESTRING((0 0,8 0),(-2 0,0 0))');
+SELECT 'P3', test_wrapx(
+ 'POINT(0 0)', -2, -10,
+ 'POINT(-10 0)');
-SELECT 'L3', test(
- 'LINESTRING(0 0,10 0)', 0, 10,
- 'LINESTRING(0 0,10 0)');
+SELECT 'L1', test_wrapx(
+ 'LINESTRING(0 0,10 0)', 2, 10,
+ CASE WHEN geos_version() >= 315
+ THEN 'LINESTRING(2 0,10 0,12 0)'
+ ELSE 'MULTILINESTRING((10 0,12 0),(2 0,10 0))'
+ END);
-SELECT 'L4', test(
- 'LINESTRING(0 0,10 0)', 10, -10,
- 'LINESTRING(0 0,10 0)');
+SELECT 'L2', test_wrapx(
+ 'LINESTRING(0 0,10 0)', 8, -10,
+ CASE WHEN geos_version() >= 315
+ THEN 'LINESTRING(-2 0,0 0,8 0)'
+ ELSE 'MULTILINESTRING((0 0,8 0),(-2 0,0 0))'
+ END);
-SELECT 'ML1', test(
- 'MULTILINESTRING((-10 0,0 0),(0 0,10 0))', 0, 20,
- 'MULTILINESTRING((10 0,20 0),(0 0,10 0))');
+SELECT 'L3', test_wrapx(
+ 'LINESTRING(0 0,10 0)', 0, 10,
+ 'LINESTRING(0 0,10 0)');
-SELECT 'ML2', test(
- 'MULTILINESTRING((-10 0,0 0),(0 0,10 0))', 0, -20,
- 'MULTILINESTRING((-10 0,0 0),(-20 0,-10 0))');
+SELECT 'L4', test_wrapx(
+ 'LINESTRING(0 0,10 0)', 10, -10,
+ 'LINESTRING(0 0,10 0)');
-SELECT 'ML3', test(
- 'MULTILINESTRING((10 0,5 0),(-10 0,0 0),(0 0,5 0))', 0, -20,
- 'MULTILINESTRING((-10 0,0 0),(-15 0,-10 0),(-20 0,-15 0))');
+SELECT 'ML1', test_wrapx(
+ 'MULTILINESTRING((-10 0,0 0),(0 0,10 0))', 0, 20,
+ 'MULTILINESTRING((10 0,20 0),(0 0,10 0))');
-SELECT 'A1', test(
- 'POLYGON((0 0,10 0,10 10,0 10,0 0),
- (1 2,3 2,3 4,1 4,1 2),
- (4 2,6 2,6 4,4 4,4 2),
- (7 2,9 2,9 4,7 4,7 2))', 5, 10,
- 'POLYGON((5 0,5 2,6 2,6 4,5 4,5 10,10 10,15 10,15 4,14 4,14 2,15 2,15 0,10 0,5 0),
- (11 2,13 2,13 4,11 4,11 2),
- (7 2,9 2,9 4,7 4,7 2))');
+SELECT 'ML2', test_wrapx(
+ 'MULTILINESTRING((-10 0,0 0),(0 0,10 0))', 0, -20,
+ 'MULTILINESTRING((-10 0,0 0),(-20 0,-10 0))');
-SELECT 'A2', test(
- 'POLYGON((0 0,10 0,10 10,0 10,0 0),
- (1 2,3 2,3 4,1 4,1 2),
- (4 2,6 2,6 4,4 4,4 2),
- (7 2,9 2,9 4,7 4,7 2))', 5, -10,
- 'POLYGON((-5 0,-5 2,-4 2,-4 4,-5 4,-5 10,0 10,5 10,5 4,4 4,4 2,5 2,5 0,0 0,-5 0),
- (1 2,3 2,3 4,1 4,1 2),
- (-3 2,-1 2,-1 4,-3 4,-3 2))');
+SELECT 'ML3', test_wrapx(
+ 'MULTILINESTRING((10 0,5 0),(-10 0,0 0),(0 0,5 0))', 0, -20,
+ 'MULTILINESTRING((-10 0,0 0),(-15 0,-10 0),(-20 0,-15 0))');
-SELECT 'C1', test(
- 'GEOMETRYCOLLECTION(
- POLYGON((0 0,10 0,10 10,0 10,0 0),
- (1 2,3 2,3 4,1 4,1 2),
- (4 2,6 2,6 4,4 4,4 2),
- (7 2,9 2,9 4,7 4,7 2)),
- POINT(2 20),
- POINT(7 -20),
- LINESTRING(0 40,10 40)
- )',
- 5, -10,
- 'GEOMETRYCOLLECTION(
- POLYGON((-5 0,-5 2,-4 2,-4 4,-5 4,-5 10,0 10,5 10,5 4,4 4,4 2,5 2,5 0,0 0,-5 0),
- (1 2,3 2,3 4,1 4,1 2),
- (-3 2,-1 2,-1 4,-3 4,-3 2)),
- MULTILINESTRING((0 40,5 40),(-5 40,0 40)),
- POINT(2 20),
- POINT(-3 -20)
- )');
+SELECT 'A1', test_wrapx(
+ 'POLYGON((0 0,10 0,10 10,0 10,0 0),
+ (1 2,3 2,3 4,1 4,1 2),
+ (4 2,6 2,6 4,4 4,4 2),
+ (7 2,9 2,9 4,7 4,7 2))', 5, 10,
+ 'POLYGON((5 0,5 2,6 2,6 4,5 4,5 10,10 10,15 10,15 4,14 4,14 2,15 2,15 0,10 0,5 0),
+ (11 2,13 2,13 4,11 4,11 2),
+ (7 2,9 2,9 4,7 4,7 2))');
-DROP FUNCTION test(geometry, float8, float8, geometry);
+SELECT 'A2', test_wrapx(
+ 'POLYGON((0 0,10 0,10 10,0 10,0 0),
+ (1 2,3 2,3 4,1 4,1 2),
+ (4 2,6 2,6 4,4 4,4 2),
+ (7 2,9 2,9 4,7 4,7 2))', 5, -10,
+ 'POLYGON((-5 0,-5 2,-4 2,-4 4,-5 4,-5 10,0 10,5 10,5 4,4 4,4 2,5 2,5 0,0 0,-5 0),
+ (1 2,3 2,3 4,1 4,1 2),
+ (-3 2,-1 2,-1 4,-3 4,-3 2))');
+
+SELECT 'C1', test_wrapx(
+ 'GEOMETRYCOLLECTION(
+ POLYGON((0 0,10 0,10 10,0 10,0 0),
+ (1 2,3 2,3 4,1 4,1 2),
+ (4 2,6 2,6 4,4 4,4 2),
+ (7 2,9 2,9 4,7 4,7 2)),
+ POINT(2 20),
+ POINT(7 -20),
+ LINESTRING(0 40,10 40)
+ )',
+ 5, -10,
+ CASE WHEN geos_version() >= 315
+ THEN 'GEOMETRYCOLLECTION(POLYGON((-5 0,-5 2,-4 2,-4 4,-5 4,-5 10,0 10,5 10,5 4,4 4,4 2,5 2,5 0,0 0,-5 0),(1 2,3 2,3 4,1 4,1 2),(-3 2,-1 2,-1 4,-3 4,-3 2)),LINESTRING(-5 40,0 40,5 40),POINT(2 20),POINT(-3 -20))'
+ ELSE 'GEOMETRYCOLLECTION(
+ POLYGON((-5 0,-5 2,-4 2,-4 4,-5 4,-5 10,0 10,5 10,5 4,4 4,4 2,5 2,5 0,0 0,-5 0),
+ (1 2,3 2,3 4,1 4,1 2),
+ (-3 2,-1 2,-1 4,-3 4,-3 2)),
+ MULTILINESTRING((0 40,5 40),(-5 40,0 40)),
+ POINT(2 20),
+ POINT(-3 -20)
+ )'
+ END);
+
+
+
+DROP FUNCTION geos_version();
+DROP FUNCTION test_wrapx(geometry, float8, float8, geometry);
commit 62c24a2c44963458aa232e50b26064f9c6d6ceb2
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date: Tue Jun 30 12:05:14 2026 -0700
Use GEOSSplit where available for ST_Split
(cherry picked from commit 370c6a160a21d46b0768fb70ea0d75292cc475d0)
diff --git a/liblwgeom/lwgeom_geos_split.c b/liblwgeom/lwgeom_geos_split.c
index 15ca6ff5c..883a17751 100644
--- a/liblwgeom/lwgeom_geos_split.c
+++ b/liblwgeom/lwgeom_geos_split.c
@@ -112,12 +112,23 @@ lwline_split_by_line(const LWLINE* lwline_in, const LWGEOM* blade_in)
}
- gdiff = GEOSDifference(g1,g2);
+#if POSTGIS_GEOS_VERSION >= 31500
+ /* GEOS 3.15 added an explicit splitter. Older GEOS relies on the
+ * side-effect of GEOSDifference returning the input split at the
+ * crossing points of the (non-overlapping) blade. */
+ gdiff = GEOSSplit(g1, g2);
+#else
+ gdiff = GEOSDifference(g1, g2);
+#endif
GEOSGeom_destroy(g1);
GEOSGeom_destroy(g2);
if (gdiff == NULL)
{
+#if POSTGIS_GEOS_VERSION >= 31500
+ lwerror("GEOSSplit: %s", lwgeom_geos_errmsg);
+#else
lwerror("GEOSDifference: %s", lwgeom_geos_errmsg);
+#endif
return NULL;
}
@@ -353,6 +364,69 @@ lwline_split(const LWLINE* lwline_in, const LWGEOM* blade_in)
static LWGEOM*
lwpoly_split_by_line(const LWPOLY* lwpoly_in, const LWGEOM* blade_in)
{
+#if POSTGIS_GEOS_VERSION >= 31500
+ /* GEOS 3.15 splits polygons directly, filtering out the pieces that
+ * fall inside holes for us. On older GEOS we reproduce that logic by
+ * polygonizing the boundary unioned with the blade and discarding the
+ * pieces whose point-on-surface is not contained by the input (#else). */
+ LWGEOM* split;
+ LWCOLLECTION* out;
+ GEOSGeometry* g1;
+ GEOSGeometry* g2;
+ GEOSGeometry* gsplit;
+ int hasZ = FLAGS_GET_Z(lwpoly_in->flags);
+
+ initGEOS(lwgeom_geos_error, lwgeom_geos_error);
+
+ g1 = LWGEOM2GEOS((LWGEOM*)lwpoly_in, 0);
+ if ( NULL == g1 )
+ {
+ lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg);
+ return NULL;
+ }
+
+ g2 = LWGEOM2GEOS(blade_in, 0);
+ if ( NULL == g2 )
+ {
+ GEOSGeom_destroy(g1);
+ lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg);
+ return NULL;
+ }
+
+ gsplit = GEOSSplit(g1, g2);
+ GEOSGeom_destroy(g1);
+ GEOSGeom_destroy(g2);
+ if ( NULL == gsplit )
+ {
+ lwerror("GEOSSplit: %s", lwgeom_geos_errmsg);
+ return NULL;
+ }
+
+ split = GEOS2LWGEOM(gsplit, hasZ);
+ GEOSGeom_destroy(gsplit);
+ if ( NULL == split )
+ {
+ lwerror("GEOS2LWGEOM: %s", lwgeom_geos_errmsg);
+ return NULL;
+ }
+
+ /* GEOSSplit always returns a collection, but wrap defensively */
+ out = lwgeom_as_lwcollection(split);
+ if ( ! out )
+ {
+ LWGEOM** components = lwalloc(sizeof(LWGEOM*));
+ components[0] = split;
+ out = lwcollection_construct(COLLECTIONTYPE, lwpoly_in->srid,
+ NULL, 1, components);
+ }
+ else
+ {
+ lwgeom_set_srid((LWGEOM*)out, lwpoly_in->srid);
+ out->type = COLLECTIONTYPE;
+ }
+
+ return (LWGEOM*)out;
+#else
LWCOLLECTION* out;
GEOSGeometry* g1;
GEOSGeometry* g2;
@@ -491,6 +565,7 @@ lwpoly_split_by_line(const LWPOLY* lwpoly_in, const LWGEOM* blade_in)
GEOSGeom_destroy(polygons);
return (LWGEOM*)out;
+#endif /* POSTGIS_GEOS_VERSION >= 31500 */
}
static LWGEOM*
-----------------------------------------------------------------------
Summary of changes:
liblwgeom/cunit/cu_wrapx.c | 8 +-
liblwgeom/lwgeom_geos_split.c | 77 ++++++++++++++-
regress/core/fixedoverlay.sql | 16 +--
regress/core/fixedoverlay_expected | 2 -
regress/core/wrapx.sql | 198 ++++++++++++++++++++-----------------
5 files changed, 198 insertions(+), 103 deletions(-)
hooks/post-receive
--
PostGIS
More information about the postgis-tickets
mailing list