[SCM] PostGIS branch master updated. 3.6.0rc2-303-g41d995e10

git at osgeo.org git at osgeo.org
Thu Jan 22 09:22:03 PST 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, master has been updated
       via  41d995e10a9450f5e31e1b2030d64df16c6135cd (commit)
       via  f590847fb9d74a893c8a153cb316fd9d540a1f1e (commit)
       via  72b446cf811528a5d5972a65a58ab0f76a57a876 (commit)
       via  01838882f3397befd7c18bdd43659280d8a93637 (commit)
       via  0349d9a62afb5b9eb88b84480ed96b8fc2256793 (commit)
       via  19d0109fcea53b479beb9f4303e2f3ebca201e47 (commit)
       via  bdbcdf420959d21840004f5137540660d30663c2 (commit)
       via  63c8eb031b3dd2a6cb85d3a9d6208167c8d2648d (commit)
      from  da86ae2c0914287fe2914e28aea5360dc8af0131 (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 41d995e10a9450f5e31e1b2030d64df16c6135cd
Merge: da86ae2c0 f590847fb
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date:   Thu Jan 22 09:21:43 2026 -0800

    Merge branch 'ProjectMutilation-shp2pgsql-core-fix-memleak'


commit f590847fb9d74a893c8a153cb316fd9d540a1f1e
Author: Loïc Bartoletti <loic.bartoletti at oslandia.com>
Date:   Thu Jun 5 10:30:15 2025 +0200

    fix(TriangulatedSurface): TIN can be closed as PolyhedralSurface

diff --git a/liblwgeom/lwgeom.c b/liblwgeom/lwgeom.c
index c6562b5fa..b1a557feb 100644
--- a/liblwgeom/lwgeom.c
+++ b/liblwgeom/lwgeom.c
@@ -1451,8 +1451,13 @@ int lwgeom_dimension(const LWGEOM *geom)
 	case CURVEPOLYTYPE:
 	case MULTISURFACETYPE:
 	case MULTIPOLYGONTYPE:
-	case TINTYPE:
 		return 2;
+	case TINTYPE:
+	{
+		/* A closed tin surface contains a volume. */
+		int closed = lwtin_is_closed((LWTIN*)geom);
+		return ( closed ? 3 : 2 );
+	}
 	case POLYHEDRALSURFACETYPE:
 	{
 		/* A closed polyhedral surface contains a volume. */

commit 72b446cf811528a5d5972a65a58ab0f76a57a876
Author: Loïc Bartoletti <loic.bartoletti at oslandia.com>
Date:   Thu Jun 5 10:29:41 2025 +0200

    test(TriangulatedSurface): Add tests

diff --git a/regress/core/tests.mk.in b/regress/core/tests.mk.in
index a959ad92f..a89b77bfc 100644
--- a/regress/core/tests.mk.in
+++ b/regress/core/tests.mk.in
@@ -119,6 +119,7 @@ TESTS += \
 	$(top_srcdir)/regress/core/temporal \
 	$(top_srcdir)/regress/core/temporal_knn \
 	$(top_srcdir)/regress/core/tickets \
+	$(top_srcdir)/regress/core/triangulatedsurface \
 	$(top_srcdir)/regress/core/twkb \
 	$(top_srcdir)/regress/core/typmod \
 	$(top_srcdir)/regress/core/wkb \
diff --git a/regress/core/triangulatedsurface.sql b/regress/core/triangulatedsurface.sql
new file mode 100644
index 000000000..cf0892e49
--- /dev/null
+++ b/regress/core/triangulatedsurface.sql
@@ -0,0 +1,40 @@
+-- ST_Dimension on 2D: not closed
+SELECT 'dimension_01', ST_Dimension('TIN(((0 0,1 1,0 1,0 0)))'::geometry);
+SELECT 'dimension_02', ST_Dimension('GEOMETRYCOLLECTION(TIN(((0 0,1 1,0 1,0 0))))'::geometry);
+
+-- ST_Dimension on 3D: closed
+SELECT 'dimension_03', ST_Dimension('TIN(((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 0 0,0 0 0)),((0 0 0,1 0 0,0 0 1,0 0 0)),((1 0 0,0 1 0,0 0 1,1 0 0)))'::geometry);
+SELECT 'dimension_04', ST_Dimension('GEOMETRYCOLLECTION(TIN(((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 0 0,0 0 0)),((0 0 0,1 0 0,0 0 1,0 0 0)),((1 0 0,0 1 0,0 0 1,1 0 0))))'::geometry);
+
+-- ST_Dimension on 4D: closed
+SELECT 'dimension_05', ST_Dimension('TIN(((0 0 0 0,0 0 1 0,0 1 0 2,0 0 0 0)),((0 0 0 0,0 1 0 0,1 0 0 4,0 0 0 0)),((0 0 0 0,1 0 0 0,0 0 1 6,0 0 0 0)),((1 0 0 0,0 1 0 0,0 0 1 0,1 0 0 0)))'::geometry);
+SELECT 'dimension_06', ST_Dimension('GEOMETRYCOLLECTION(TIN(((0 0 0 0,0 0 1 0,0 1 0 2,0 0 0 0)),((0 0 0 0,0 1 0 0,1 0 0 4,0 0 0 0)),((0 0 0 0,1 0 0 0,0 0 1 6,0 0 0 0)),((1 0 0 0,0 1 0 0,0 0 1 0,1 0 0 0))))'::geometry);
+
+-- ST_Dimension on 3D: invalid polyedron (a single edge is shared 3 times)
+SELECT 'dimension_07', ST_Dimension('TIN(((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 0 0,0 0 0)),((0 0 0,0 1 0,0 0 1,0 0 0)),((1 0 0,0 1 0,0 0 1,1 0 0)))'::geometry);
+
+-- ST_Dimension on 3D: invalid polyedron (redundant point inside each face)
+SELECT 'dimension_08', ST_Dimension('TIN(((0 0 0,1 0 0,1 0 0,0 0 0)),((0 0 1,1 0 1,1 0 1,0 0 1)),((0 0 2,1 0 2,1 0 2,0 0 2)),((0 0 3,1 0 3,1 0 3,0 0 3)))'::geometry);
+
+-- ST_NumPatches
+SELECT 'numpatches_01', ST_NumPatches('TIN EMPTY'::geometry);
+SELECT 'numpatches_02', ST_NumPatches('TIN(((0 0,0 0,0 1,0 0)))'::geometry);
+SELECT 'numpatches_03', ST_NumPatches('TIN(((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 0 0,0 0 0)),((0 0 0,1 0 0,0 0 1,0 0 0)),((1 0 0,0 1 0,0 0 1,1 0 0)))'::geometry);
+
+-- ST_PatchN
+SELECT 'patchN_01', ST_AsEWKT(ST_patchN('TIN EMPTY'::geometry, 1));
+SELECT 'patchN_02', ST_AsEWKT(ST_patchN('TIN(((0 0,0 0,0 1,0 0)))'::geometry, 1));
+SELECT 'patchN_03', ST_AsEWKT(ST_patchN('TIN(((0 0,0 0,0 1,0 0)))'::geometry, 0));
+SELECT 'patchN_04', ST_AsEWKT(ST_patchN('TIN(((0 0,0 0,0 1,0 0)))'::geometry, 2));
+SELECT 'patchN_05', ST_AsEWKT(ST_patchN('TIN(((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 0 0,0 0 0)),((0 0 0,1 0 0,0 0 1,0 0 0)),((1 0 0,0 1 0,0 0 1,1 0 0)))'::geometry, 2));
+
+-- ST_NumGeometries
+SELECT 'numgeometries_01', ST_NumGeometries('TIN EMPTY'::geometry);
+SELECT 'numgeometries_02', ST_NumGeometries('TIN(((0 0,0 0,0 1,0 0)))'::geometry);
+SELECT 'numgeometries_03', ST_NumGeometries('TIN(((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 0 0,0 0 0)),((0 0 0,1 0 0,0 0 1,0 0 0)),((1 0 0,0 1 0,0 0 1,1 0 0)))'::geometry);
+
+-- ST_GeometryN
+SELECT 'geometryN_01', ST_AsEWKT(ST_GeometryN('TIN EMPTY'::geometry, 1));
+SELECT 'geometryN_02', ST_AsEWKT(ST_GeometryN('TIN(((0 0,0 0,0 1,0 0)))'::geometry, 1));
+SELECT 'geometryN_03', ST_AsEWKT(ST_GeometryN('TIN(((0 0,0 0,0 1,0 0)))'::geometry, 0));
+SELECT 'geometryN_04', ST_AsEWKT(ST_GeometryN('TIN(((0 0,0 0,0 1,0 0)))'::geometry, 2));
diff --git a/regress/core/triangulatedsurface_expected b/regress/core/triangulatedsurface_expected
new file mode 100644
index 000000000..ab5d737f8
--- /dev/null
+++ b/regress/core/triangulatedsurface_expected
@@ -0,0 +1,23 @@
+dimension_01|2
+dimension_02|2
+dimension_03|3
+dimension_04|3
+dimension_05|3
+dimension_06|3
+dimension_07|2
+dimension_08|2
+numpatches_01|0
+numpatches_02|1
+numpatches_03|4
+patchN_01|
+patchN_02|TRIANGLE((0 0,0 0,0 1,0 0))
+patchN_03|
+patchN_04|
+patchN_05|TRIANGLE((0 0 0,0 1 0,1 0 0,0 0 0))
+numgeometries_01|0
+numgeometries_02|1
+numgeometries_03|1
+geometryN_01|
+geometryN_02|TIN(((0 0,0 0,0 1,0 0)))
+geometryN_03|
+geometryN_04|

commit 01838882f3397befd7c18bdd43659280d8a93637
Author: Sandro Santilli <strk at kbt.io>
Date:   Fri Feb 4 21:43:45 2022 +0100

    Improve error message from libproj failures

diff --git a/libpgcommon/lwgeom_transform.c b/libpgcommon/lwgeom_transform.c
index 1fe21fa16..61975dc0f 100644
--- a/libpgcommon/lwgeom_transform.c
+++ b/libpgcommon/lwgeom_transform.c
@@ -390,7 +390,6 @@ AddToPROJSRSCache(PROJSRSCache *PROJCache, int32_t srid_from, int32_t srid_to)
 
 	oldContext = MemoryContextSwitchTo(PROJCache->PROJSRSCacheContext);
 
-
 	LWPROJ *projection = NULL;
 	/* Try combinations of AUTH_NAME:AUTH_SRID/SRTEXT/PROJ4TEXT until we find */
 	/* one that gives us a usable transform. Note that we prefer */
@@ -410,7 +409,13 @@ AddToPROJSRSCache(PROJSRSCache *PROJCache, int32_t srid_from, int32_t srid_to)
 	}
 	if (!projection)
 	{
-		elog(ERROR, "could not form projection (LWPROJ) from 'srid=%d' to 'srid=%d'", srid_from, srid_to);
+		elog(ERROR,
+		    "could not form projection (LWPROJ) from srid %d ('%s') to srid %d ('%s')",
+		    srid_from,
+				( pj_from_str ? pj_from_str : "(null)" ),
+				srid_to,
+				( pj_to_str ? pj_to_str : "(null)" )
+		);
 		return NULL;
 	}
 

commit 0349d9a62afb5b9eb88b84480ed96b8fc2256793
Author: Paul Ramsey <pramsey at cleverelephant.ca>
Date:   Tue Jan 20 12:35:16 2026 -0800

    NEWS entry for GH-839

diff --git a/NEWS b/NEWS
index 9e96fdbe3..43c732569 100644
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,7 @@ xxxx/xx/xx
  - #5109, Document the meaning of topology.next_left_edge and topology.next_right_edge links (Darafei Praliaskouski)
  - #5889, [topology] Include representative locations in topology build errors (Darafei Praliaskouski)
  - #2614, Use GEOSPreparedDistance and caching to accelerate ST_DWithin (Paul Ramsey)
+ - GH-839, ST_Multi support for TIN and surfaces (Luca Bartoletti)
 
 * Bug Fixes *
 

commit 19d0109fcea53b479beb9f4303e2f3ebca201e47
Author: Loïc Bartoletti <loic.bartoletti at oslandia.com>
Date:   Fri Dec 19 07:30:24 2025 +0100

    Convert PolyhedralSurface/TIN to MultiPolygon

diff --git a/liblwgeom/lwgeom.c b/liblwgeom/lwgeom.c
index a2d65dc0f..c6562b5fa 100644
--- a/liblwgeom/lwgeom.c
+++ b/liblwgeom/lwgeom.c
@@ -414,6 +414,43 @@ lwgeom_as_multi(const LWGEOM *lwgeom)
 
 	type = lwgeom->type;
 
+	/*
+	* PolyhedralSurface and MultiPolygon have identical structures
+	* (both are collections of LWPOLY). Convert PolyhedralSurface
+	* to MultiPolygon by cloning and changing the type.
+	*/
+	if (type == POLYHEDRALSURFACETYPE)
+	{
+		ogeom = (LWGEOM *)lwcollection_clone((LWCOLLECTION *)lwgeom);
+		ogeom->type = MULTIPOLYGONTYPE;
+		return ogeom;
+	}
+
+	/*
+	* TIN to MultiPolygon: convert each triangle to a polygon.
+	* LWTRIANGLE and LWLINE have compatible memory layouts,
+	* so we can use lwpoly_from_lwlines to create polygons.
+	*/
+	if (type == TINTYPE)
+	{
+		uint32_t i;
+		LWCOLLECTION *col = (LWCOLLECTION *)lwgeom;
+		LWMPOLY *mpoly = lwmpoly_construct_empty(lwgeom->srid,
+			FLAGS_GET_Z(lwgeom->flags),
+			FLAGS_GET_M(lwgeom->flags));
+
+		for (i = 0; i < col->ngeoms; i++)
+		{
+			LWPOLY *poly = lwpoly_from_lwlines((LWLINE *)col->geoms[i], 0, NULL);
+			lwmpoly_add_lwpoly(mpoly, poly);
+		}
+
+		if (lwgeom->bbox)
+			mpoly->bbox = gbox_clone(lwgeom->bbox);
+
+		return lwmpoly_as_lwgeom(mpoly);
+	}
+
 	if ( ! MULTITYPE[type] ) return lwgeom_clone(lwgeom);
 
 	if( lwgeom_is_empty(lwgeom) )
diff --git a/postgis/lwgeom_functions_basic.c b/postgis/lwgeom_functions_basic.c
index ed5f076f2..0cfa08da7 100644
--- a/postgis/lwgeom_functions_basic.c
+++ b/postgis/lwgeom_functions_basic.c
@@ -532,7 +532,6 @@ Datum LWGEOM_force_multi(PG_FUNCTION_ARGS)
 		case COLLECTIONTYPE:
 		case MULTICURVETYPE:
 		case MULTISURFACETYPE:
-		case TINTYPE:
 			PG_RETURN_POINTER(geom);
 		default:
 			break;
diff --git a/regress/core/tickets.sql b/regress/core/tickets.sql
index eec195810..4c1fcb862 100644
--- a/regress/core/tickets.sql
+++ b/regress/core/tickets.sql
@@ -67,6 +67,14 @@ SELECT '#80', ST_AsText(ST_Multi('MULTILINESTRING((0 0,1 1))'));
 -- #83 --
 SELECT '#83', ST_AsText(ST_Multi(ST_GeomFromText('CIRCULARSTRING(220268 150415,220227 150505,220227 150406)')));
 
+-- ST_Multi with PolyhedralSurface -> MultiPolygon
+SELECT 'ST_Multi_psurface', ST_GeometryType(ST_Multi('POLYHEDRALSURFACE Z(((0 0 0,0 1 0,1 1 0,1 0 0,0 0 0)),((0 0 0,0 1 0,0 1 1,0 0 1,0 0 0)))'::geometry));
+SELECT 'ST_Multi_psurface_empty', ST_GeometryType(ST_Multi('POLYHEDRALSURFACE EMPTY'::geometry));
+
+-- ST_Multi with TIN -> MultiPolygon
+SELECT 'ST_Multi_tin', ST_GeometryType(ST_Multi('TIN Z(((0 0 0,0 0 1,0 1 0,0 0 0)),((0 0 0,0 1 0,1 1 0,0 0 0)))'::geometry));
+SELECT 'ST_Multi_tin_empty', ST_GeometryType(ST_Multi('TIN EMPTY'::geometry));
+
 -- #85 --
 SELECT '#85', ST_Distance(ST_GeomFromText('CIRCULARSTRING(220268 150415,220227 150505,220227 150406)'), ST_Point(220268, 150415));
 
diff --git a/regress/core/tickets_expected b/regress/core/tickets_expected
index d8f7f5cf5..76ea65e71 100644
--- a/regress/core/tickets_expected
+++ b/regress/core/tickets_expected
@@ -14,6 +14,10 @@ ERROR:  lwgeom_longitude_shift: unsupported geom type: CircularString
 #73|GEOMETRYCOLLECTION(CIRCULARSTRING(1 1,2 3,4 5,6 7,5 6))
 #80|MULTILINESTRING((0 0,1 1))
 #83|MULTICURVE(CIRCULARSTRING(220268 150415,220227 150505,220227 150406))
+ST_Multi_psurface|ST_MultiPolygon
+ST_Multi_psurface_empty|ST_MultiPolygon
+ST_Multi_tin|ST_MultiPolygon
+ST_Multi_tin_empty|ST_MultiPolygon
 #85|0
 #112|GEOMETRYCOLLECTION(POINT(-10 50))
 ERROR:  Input geometry does not have a measure dimension

commit bdbcdf420959d21840004f5137540660d30663c2
Author: Maksim Korotkov <m.korotkov at postgrespro.ru>
Date:   Tue Jan 20 17:51:57 2026 +0300

    Avoid potential NULL dereference in std_free()
    After check against NULL the pointer std -> pagc_p was used unsafely.
    
    Found by PostgresPro with Svace Static Analyzer.
    Fixes: c6091a4bb ("Prep to move address_standardizer into extensions folder")
    Signed-off-by: Maksim Korotkov <m.korotkov at postgrespro.ru>

diff --git a/extensions/address_standardizer/standard.c b/extensions/address_standardizer/standard.c
index 4fe63e3ed..9fed23411 100644
--- a/extensions/address_standardizer/standard.c
+++ b/extensions/address_standardizer/standard.c
@@ -379,13 +379,15 @@ void std_free(STANDARDIZER *std)
 {
     if ( std == NULL ) return;
     DBG("Calling close_stand_process");
-    if ( std -> pagc_p != NULL ) close_stand_process( std -> pagc_p ) ;
-    if ( std -> pagc_p -> process_errors != NULL ) {
-        DBG("Calling close_errors");
-        close_errors( std -> pagc_p -> process_errors );
-        DBG("Calling FREE_AND_NULL");
-        FREE_AND_NULL( std -> pagc_p ) ;
-    }
+    if ( std -> pagc_p != NULL ) {
+		close_stand_process( std -> pagc_p ) ;
+		if ( std -> pagc_p -> process_errors != NULL ) {
+			DBG("Calling close_errors");
+			close_errors( std -> pagc_p -> process_errors );
+		}
+		DBG("Calling FREE_AND_NULL");
+		FREE_AND_NULL( std -> pagc_p );
+	}
     DBG("Calling close_stand_context");
     close_stand_context( std -> misc_stand );
     DBG("Calling free");

commit 63c8eb031b3dd2a6cb85d3a9d6208167c8d2648d
Author: Maksim Korotkov <m.korotkov at postgrespro.ru>
Date:   Thu Jan 22 13:39:09 2026 +0300

    Add missed deallocation in GeneratePointGeometry()
    In error handling return error code without freeing the lwgeom pointer.
    
    Found by PostgresPro.
    Fixes: 1ae5b8f68 ("ptarray_free now frees the serialized_ptlist, unless FLAGS_GET_READONLY is set.")
    Signed-off-by: Maksim Korotkov <m.korotkov at postgrespro.ru>

diff --git a/loader/shp2pgsql-core.c b/loader/shp2pgsql-core.c
index d13f52451..8db842117 100644
--- a/loader/shp2pgsql-core.c
+++ b/loader/shp2pgsql-core.c
@@ -300,6 +300,7 @@ GeneratePointGeometry(SHPLOADERSTATE *state, SHPObject *obj, char **geometry, in
 	if ( !mem )
 	{
 		snprintf(state->message, SHPLOADERMSGLEN, "unable to write geometry");
+		lwgeom_free(lwgeom);
 		return SHPLOADERERR;
 	}
 

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

Summary of changes:
 loader/shp2pgsql-core.c | 1 +
 1 file changed, 1 insertion(+)


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list