[SCM] PostGIS branch master updated. 3.6.0rc2-250-gb0dcc8510
git at osgeo.org
git at osgeo.org
Thu Dec 4 12:14:47 PST 2025
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 b0dcc8510fd7930752db4e65a9e7f368b63a139c (commit)
from e1451a6693ed13774962d168d921be65fb6702f1 (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 b0dcc8510fd7930752db4e65a9e7f368b63a139c
Author: Darafei Praliaskouski <me at komzpa.net>
Date: Fri Dec 5 00:14:34 2025 +0400
[topology] Include representative locations in topology build errors
Closes #5889
diff --git a/NEWS b/NEWS
index a32a41abc..f4c61cbc6 100644
--- a/NEWS
+++ b/NEWS
@@ -23,7 +23,7 @@ xxxx/xx/xx
- #4332, Clarify the scope of several Function Reference categories (Darafei Praliaskouski)
- #4222, [raster] ST_DumpAsPolygons honours PostgreSQL interrupts (Darafei Praliaskouski)
- #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)
* Bug Fixes *
diff --git a/liblwgeom/topo/lwgeom_topo.c b/liblwgeom/topo/lwgeom_topo.c
index 3e7cfdc1e..61edd3ef5 100644
--- a/liblwgeom/topo/lwgeom_topo.c
+++ b/liblwgeom/topo/lwgeom_topo.c
@@ -19,11 +19,10 @@
**********************************************************************
*
* Copyright (C) 2015-2024 Sandro Santilli <strk at kbt.io>
+ * Copyright (C) 2025 Darafei Praliaskouski <me at komzpa.net>
*
**********************************************************************/
-
-
#include "../postgis_config.h"
//#define POSTGIS_DEBUG_LEVEL 1
@@ -38,6 +37,67 @@
#include <inttypes.h>
+/*
+ * Report a human readable location along with topology errors so callers can
+ * narrow down robustness issues such as #5886/#5889 without further tracing.
+ * Using a point-on-surface keeps the message compact while remaining
+ * representative for any dimensionality of the offending intersection.
+ */
+static bool
+_lwt_describe_intersection_point(const GEOSGeometry *g1, const GEOSGeometry *g2, char *buf, size_t bufsize)
+{
+ unsigned int n = 0;
+ POINT2D pt;
+ GEOSGeometry *isect;
+ GEOSGeometry *surface_pt;
+ const GEOSCoordSequence *seq;
+
+ isect = GEOSIntersection(g1, g2);
+ if (!isect)
+ return false;
+
+ surface_pt = GEOSPointOnSurface(isect);
+ GEOSGeom_destroy(isect);
+ if (!surface_pt)
+ return false;
+
+ seq = GEOSGeom_getCoordSeq(surface_pt);
+ if (!seq)
+ {
+ GEOSGeom_destroy(surface_pt);
+ return false;
+ }
+
+ if (!GEOSCoordSeq_getSize(seq, &n) || !n)
+ {
+ GEOSGeom_destroy(surface_pt);
+ return false;
+ }
+
+ if (!GEOSCoordSeq_getX(seq, 0, &pt.x) || !GEOSCoordSeq_getY(seq, 0, &pt.y))
+ {
+ GEOSGeom_destroy(surface_pt);
+ return false;
+ }
+
+ GEOSGeom_destroy(surface_pt);
+ snprintf(buf, bufsize, " at POINT(%.15g %.15g)", pt.x, pt.y);
+ return true;
+}
+
+static bool
+_lwt_describe_point(const LWPOINT *pt, char *buf, size_t bufsize)
+{
+ POINT2D p;
+
+ if (!pt || !pt->point || !pt->point->npoints)
+ return false;
+
+ getPoint2d_p(pt->point, 0, &p);
+ snprintf(buf, bufsize, " at POINT(%.15g %.15g)", p.x, p.y);
+ return true;
+}
+
/*********************************************************************
*
* Backend iface
@@ -527,6 +587,8 @@ _lwt_AddIsoNode( LWT_TOPOLOGY* topo, LWT_ELEMID face,
LWPOINT* pt, int skipISOChecks, int checkFace )
{
LWT_ELEMID foundInFace = -1;
+ char locinfo[128] = "";
+ const char *locsuffix = _lwt_describe_point(pt, locinfo, sizeof(locinfo)) ? locinfo : "";
if ( lwpoint_is_empty(pt) )
{
@@ -539,13 +601,13 @@ _lwt_AddIsoNode( LWT_TOPOLOGY* topo, LWT_ELEMID face,
{
if ( lwt_be_ExistsCoincidentNode(topo, pt) ) /*x*/
{
- lwerror("SQL/MM Spatial exception - coincident node");
- return -1;
+ lwerror("SQL/MM Spatial exception - coincident node%s", locsuffix);
+ return -1;
}
if ( lwt_be_ExistsEdgeIntersectingPoint(topo, pt) ) /*x*/
{
- lwerror("SQL/MM Spatial exception - edge crosses node.");
- return -1;
+ lwerror("SQL/MM Spatial exception - edge crosses node.%s", locsuffix);
+ return -1;
}
}
@@ -634,21 +696,33 @@ _lwt_CheckEdgeCrossing( LWT_TOPOLOGY* topo,
}
for ( i=0; i<num_nodes; ++i )
{
- const POINT2D *pt;
- LWT_ISO_NODE* node = &(nodes[i]);
- if ( node->node_id == start_node ) continue;
- if ( node->node_id == end_node ) continue;
- /* check if the edge contains this node (not on boundary) */
- /* ST_RelateMatch(rec.relate, 'T********') */
- pt = getPoint2d_cp(node->geom->point, 0);
- int contains = ptarray_contains_point_partial(geom->points, pt, LW_FALSE, NULL) == LW_BOUNDARY;
- if ( contains )
- {
- GEOSGeom_destroy(edgegg);
- _lwt_release_nodes(nodes, num_nodes);
- lwerror("SQL/MM Spatial exception - geometry crosses a node");
- return -1;
- }
+ POINT2D p;
+ LWT_ISO_NODE *node = &(nodes[i]);
+ if (node->node_id == start_node)
+ continue;
+ if (node->node_id == end_node)
+ continue;
+ /* check if the edge contains this node (not on boundary) */
+ /* ST_RelateMatch(rec.relate, 'T********') */
+ if (!node->geom || !node->geom->point || !node->geom->point->npoints)
+ {
+ GEOSGeom_destroy(edgegg);
+ _lwt_release_nodes(nodes, num_nodes);
+ lwerror("SQL/MM Spatial exception - geometry crosses a node");
+ return -1;
+ }
+
+ getPoint2d_p(node->geom->point, 0, &p);
+ int contains = ptarray_contains_point_partial(geom->points, &p, LW_FALSE, NULL) == LW_BOUNDARY;
+ if (contains)
+ {
+ char locinfo[128] = "";
+ snprintf(locinfo, sizeof(locinfo), " at POINT(%.15g %.15g)", p.x, p.y);
+ GEOSGeom_destroy(edgegg);
+ _lwt_release_nodes(nodes, num_nodes);
+ lwerror("SQL/MM Spatial exception - geometry crosses a node%s", locinfo);
+ return -1;
+ }
}
if ( nodes ) _lwt_release_nodes(nodes, num_nodes);
/* may be NULL if num_nodes == 0 */
@@ -691,12 +765,12 @@ _lwt_CheckEdgeCrossing( LWT_TOPOLOGY* topo,
/* check if the edge has a non-boundary-boundary intersection with our edge */
relate = GEOSRelateBoundaryNodeRule(eegg, edgegg, 2);
- GEOSGeom_destroy(eegg);
if ( ! relate ) {
- GEOSGeom_destroy(edgegg);
- _lwt_release_edges(edges, num_edges);
- lwerror("GEOSRelateBoundaryNodeRule error: %s", lwgeom_geos_errmsg);
- return -1;
+ GEOSGeom_destroy(eegg);
+ GEOSGeom_destroy(edgegg);
+ _lwt_release_edges(edges, num_edges);
+ lwerror("GEOSRelateBoundaryNodeRule error: %s", lwgeom_geos_errmsg);
+ return -1;
}
LWDEBUGF(2, "Edge %" LWTFMT_ELEMID " relate pattern is %s", edge_id, relate);
@@ -705,87 +779,130 @@ _lwt_CheckEdgeCrossing( LWT_TOPOLOGY* topo,
if ( match ) {
/* error or no interior intersection */
GEOSFree(relate);
+ GEOSGeom_destroy(eegg);
if ( match == 2 ) {
_lwt_release_edges(edges, num_edges);
GEOSGeom_destroy(edgegg);
lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
return -1;
}
- else continue; /* no interior intersection */
+ continue; /* no interior intersection */
}
match = GEOSRelatePatternMatch(relate, "1FFF*FFF2");
if ( match ) {
- _lwt_release_edges(edges, num_edges);
- GEOSGeom_destroy(edgegg);
- GEOSFree(relate);
- if ( match == 2 ) {
- lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
- } else {
- lwerror("SQL/MM Spatial exception - coincident edge %" LWTFMT_ELEMID,
- edge_id);
- }
+ char locinfo[128] = "";
+ const char *locsuffix = match == 2 ? ""
+ : _lwt_describe_intersection_point(edgegg, eegg, locinfo, sizeof(locinfo)) ? locinfo
+ : "";
+ GEOSGeom_destroy(eegg);
+ GEOSGeom_destroy(edgegg);
+ _lwt_release_edges(edges, num_edges);
+ GEOSFree(relate);
+ if (match == 2)
+ {
+ lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
+ }
+ else
+ {
+ lwerror("SQL/MM Spatial exception - coincident edge %" LWTFMT_ELEMID "%s", edge_id, locsuffix);
+ }
return -1;
}
match = GEOSRelatePatternMatch(relate, "1********");
if ( match ) {
- _lwt_release_edges(edges, num_edges);
- GEOSGeom_destroy(edgegg);
- GEOSFree(relate);
- if ( match == 2 ) {
- lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
- } else {
- lwerror("Spatial exception - geometry intersects edge %"
- LWTFMT_ELEMID, edge_id);
- }
+ char locinfo[128] = "";
+ const char *locsuffix = match == 2 ? ""
+ : _lwt_describe_intersection_point(edgegg, eegg, locinfo, sizeof(locinfo)) ? locinfo
+ : "";
+ GEOSGeom_destroy(eegg);
+ GEOSGeom_destroy(edgegg);
+ _lwt_release_edges(edges, num_edges);
+ GEOSFree(relate);
+ if (match == 2)
+ {
+ lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
+ }
+ else
+ {
+ lwerror("Spatial exception - geometry intersects edge %" LWTFMT_ELEMID "%s", edge_id, locsuffix);
+ }
return -1;
}
match = GEOSRelatePatternMatch(relate, "T********");
if ( match ) {
- _lwt_release_edges(edges, num_edges);
- GEOSGeom_destroy(edgegg);
- GEOSFree(relate);
- if ( match == 2 ) {
- lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
- } else {
- lwerror("SQL/MM Spatial exception - geometry crosses edge %"
- LWTFMT_ELEMID, edge_id);
- }
+ char locinfo[128] = "";
+ const char *locsuffix = match == 2 ? ""
+ : _lwt_describe_intersection_point(edgegg, eegg, locinfo, sizeof(locinfo)) ? locinfo
+ : "";
+ GEOSGeom_destroy(eegg);
+ GEOSGeom_destroy(edgegg);
+ _lwt_release_edges(edges, num_edges);
+ GEOSFree(relate);
+ if (match == 2)
+ {
+ lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
+ }
+ else
+ {
+ lwerror(
+ "SQL/MM Spatial exception - geometry crosses edge %" LWTFMT_ELEMID "%s", edge_id, locsuffix);
+ }
return -1;
}
match = GEOSRelatePatternMatch(relate, "*T*******");
if ( match ) {
- _lwt_release_edges(edges, num_edges);
- GEOSGeom_destroy(edgegg);
- GEOSFree(relate);
- if ( match == 2 ) {
- lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
- } else {
- lwerror("Spatial exception - geometry boundary touches interior of edge %"
- LWTFMT_ELEMID, edge_id);
- }
+ char locinfo[128] = "";
+ const char *locsuffix = match == 2 ? ""
+ : _lwt_describe_intersection_point(edgegg, eegg, locinfo, sizeof(locinfo)) ? locinfo
+ : "";
+ GEOSGeom_destroy(eegg);
+ GEOSGeom_destroy(edgegg);
+ _lwt_release_edges(edges, num_edges);
+ GEOSFree(relate);
+ if (match == 2)
+ {
+ lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
+ }
+ else
+ {
+ lwerror("Spatial exception - geometry boundary touches interior of edge %" LWTFMT_ELEMID "%s",
+ edge_id,
+ locsuffix);
+ }
return -1;
}
match = GEOSRelatePatternMatch(relate, "***T*****");
if ( match ) {
- _lwt_release_edges(edges, num_edges);
- GEOSGeom_destroy(edgegg);
- GEOSFree(relate);
- if ( match == 2 ) {
- lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
- } else {
- lwerror("Spatial exception - boundary of edge %" LWTFMT_ELEMID" touches interior of geometry", edge_id);
- }
+ char locinfo[128] = "";
+ const char *locsuffix = match == 2 ? ""
+ : _lwt_describe_intersection_point(edgegg, eegg, locinfo, sizeof(locinfo)) ? locinfo
+ : "";
+ GEOSGeom_destroy(eegg);
+ GEOSGeom_destroy(edgegg);
+ _lwt_release_edges(edges, num_edges);
+ GEOSFree(relate);
+ if (match == 2)
+ {
+ lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
+ }
+ else
+ {
+ lwerror("Spatial exception - boundary of edge %" LWTFMT_ELEMID " touches interior of geometry%s",
+ edge_id,
+ locsuffix);
+ }
return -1;
}
LWDEBUGF(2, "Edge %" LWTFMT_ELEMID " analysis completed, it does no harm", edge_id);
GEOSFree(relate);
+ GEOSGeom_destroy(eegg);
}
LWDEBUGF(1, "No edge crossing detected among the %llu candidate edges", num_edges);
if ( edges ) _lwt_release_edges(edges, num_edges);
diff --git a/topology/test/regress/sqlmm_expected b/topology/test/regress/sqlmm_expected
index e62599aac..8cf854a19 100644
--- a/topology/test/regress/sqlmm_expected
+++ b/topology/test/regress/sqlmm_expected
@@ -9,15 +9,15 @@ ERROR: SQL/MM Spatial exception - null argument
4
5
6
-ERROR: SQL/MM Spatial exception - coincident node
-ERROR: SQL/MM Spatial exception - coincident node
+ERROR: SQL/MM Spatial exception - coincident node at POINT(0 0)
+ERROR: SQL/MM Spatial exception - coincident node at POINT(10 0)
7
8
ERROR: SQL/MM Spatial exception - not within face
ERROR: SQL/MM Spatial exception - invalid point
-ERROR: SQL/MM Spatial exception - coincident node
-ERROR: SQL/MM Spatial exception - coincident node
-ERROR: SQL/MM Spatial exception - coincident node
+ERROR: SQL/MM Spatial exception - coincident node at POINT(10 0)
+ERROR: SQL/MM Spatial exception - coincident node at POINT(0 0)
+ERROR: SQL/MM Spatial exception - coincident node at POINT(10 0)
-- ST_AddIsoEdge ------------------------
ERROR: SQL/MM Spatial exception - null argument
ERROR: SQL/MM Spatial exception - null argument
@@ -28,14 +28,14 @@ ERROR: SQL/MM Spatial exception - curve not simple
ERROR: SQL/MM Spatial exception - non-existent node
ERROR: SQL/MM Spatial exception - end node not geometry end point.
ERROR: SQL/MM Spatial exception - start node not geometry start point.
-ERROR: SQL/MM Spatial exception - geometry crosses a node
+ERROR: SQL/MM Spatial exception - geometry crosses a node at POINT(5 0)
1
2
ERROR: SQL/MM Spatial exception - not isolated node
ERROR: SQL/MM Spatial exception - not isolated node
ERROR: SQL/MM Spatial exception - not isolated node
-- ST_AddIsoNode(2) ------------------------
-ERROR: SQL/MM Spatial exception - edge crosses node.
+ERROR: SQL/MM Spatial exception - edge crosses node. at POINT(5 9.5)
-- ST_RemoveIsoEdge ---------------------
#3351.1|4|
#3351.1|5|
diff --git a/topology/test/regress/st_addedgemodface_expected b/topology/test/regress/st_addedgemodface_expected
index 26e39df63..d55e6ce19 100644
--- a/topology/test/regress/st_addedgemodface_expected
+++ b/topology/test/regress/st_addedgemodface_expected
@@ -1,16 +1,16 @@
ERROR: SQL/MM Spatial exception - start node not geometry start point.
ERROR: SQL/MM Spatial exception - end node not geometry end point.
ERROR: SQL/MM Spatial exception - end node not geometry end point.
-ERROR: SQL/MM Spatial exception - geometry crosses a node
+ERROR: SQL/MM Spatial exception - geometry crosses a node at POINT(41 40)
ERROR: SQL/MM Spatial exception - non-existent node
ERROR: SQL/MM Spatial exception - non-existent node
ERROR: SQL/MM Spatial exception - curve not simple
ERROR: Invalid edge (no two distinct vertices exist)
ERROR: Invalid edge (no two distinct vertices exist)
-ERROR: SQL/MM Spatial exception - coincident edge 8
-ERROR: SQL/MM Spatial exception - geometry crosses edge 5
-ERROR: SQL/MM Spatial exception - geometry crosses edge 4
-ERROR: Spatial exception - geometry intersects edge 4
+ERROR: SQL/MM Spatial exception - coincident edge 8 at POINT(35 22)
+ERROR: SQL/MM Spatial exception - geometry crosses edge 5 at POINT(48.0714285714286 41.9285714285714)
+ERROR: SQL/MM Spatial exception - geometry crosses edge 4 at POINT(45 32)
+ERROR: Spatial exception - geometry intersects edge 4 at POINT(36 38)
L1
L2
T1|E7|8|-19|0|10
diff --git a/topology/test/regress/st_addedgenewfaces_expected b/topology/test/regress/st_addedgenewfaces_expected
index 9f14187a6..bb2a7a572 100644
--- a/topology/test/regress/st_addedgenewfaces_expected
+++ b/topology/test/regress/st_addedgenewfaces_expected
@@ -1,16 +1,16 @@
ERROR: SQL/MM Spatial exception - start node not geometry start point.
ERROR: SQL/MM Spatial exception - end node not geometry end point.
ERROR: SQL/MM Spatial exception - end node not geometry end point.
-ERROR: SQL/MM Spatial exception - geometry crosses a node
+ERROR: SQL/MM Spatial exception - geometry crosses a node at POINT(41 40)
ERROR: SQL/MM Spatial exception - non-existent node
ERROR: SQL/MM Spatial exception - non-existent node
ERROR: SQL/MM Spatial exception - curve not simple
ERROR: Invalid edge (no two distinct vertices exist)
ERROR: Invalid edge (no two distinct vertices exist)
-ERROR: SQL/MM Spatial exception - coincident edge 8
-ERROR: SQL/MM Spatial exception - geometry crosses edge 5
-ERROR: SQL/MM Spatial exception - geometry crosses edge 4
-ERROR: Spatial exception - geometry intersects edge 4
+ERROR: SQL/MM Spatial exception - coincident edge 8 at POINT(35 22)
+ERROR: SQL/MM Spatial exception - geometry crosses edge 5 at POINT(48.0714285714286 41.9285714285714)
+ERROR: SQL/MM Spatial exception - geometry crosses edge 4 at POINT(45 32)
+ERROR: Spatial exception - geometry intersects edge 4 at POINT(36 38)
L1
L2
T1|E7|8|-19|0|11
diff --git a/topology/test/regress/st_addisoedge_expected b/topology/test/regress/st_addisoedge_expected
index f1ae4f023..46d9f9916 100644
--- a/topology/test/regress/st_addisoedge_expected
+++ b/topology/test/regress/st_addisoedge_expected
@@ -15,7 +15,7 @@ ERROR: SQL/MM Spatial exception - curve not simple
ERROR: SQL/MM Spatial exception - non-existent node
ERROR: SQL/MM Spatial exception - end node not geometry end point.
ERROR: SQL/MM Spatial exception - start node not geometry start point.
-ERROR: SQL/MM Spatial exception - geometry crosses a node
+ERROR: SQL/MM Spatial exception - geometry crosses a node at POINT(5 0)
E1
E2
N1|
@@ -29,5 +29,5 @@ ERROR: SQL/MM Spatial exception - not isolated node
ERROR: SQL/MM Spatial exception - not isolated node
ERROR: Closed edges would not be isolated, try ST_AddEdgeNewFaces
ERROR: SQL/MM Spatial exception - not isolated node
-ERROR: SQL/MM Spatial exception - geometry crosses edge 2
+ERROR: SQL/MM Spatial exception - geometry crosses edge 2 at POINT(10 3.33333333333333)
Topology 'tt' dropped
diff --git a/topology/test/regress/st_addisonode_expected b/topology/test/regress/st_addisonode_expected
index 31f74e5a6..6a7093778 100644
--- a/topology/test/regress/st_addisonode_expected
+++ b/topology/test/regress/st_addisonode_expected
@@ -7,10 +7,10 @@ ERROR: SQL/MM Spatial exception - invalid topology name
ERROR: SQL/MM Spatial exception - not within face
ERROR: SQL/MM Spatial exception - not within face
ERROR: SQL/MM Spatial exception - not within face
-ERROR: SQL/MM Spatial exception - coincident node
-ERROR: SQL/MM Spatial exception - coincident node
-ERROR: SQL/MM Spatial exception - coincident node
-ERROR: SQL/MM Spatial exception - edge crosses node.
+ERROR: SQL/MM Spatial exception - coincident node at POINT(21 22)
+ERROR: SQL/MM Spatial exception - coincident node at POINT(21 22)
+ERROR: SQL/MM Spatial exception - coincident node at POINT(21 22)
+ERROR: SQL/MM Spatial exception - edge crosses node. at POINT(28 14)
T1|23|5
T2|24|0
T3|25|9
diff --git a/topology/test/regress/st_changeedgegeom_expected b/topology/test/regress/st_changeedgegeom_expected
index bfb094b73..c4dd61a06 100644
--- a/topology/test/regress/st_changeedgegeom_expected
+++ b/topology/test/regress/st_changeedgegeom_expected
@@ -1,11 +1,11 @@
T1|Edge 25 changed
ERROR: SQL/MM Spatial exception - start node not geometry start point.
ERROR: SQL/MM Spatial exception - end node not geometry end point.
-ERROR: SQL/MM Spatial exception - geometry crosses a node
+ERROR: SQL/MM Spatial exception - geometry crosses a node at POINT(20 37)
ERROR: SQL/MM Spatial exception - curve not simple
ERROR: Invalid edge (no two distinct vertices exist)
ERROR: SQL/MM Spatial exception - non-existent edge 666
-ERROR: SQL/MM Spatial exception - geometry crosses edge 1
+ERROR: SQL/MM Spatial exception - geometry crosses edge 1 at POINT(11.8 38)
T2|Edge 5 changed
T3|Edge 5 changed
T4|Edge 26 changed
diff --git a/topology/test/regress/topology_error_location.sql b/topology/test/regress/topology_error_location.sql
new file mode 100644
index 000000000..37c199e4e
--- /dev/null
+++ b/topology/test/regress/topology_error_location.sql
@@ -0,0 +1,38 @@
+-- Ensure prior runs do not leak topologies or noisy notices
+SET client_min_messages TO NOTICE;
+DO $$
+BEGIN
+ PERFORM topology.DropTopology('err_loc');
+EXCEPTION WHEN OTHERS THEN
+ -- Topology may not exist yet; ignore.
+END;
+$$ LANGUAGE plpgsql;
+
+SELECT 'created', topology.CreateTopology('err_loc', 0, 0) > 0;
+
+SELECT 'n1', topology.ST_AddIsoNode('err_loc', NULL::integer, ST_GeomFromText('POINT(0 0)', 0));
+SELECT 'n2', topology.ST_AddIsoNode('err_loc', NULL::integer, ST_GeomFromText('POINT(10 0)', 0));
+SELECT 'n3', topology.ST_AddIsoNode('err_loc', NULL::integer, ST_GeomFromText('POINT(5 -5)', 0));
+SELECT 'n4', topology.ST_AddIsoNode('err_loc', NULL::integer, ST_GeomFromText('POINT(5 5)', 0));
+
+DO $$
+BEGIN
+ PERFORM topology.ST_AddIsoNode('err_loc', NULL::integer, ST_GeomFromText('POINT(0 0)', 0));
+EXCEPTION WHEN OTHERS THEN
+ RAISE NOTICE 'duplicate node: %', regexp_replace(SQLERRM, E'^.*: ', '');
+END;
+$$ LANGUAGE plpgsql;
+
+SELECT 'base_edge', topology.ST_AddEdgeModFace('err_loc', 1, 2, ST_GeomFromText('LINESTRING(0 0, 10 0)', 0));
+
+DO $$
+BEGIN
+ PERFORM topology.ST_AddEdgeModFace('err_loc', 3, 4, ST_GeomFromText('LINESTRING(5 -5, 5 5)', 0));
+EXCEPTION WHEN OTHERS THEN
+ RAISE NOTICE 'crossing edge: %', regexp_replace(SQLERRM, E'^.*: ', '');
+END;
+$$ LANGUAGE plpgsql;
+
+SET client_min_messages TO WARNING;
+SELECT 'dropped', topology.DropTopology('err_loc') IS NOT NULL;
+RESET client_min_messages;
diff --git a/topology/test/regress/topology_error_location_expected b/topology/test/regress/topology_error_location_expected
new file mode 100644
index 000000000..85bd4abe3
--- /dev/null
+++ b/topology/test/regress/topology_error_location_expected
@@ -0,0 +1,9 @@
+created|t
+n1|1
+n2|2
+n3|3
+n4|4
+NOTICE: duplicate node: SQL/MM Spatial exception - coincident node at POINT(0 0)
+base_edge|1
+NOTICE: crossing edge: SQL/MM Spatial exception - geometry crosses edge 1 at POINT(5 0)
+dropped|t
diff --git a/topology/test/tests.mk b/topology/test/tests.mk
index 0b0ab3ff9..ba1d2e204 100644
--- a/topology/test/tests.mk
+++ b/topology/test/tests.mk
@@ -88,6 +88,7 @@ TESTS += \
$(top_srcdir)/topology/test/regress/topogeometry_srid.sql \
$(top_srcdir)/topology/test/regress/topogeometry_type.sql \
$(top_srcdir)/topology/test/regress/topojson.sql \
+ $(top_srcdir)/topology/test/regress/topology_error_location.sql \
$(top_srcdir)/topology/test/regress/topologysummary.sql \
$(top_srcdir)/topology/test/regress/totaltopologysize.sql \
$(top_srcdir)/topology/test/regress/totopogeom.sql \
-----------------------------------------------------------------------
Summary of changes:
NEWS | 2 +-
liblwgeom/topo/lwgeom_topo.c | 259 +++++++++++++++------
topology/test/regress/sqlmm_expected | 14 +-
topology/test/regress/st_addedgemodface_expected | 10 +-
topology/test/regress/st_addedgenewfaces_expected | 10 +-
topology/test/regress/st_addisoedge_expected | 4 +-
topology/test/regress/st_addisonode_expected | 8 +-
topology/test/regress/st_changeedgegeom_expected | 4 +-
topology/test/regress/topology_error_location.sql | 38 +++
.../test/regress/topology_error_location_expected | 9 +
topology/test/tests.mk | 1 +
11 files changed, 262 insertions(+), 97 deletions(-)
create mode 100644 topology/test/regress/topology_error_location.sql
create mode 100644 topology/test/regress/topology_error_location_expected
hooks/post-receive
--
PostGIS
More information about the postgis-tickets
mailing list