return _lwt_AddEdge( topo, start_node, end_node, geom, skipChecks, 0 );
}
+static LWGEOM *
+_lwt_FaceByEdges(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edges, int numfaceedges)
+{
+ LWGEOM *outg;
+ LWCOLLECTION *bounds;
+ LWGEOM **geoms = lwalloc( sizeof(LWGEOM*) * numfaceedges );
+ int i, validedges = 0;
+
+ for ( i=0; i<numfaceedges; ++i )
+ {
+ /* NOTE: skipping edges with same face on both sides, although
+ * correct, results in a failure to build faces from
+ * invalid topologies as expected by legacy tests.
+ * TODO: update legacy tests expectances/unleash this skipping ?
+ */
+ /* if ( edges[i].face_left == edges[i].face_right ) continue; */
+ geoms[validedges++] = lwline_as_lwgeom(edges[i].geom);
+ }
+ if ( ! validedges )
+ {
+ /* Face has no valid boundary edges, we'll return EMPTY, see
+ * https://trac.osgeo.org/postgis/ticket/3221 */
+ if ( numfaceedges ) lwfree(geoms);
+ LWDEBUG(1, "_lwt_FaceByEdges returning empty polygon");
+ return lwpoly_as_lwgeom(
+ lwpoly_construct_empty(topo->srid, topo->hasZ, 0)
+ );
+ }
+ bounds = lwcollection_construct(MULTILINETYPE,
+ topo->srid,
+ NULL, /* gbox */
+ validedges,
+ geoms);
+ outg = lwgeom_buildarea( lwcollection_as_lwgeom(bounds) );
+ lwcollection_release(bounds);
+ lwfree(geoms);
+#if 0
+ {
+ size_t sz;
+ char *wkt = lwgeom_to_wkt(outg, WKT_ISO, 2, &sz);
+ LWDEBUGF(1, "_lwt_FaceByEdges returning area: %s", wkt);
+ lwfree(wkt);
+ }
+#endif
+ return outg;
+}
+
LWGEOM*
lwt_GetFaceGeometry(LWT_TOPOLOGY* topo, LWT_ELEMID faceid)
{
return lwpoly_as_lwgeom(out);
}
- /* Linemerge polygon boundaries */
+ outg = _lwt_FaceByEdges( topo, edges, numfaceedges );
+ _lwt_release_edges(edges, numfaceedges);
- LWGEOM **geoms = lwalloc( sizeof(LWGEOM*) * numfaceedges );
- int validedges = 0;
- for ( i=0; i<numfaceedges; ++i )
- {
- /* NOTE: skipping edges with same face on both sides, although
- * correct, results in a failure to build faces from
- * invalid topologies as expected by legacy tests.
- * TODO: update legacy tests expectances/unleash this skipping ?
- */
- /* if ( edges[i].face_left == edges[i].face_right ) continue; */
- geoms[validedges++] = lwline_as_lwgeom(edges[i].geom);
- }
- if ( ! validedges )
+ return outg;
+}
+
+/* Find which edge from the "edges" set defines the next
+ * portion of the given "ring".
+ *
+ * The edge might be either forward or backward.
+ *
+ * @param ring The ring to find definition of.
+ * It is assumed it does not contain duplicated vertices.
+ * @param from offset of the ring point to start looking from
+ * @param edges array of edges to search into
+ * @param numedges number of edges in the edges array
+ *
+ * @return index of the edge defining the next ring portion or
+ * -1 if no edge was found to be part of the ring
+ */
+static int
+_lwt_FindNextRingEdge(const POINTARRAY *ring, int from,
+ const LWT_ISO_EDGE *edges, int numedges)
+{
+ int i;
+ POINT2D p1;
+
+ /* Get starting ring point */
+ getPoint2d_p(ring, from, &p1);
+
+ LWDEBUGF(1, "Ring's 'from' point (%d) is %g,%g", from, p1.x, p1.y);
+
+ /* find the edges defining the next portion of ring starting from
+ * vertex "from" */
+ for ( i=0; i<numedges; ++i )
{
- lwfree(geoms);
- /* Face has no valid boundary edges, we'll return EMPTY, see
- * https://trac.osgeo.org/postgis/ticket/3221 */
- out = lwpoly_construct_empty(topo->srid, topo->hasZ, 0);
- return lwpoly_as_lwgeom(out);
- }
- LWCOLLECTION *bounds = lwcollection_construct(MULTILINETYPE,
- topo->srid,
- NULL, /* gbox */
- validedges,
- geoms);
-#if 0 /* debugging (a leaking one) */
- lwnotice("Collected face bounds: %s", lwgeom_to_wkt((LWGEOM*)bounds,
- WKT_ISO, 2, NULL));
+ const LWT_ISO_EDGE *isoe = &(edges[i]);
+ LWLINE *edge = isoe->geom;
+ POINTARRAY *epa = edge->points;
+ POINT2D p2, pt;
+ int match = 0;
+ int j;
+
+ /* Skip if the edge is a dangling one */
+ if ( isoe->face_left == isoe->face_right )
+ {
+ LWDEBUGF(3, "_lwt_FindNextRingEdge: edge %" PRId64
+ " has same face (%" PRId64
+ ") on both sides, skipping",
+ isoe->edge_id, isoe->face_left);
+ continue;
+ }
+
+#if 0
+ size_t sz;
+ LWDEBUGF(1, "Edge %" PRId64 " is %s",
+ isoe->edge_id,
+ lwgeom_to_wkt(lwline_as_lwgeom(edge), WKT_ISO, 2, &sz));
#endif
- outg = lwgeom_buildarea( lwcollection_as_lwgeom(bounds) );
+ /* ptarray_remove_repeated_points ? */
- _lwt_release_edges(edges, numfaceedges);
- lwcollection_release(bounds);
+ getPoint2d_p(epa, 0, &p2);
+ LWDEBUGF(1, "Edges's 'first' point is %g,%g", p2.x, p2.y);
+ LWDEBUGF(1, "Rings's 'from' point is still %g,%g", p1.x, p1.y);
+ if ( p2d_same(&p1, &p2) )
+ {
+ LWDEBUG(1, "p2d_same(p1,p2) returned true");
+ LWDEBUGF(1, "First point of edge %" PRId64
+ " matches ring vertex %d", isoe->edge_id, from);
+ /* first point matches, let's check next non-equal one */
+ for ( j=1; j<epa->npoints; ++j )
+ {
+ getPoint2d_p(epa, j, &p2);
+ /* we won't check duplicated edge points */
+ if ( p2d_same(&p1, &p2) ) continue;
+ /* we assume there are no duplicated points in ring */
+ getPoint2d_p(ring, from+1, &pt);
+ if ( p2d_same(&pt, &p2) )
+ {
+ match = 1;
+ break; /* no need to check more */
+ }
+ }
+ }
+ else
+ {
+ LWDEBUG(1, "p2d_same(p1,p2) returned false");
+ getPoint2d_p(epa, epa->npoints-1, &p2);
+ LWDEBUGF(1, "Edges's 'last' point is %g,%g", p2.x, p2.y);
+ if ( p2d_same(&p1, &p2) )
+ {
+ LWDEBUGF(1, "Last point of edge %" PRId64
+ " matches ring vertex %d", isoe->edge_id, from);
+ /* last point matches, let's check next non-equal one */
+ for ( j=epa->npoints-2; j>=0; --j )
+ {
+ getPoint2d_p(epa, j, &p2);
+ /* we won't check duplicated edge points */
+ if ( p2d_same(&p1, &p2) ) continue;
+ /* we assume there are no duplicated points in ring */
+ getPoint2d_p(ring, from+1, &pt);
+ if ( p2d_same(&pt, &p2) )
+ {
+ match = 1;
+ break; /* no need to check more */
+ }
+ }
+ }
+ }
- return outg;
+ if ( match ) return i;
+
+ }
+
+ return -1;
}
+/* Reverse values in array between "from" (inclusive)
+ * and "to" (exclusive) indexes */
+static void
+_lwt_ReverseElemidArray(LWT_ELEMID *ary, int from, int to)
+{
+ LWT_ELEMID t;
+ while (from < to)
+ {
+ t = ary[from];
+ ary[from++] = ary[to];
+ ary[to--] = t;
+ }
+}
+
+/* Rotate values in array between "from" (inclusive)
+ * and "to" (exclusive) indexes, so that "rotidx" is
+ * the new value at "from" */
+static void
+_lwt_RotateElemidArray(LWT_ELEMID *ary, int from, int to, int rotidx)
+{
+ _lwt_ReverseElemidArray(ary, from, rotidx-1);
+ _lwt_ReverseElemidArray(ary, rotidx, to-1);
+ _lwt_ReverseElemidArray(ary, from, to-1);
+}
+
+
int
-lwt_GetFaceEdges(LWT_TOPOLOGY* topo, LWT_ELEMID face, LWT_ELEMID **edges)
+lwt_GetFaceEdges(LWT_TOPOLOGY* topo, LWT_ELEMID face_id, LWT_ELEMID **out )
{
- /* TODO: Construct the face geometry */
- /* TODO: Then for each ring of the face polygon... */
- lwerror("lwt_GetFaceEdges not implemented yet");
- return -1;
+ LWGEOM *face;
+ LWPOLY *facepoly;
+ LWT_ISO_EDGE *edges;
+ int numfaceedges;
+ int fields, i;
+ int nseid = 0; /* number of signed edge ids */
+ int prevseid;
+ LWT_ELEMID *seid; /* signed edge ids */
+
+ /* Get list of face edges */
+ numfaceedges = 1;
+ fields = LWT_COL_EDGE_EDGE_ID |
+ LWT_COL_EDGE_GEOM |
+ LWT_COL_EDGE_FACE_LEFT |
+ LWT_COL_EDGE_FACE_RIGHT
+ ;
+ edges = lwt_be_getEdgeByFace( topo, &face_id, &numfaceedges, fields );
+ if ( numfaceedges == -1 ) {
+ lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
+ return -1;
+ }
+ if ( ! numfaceedges ) return 0; /* no edges in output */
+
+ /* order edges by occurrence in face */
+
+ face = _lwt_FaceByEdges(topo, edges, numfaceedges);
+ if ( ! face )
+ {
+ /* _lwt_FaceByEdges should have already invoked lwerror in this case */
+ _lwt_release_edges(edges, numfaceedges);
+ return -1;
+ }
+
+ if ( lwgeom_is_empty(face) )
+ {
+ /* no edges in output */
+ _lwt_release_edges(edges, numfaceedges);
+ lwgeom_free(face);
+ return 0;
+ }
+
+ /* force_lhr, if the face is not the universe */
+ /* _lwt_FaceByEdges seems to guaranteed RHR */
+ /* lwgeom_force_clockwise(face); */
+ if ( face_id ) lwgeom_reverse(face);
+
+#if 0
+ {
+ size_t sz;
+ char *wkt = lwgeom_to_wkt(face, WKT_ISO, 2, &sz);
+ LWDEBUGF(1, "Geometry of face %" PRId64 " is: %s",
+ face_id, wkt);
+ lwfree(wkt);
+ }
+#endif
+
+ facepoly = lwgeom_as_lwpoly(face);
+ if ( ! facepoly )
+ {
+ _lwt_release_edges(edges, numfaceedges);
+ lwgeom_free(face);
+ lwerror("Geometry of face %" PRId64 " is not a polygon", face_id);
+ return -1;
+ }
+
+ nseid = prevseid = 0;
+ seid = lwalloc( sizeof(LWT_ELEMID) * numfaceedges );
+
+ /* for each ring of the face polygon... */
+ for ( i=0; i<facepoly->nrings; ++i )
+ {
+ const POINTARRAY *ring = facepoly->rings[i];
+ int j = 0;
+ LWT_ISO_EDGE *nextedge;
+ LWLINE *nextline;
+
+ LWDEBUGF(1, "Ring %d has %d points", i, ring->npoints);
+
+ while ( j < ring->npoints-1 )
+ {
+ LWDEBUGF(1, "Looking for edge covering ring %d from vertex %d",
+ i, j);
+
+ int edgeno = _lwt_FindNextRingEdge(ring, j, edges, numfaceedges);
+ if ( edgeno == -1 )
+ {
+ /* should never happen */
+ _lwt_release_edges(edges, numfaceedges);
+ lwgeom_free(face);
+ lwfree(seid);
+ lwerror("No edge (among %d) found to be defining geometry of face %"
+ PRId64, face_id);
+ return -1;
+ }
+
+ nextedge = &(edges[edgeno]);
+ nextline = nextedge->geom;
+
+ LWDEBUGF(1, "Edge %" PRId64
+ " covers ring %d from vertex %d to %d",
+ nextedge->edge_id, i, j, j + nextline->points->npoints - 1);
+
+#if 0
+ size_t sz;
+ LWDEBUGF(1, "Edge %" PRId64 " is %s",
+ nextedge->edge_id,
+lwgeom_to_wkt(lwline_as_lwgeom(nextline), WKT_ISO, 2, &sz));
+#endif
+
+ j += nextline->points->npoints - 1;
+
+ /* Add next edge to the output array */
+ seid[nseid++] = nextedge->face_left == face_id ?
+ nextedge->edge_id :
+ -nextedge->edge_id;
+
+ /* avoid checking again on next time turn */
+ nextedge->face_left = nextedge->face_right = -1;
+ }
+
+ /* TODO: now "scroll" the list of edges so that the one
+ * with smaller absolute edge_id is first */
+ /* Range is: [prevseid, nseid) -- [inclusive, exclusive) */
+ if ( (nseid - prevseid) > 1 )
+ {{
+ LWT_ELEMID minid = 0;
+ int minidx = 0;
+ LWDEBUGF(1, "Looking for smallest id among the %d edges "
+ "composing ring %d", (nseid-prevseid), i);
+ for ( j=prevseid; j<nseid; ++j )
+ {
+ LWT_ELEMID id = llabs(seid[j]);
+ LWDEBUGF(1, "Abs id of edge in pos %d is %" PRId64, j, id);
+ if ( ! minid || id < minid )
+ {
+ minid = id;
+ minidx = j;
+ }
+ }
+ LWDEBUGF(1, "Smallest id is %" PRId64
+ " at position %d", minid, minidx);
+ if ( minidx != prevseid )
+ {
+ _lwt_RotateElemidArray(seid, prevseid, nseid, minidx);
+ }
+ }}
+
+ prevseid = nseid;
+ }
+
+ lwgeom_free(face);
+ _lwt_release_edges(edges, numfaceedges);
+
+ *out = seid;
+ return nseid;
}
#include "utils/elog.h"
#include "utils/memutils.h" /* for TopMemoryContext */
#include "lib/stringinfo.h"
-//#include "funcapi.h"
+#include "funcapi.h" /* for FuncCallContext */
#include "executor/spi.h" /* this is what you need to work with SPI */
#include "inttypes.h" /* for PRId64 */
#include "liblwgeom_internal.h" /* for gbox_clone */
#include "liblwgeom_topo.h"
-/*#define POSTGIS_DEBUG_LEVEL 1*/
+#define POSTGIS_DEBUG_LEVEL 1
#include "lwgeom_log.h"
#include "lwgeom_pg.h"
Datum dat;
bool isnull;
LWT_BE_TOPOLOGY *topo;
+ MemoryContext oldcontext = CurrentMemoryContext;
initStringInfo(sql);
appendStringInfo(sql, "SELECT id,srid FROM topology.topology "
"WHERE name = '%s'", name);
spi_result = SPI_execute(sql->data, !be->data_changed, 0);
+ MemoryContextSwitchTo( oldcontext ); /* switch back */
if ( spi_result != SPI_OK_SELECT ) {
pfree(sqldata.data);
cberror(be, "unexpected return (%d) from query execution: %s", spi_result, sql->data);
{
LWT_ISO_EDGE *edges;
int spi_result;
-
+ MemoryContext oldcontext = CurrentMemoryContext;
StringInfoData sqldata;
StringInfo sql = &sqldata;
int i;
POSTGIS_DEBUGF(1, "cb_getEdgeById query: %s", sql->data);
spi_result = SPI_execute(sql->data, !topo->be_data->data_changed, *numelems);
+ 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);
*numelems = -1; return NULL;
StringInfoData sqldata;
StringInfo sql = &sqldata;
int i;
+ MemoryContext oldcontext = CurrentMemoryContext;
initStringInfo(sql);
appendStringInfoString(sql, "SELECT ");
POSTGIS_DEBUGF(1, "data_changed is %d", topo->be_data->data_changed);
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);
*numelems = -1; return NULL;
{
LWT_ISO_EDGE *edges;
int spi_result;
+ MemoryContext oldcontext = CurrentMemoryContext;
StringInfoData sqldata;
StringInfo sql = &sqldata;
POSTGIS_DEBUGF(1, "data_changed is %d", topo->be_data->data_changed);
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);
*numelems = -1; return NULL;
{
LWT_ISO_FACE *faces;
int spi_result;
-
StringInfoData sqldata;
StringInfo sql = &sqldata;
int i;
+ MemoryContext oldcontext = CurrentMemoryContext;
initStringInfo(sql);
appendStringInfoString(sql, "SELECT ");
POSTGIS_DEBUGF(1, "data_changed is %d", topo->be_data->data_changed);
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);
*numelems = -1; return NULL;
StringInfoData sqldata;
StringInfo sql = &sqldata;
int i;
+ MemoryContext oldcontext = CurrentMemoryContext;
initStringInfo(sql);
appendStringInfo(sql, "WITH RECURSIVE edgering AS ( "
POSTGIS_DEBUGF(1, "cb_getRingEdges query (limit %d): %s", limit, sql->data);
spi_result = SPI_execute(sql->data, !topo->be_data->data_changed, limit);
+ 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);
*numelems = -1; return NULL;
}
val = DatumGetInt32(dat);
edges[i] = val;
- POSTGIS_DEBUGF(1, "Component %d in ring of edge %" PRId64 " is edge %d",
- i, edge, val);
+ POSTGIS_DEBUGF(1, "Component %d in ring of edge " INT64_FORMAT
+ " is edge %d", i, edge, val);
}
return edges;
StringInfoData sqldata;
StringInfo sql = &sqldata;
int i;
+ MemoryContext oldcontext = CurrentMemoryContext;
initStringInfo(sql);
appendStringInfoString(sql, "SELECT ");
appendStringInfoString(sql, ")");
POSTGIS_DEBUGF(1, "cb_getNodeById query: %s", sql->data);
spi_result = SPI_execute(sql->data, !topo->be_data->data_changed, *numelems);
+ 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);
*numelems = -1; return NULL;
{
LWT_ISO_NODE *nodes;
int spi_result;
-
+ MemoryContext oldcontext = CurrentMemoryContext;
StringInfoData sqldata;
StringInfo sql = &sqldata;
int i;
POSTGIS_DEBUGF(1, "cb_getNodeByFace query: %s", sql->data);
POSTGIS_DEBUGF(1, "data_changed is %d", topo->be_data->data_changed);
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);
*numelems = -1; return NULL;
int elems_requested = limit;
size_t hexewkb_size;
char *hexewkb;
-
+ MemoryContext oldcontext = CurrentMemoryContext;
StringInfoData sqldata;
StringInfo sql = &sqldata;
int i;
}
lwpgnotice("cb_getEdgeWithinDistance2D: query is: %s", sql->data);
spi_result = SPI_execute(sql->data, !topo->be_data->data_changed, limit >= 0 ? limit : 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);
*numelems = -1; return NULL;
const LWPOINT* pt, double dist, int* numelems,
int fields, int limit)
{
+ MemoryContext oldcontext = CurrentMemoryContext;
LWT_ISO_NODE *nodes;
int spi_result;
size_t hexewkb_size;
appendStringInfo(sql, " LIMIT %d", elems_requested);
}
spi_result = SPI_execute(sql->data, !topo->be_data->data_changed, limit >= 0 ? limit : 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);
cb_insertNodes( const LWT_BE_TOPOLOGY* topo,
LWT_ISO_NODE* nodes, int numelems )
{
+ MemoryContext oldcontext = CurrentMemoryContext;
int spi_result;
StringInfoData sqldata;
StringInfo sql = &sqldata;
POSTGIS_DEBUGF(1, "cb_insertNodes query: %s", sql->data);
spi_result = SPI_execute(sql->data, false, numelems);
+ MemoryContextSwitchTo( oldcontext ); /* switch back */
if ( spi_result != SPI_OK_INSERT_RETURNING ) {
cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
spi_result, sql->data);
cb_insertEdges( const LWT_BE_TOPOLOGY* topo,
LWT_ISO_EDGE* edges, int numelems )
{
+ MemoryContext oldcontext = CurrentMemoryContext;
int spi_result;
StringInfoData sqldata;
StringInfo sql = &sqldata;
POSTGIS_DEBUGF(1, "cb_insertEdges query (%d elems): %s", numelems, sql->data);
spi_result = SPI_execute(sql->data, false, numelems);
+ MemoryContextSwitchTo( oldcontext ); /* switch back */
if ( spi_result != ( needsEdgeIdReturn ? SPI_OK_INSERT_RETURNING : SPI_OK_INSERT ) )
{
cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
cb_insertFaces( const LWT_BE_TOPOLOGY* topo,
LWT_ISO_FACE* faces, int numelems )
{
+ MemoryContext oldcontext = CurrentMemoryContext;
int spi_result;
StringInfoData sqldata;
StringInfo sql = &sqldata;
POSTGIS_DEBUGF(1, "cb_insertFaces query (%d elems): %s", numelems, sql->data);
spi_result = SPI_execute(sql->data, false, numelems);
+ MemoryContextSwitchTo( oldcontext ); /* switch back */
if ( spi_result != ( needsFaceIdReturn ? SPI_OK_INSERT_RETURNING : SPI_OK_INSERT ) )
{
cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
const LWT_ISO_EDGE* upd_edge, int upd_fields,
const LWT_ISO_EDGE* exc_edge, int exc_fields )
{
+ MemoryContext oldcontext = CurrentMemoryContext;
int spi_result;
StringInfoData sqldata;
StringInfo sql = &sqldata;
POSTGIS_DEBUGF(1, "cb_updateEdges query: %s", sql->data);
spi_result = SPI_execute( sql->data, false, 0 );
+ MemoryContextSwitchTo( oldcontext ); /* switch back */
if ( spi_result != SPI_OK_UPDATE )
{
cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
const LWT_ISO_NODE* upd_node, int upd_fields,
const LWT_ISO_NODE* exc_node, int exc_fields )
{
+ MemoryContext oldcontext = CurrentMemoryContext;
int spi_result;
StringInfoData sqldata;
StringInfo sql = &sqldata;
POSTGIS_DEBUGF(1, "cb_updateNodes: %s", sql->data);
spi_result = SPI_execute( sql->data, false, 0 );
+ MemoryContextSwitchTo( oldcontext ); /* switch back */
if ( spi_result != SPI_OK_UPDATE )
{
cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
cb_updateNodesById( const LWT_BE_TOPOLOGY* topo,
const LWT_ISO_NODE* nodes, int numnodes, int fields )
{
+ MemoryContext oldcontext = CurrentMemoryContext;
int i;
int spi_result;
StringInfoData sqldata;
POSTGIS_DEBUGF(1, "cb_updateNodesById query: %s", sql->data);
spi_result = SPI_execute( sql->data, false, 0 );
+ MemoryContextSwitchTo( oldcontext ); /* switch back */
if ( spi_result != SPI_OK_UPDATE )
{
cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
cb_updateFacesById( const LWT_BE_TOPOLOGY* topo,
const LWT_ISO_FACE* faces, int numfaces )
{
+ MemoryContext oldcontext = CurrentMemoryContext;
int i;
int spi_result;
StringInfoData sqldata;
POSTGIS_DEBUGF(1, "cb_updateFacesById query: %s", sql->data);
spi_result = SPI_execute( sql->data, false, 0 );
+ MemoryContextSwitchTo( oldcontext ); /* switch back */
if ( spi_result != SPI_OK_UPDATE )
{
cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
cb_updateEdgesById( const LWT_BE_TOPOLOGY* topo,
const LWT_ISO_EDGE* edges, int numedges, int fields )
{
+ MemoryContext oldcontext = CurrentMemoryContext;
int i;
int spi_result;
StringInfoData sqldata;
POSTGIS_DEBUGF(1, "cb_updateEdgesById query: %s", sql->data);
spi_result = SPI_execute( sql->data, false, 0 );
+ MemoryContextSwitchTo( oldcontext ); /* switch back */
if ( spi_result != SPI_OK_UPDATE )
{
cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
cb_deleteEdges( const LWT_BE_TOPOLOGY* topo,
const LWT_ISO_EDGE* sel_edge, int sel_fields )
{
+ MemoryContext oldcontext = CurrentMemoryContext;
int spi_result;
StringInfoData sqldata;
StringInfo sql = &sqldata;
POSTGIS_DEBUGF(1, "cb_deleteEdges: %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",
static LWT_ELEMID
cb_getNextEdgeId( const LWT_BE_TOPOLOGY* topo )
{
+ MemoryContext oldcontext = CurrentMemoryContext;
int spi_result;
StringInfoData sqldata;
StringInfo sql = &sqldata;
appendStringInfo(sql, "SELECT nextval('\"%s\".edge_data_edge_id_seq')",
topo->name);
spi_result = SPI_execute(sql->data, false, 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);
cb_updateTopoGeomEdgeSplit ( const LWT_BE_TOPOLOGY* topo,
LWT_ELEMID split_edge, LWT_ELEMID new_edge1, LWT_ELEMID new_edge2 )
{
+ MemoryContext oldcontext = CurrentMemoryContext;
int spi_result;
StringInfoData sqldata;
StringInfo sql = &sqldata;
POSTGIS_DEBUGF(1, "cb_updateTopoGeomEdgeSplit query: %s", sql->data);
spi_result = SPI_execute(sql->data, new_edge2 == -1 ? !topo->be_data->data_changed : false, 0);
+ MemoryContextSwitchTo( oldcontext ); /* switch back */
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);
"%d,%d," INT64_FORMAT ",%d)", topo->name,
topogeo_id, layer_id, negate ? -new_edge1 : new_edge1, element_type);
spi_result = SPI_execute(sql->data, false, 0);
+ MemoryContextSwitchTo( oldcontext ); /* switch back */
if ( spi_result != SPI_OK_INSERT ) {
cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
spi_result, sql->data);
"%d,%d," INT64_FORMAT ",%d", topo->name,
topogeo_id, layer_id, negate ? -new_edge2 : new_edge2, element_type);
spi_result = SPI_execute(sql->data, false, 0);
+ MemoryContextSwitchTo( oldcontext ); /* switch back */
if ( spi_result != SPI_OK_INSERT ) {
cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
spi_result, sql->data);
}
}
+ /* TODO: release string info ! */
+
POSTGIS_DEBUGF(1, "cb_updateTopoGeomEdgeSplit: updated %d topogeoms", ntopogeoms);
return 1;
cb_updateTopoGeomFaceSplit ( const LWT_BE_TOPOLOGY* topo,
LWT_ELEMID split_face, LWT_ELEMID new_face1, LWT_ELEMID new_face2 )
{
+ MemoryContext oldcontext = CurrentMemoryContext;
int spi_result;
StringInfoData sqldata;
StringInfo sql = &sqldata;
const char *proj = "r.element_id, r.topogeo_id, r.layer_id, r.element_type";
POSTGIS_DEBUGF(1, "cb_updateTopoGeomFaceSplit signalled "
- "split of face %" PRId64 " into %" PRId64
- " and %" PRId64,
+ "split of face " INT64_FORMAT " into "
+ INT64_FORMAT " and " INT64_FORMAT,
split_face, new_face1, new_face2);
initStringInfo(sql);
POSTGIS_DEBUGF(1, "cb_updateTopoGeomFaceSplit query: %s", sql->data);
spi_result = SPI_execute(sql->data, new_face2 == -1 ? !topo->be_data->data_changed : false, 0);
+ MemoryContextSwitchTo( oldcontext ); /* switch back */
if ( spi_result != ( new_face2 == -1 ? SPI_OK_SELECT : SPI_OK_DELETE_RETURNING ) ) {
cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
spi_result, sql->data);
POSTGIS_DEBUGF(1, "cb_updateTopoGeomFaceSplit query: %s", sql->data);
spi_result = SPI_execute(sql->data, false, 0);
+ MemoryContextSwitchTo( oldcontext ); /* switch back */
if ( spi_result != SPI_OK_INSERT ) {
cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
spi_result, sql->data);
POSTGIS_DEBUGF(1, "cb_updateTopoGeomFaceSplit query: %s", sql->data);
spi_result = SPI_execute(sql->data, false, 0);
+ MemoryContextSwitchTo( oldcontext ); /* switch back */
if ( spi_result != SPI_OK_INSERT ) {
cberror(topo->be_data, "unexpected return (%d) from query execution: %s",
spi_result, sql->data);
}
}
+ /* TODO: release string info */
+
POSTGIS_DEBUGF(1, "cb_updateTopoGeomFaceSplit: updated %d topogeoms", ntopogeoms);
return 1;
static LWT_ELEMID
cb_getFaceContainingPoint( const LWT_BE_TOPOLOGY* topo, const LWPOINT* pt )
{
+ MemoryContext oldcontext = CurrentMemoryContext;
int spi_result;
StringInfoData sqldata;
StringInfo sql = &sqldata;
lwfree(hexewkb);
spi_result = SPI_execute(sql->data, !topo->be_data->data_changed, 1);
+ 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);
cb_deleteFacesById( const LWT_BE_TOPOLOGY* topo,
const LWT_ELEMID* ids, int numelems )
{
+ MemoryContext oldcontext = CurrentMemoryContext;
int spi_result, i;
StringInfoData sqldata;
StringInfo sql = &sqldata;
POSTGIS_DEBUGF(1, "cb_deleteFacesById 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",
cb_getNodeWithinBox2D ( const LWT_BE_TOPOLOGY* topo, const GBOX* box,
int* numelems, int fields, int limit )
{
+ MemoryContext oldcontext = CurrentMemoryContext;
int spi_result;
StringInfoData sqldata;
StringInfo sql = &sqldata;
}
lwpgnotice("cb_getNodeWithinBox2D: query is: %s", sql->data);
spi_result = SPI_execute(sql->data, !topo->be_data->data_changed, limit >= 0 ? limit : 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);
*numelems = -1; return NULL;
cb_getEdgeWithinBox2D ( const LWT_BE_TOPOLOGY* topo, const GBOX* box,
int* numelems, int fields, int limit )
{
+ MemoryContext oldcontext = CurrentMemoryContext;
int spi_result;
StringInfoData sqldata;
StringInfo sql = &sqldata;
}
lwpgnotice("cb_getEdgeWithinBox2D: query is: %s", sql->data);
spi_result = SPI_execute(sql->data, !topo->be_data->data_changed, limit >= 0 ? limit : 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);
*numelems = -1; return NULL;
PG_RETURN_POINTER(geom);
}
+
+typedef struct FACEEDGESSTATE
+{
+ LWT_ELEMID *elems;
+ int nelems;
+ int curr;
+}
+FACEEDGESSTATE;
+
+/* ST_GetFaceEdges(atopology, aface) */
+Datum ST_GetFaceEdges(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(ST_GetFaceEdges);
+Datum ST_GetFaceEdges(PG_FUNCTION_ARGS)
+{
+ text* toponame_text;
+ char* toponame;
+ LWT_ELEMID face_id;
+ int nelems;
+ LWT_ELEMID *elems;
+ LWT_TOPOLOGY *topo;
+ FuncCallContext *funcctx;
+ MemoryContext oldcontext, newcontext;
+ TupleDesc tupdesc;
+ HeapTuple tuple;
+ AttInMetadata *attinmeta;
+ FACEEDGESSTATE *state;
+ char buf[64];
+ char *values[2];
+ Datum result;
+
+ values[0] = buf;
+ values[1] = &(buf[32]);
+
+ if (SRF_IS_FIRSTCALL())
+ {
+
+ POSTGIS_DEBUG(1, "ST_GetFaceEdges first call");
+ funcctx = SRF_FIRSTCALL_INIT();
+ newcontext = funcctx->multi_call_memory_ctx;
+
+ 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);
+
+ face_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);
+ oldcontext = MemoryContextSwitchTo( newcontext );
+ 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_GetFaceEdges");
+ nelems = lwt_GetFaceEdges(topo, face_id, &elems);
+ POSTGIS_DEBUGF(1, "lwt_GetFaceEdges returned %d", nelems);
+ lwt_FreeTopology(topo);
+
+ if ( nelems < 0 ) {
+ /* should never reach this point, as lwerror would raise an exception */
+ SPI_finish();
+ PG_RETURN_NULL();
+ }
+
+ state = lwalloc(sizeof(FACEEDGESSTATE));
+ state->elems = elems;
+ state->nelems = nelems;
+ state->curr = 0;
+ funcctx->user_fctx = state;
+
+ /*
+ * Build a tuple description for an
+ * geometry_dump tuple
+ */
+ tupdesc = RelationNameGetTupleDesc("topology.getfaceedges_returntype");
+
+ /*
+ * generate attribute metadata needed later to produce
+ * tuples from raw C strings
+ */
+ attinmeta = TupleDescGetAttInMetadata(tupdesc);
+ funcctx->attinmeta = attinmeta;
+
+ POSTGIS_DEBUG(1, "lwt_GetFaceEdges calling SPI_finish");
+
+ MemoryContextSwitchTo(oldcontext);
+
+ SPI_finish();
+ }
+
+ /* stuff done on every call of the function */
+ funcctx = SRF_PERCALL_SETUP();
+
+ /* get state */
+ state = funcctx->user_fctx;
+
+ if ( state->curr == state->nelems )
+ {
+ SRF_RETURN_DONE(funcctx);
+ }
+
+ if ( snprintf(values[0], 32, "%d", state->curr+1) >= 32 )
+ {
+ lwerror("Face edge sequence number does not fit 32 chars ?!: %d",
+ state->curr+1);
+ }
+ if ( snprintf(values[1], 32, INT64_FORMAT,
+ state->elems[state->curr]) >= 32 )
+ {
+ lwerror("Signed edge identifier does not fit 32 chars ?!: "
+ INT64_FORMAT, state->elems[state->curr]);
+ }
+
+ POSTGIS_DEBUGF(1, "ST_GetFaceEdges: cur:%d, val0:%s, val1:%s",
+ state->curr, values[0], values[1]);
+
+ tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
+ result = HeapTupleGetDatum(tuple);
+ state->curr++;
+
+ SRF_RETURN_NEXT(funcctx, result);
+}