lwt_GetFaceGeometry X
lwt_GetFaceEdges X
lwt_ChangeEdgeGeom X
+lwt_RemoveIsoNode X
lwt_RemEdgeNewFace
lwt_RemEdgeModFace
lwt_ModEdgeHeal
lwt_NewEdgeHeal
lwt_MoveIsoNode
-lwt_RemoveIsoNode
* LWT_COL_NODE_* macros
*
* @return an array of nodes
- * or NULL on error (@see lastErrorMessage)
+ * or NULL in the following cases:
+ * - no edge found ("numelems" is set to 0)
+ * - error ("numelems" is set to -1)
+ * (@see lastErrorMessage)
*
*/
LWT_ISO_NODE* (*getNodeById) (
* or NULL in the following cases:
* - no edge found ("numelems" is set to 0)
* - error ("numelems" is set to -1)
+ * (@see lastErrorMessage)
*/
LWT_ISO_EDGE* (*getEdgeByNode) (
const LWT_BE_TOPOLOGY* topo,
const LWT_BE_TOPOLOGY* topo
);
+ /**
+ * Delete nodes by id
+ *
+ * @param topo the topology to act upon
+ * @param ids an array of node identifiers
+ * @param numelems number of node identifiers in the ids array
+ *
+ * @return number of nodes being deleted or -1 on error
+ * (@see lastErroMessage)
+ */
+ int (*deleteNodesById) (
+ const LWT_BE_TOPOLOGY* topo,
+ const LWT_ELEMID* ids,
+ int numelems
+ );
+
} LWT_BE_CALLBACKS;
* @param topo the topology to operate on
* @param node the identifier of the nod to be moved
* @param pt the new node position
+ * @return 0 on success, -1 on error
+ * (liblwgeom error handler will be invoked with error message)
*
*/
-void lwt_MoveIsoNode(LWT_TOPOLOGY* topo,
- LWT_ELEMID node, LWPOINT* pt);
+int lwt_MoveIsoNode(LWT_TOPOLOGY* topo,
+ LWT_ELEMID node, LWPOINT* pt);
/**
* Remove an isolated node
*
* @param topo the topology to operate on
* @param node the identifier of the nod to be moved
+ * @return 0 on success, -1 on error
+ * (liblwgeom error handler will be invoked with error message)
*
*/
-void lwt_RemoveIsoNode(LWT_TOPOLOGY* topo, LWT_ELEMID node);
+int lwt_RemoveIsoNode(LWT_TOPOLOGY* topo, LWT_ELEMID node);
/**
* Add an isolated edge connecting two existing isolated nodes
CBT2(topo, deleteFacesById, ids, numelems);
}
+static int
+lwt_be_deleteNodesById(const LWT_TOPOLOGY* topo, const LWT_ELEMID* ids, int numelems)
+{
+ CBT2(topo, deleteNodesById, ids, numelems);
+}
+
LWT_ELEMID
lwt_be_getNextEdgeId(LWT_TOPOLOGY* topo)
{
node_ids[1] = endNode;
endpoints = lwt_be_getNodeById( topo, node_ids, &num_nodes,
LWT_COL_NODE_ALL );
- if ( ! endpoints ) {
+ if ( num_nodes < 0 )
+ {
lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
return -1;
}
- if ( num_nodes < 2 )
+ else if ( num_nodes < 2 )
{
- _lwt_release_nodes(endpoints, num_nodes);
+ if ( num_nodes ) _lwt_release_nodes(endpoints, num_nodes);
lwerror("SQL/MM Spatial exception - non-existent node");
return -1;
}
}
endpoints = lwt_be_getNodeById( topo, node_ids, &num_nodes, LWT_COL_NODE_ALL );
- if ( ! endpoints ) {
+ if ( num_nodes < 0 ) {
lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
return -1;
}
_lwt_release_edges(oldedge, 1);
return 0; /* success */
}
+
+static LWT_ISO_NODE *
+_lwt_GetIsoNode(LWT_TOPOLOGY* topo, LWT_ELEMID nid)
+{
+ LWT_ISO_NODE *node;
+ int n = 1;
+
+ node = lwt_be_getNodeById( topo, &nid, &n, LWT_COL_NODE_CONTAINING_FACE );
+ if ( n < 0 ) {
+ lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+ return 0;
+ }
+ if ( n < 1 ) {
+ lwerror("SQL/MM Spatial exception - non-existent node");
+ return 0;
+ }
+ if ( node->containing_face == -1 )
+ {
+ lwfree(node);
+ lwerror("SQL/MM Spatial exception - not isolated node");
+ return 0;
+ }
+
+ return node;
+}
+
+int
+lwt_MoveIsoNode(LWT_TOPOLOGY* topo, LWT_ELEMID nid, LWPOINT *pt)
+{
+ LWT_ISO_NODE *node;
+
+ node = _lwt_GetIsoNode( topo, nid );
+ if ( ! node ) return -1;
+
+ lwfree(node);
+ lwerror("lwt_MoveIsoNode not implemented yet");
+ return -1;
+}
+
+int
+lwt_RemoveIsoNode(LWT_TOPOLOGY* topo, LWT_ELEMID nid)
+{
+ LWT_ISO_NODE *node;
+ int n = 1;
+
+ node = _lwt_GetIsoNode( topo, nid );
+ if ( ! node ) return -1;
+
+ n = lwt_be_deleteNodesById( topo, &nid, n );
+ if ( n == -1 )
+ {
+ lwerror("SQL/MM Spatial exception - not isolated node");
+ return -1;
+ }
+ if ( n != 1 )
+ {
+ lwerror("Unexpected error: %d nodes deleted when expecting 1", n);
+ return -1;
+ }
+
+ return 0; /* success */
+}
return SPI_processed;
}
+static int
+cb_deleteNodesById( const LWT_BE_TOPOLOGY* topo,
+ const LWT_ELEMID* ids, int numelems )
+{
+ MemoryContext oldcontext = CurrentMemoryContext;
+ int spi_result, i;
+ StringInfoData sqldata;
+ StringInfo sql = &sqldata;
+
+ initStringInfo(sql);
+ appendStringInfo(sql, "DELETE FROM \"%s\".node WHERE node_id IN (",
+ topo->name);
+ for (i=0; i<numelems; ++i) {
+ appendStringInfo(sql, "%s" INT64_FORMAT, (i?",":""), ids[i]);
+ }
+ appendStringInfoString(sql, ")");
+
+ POSTGIS_DEBUGF(1, "cb_deleteNodesById query: %s", sql->data);
+
+ spi_result = SPI_execute( sql->data, false, 0 );
+ MemoryContextSwitchTo( oldcontext ); /* switch back */
+ if ( spi_result != SPI_OK_DELETE )
+ {
+ cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
+ spi_result, sql->data);
+ return -1;
+ }
+ pfree(sqldata.data);
+
+ if ( SPI_processed ) topo->be_data->data_changed = true;
+
+ POSTGIS_DEBUGF(1, "cb_deleteNodesById: delete query processed %d rows",
+ SPI_processed);
+
+ return SPI_processed;
+}
+
static LWT_ISO_NODE*
cb_getNodeWithinBox2D ( const LWT_BE_TOPOLOGY* topo, const GBOX* box,
int* numelems, int fields, int limit )
cb_deleteFacesById,
cb_topoGetSRID,
cb_topoGetPrecision,
- cb_topoHasZ
+ cb_topoHasZ,
+ cb_deleteNodesById
};
}
PG_RETURN_TEXT_P(cstring2text(buf));
}
+
+/* ST_RemoveIsoNode(atopology, anode) */
+Datum ST_RemoveIsoNode(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(ST_RemoveIsoNode);
+Datum ST_RemoveIsoNode(PG_FUNCTION_ARGS)
+{
+ text* toponame_text;
+ char buf[64];
+ char* toponame;
+ int ret;
+ LWT_ELEMID node_id;
+ LWT_TOPOLOGY *topo;
+
+ if ( PG_ARGISNULL(0) || PG_ARGISNULL(1) ) {
+ lwpgerror("SQL/MM Spatial exception - null argument");
+ PG_RETURN_NULL();
+ }
+
+ toponame_text = PG_GETARG_TEXT_P(0);
+ toponame = text2cstring(toponame_text);
+ PG_FREE_IF_COPY(toponame_text, 0);
+
+ node_id = PG_GETARG_INT32(1) ;
+
+ if ( SPI_OK_CONNECT != SPI_connect() ) {
+ lwpgerror("Could not connect to SPI");
+ PG_RETURN_NULL();
+ }
+ be_data.data_changed = false;
+
+ topo = lwt_LoadTopology(be_iface, toponame);
+ pfree(toponame);
+ if ( ! topo ) {
+ /* should never reach this point, as lwerror would raise an exception */
+ SPI_finish();
+ PG_RETURN_NULL();
+ }
+
+ POSTGIS_DEBUG(1, "Calling lwt_RemoveIsoNode");
+ ret = lwt_RemoveIsoNode(topo, node_id);
+ POSTGIS_DEBUG(1, "lwt_RemoveIsoNode returned");
+ lwt_FreeTopology(topo);
+
+ if ( ret == -1 ) {
+ /* should never reach this point, as lwerror would raise an exception */
+ SPI_finish();
+ PG_RETURN_NULL();
+ }
+
+ /* TODO: check if any TopoGeometry exists including this point in
+ * its definition ! */
+
+ SPI_finish();
+
+ if ( snprintf(buf, 64, "Isolated node " INT64_FORMAT
+ " removed", node_id) >= 64 )
+ {
+ buf[63] = '\0';
+ }
+ PG_RETURN_TEXT_P(cstring2text(buf));
+}
--
CREATE OR REPLACE FUNCTION topology.ST_RemoveIsoNode(atopology varchar, anode integer)
RETURNS TEXT AS
-$$
-DECLARE
- rec RECORD;
-BEGIN
-
- --
- -- Atopology and apoint are required
- --
- IF atopology IS NULL OR anode IS NULL THEN
- RAISE EXCEPTION
- 'SQL/MM Spatial exception - null argument';
- END IF;
-
- --
- -- Check node isolation.
- --
- FOR rec IN EXECUTE 'SELECT edge_id FROM '
- || quote_ident(atopology) || '.edge_data ' ||
- ' WHERE start_node = ' || anode ||
- ' OR end_node = ' || anode
- LOOP
- RAISE EXCEPTION
- 'SQL/MM Spatial exception - not isolated node';
- END LOOP;
-
- EXECUTE 'DELETE FROM ' || quote_ident(atopology) || '.node '
- || ' WHERE node_id = ' || anode;
-
- RETURN 'Isolated node ' || anode || ' removed';
-END
-$$
-LANGUAGE 'plpgsql' VOLATILE;
+ 'MODULE_PATHNAME','ST_RemoveIsoNode'
+ LANGUAGE 'c' VOLATILE;
--} ST_RemoveIsoNode
--{
--
CREATE OR REPLACE FUNCTION topology.ST_RemIsoNode(varchar, integer)
RETURNS TEXT AS
-$$
- SELECT topology.ST_RemoveIsoNode($1, $2)
-$$ LANGUAGE 'sql' VOLATILE;
+ 'MODULE_PATHNAME','ST_RemoveIsoNode'
+ LANGUAGE 'c' VOLATILE;
+--} ST_RemIsoNode
--{
-- Topo-Geo and Topo-Net 3: Routine Details