LWT_ELEMID split_edge, LWT_ELEMID new_edge1, LWT_ELEMID new_edge2
);
+ /**
+ * Delete edges
+ *
+ * @param topo the topology to act upon
+ * @param sel_edge an LWT_ISO_EDGE object with selecting fields set.
+ * @param sel_fields fields used to select edges to be deleted,
+ * see LWT_COL_EDGE_* macros
+ *
+ * @return number of edges being deleted or -1 on error
+ * (@see lastErroMessage)
+ */
+ int (*deleteEdges) (
+ const LWT_BE_TOPOLOGY* topo,
+ const LWT_ISO_EDGE* sel_edge, int sel_fields
+ );
+
} LWT_BE_CALLBACKS;
* @param edge identifier of the edge to be split
* @param pt geometry of the new node
* @param skipChecks if non-zero skips consistency checks
- * (coincident node)
+ * (coincident node, point not on edge...)
* @return the id of newly created node, or -1 on error
* (liblwgeom error handler will be invoked with error message)
*
* @param topo the topology to operate on
* @param edge identifier of the edge to be split
* @param pt geometry of the new node
+ * @param skipChecks if non-zero skips consistency checks
+ * (coincident node, point not on edge...)
* @return the id of newly created node
*
*/
-LWT_ELEMID lwt_NewEdgesSplit(LWT_TOPOLOGY* topo, LWT_ELEMID edge, LWPOINT* pt);
+LWT_ELEMID lwt_NewEdgesSplit(LWT_TOPOLOGY* topo, LWT_ELEMID edge, LWPOINT* pt, int skipChecks);
/**
* Merge two edges, modifying the first and deleting the second
lwt_be_insertEdges(LWT_TOPOLOGY* topo, LWT_ISO_EDGE* edge, int numelems);
int
lwt_be_updateEdges(LWT_TOPOLOGY* topo, const LWT_ISO_EDGE* sel_edge, int sel_fields, const LWT_ISO_EDGE* upd_edge, int upd_fields, const LWT_ISO_EDGE* exc_edge, int exc_fields);
+int
+lwt_be_deleteEdges(LWT_TOPOLOGY* topo, const LWT_ISO_EDGE* sel_edge, int sel_fields);
LWT_ELEMID lwt_be_getFaceContainingPoint(LWT_TOPOLOGY* topo, LWPOINT* pt);
exc_edge, exc_fields);
}
+int
+lwt_be_deleteEdges(LWT_TOPOLOGY* topo,
+ const LWT_ISO_EDGE* sel_edge, int sel_fields
+)
+{
+ CBT2(topo, deleteEdges, sel_edge, sel_fields);
+}
+
LWT_ELEMID
lwt_be_getFaceContainingPoint(LWT_TOPOLOGY* topo, LWPOINT* pt)
{
/* return new node id */
return node.node_id;
}
+
+LWT_ELEMID
+lwt_NewEdgesSplit( LWT_TOPOLOGY* topo, LWT_ELEMID edge,
+ LWPOINT* pt, int skipISOChecks )
+{
+ LWT_ISO_NODE node;
+ LWT_ISO_EDGE* oldedge = NULL;
+ LWCOLLECTION *split_col;
+ const LWGEOM *oldedge_geom;
+ const LWGEOM *newedge_geom;
+ LWT_ISO_EDGE newedges[2];
+ //LWT_ISO_EDGE newedge1, newedge2;
+ LWT_ISO_EDGE seledge, updedge;
+ int ret;
+
+ split_col = _lwt_EdgeSplit( topo, edge, pt, skipISOChecks, &oldedge );
+ if ( ! split_col ) return -1; /* should have raised an exception */
+ oldedge_geom = split_col->geoms[0];
+ newedge_geom = split_col->geoms[1];
+
+ /* Add new node, getting new id back */
+ node.node_id = -1;
+ node.containing_face = -1; /* means not-isolated */
+ node.geom = pt;
+ if ( ! lwt_be_insertNodes(topo, &node, 1) )
+ {
+ lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+ return -1;
+ }
+ if (node.node_id == -1) {
+ /* should have been set by backend */
+ lwerror("Backend coding error: "
+ "insertNodes callback did not return node_id");
+ return -1;
+ }
+
+ /* Delete the old edge */
+ seledge.edge_id = edge;
+ ret = lwt_be_deleteEdges(topo, &seledge, LWT_COL_EDGE_EDGE_ID);
+ if ( ret == -1 ) {
+ lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+ return -1;
+ }
+
+ /* Get new edges identifiers */
+ newedges[0].edge_id = lwt_be_getNextEdgeId(topo);
+ if ( newedges[0].edge_id == -1 ) {
+ lwcollection_release(split_col);
+ lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+ return -1;
+ }
+ newedges[1].edge_id = lwt_be_getNextEdgeId(topo);
+ if ( newedges[1].edge_id == -1 ) {
+ lwcollection_release(split_col);
+ lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+ return -1;
+ }
+
+ /* Define the first new edge (to new node) */
+ newedges[0].start_node = oldedge->start_node;
+ newedges[0].end_node = node.node_id;
+ newedges[0].face_left = oldedge->face_left;
+ newedges[0].face_right = oldedge->face_right;
+ newedges[0].next_left = newedges[1].edge_id;
+ if ( oldedge->next_right == edge )
+ newedges[0].next_right = newedges[0].edge_id;
+ else if ( oldedge->next_right == -edge )
+ newedges[0].next_right = -newedges[1].edge_id;
+ else
+ newedges[0].next_right = oldedge->next_right;
+ newedges[0].geom = lwgeom_as_lwline(oldedge_geom);
+ /* lwgeom_split of a line should only return lines ... */
+ if ( ! newedges[0].geom ) {
+ lwcollection_release(split_col);
+ lwerror("first geometry in lwgeom_split output is not a line");
+ return -1;
+ }
+
+ /* Define the second new edge (from new node) */
+ newedges[1].start_node = node.node_id;
+ newedges[1].end_node = oldedge->end_node;
+ newedges[1].face_left = oldedge->face_left;
+ newedges[1].face_right = oldedge->face_right;
+ newedges[1].next_right = -newedges[0].edge_id;
+ if ( oldedge->next_left == -edge )
+ newedges[1].next_left = -newedges[1].edge_id;
+ else if ( oldedge->next_left == edge )
+ newedges[1].next_left = newedges[0].edge_id;
+ else
+ newedges[1].next_left = oldedge->next_left;
+ newedges[1].geom = lwgeom_as_lwline(newedge_geom);
+ /* lwgeom_split of a line should only return lines ... */
+ if ( ! newedges[1].geom ) {
+ lwcollection_release(split_col);
+ lwerror("second geometry in lwgeom_split output is not a line");
+ return -1;
+ }
+
+ /* Insert both new edges */
+ ret = lwt_be_insertEdges(topo, newedges, 2);
+ if ( ret == -1 ) {
+ lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+ return -1;
+ } else if ( ret == 0 ) {
+ lwcollection_release(split_col);
+ lwerror("Insertion of split edge failed (no reason)");
+ return -1;
+ }
+
+ /* Update all next edge references pointing to old edge id */
+
+ updedge.next_right = newedges[1].edge_id;
+ seledge.next_right = edge;
+ seledge.start_node = oldedge->start_node;
+ ret = lwt_be_updateEdges(topo,
+ &seledge, LWT_COL_EDGE_NEXT_RIGHT|LWT_COL_EDGE_START_NODE,
+ &updedge, LWT_COL_EDGE_NEXT_RIGHT,
+ NULL, 0);
+ if ( ret == -1 ) {
+ lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+ return -1;
+ }
+
+ updedge.next_right = -newedges[0].edge_id;
+ seledge.next_right = -edge;
+ seledge.start_node = oldedge->end_node;
+ ret = lwt_be_updateEdges(topo,
+ &seledge, LWT_COL_EDGE_NEXT_RIGHT|LWT_COL_EDGE_START_NODE,
+ &updedge, LWT_COL_EDGE_NEXT_RIGHT,
+ NULL, 0);
+ if ( ret == -1 ) {
+ lwcollection_release(split_col);
+ lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+ return -1;
+ }
+
+ updedge.next_left = newedges[0].edge_id;
+ seledge.next_left = edge;
+ seledge.end_node = oldedge->start_node;
+ ret = lwt_be_updateEdges(topo,
+ &seledge, LWT_COL_EDGE_NEXT_LEFT|LWT_COL_EDGE_END_NODE,
+ &updedge, LWT_COL_EDGE_NEXT_LEFT,
+ NULL, 0);
+ if ( ret == -1 ) {
+ lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+ return -1;
+ }
+
+ updedge.next_left = -newedges[1].edge_id;
+ seledge.next_left = -edge;
+ seledge.end_node = oldedge->end_node;
+ ret = lwt_be_updateEdges(topo,
+ &seledge, LWT_COL_EDGE_NEXT_LEFT|LWT_COL_EDGE_END_NODE,
+ &updedge, LWT_COL_EDGE_NEXT_LEFT,
+ NULL, 0);
+ if ( ret == -1 ) {
+ lwcollection_release(split_col);
+ lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+ return -1;
+ }
+
+ /* Update TopoGeometries composition -- TODO */
+ ret = lwt_be_updateTopoGeomEdgeSplit(topo, oldedge->edge_id, newedges[0].edge_id, newedges[1].edge_id);
+ if ( ! ret ) {
+ lwcollection_release(split_col);
+ lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+ return -1;
+ }
+
+ lwcollection_release(split_col);
+
+ /* return new node id */
+ return node.node_id;
+}
return SPI_processed;
}
+static int
+cb_deleteEdges( const LWT_BE_TOPOLOGY* topo,
+ const LWT_ISO_EDGE* sel_edge, int sel_fields )
+{
+ int spi_result;
+ StringInfoData sqldata;
+ StringInfo sql = &sqldata;
+
+ initStringInfo(sql);
+ appendStringInfo(sql, "DELETE FROM \"%s\".edge_data WHERE ", topo->name);
+ addEdgeUpdate( sql, sel_edge, sel_fields, 0, updSel );
+
+ /* lwpgnotice("cb_deleteEdges: %s", sql->data); */
+
+ spi_result = SPI_execute( sql->data, false, 0 );
+ 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);
+
+ lwpgnotice("cb_deleteEdges: delete query processed %d rows", SPI_processed);
+
+ return SPI_processed;
+}
+
static LWT_ELEMID
cb_getNextEdgeId( const LWT_BE_TOPOLOGY* topo )
{
} else {
appendStringInfoString(sql, "DELETE");
}
- appendStringInfo(sql, " FROM \"%s\".relation r, topology.layer l WHERE "
+ appendStringInfo( sql, " FROM \"%s\".relation r %s topology.layer l WHERE "
"l.topology_id = %d AND l.level = 0 AND l.layer_id = r.layer_id "
"AND abs(r.element_id) = %lld AND r.element_type = 2",
- topo->name, topo->id, split_edge);
+ topo->name, (new_edge2 == -1 ? "," : "USING" ), topo->id, split_edge );
if ( new_edge2 != -1 ) {
appendStringInfo(sql, " RETURNING %s", proj);
}
- spi_result = SPI_execute(sql->data, true, 0);
+ spi_result = SPI_execute(sql->data, new_edge2 == -1, 0);
if ( spi_result != ( new_edge2 == -1 ? SPI_OK_SELECT : SPI_OK_DELETE_RETURNING ) ) {
cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
spi_result, sql->data);
cb_updateEdges,
NULL, /* getFacesById */
cb_getFaceContainingPoint,
- cb_updateTopoGeomEdgeSplit
+ cb_updateTopoGeomEdgeSplit,
+ cb_deleteEdges
};
PG_RETURN_INT32(node_id);
}
+/* ST_NewEdgesSplit(atopology, anedge, apoint) */
+Datum ST_NewEdgesSplit(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(ST_NewEdgesSplit);
+Datum ST_NewEdgesSplit(PG_FUNCTION_ARGS)
+{
+ text* toponame_text;
+ char* toponame;
+ LWT_ELEMID edge_id;
+ LWT_ELEMID node_id;
+ GSERIALIZED *geom;
+ LWGEOM *lwgeom;
+ LWPOINT *pt;
+ LWT_TOPOLOGY *topo;
+
+ if ( PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2) ) {
+ 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);
+
+ edge_id = PG_GETARG_INT32(1) ;
+
+ geom = PG_GETARG_GSERIALIZED_P(2);
+ lwgeom = lwgeom_from_gserialized(geom);
+ pt = lwgeom_as_lwpoint(lwgeom);
+ if ( ! pt ) {
+ lwgeom_free(lwgeom);
+ PG_FREE_IF_COPY(geom, 2);
+ lwpgerror("ST_NewEdgesSplit third argument must be a point geometry");
+ PG_RETURN_NULL();
+ }
+
+ if ( SPI_OK_CONNECT != SPI_connect() ) {
+ lwpgerror("Could not connect to SPI");
+ PG_RETURN_NULL();
+ }
+
+ 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_NewEdgesSplit");
+ node_id = lwt_NewEdgesSplit(topo, edge_id, pt, 0);
+ POSTGIS_DEBUG(1, "lwt_NewEdgesSplit returned");
+ lwgeom_free(lwgeom);
+ PG_FREE_IF_COPY(geom, 3);
+ lwt_FreeTopology(topo);
+
+ if ( node_id == -1 ) {
+ /* should never reach this point, as lwerror would raise an exception */
+ SPI_finish();
+ PG_RETURN_NULL();
+ }
+
+ SPI_finish();
+ PG_RETURN_INT32(node_id);
+}
+
/* ST_AddIsoNode(atopology, aface, apoint) */
Datum ST_AddIsoNode(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(ST_AddIsoNode);
--
CREATE OR REPLACE FUNCTION topology.ST_NewEdgesSplit(atopology varchar, anedge integer, apoint geometry)
RETURNS INTEGER AS
-$$
-DECLARE
- oldedge RECORD;
- rec RECORD;
- tmp integer;
- topoid integer;
- nodeid integer;
- nodepos float8;
- edgeid1 integer;
- edgeid2 integer;
- edge1 geometry;
- edge2 geometry;
- ok BOOL;
-BEGIN
-
- --
- -- All args required
- --
- IF atopology IS NULL OR anedge IS NULL OR apoint IS NULL THEN
- RAISE EXCEPTION
- 'SQL/MM Spatial exception - null argument';
- END IF;
-
- -- Get topology id
- BEGIN
- SELECT id FROM topology.topology
- INTO STRICT topoid WHERE name = atopology;
- EXCEPTION
- WHEN NO_DATA_FOUND THEN
- RAISE EXCEPTION 'SQL/MM Spatial exception - invalid topology name';
- END;
-
- --
- -- Check edge existance
- --
- ok = false;
- FOR oldedge IN EXECUTE 'SELECT * FROM '
- || quote_ident(atopology) || '.edge_data ' ||
- ' WHERE edge_id = ' || anedge
- LOOP
- ok = true;
- END LOOP;
- IF NOT ok THEN
- RAISE EXCEPTION
- 'SQL/MM Spatial exception - non-existent edge';
- END IF;
-
- --
- -- Check that given point is Within(anedge.geom)
- --
- IF NOT ST_Within(apoint, oldedge.geom) THEN
- RAISE EXCEPTION
- 'SQL/MM Spatial exception - point not on edge';
- END IF;
-
- --
- -- Check if a coincident node already exists
- --
- FOR rec IN EXECUTE 'SELECT node_id FROM '
- || quote_ident(atopology) || '.node WHERE geom && $1 '
- || ' AND ST_X(geom) = ST_X($1) AND ST_Y(geom) = ST_Y($1)'
- USING apoint
- LOOP
- RAISE EXCEPTION
- 'SQL/MM Spatial exception - coincident node';
- END LOOP;
-
- --
- -- Get new node id
- --
- FOR rec IN EXECUTE 'SELECT nextval(''' ||
- atopology || '.node_node_id_seq'')'
- LOOP
- nodeid = rec.nextval;
- END LOOP;
-
- --RAISE NOTICE 'Next node id = % ', nodeid;
-
- --
- -- Add the new node
- --
- EXECUTE 'INSERT INTO ' || quote_ident(atopology)
- || '.node(node_id, geom) VALUES($1, $2)'
- USING nodeid, apoint;
-
- --
- -- Delete the old edge
- --
- EXECUTE 'DELETE FROM ' || quote_ident(atopology)
- || '.edge_data WHERE edge_id = $1'
- USING anedge;
-
- --
- -- Compute new edges
- --
- edge2 := ST_Split(oldedge.geom, apoint);
- edge1 := ST_GeometryN(edge2, 1);
- edge2 := ST_GeometryN(edge2, 2);
-
- --
- -- Get ids for the new edges
- --
- FOR rec IN EXECUTE 'SELECT nextval(''' ||
- atopology || '.edge_data_edge_id_seq'')'
- LOOP
- edgeid1 = rec.nextval;
- END LOOP;
- FOR rec IN EXECUTE 'SELECT nextval(''' ||
- atopology || '.edge_data_edge_id_seq'')'
- LOOP
- edgeid2 = rec.nextval;
- END LOOP;
-
-#ifdef POSTGIS_TOPOLOGY_DEBUG
- RAISE DEBUG ' inserting new edges % and % split from %', edgeid1, edgeid2, anedge;
-#endif
-
- --RAISE NOTICE 'EdgeId1 % EdgeId2 %', edgeid1, edgeid2;
-
- --RAISE DEBUG 'oldedge.next_left_edge: %', oldedge.next_left_edge;
- --RAISE DEBUG 'oldedge.next_right_edge: %', oldedge.next_right_edge;
-
- --
- -- Insert the two new edges
- --
- EXECUTE 'INSERT INTO ' || quote_ident(atopology)
- || '.edge VALUES('
- || edgeid1 -- edge_id
- || ',' || oldedge.start_node -- start_node
- || ',' || nodeid -- end_node
- || ',' || edgeid2 -- next_left_edge
- || ',' || CASE -- next_right_edge
- WHEN
- oldedge.next_right_edge = anedge
- THEN edgeid1
- WHEN
- oldedge.next_right_edge = -anedge
- THEN -edgeid2
- ELSE oldedge.next_right_edge
- END
- || ',' || oldedge.left_face -- left_face
- || ',' || oldedge.right_face -- right_face
- || ',$1)' -- geom
- USING edge1;
-
- EXECUTE 'INSERT INTO ' || quote_ident(atopology)
- || '.edge VALUES('
- || edgeid2 -- edge_id
- || ',' || nodeid -- start_node
- || ',' || oldedge.end_node -- end_node
- || ',' || CASE -- next_left_edge
- WHEN
- oldedge.next_left_edge =
- -anedge
- THEN -edgeid2
- WHEN
- oldedge.next_left_edge =
- anedge
- THEN edgeid1
- ELSE oldedge.next_left_edge
- END
- || ',' || -edgeid1 -- next_right_edge
- || ',' || oldedge.left_face -- left_face
- || ',' || oldedge.right_face -- right_face
- || ',$1)' -- geom
- USING edge2;
-
- --
- -- Update all next edge references to match new layout (ST_NewEdgeSplit)
- --
-
- EXECUTE 'UPDATE ' || quote_ident(atopology)
- || '.edge_data SET next_right_edge = '
- || edgeid2
- || ','
- || ' abs_next_right_edge = ' || edgeid2
- || ' WHERE next_right_edge = ' || anedge
- || ' AND start_node = ' || oldedge.start_node
- || ' AND edge_id NOT IN (' || edgeid1 || ',' || edgeid2 || ')'
- ;
- EXECUTE 'UPDATE ' || quote_ident(atopology)
- || '.edge_data SET next_right_edge = '
- || -edgeid1
- || ','
- || ' abs_next_right_edge = ' || edgeid1
- || ' WHERE next_right_edge = ' || -anedge
- || ' AND start_node = ' || oldedge.end_node
- || ' AND edge_id NOT IN (' || edgeid1 || ',' || edgeid2 || ')'
- ;
-
- EXECUTE 'UPDATE ' || quote_ident(atopology)
- || '.edge_data SET next_left_edge = '
- || edgeid1
- || ','
- || ' abs_next_left_edge = ' || edgeid1
- || ' WHERE next_left_edge = ' || anedge
- || ' AND end_node = ' || oldedge.start_node
- || ' AND edge_id NOT IN (' || edgeid1 || ',' || edgeid2 || ')'
- ;
- EXECUTE 'UPDATE ' || quote_ident(atopology)
- || '.edge_data SET '
- || ' next_left_edge = ' || -edgeid2
- || ','
- || ' abs_next_left_edge = ' || edgeid2
- || ' WHERE next_left_edge = ' || -anedge
- || ' AND end_node = ' || oldedge.end_node
- || ' AND edge_id NOT IN (' || edgeid1 || ',' || edgeid2 || ')'
- ;
-
- --
- -- Update references in the Relation table.
- -- We only take into considerations non-hierarchical
- -- TopoGeometry here, for obvious reasons.
- --
- FOR rec IN EXECUTE 'SELECT r.* FROM '
- || quote_ident(atopology)
- || '.relation r, topology.layer l '
- || ' WHERE '
- || ' l.topology_id = ' || topoid
- || ' AND l.level = 0 '
- || ' AND l.layer_id = r.layer_id '
- || ' AND abs(r.element_id) = ' || anedge
- || ' AND r.element_type = 2'
- LOOP
- --RAISE NOTICE 'TopoGeometry % in layer % contains the edge being split', rec.topogeo_id, rec.layer_id;
-
- -- Delete old reference
- EXECUTE 'DELETE FROM ' || quote_ident(atopology)
- || '.relation '
- || ' WHERE '
- || 'layer_id = ' || rec.layer_id
- || ' AND '
- || 'topogeo_id = ' || rec.topogeo_id
- || ' AND '
- || 'element_type = ' || rec.element_type
- || ' AND '
- || 'abs(element_id) = ' || anedge;
-
- -- Add new reference to edge1
- IF rec.element_id < 0 THEN
- tmp = -edgeid1;
- ELSE
- tmp = edgeid1;
- END IF;
- EXECUTE 'INSERT INTO ' || quote_ident(atopology)
- || '.relation '
- || ' VALUES( '
- || rec.topogeo_id
- || ','
- || rec.layer_id
- || ','
- || tmp
- || ','
- || rec.element_type
- || ')';
-
- -- Add new reference to edge2
- IF rec.element_id < 0 THEN
- tmp = -edgeid2;
- ELSE
- tmp = edgeid2;
- END IF;
- EXECUTE 'INSERT INTO ' || quote_ident(atopology)
- || '.relation '
- || ' VALUES( '
- || rec.topogeo_id
- || ','
- || rec.layer_id
- || ','
- || tmp
- || ','
- || rec.element_type
- || ')';
-
- END LOOP;
-
- --RAISE NOTICE 'Edge % split in edges % and % by node %',
- -- anedge, edgeid1, edgeid2, nodeid;
-
- RETURN nodeid;
-END
-$$
-LANGUAGE 'plpgsql' VOLATILE;
+ 'MODULE_PATHNAME','ST_NewEdgesSplit'
+ LANGUAGE 'c' VOLATILE;
--} ST_NewEdgesSplit
--{