[postgis-tickets] [SCM] PostGIS branch main updated. 3.1.0rc1-344-ged2de5c

git at osgeo.org git at osgeo.org
Wed Jul 14 15:57:52 PDT 2021


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, main has been updated
       via  ed2de5c0a99c08e72f3736a42d378383a4a24410 (commit)
      from  76cf8de9bc301b9a28809ce8dd5ca4e92fcab559 (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 ed2de5c0a99c08e72f3736a42d378383a4a24410
Author: Sandro Santilli <strk at kbt.io>
Date:   Thu Jul 15 00:57:14 2021 +0200

    Prevent removing isolated edge used in TopoGeometry objects
    
    Closes #3248 in main branch (3.2.0dev)
    Includes regression tests

diff --git a/liblwgeom/liblwgeom_topo.h b/liblwgeom/liblwgeom_topo.h
index cb56f12..665e9c5 100644
--- a/liblwgeom/liblwgeom_topo.h
+++ b/liblwgeom/liblwgeom_topo.h
@@ -832,6 +832,20 @@ typedef struct LWT_BE_CALLBACKS_T {
       LWT_ELEMID rem_node
   );
 
+  /**
+   * Check TopoGeometry objects before an isolated edge removal event
+   *
+   * @param topo the topology to act upon
+   * @param rem_edge identifier of the edge that's been removed
+   *
+   * @return 1 to allow, 0 to forbid the operation
+   *         (reporting reason via lastErrorMessage)
+   */
+  int (*checkTopoGeomRemIsoEdge) (
+      const LWT_BE_TOPOLOGY* topo,
+      LWT_ELEMID rem_edge
+  );
+
 } LWT_BE_CALLBACKS;
 
 
diff --git a/liblwgeom/lwgeom_topo.c b/liblwgeom/lwgeom_topo.c
index 60df671..51c4639 100644
--- a/liblwgeom/lwgeom_topo.c
+++ b/liblwgeom/lwgeom_topo.c
@@ -347,6 +347,12 @@ lwt_be_checkTopoGeomRemEdge(LWT_TOPOLOGY* topo, LWT_ELEMID edge_id,
 }
 
 static int
+lwt_be_checkTopoGeomRemIsoEdge(LWT_TOPOLOGY* topo, LWT_ELEMID edge_id)
+{
+  CBT1(topo, checkTopoGeomRemIsoEdge, edge_id);
+}
+
+static int
 lwt_be_checkTopoGeomRemNode(LWT_TOPOLOGY* topo, LWT_ELEMID node_id,
                             LWT_ELEMID eid1, LWT_ELEMID eid2)
 {
@@ -3767,9 +3773,14 @@ lwt_RemIsoEdge(LWT_TOPOLOGY* topo, LWT_ELEMID id)
     return -1;
   }
 
-  /* TODO: notify to caller about edge being removed ?
+  /* Check that the edge can be safely removed
    * See https://trac.osgeo.org/postgis/ticket/3248
    */
+  if ( ! lwt_be_checkTopoGeomRemIsoEdge(topo, id) )
+  {
+    lwerror("%s", lwt_be_lastErrorMessage(topo->be_iface));
+    return -1;
+  }
 
   return 0; /* success */
 }
diff --git a/topology/postgis_topology.c b/topology/postgis_topology.c
index c02ab6a..aae7e48 100644
--- a/topology/postgis_topology.c
+++ b/topology/postgis_topology.c
@@ -2552,6 +2552,66 @@ cb_checkTopoGeomRemEdge ( const LWT_BE_TOPOLOGY* topo,
 }
 
 static int
+cb_checkTopoGeomRemIsoEdge ( const LWT_BE_TOPOLOGY* topo,
+                          LWT_ELEMID rem_edge )
+{
+  MemoryContext oldcontext = CurrentMemoryContext;
+  int spi_result;
+  StringInfoData sqldata;
+  StringInfo sql = &sqldata;
+  const char *tg_id, *layer_id;
+  const char *schema_name, *table_name, *col_name;
+  HeapTuple row;
+  TupleDesc tdesc;
+
+  POSTGIS_DEBUG(1, "cb_checkTopoGeomRemIsoEdge enter ");
+
+  initStringInfo(sql);
+  appendStringInfo( sql, "SELECT r.topogeo_id, r.layer_id, "
+                    "l.schema_name, l.table_name, l.feature_column FROM "
+                    "topology.layer l INNER JOIN \"%s\".relation r "
+                    "ON (l.layer_id = r.layer_id) WHERE l.level = 0 AND "
+                    "l.feature_type IN ( 2, 4 ) AND l.topology_id = %d"
+                    " AND r.element_type = 2 AND abs(r.element_id) = %" LWTFMT_ELEMID,
+                    topo->name, topo->id, rem_edge );
+
+  POSTGIS_DEBUGF(1, "cb_checkTopoGeomRemIsoEdge query 1: %s", sql->data);
+
+  spi_result = SPI_execute(sql->data, !topo->be_data->data_changed, 0);
+  MemoryContextSwitchTo( oldcontext ); /* switch back */
+  if ( spi_result != SPI_OK_SELECT )
+  {
+    cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
+            spi_result, sql->data);
+    pfree(sqldata.data);
+    return 0;
+  }
+
+  if ( SPI_processed )
+  {
+    row = SPI_tuptable->vals[0];
+    tdesc = SPI_tuptable->tupdesc;
+
+    tg_id = SPI_getvalue(row, tdesc, 1);
+    layer_id = SPI_getvalue(row, tdesc, 2);
+    schema_name = SPI_getvalue(row, tdesc, 3);
+    table_name = SPI_getvalue(row, tdesc, 4);
+    col_name = SPI_getvalue(row, tdesc, 5);
+
+    SPI_freetuptable(SPI_tuptable);
+
+    cberror(topo->be_data, "TopoGeom %s in layer %s "
+            "(%s.%s.%s) cannot be represented "
+            "dropping edge %" LWTFMT_ELEMID,
+            tg_id, layer_id, schema_name, table_name,
+            col_name, rem_edge);
+    return 0;
+  }
+
+  return 1;
+}
+
+static int
 cb_checkTopoGeomRemNode ( const LWT_BE_TOPOLOGY* topo,
                           LWT_ELEMID rem_node, LWT_ELEMID edge1, LWT_ELEMID edge2 )
 {
@@ -3336,7 +3396,8 @@ static LWT_BE_CALLBACKS be_callbacks =
   cb_checkTopoGeomRemNode,
   cb_updateTopoGeomEdgeHeal,
   cb_getFaceWithinBox2D,
-  cb_checkTopoGeomRemIsoNode
+  cb_checkTopoGeomRemIsoNode,
+  cb_checkTopoGeomRemIsoEdge
 };
 
 static void
diff --git a/topology/test/regress/st_removeisoedge.sql b/topology/test/regress/st_removeisoedge.sql
new file mode 100644
index 0000000..38a2db0
--- /dev/null
+++ b/topology/test/regress/st_removeisoedge.sql
@@ -0,0 +1,40 @@
+\set VERBOSITY terse
+set client_min_messages to ERROR;
+
+-- Import city_data
+\i ../load_topology.sql
+
+CREATE TABLE city_data.f_lin(id serial primary key);
+SELECT NULL FROM AddTopoGeometryColumn('city_data', 'city_data', 'f_lin', 'tg', 'LINE');
+CREATE TABLE city_data.f_mix(id serial primary key);
+SELECT NULL FROM AddTopoGeometryColumn('city_data', 'city_data', 'f_mix', 'tg', 'COLLECTION');
+
+BEGIN;
+INSERT INTO city_data.f_lin(tg) VALUES(
+  topology.CreateTopoGeom(
+    'city_data', -- Topology name
+    2, -- Topology geometry type (line)
+    1, -- TG_LAYER_ID for this topology (from topology.layer)
+    '{{25,2}}'
+  )
+);
+SELECT '#3248.line', topology.ST_RemoveIsoEdge('city_data', 25);
+ROLLBACK;
+
+BEGIN;
+INSERT INTO city_data.f_mix(tg) VALUES(
+  topology.CreateTopoGeom(
+    'city_data', -- Topology name
+    4, -- Topology geometry type (collection)
+    2, -- TG_LAYER_ID for this topology (from topology.layer)
+    '{{25,2}}'
+  )
+);
+SELECT '#3248.collection', topology.ST_RemoveIsoEdge('city_data', 25);
+ROLLBACK;
+
+SELECT 'non-iso', topology.ST_RemoveIsoEdge('city_data', 1);
+SELECT 'iso', topology.ST_RemoveIsoEdge('city_data', 25);
+
+SELECT NULL FROM topology.DropTopology('city_data');
+
diff --git a/topology/test/regress/st_removeisoedge_expected b/topology/test/regress/st_removeisoedge_expected
new file mode 100644
index 0000000..ad2cd1d
--- /dev/null
+++ b/topology/test/regress/st_removeisoedge_expected
@@ -0,0 +1,4 @@
+ERROR:  TopoGeom 1 in layer 1 (city_data.f_lin.tg) cannot be represented dropping edge 25
+ERROR:  TopoGeom 1 in layer 2 (city_data.f_mix.tg) cannot be represented dropping edge 25
+ERROR:  SQL/MM Spatial exception - not isolated edge
+iso|Isolated edge 25 removed

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

Summary of changes:
 liblwgeom/liblwgeom_topo.h                      | 14 ++++++
 liblwgeom/lwgeom_topo.c                         | 13 ++++-
 topology/postgis_topology.c                     | 63 ++++++++++++++++++++++++-
 topology/test/regress/st_removeisoedge.sql      | 40 ++++++++++++++++
 topology/test/regress/st_removeisoedge_expected |  4 ++
 5 files changed, 132 insertions(+), 2 deletions(-)
 create mode 100644 topology/test/regress/st_removeisoedge.sql
 create mode 100644 topology/test/regress/st_removeisoedge_expected


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list