1 /*
2 
3  topo_callbacks.c -- implementation of Topology callback functions
4 
5  version 5.0, 2020 August 1
6 
7  Author: Sandro Furieri a.furieri@lqt.it
8 
9  -----------------------------------------------------------------------------
10 
11  Version: MPL 1.1/GPL 2.0/LGPL 2.1
12 
13  The contents of this file are subject to the Mozilla Public License Version
14  1.1 (the "License"); you may not use this file except in compliance with
15  the License. You may obtain a copy of the License at
16  http://www.mozilla.org/MPL/
17 
18 Software distributed under the License is distributed on an "AS IS" basis,
19 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
20 for the specific language governing rights and limitations under the
21 License.
22 
23 The Original Code is the SpatiaLite library
24 
25 The Initial Developer of the Original Code is Alessandro Furieri
26 
27 Portions created by the Initial Developer are Copyright (C) 2015-2021
28 the Initial Developer. All Rights Reserved.
29 
30 Contributor(s):
31 
32 Alternatively, the contents of this file may be used under the terms of
33 either the GNU General Public License Version 2 or later (the "GPL"), or
34 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
35 in which case the provisions of the GPL or the LGPL are applicable instead
36 of those above. If you wish to allow use of your version of this file only
37 under the terms of either the GPL or the LGPL, and not to allow others to
38 use your version of this file under the terms of the MPL, indicate your
39 decision by deleting the provisions above and replace them with the notice
40 and other provisions required by the GPL or the LGPL. If you do not delete
41 the provisions above, a recipient may use your version of this file under
42 the terms of any one of the MPL, the GPL or the LGPL.
43 
44 */
45 
46 /*
47 
48 CREDITS:
49 
50 this module has been completely funded by:
51 Regione Toscana - Settore Sistema Informativo Territoriale ed Ambientale
52 (Topology support)
53 
54 CIG: 6038019AE5
55 
56 */
57 
58 #include <stdlib.h>
59 #include <stdio.h>
60 #include <string.h>
61 #include <math.h>
62 
63 #if defined(_WIN32) && !defined(__MINGW32__)
64 #include "config-msvc.h"
65 #else
66 #include "config.h"
67 #endif
68 
69 #ifdef ENABLE_RTTOPO		/* only if RTTOPO is enabled */
70 
71 #include <spatialite/sqlite.h>
72 #include <spatialite/debug.h>
73 #include <spatialite/gaiageo.h>
74 #include <spatialite/gaia_topology.h>
75 #include <spatialite/gaiaaux.h>
76 
77 #include <spatialite.h>
78 #include <spatialite_private.h>
79 
80 #include <librttopo.h>
81 
82 #include "topology_private.h"
83 
84 struct topo_node
85 {
86 /* a struct wrapping a Topology Node */
87     sqlite3_int64 node_id;
88     sqlite3_int64 containing_face;
89     double x;
90     double y;
91     double z;
92     int has_z;
93     struct topo_node *next;
94 };
95 
96 struct topo_nodes_list
97 {
98 /* a struct wrapping a list of Topology Nodes */
99     struct topo_node *first;
100     struct topo_node *last;
101     int count;
102 };
103 
104 struct topo_edge
105 {
106 /* a struct wrapping a Topology Edge */
107     sqlite3_int64 edge_id;
108     sqlite3_int64 start_node;
109     sqlite3_int64 end_node;
110     sqlite3_int64 face_left;
111     sqlite3_int64 face_right;
112     sqlite3_int64 next_left;
113     sqlite3_int64 next_right;
114     gaiaLinestringPtr geom;
115     struct topo_edge *next;
116 };
117 
118 struct topo_edges_list
119 {
120 /* a struct wrapping a list of Topology Edegs */
121     struct topo_edge *first;
122     struct topo_edge *last;
123     int count;
124 };
125 
126 struct topo_face
127 {
128 /* a struct wrapping a Topology Face */
129     sqlite3_int64 id;
130     sqlite3_int64 face_id;
131     double minx;
132     double miny;
133     double maxx;
134     double maxy;
135     struct topo_face *next;
136 };
137 
138 struct topo_faces_list
139 {
140 /* a struct wrapping a list of Topology Edegs */
141     struct topo_face *first;
142     struct topo_face *last;
143     int count;
144 };
145 
146 static struct topo_node *
create_topo_node(sqlite3_int64 node_id,sqlite3_int64 containing_face,double x,double y,double z,int has_z)147 create_topo_node (sqlite3_int64 node_id, sqlite3_int64 containing_face,
148 		  double x, double y, double z, int has_z)
149 {
150 /* creating a Topology Node */
151     struct topo_node *ptr = malloc (sizeof (struct topo_node));
152     ptr->node_id = node_id;
153     ptr->containing_face = containing_face;
154     ptr->x = x;
155     ptr->y = y;
156     ptr->z = z;
157     ptr->has_z = has_z;
158     ptr->next = NULL;
159     return ptr;
160 }
161 
162 static void
destroy_topo_node(struct topo_node * ptr)163 destroy_topo_node (struct topo_node *ptr)
164 {
165 /* destroying a Topology Node */
166     if (ptr == NULL)
167 	return;
168     free (ptr);
169 }
170 
171 static struct topo_edge *
create_topo_edge(sqlite3_int64 edge_id,sqlite3_int64 start_node,sqlite3_int64 end_node,sqlite3_int64 face_left,sqlite3_int64 face_right,sqlite3_int64 next_left,sqlite3_int64 next_right,gaiaLinestringPtr ln)172 create_topo_edge (sqlite3_int64 edge_id, sqlite3_int64 start_node,
173 		  sqlite3_int64 end_node, sqlite3_int64 face_left,
174 		  sqlite3_int64 face_right, sqlite3_int64 next_left,
175 		  sqlite3_int64 next_right, gaiaLinestringPtr ln)
176 {
177 /* creating a Topology Edge */
178     struct topo_edge *ptr = malloc (sizeof (struct topo_edge));
179     ptr->edge_id = edge_id;
180     ptr->start_node = start_node;
181     ptr->end_node = end_node;
182     ptr->face_left = face_left;
183     ptr->face_right = face_right;
184     ptr->next_left = next_left;
185     ptr->next_right = next_right;
186     ptr->geom = ln;
187     ptr->next = NULL;
188     return ptr;
189 }
190 
191 static void
destroy_topo_edge(struct topo_edge * ptr)192 destroy_topo_edge (struct topo_edge *ptr)
193 {
194 /* destroying a Topology Edge */
195     if (ptr == NULL)
196 	return;
197     if (ptr->geom != NULL)
198 	gaiaFreeLinestring (ptr->geom);
199     free (ptr);
200 }
201 
202 static struct topo_face *
create_topo_face(sqlite3_int64 id,sqlite3_int64 face_id,double minx,double miny,double maxx,double maxy)203 create_topo_face (sqlite3_int64 id, sqlite3_int64 face_id, double minx,
204 		  double miny, double maxx, double maxy)
205 {
206 /* creating a Topology Face */
207     struct topo_face *ptr = malloc (sizeof (struct topo_face));
208     ptr->id = id;
209     ptr->face_id = face_id;
210     ptr->minx = minx;
211     ptr->miny = miny;
212     ptr->maxx = maxx;
213     ptr->maxy = maxy;
214     ptr->next = NULL;
215     return ptr;
216 }
217 
218 static void
destroy_topo_face(struct topo_face * ptr)219 destroy_topo_face (struct topo_face *ptr)
220 {
221 /* destroying a Topology Face */
222     if (ptr == NULL)
223 	return;
224     free (ptr);
225 }
226 
227 static struct topo_nodes_list *
create_nodes_list(void)228 create_nodes_list (void)
229 {
230 /* creating an empty list of Topology Nodes */
231     struct topo_nodes_list *ptr = malloc (sizeof (struct topo_nodes_list));
232     ptr->first = NULL;
233     ptr->last = NULL;
234     ptr->count = 0;
235     return ptr;
236 }
237 
238 static void
destroy_nodes_list(struct topo_nodes_list * ptr)239 destroy_nodes_list (struct topo_nodes_list *ptr)
240 {
241 /* destroying a list of Topology Nodes */
242     struct topo_node *p;
243     struct topo_node *pn;
244     if (ptr == NULL)
245 	return;
246 
247     p = ptr->first;
248     while (p != NULL)
249       {
250 	  pn = p->next;
251 	  destroy_topo_node (p);
252 	  p = pn;
253       }
254     free (ptr);
255 }
256 
257 static void
add_node_2D(struct topo_nodes_list * list,sqlite3_int64 node_id,sqlite3_int64 containing_face,double x,double y)258 add_node_2D (struct topo_nodes_list *list, sqlite3_int64 node_id,
259 	     sqlite3_int64 containing_face, double x, double y)
260 {
261 /* inserting a Topology Node 2D into the list */
262     struct topo_node *ptr;
263     if (list == NULL)
264 	return;
265 
266     ptr = create_topo_node (node_id, containing_face, x, y, 0.0, 0);
267     if (list->first == NULL)
268 	list->first = ptr;
269     if (list->last != NULL)
270 	list->last->next = ptr;
271     list->last = ptr;
272     list->count++;
273 }
274 
275 static void
add_node_3D(struct topo_nodes_list * list,sqlite3_int64 node_id,sqlite3_int64 containing_face,double x,double y,double z)276 add_node_3D (struct topo_nodes_list *list, sqlite3_int64 node_id,
277 	     sqlite3_int64 containing_face, double x, double y, double z)
278 {
279 /* inserting a Topology Node 3D into the list */
280     struct topo_node *ptr;
281     if (list == NULL)
282 	return;
283 
284     ptr = create_topo_node (node_id, containing_face, x, y, z, 1);
285     if (list->first == NULL)
286 	list->first = ptr;
287     if (list->last != NULL)
288 	list->last->next = ptr;
289     list->last = ptr;
290     list->count++;
291 }
292 
293 static struct topo_edges_list *
create_edges_list(void)294 create_edges_list (void)
295 {
296 /* creating an empty list of Topology Edges */
297     struct topo_edges_list *ptr = malloc (sizeof (struct topo_edges_list));
298     ptr->first = NULL;
299     ptr->last = NULL;
300     ptr->count = 0;
301     return ptr;
302 }
303 
304 static void
destroy_edges_list(struct topo_edges_list * ptr)305 destroy_edges_list (struct topo_edges_list *ptr)
306 {
307 /* destroying a list of Topology Edges */
308     struct topo_edge *p;
309     struct topo_edge *pn;
310     if (ptr == NULL)
311 	return;
312 
313     p = ptr->first;
314     while (p != NULL)
315       {
316 	  pn = p->next;
317 	  destroy_topo_edge (p);
318 	  p = pn;
319       }
320     free (ptr);
321 }
322 
323 static void
add_edge(struct topo_edges_list * list,sqlite3_int64 edge_id,sqlite3_int64 start_node,sqlite3_int64 end_node,sqlite3_int64 face_left,sqlite3_int64 face_right,sqlite3_int64 next_left,sqlite3_int64 next_right,gaiaLinestringPtr ln)324 add_edge (struct topo_edges_list *list, sqlite3_int64 edge_id,
325 	  sqlite3_int64 start_node, sqlite3_int64 end_node,
326 	  sqlite3_int64 face_left, sqlite3_int64 face_right,
327 	  sqlite3_int64 next_left, sqlite3_int64 next_right,
328 	  gaiaLinestringPtr ln)
329 {
330 /* inserting a Topology Edge into the list */
331     struct topo_edge *ptr;
332     if (list == NULL)
333 	return;
334 
335     ptr = list->first;
336     while (ptr != NULL)
337       {
338 	  /* avoiding to insert duplicate entries */
339 	  if (ptr->edge_id == edge_id)
340 	      return;
341 	  ptr = ptr->next;
342       }
343 
344     ptr =
345 	create_topo_edge (edge_id, start_node, end_node, face_left, face_right,
346 			  next_left, next_right, ln);
347     if (list->first == NULL)
348 	list->first = ptr;
349     if (list->last != NULL)
350 	list->last->next = ptr;
351     list->last = ptr;
352     list->count++;
353 }
354 
355 static struct topo_faces_list *
create_faces_list(void)356 create_faces_list (void)
357 {
358 /* creating an empty list of Topology Faces */
359     struct topo_faces_list *ptr = malloc (sizeof (struct topo_faces_list));
360     ptr->first = NULL;
361     ptr->last = NULL;
362     ptr->count = 0;
363     return ptr;
364 }
365 
366 static void
destroy_faces_list(struct topo_faces_list * ptr)367 destroy_faces_list (struct topo_faces_list *ptr)
368 {
369 /* destroying a list of Topology Faces */
370     struct topo_face *p;
371     struct topo_face *pn;
372     if (ptr == NULL)
373 	return;
374 
375     p = ptr->first;
376     while (p != NULL)
377       {
378 	  pn = p->next;
379 	  destroy_topo_face (p);
380 	  p = pn;
381       }
382     free (ptr);
383 }
384 
385 static void
add_face(struct topo_faces_list * list,sqlite3_int64 id,sqlite3_int64 face_id,double minx,double miny,double maxx,double maxy)386 add_face (struct topo_faces_list *list, sqlite3_int64 id, sqlite3_int64 face_id,
387 	  double minx, double miny, double maxx, double maxy)
388 {
389 /* inserting a Topology Face into the list */
390     struct topo_face *ptr;
391     if (list == NULL)
392 	return;
393 
394     ptr = create_topo_face (id, face_id, minx, miny, maxx, maxy);
395     if (list->first == NULL)
396 	list->first = ptr;
397     if (list->last != NULL)
398 	list->last->next = ptr;
399     list->last = ptr;
400     list->count++;
401 }
402 
403 TOPOLOGY_PRIVATE RTLINE *
gaia_convert_linestring_to_rtline(const RTCTX * ctx,gaiaLinestringPtr ln,int srid,int has_z)404 gaia_convert_linestring_to_rtline (const RTCTX * ctx, gaiaLinestringPtr ln,
405 				   int srid, int has_z)
406 {
407 /* converting a Linestring into an RTLINE */
408     RTPOINTARRAY *pa;
409     RTPOINT4D point;
410     int iv;
411     double x;
412     double y;
413     double z;
414     double m;
415 
416     pa = ptarray_construct (ctx, has_z, 0, ln->Points);
417     for (iv = 0; iv < ln->Points; iv++)
418       {
419 	  /* copying vertices */
420 	  if (ln->DimensionModel == GAIA_XY_Z)
421 	    {
422 		gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
423 	    }
424 	  else if (ln->DimensionModel == GAIA_XY_M)
425 	    {
426 		gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
427 	    }
428 	  else if (ln->DimensionModel == GAIA_XY_Z_M)
429 	    {
430 		gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
431 	    }
432 	  else
433 	    {
434 		gaiaGetPoint (ln->Coords, iv, &x, &y);
435 	    }
436 	  point.x = x;
437 	  point.y = y;
438 	  if (has_z)
439 	      point.z = z;
440 	  ptarray_set_point4d (ctx, pa, iv, &point);
441       }
442     return rtline_construct (ctx, srid, NULL, pa);
443 }
444 
445 static int
check_unclosed_ring(gaiaRingPtr rng)446 check_unclosed_ring (gaiaRingPtr rng)
447 {
448 /* checks if a Ring is closed or not */
449     double x0;
450     double y0;
451     double z0 = 0.0;
452     double m0 = 0.0;
453     double x1;
454     double y1;
455     double z1 = 0.0;
456     double m1 = 0.0;
457     int last = rng->Points - 1;
458     if (rng->DimensionModel == GAIA_XY_Z)
459       {
460 	  gaiaGetPointXYZ (rng->Coords, 0, &x0, &y0, &z0);
461       }
462     else if (rng->DimensionModel == GAIA_XY_M)
463       {
464 	  gaiaGetPointXYM (rng->Coords, 0, &x0, &y0, &m0);
465       }
466     else if (rng->DimensionModel == GAIA_XY_Z_M)
467       {
468 	  gaiaGetPointXYZM (rng->Coords, 0, &x0, &y0, &z0, &m0);
469       }
470     else
471       {
472 	  gaiaGetPoint (rng->Coords, 0, &x0, &y0);
473       }
474     if (rng->DimensionModel == GAIA_XY_Z)
475       {
476 	  gaiaGetPointXYZ (rng->Coords, last, &x1, &y1, &z1);
477       }
478     else if (rng->DimensionModel == GAIA_XY_M)
479       {
480 	  gaiaGetPointXYM (rng->Coords, last, &x1, &y1, &m1);
481       }
482     else if (rng->DimensionModel == GAIA_XY_Z_M)
483       {
484 	  gaiaGetPointXYZM (rng->Coords, last, &x1, &y1, &z1, &m1);
485       }
486     else
487       {
488 	  gaiaGetPoint (rng->Coords, last, &x1, &y1);
489       }
490     if (x0 == x1 && y0 == y1 && z0 == z1 && m0 == m1)
491 	return 0;
492     return 1;
493 }
494 
495 TOPOLOGY_PRIVATE RTPOLY *
gaia_convert_polygon_to_rtpoly(const RTCTX * ctx,gaiaPolygonPtr pg,int srid,int has_z)496 gaia_convert_polygon_to_rtpoly (const RTCTX * ctx, gaiaPolygonPtr pg, int srid,
497 				int has_z)
498 {
499 /* converting a Polygon into an RTPOLY */
500     int ngeoms;
501     RTPOINTARRAY **ppaa;
502     RTPOINT4D point;
503     gaiaRingPtr rng;
504     int close_ring;
505     int ib;
506     int iv;
507     double x;
508     double y;
509     double z;
510     double m;
511 
512     ngeoms = pg->NumInteriors;
513     ppaa = rtalloc (ctx, sizeof (RTPOINTARRAY *) * (ngeoms + 1));
514     rng = pg->Exterior;
515     close_ring = check_unclosed_ring (rng);
516     if (close_ring)
517 	ppaa[0] = ptarray_construct (ctx, has_z, 0, rng->Points + 1);
518     else
519 	ppaa[0] = ptarray_construct (ctx, has_z, 0, rng->Points);
520     for (iv = 0; iv < rng->Points; iv++)
521       {
522 	  /* copying vertices */
523 	  if (rng->DimensionModel == GAIA_XY_Z)
524 	    {
525 		gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
526 	    }
527 	  else if (rng->DimensionModel == GAIA_XY_M)
528 	    {
529 		gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
530 	    }
531 	  else if (rng->DimensionModel == GAIA_XY_Z_M)
532 	    {
533 		gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
534 	    }
535 	  else
536 	    {
537 		gaiaGetPoint (rng->Coords, iv, &x, &y);
538 	    }
539 	  point.x = x;
540 	  point.y = y;
541 	  if (has_z)
542 	      point.z = z;
543 	  ptarray_set_point4d (ctx, ppaa[0], iv, &point);
544       }
545     if (close_ring)
546       {
547 	  /* making an unclosed ring to be closed */
548 	  if (rng->DimensionModel == GAIA_XY_Z)
549 	    {
550 		gaiaGetPointXYZ (rng->Coords, 0, &x, &y, &z);
551 	    }
552 	  else if (rng->DimensionModel == GAIA_XY_M)
553 	    {
554 		gaiaGetPointXYM (rng->Coords, 0, &x, &y, &m);
555 	    }
556 	  else if (rng->DimensionModel == GAIA_XY_Z_M)
557 	    {
558 		gaiaGetPointXYZM (rng->Coords, 0, &x, &y, &z, &m);
559 	    }
560 	  else
561 	    {
562 		gaiaGetPoint (rng->Coords, 0, &x, &y);
563 	    }
564 	  point.x = x;
565 	  point.y = y;
566 	  if (has_z)
567 	      point.z = z;
568 	  ptarray_set_point4d (ctx, ppaa[0], rng->Points, &point);
569       }
570     for (ib = 0; ib < pg->NumInteriors; ib++)
571       {
572 	  /* copying vertices - Interior Rings */
573 	  rng = pg->Interiors + ib;
574 	  close_ring = check_unclosed_ring (rng);
575 	  if (close_ring)
576 	      ppaa[1 + ib] = ptarray_construct (ctx, has_z, 0, rng->Points + 1);
577 	  else
578 	      ppaa[1 + ib] = ptarray_construct (ctx, has_z, 0, rng->Points);
579 	  for (iv = 0; iv < rng->Points; iv++)
580 	    {
581 		/* copying vertices */
582 		if (rng->DimensionModel == GAIA_XY_Z)
583 		  {
584 		      gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
585 		  }
586 		else if (rng->DimensionModel == GAIA_XY_M)
587 		  {
588 		      gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
589 		  }
590 		else if (rng->DimensionModel == GAIA_XY_Z_M)
591 		  {
592 		      gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
593 		  }
594 		else
595 		  {
596 		      gaiaGetPoint (rng->Coords, iv, &x, &y);
597 		  }
598 		point.x = x;
599 		point.y = y;
600 		if (has_z)
601 		    point.z = z;
602 		ptarray_set_point4d (ctx, ppaa[1 + ib], iv, &point);
603 	    }
604 	  if (close_ring)
605 	    {
606 		/* making an unclosed ring to be closed */
607 		if (rng->DimensionModel == GAIA_XY_Z)
608 		  {
609 		      gaiaGetPointXYZ (rng->Coords, 0, &x, &y, &z);
610 		  }
611 		else if (rng->DimensionModel == GAIA_XY_M)
612 		  {
613 		      gaiaGetPointXYM (rng->Coords, 0, &x, &y, &m);
614 		  }
615 		else if (rng->DimensionModel == GAIA_XY_Z_M)
616 		  {
617 		      gaiaGetPointXYZM (rng->Coords, 0, &x, &y, &z, &m);
618 		  }
619 		else
620 		  {
621 		      gaiaGetPoint (rng->Coords, 0, &x, &y);
622 		  }
623 		point.x = x;
624 		point.y = y;
625 		if (has_z)
626 		    point.z = z;
627 		ptarray_set_point4d (ctx, ppaa[1 + ib], rng->Points, &point);
628 	    }
629       }
630     return rtpoly_construct (ctx, srid, NULL, ngeoms + 1, ppaa);
631 }
632 
633 static gaiaGeomCollPtr
do_rtline_to_geom(const RTCTX * ctx,RTLINE * rtline,int srid)634 do_rtline_to_geom (const RTCTX * ctx, RTLINE * rtline, int srid)
635 {
636 /* converting a RTLINE into a Geometry (Linestring) */
637     RTPOINTARRAY *pa;
638     RTPOINT4D pt4d;
639     int has_z = 0;
640     double x;
641     double y;
642     double z;
643     int iv;
644     gaiaGeomCollPtr geom;
645     gaiaLinestringPtr ln;
646 
647     pa = rtline->points;
648     if (RTFLAGS_GET_Z (pa->flags))
649 	has_z = 1;
650     if (has_z)
651 	geom = gaiaAllocGeomCollXYZ ();
652     else
653 	geom = gaiaAllocGeomColl ();
654     ln = gaiaAddLinestringToGeomColl (geom, pa->npoints);
655     for (iv = 0; iv < pa->npoints; iv++)
656       {
657 	  /* copying LINESTRING vertices */
658 	  rt_getPoint4d_p (ctx, pa, iv, &pt4d);
659 	  x = pt4d.x;
660 	  y = pt4d.y;
661 	  if (has_z)
662 	      z = pt4d.z;
663 	  if (has_z)
664 	    {
665 		gaiaSetPointXYZ (ln->Coords, iv, x, y, z);
666 	    }
667 	  else
668 	    {
669 		gaiaSetPoint (ln->Coords, iv, x, y);
670 	    }
671       }
672     geom->DeclaredType = GAIA_LINESTRING;
673     geom->Srid = srid;
674 
675     return geom;
676 }
677 
678 static char *
do_prepare_read_node(const char * topology_name,int fields,int has_z)679 do_prepare_read_node (const char *topology_name, int fields, int has_z)
680 {
681 /* preparing the auxiliary "read_node" SQL statement */
682     char *sql;
683     char *prev;
684     char *table;
685     char *xtable;
686     int comma = 0;
687 
688     sql = sqlite3_mprintf ("SELECT ");
689     prev = sql;
690     if (fields & RTT_COL_NODE_NODE_ID)
691       {
692 	  if (comma)
693 	      sql = sqlite3_mprintf ("%s, node_id", prev);
694 	  else
695 	      sql = sqlite3_mprintf ("%s node_id", prev);
696 	  comma = 1;
697 	  sqlite3_free (prev);
698 	  prev = sql;
699       }
700     if (fields & RTT_COL_NODE_CONTAINING_FACE)
701       {
702 	  if (comma)
703 	      sql = sqlite3_mprintf ("%s, containing_face", prev);
704 	  else
705 	      sql = sqlite3_mprintf ("%s containing_face", prev);
706 	  comma = 1;
707 	  sqlite3_free (prev);
708 	  prev = sql;
709       }
710     if (fields & RTT_COL_NODE_GEOM)
711       {
712 	  if (comma)
713 	      sql = sqlite3_mprintf ("%s, ST_X(geom), ST_Y(geom)", prev);
714 	  else
715 	      sql = sqlite3_mprintf ("%s ST_X(geom), ST_Y(geom)", prev);
716 	  comma = 1;
717 	  sqlite3_free (prev);
718 	  prev = sql;
719 	  if (has_z)
720 	    {
721 		sql = sqlite3_mprintf ("%s, ST_Z(geom)", prev);
722 		sqlite3_free (prev);
723 		prev = sql;
724 	    }
725       }
726     table = sqlite3_mprintf ("%s_node", topology_name);
727     xtable = gaiaDoubleQuotedSql (table);
728     sqlite3_free (table);
729     sql =
730 	sqlite3_mprintf ("%s FROM MAIN.\"%s\" WHERE node_id = ?", prev, xtable);
731     sqlite3_free (prev);
732     free (xtable);
733     return sql;
734 }
735 
736 static int
do_read_node(sqlite3_stmt * stmt,struct topo_nodes_list * list,sqlite3_int64 id,int fields,int has_z,const char * callback_name,char ** errmsg)737 do_read_node (sqlite3_stmt * stmt, struct topo_nodes_list *list,
738 	      sqlite3_int64 id, int fields, int has_z,
739 	      const char *callback_name, char **errmsg)
740 {
741 /* reading Nodes out from the DBMS */
742     int icol = 0;
743     int ret;
744 
745 /* setting up the prepared statement */
746     sqlite3_reset (stmt);
747     sqlite3_clear_bindings (stmt);
748     sqlite3_bind_int64 (stmt, 1, id);
749 
750     while (1)
751       {
752 	  /* scrolling the result set rows */
753 	  ret = sqlite3_step (stmt);
754 	  if (ret == SQLITE_DONE)
755 	      break;		/* end of result set */
756 	  if (ret == SQLITE_ROW)
757 	    {
758 		int ok_id = 0;
759 		int ok_face = 0;
760 		int ok_x = 0;
761 		int ok_y = 0;
762 		int ok_z = 0;
763 		sqlite3_int64 node_id = -1;
764 		sqlite3_int64 containing_face = -1;
765 		double x = 0.0;
766 		double y = 0.0;
767 		double z = 0.0;
768 		if (fields & RTT_COL_NODE_NODE_ID)
769 		  {
770 		      if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
771 			{
772 			    node_id = sqlite3_column_int64 (stmt, icol);
773 			    ok_id = 1;
774 			}
775 		      icol++;
776 		  }
777 		else
778 		    ok_id = 1;
779 		if (fields & RTT_COL_NODE_CONTAINING_FACE)
780 		  {
781 		      if (sqlite3_column_type (stmt, icol) == SQLITE_NULL)
782 			{
783 			    containing_face = -1;
784 			    ok_face = 1;
785 			}
786 		      if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
787 			{
788 			    containing_face = sqlite3_column_int64 (stmt, icol);
789 			    ok_face = 1;
790 			}
791 		      icol++;
792 		  }
793 		else
794 		    ok_face = 1;
795 		if (fields & RTT_COL_NODE_GEOM)
796 		  {
797 		      if (sqlite3_column_type (stmt, icol) == SQLITE_FLOAT)
798 			{
799 			    x = sqlite3_column_double (stmt, icol);
800 			    ok_x = 1;
801 			}
802 		      icol++;
803 		      if (sqlite3_column_type (stmt, icol) == SQLITE_FLOAT)
804 			{
805 			    y = sqlite3_column_double (stmt, icol);
806 			    ok_y = 1;
807 			}
808 		      icol++;
809 		      if (has_z)
810 			{
811 			    if (sqlite3_column_type (stmt, icol) ==
812 				SQLITE_FLOAT)
813 			      {
814 				  z = sqlite3_column_double (stmt, icol);
815 				  ok_z = 1;
816 			      }
817 			}
818 		  }
819 		else
820 		  {
821 		      ok_x = 1;
822 		      ok_y = 1;
823 		      ok_z = 1;
824 		  }
825 		if (has_z)
826 		  {
827 		      if (ok_id && ok_face && ok_x && ok_y && ok_z)
828 			{
829 			    add_node_3D (list, node_id, containing_face, x, y,
830 					 z);
831 			    *errmsg = NULL;
832 			    sqlite3_reset (stmt);
833 			    return 1;
834 			}
835 		  }
836 		else
837 		  {
838 		      if (ok_id && ok_face && ok_x && ok_y)
839 			{
840 			    add_node_2D (list, node_id, containing_face, x, y);
841 			    *errmsg = NULL;
842 			    sqlite3_reset (stmt);
843 			    return 1;
844 			}
845 		  }
846 		/* an invalid Node has been found */
847 		*errmsg =
848 		    sqlite3_mprintf
849 		    ("%s: found an invalid Node \"%lld\"", callback_name,
850 		     node_id);
851 		return 0;
852 	    }
853       }
854     *errmsg = NULL;
855     sqlite3_reset (stmt);
856     return 1;
857 }
858 
859 static int
do_read_node_by_face(sqlite3_stmt * stmt,struct topo_nodes_list * list,sqlite3_int64 id,int fields,const RTGBOX * box,int has_z,const char * callback_name,char ** errmsg)860 do_read_node_by_face (sqlite3_stmt * stmt, struct topo_nodes_list *list,
861 		      sqlite3_int64 id, int fields, const RTGBOX * box,
862 		      int has_z, const char *callback_name, char **errmsg)
863 {
864 /* reading Nodes out from the DBMS */
865     int icol = 0;
866     int ret;
867 
868 /* setting up the prepared statement */
869     sqlite3_reset (stmt);
870     sqlite3_clear_bindings (stmt);
871     sqlite3_bind_int64 (stmt, 1, id);
872     if (box != NULL)
873       {
874 	  sqlite3_bind_double (stmt, 2, box->xmin);
875 	  sqlite3_bind_double (stmt, 3, box->ymin);
876 	  sqlite3_bind_double (stmt, 4, box->xmax);
877 	  sqlite3_bind_double (stmt, 5, box->ymax);
878       }
879 
880     while (1)
881       {
882 	  /* scrolling the result set rows */
883 	  ret = sqlite3_step (stmt);
884 	  if (ret == SQLITE_DONE)
885 	      break;		/* end of result set */
886 	  if (ret == SQLITE_ROW)
887 	    {
888 		int ok_id = 0;
889 		int ok_face = 0;
890 		int ok_x = 0;
891 		int ok_y = 0;
892 		int ok_z = 0;
893 		sqlite3_int64 node_id = -1;
894 		sqlite3_int64 containing_face = -1;
895 		double x = 0.0;
896 		double y = 0.0;
897 		double z = 0.0;
898 		if (fields & RTT_COL_NODE_NODE_ID)
899 		  {
900 		      if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
901 			{
902 			    node_id = sqlite3_column_int64 (stmt, icol);
903 			    ok_id = 1;
904 			}
905 		      icol++;
906 		  }
907 		else
908 		    ok_id = 1;
909 		if (fields & RTT_COL_NODE_CONTAINING_FACE)
910 		  {
911 		      if (sqlite3_column_type (stmt, icol) == SQLITE_NULL)
912 			{
913 			    containing_face = -1;
914 			    ok_face = 1;
915 			}
916 		      if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
917 			{
918 			    containing_face = sqlite3_column_int64 (stmt, icol);
919 			    ok_face = 1;
920 			}
921 		      icol++;
922 		  }
923 		else
924 		    ok_face = 1;
925 		if (fields & RTT_COL_NODE_GEOM)
926 		  {
927 		      if (sqlite3_column_type (stmt, icol) == SQLITE_FLOAT)
928 			{
929 			    x = sqlite3_column_double (stmt, icol);
930 			    ok_x = 1;
931 			}
932 		      icol++;
933 		      if (sqlite3_column_type (stmt, icol) == SQLITE_FLOAT)
934 			{
935 			    y = sqlite3_column_double (stmt, icol);
936 			    ok_y = 1;
937 			}
938 		      icol++;
939 		      if (has_z)
940 			{
941 			    if (sqlite3_column_type (stmt, icol) ==
942 				SQLITE_FLOAT)
943 			      {
944 				  z = sqlite3_column_double (stmt, icol);
945 				  ok_z = 1;
946 			      }
947 			}
948 		  }
949 		else
950 		  {
951 		      ok_x = 1;
952 		      ok_y = 1;
953 		      ok_z = 1;
954 		  }
955 		if (has_z)
956 		  {
957 		      if (ok_id && ok_face && ok_x && ok_y && ok_z)
958 			{
959 			    add_node_3D (list, node_id, containing_face, x, y,
960 					 z);
961 			    *errmsg = NULL;
962 			    sqlite3_reset (stmt);
963 			    return 1;
964 			}
965 		  }
966 		else
967 		  {
968 		      if (ok_id && ok_face && ok_x && ok_y)
969 			{
970 			    add_node_2D (list, node_id, containing_face, x, y);
971 			    *errmsg = NULL;
972 			    sqlite3_reset (stmt);
973 			    return 1;
974 			}
975 		  }
976 		/* an invalid Node has been found */
977 		*errmsg =
978 		    sqlite3_mprintf
979 		    ("%s: found an invalid Node \"%lld\"", callback_name,
980 		     node_id);
981 		return 0;
982 	    }
983       }
984     *errmsg = NULL;
985     sqlite3_reset (stmt);
986     return 1;
987 }
988 
989 static char *
do_prepare_read_edge(const char * topology_name,int fields)990 do_prepare_read_edge (const char *topology_name, int fields)
991 {
992 /* preparing the auxiliary "read_edge" SQL statement */
993     char *sql;
994     char *prev;
995     char *table;
996     char *xtable;
997     int comma = 0;
998 
999     sql = sqlite3_mprintf ("SELECT ");
1000     prev = sql;
1001     /* unconditionally querying the Edge ID */
1002     if (comma)
1003 	sql = sqlite3_mprintf ("%s, edge_id", prev);
1004     else
1005 	sql = sqlite3_mprintf ("%s edge_id", prev);
1006     comma = 1;
1007     sqlite3_free (prev);
1008     prev = sql;
1009     if (fields & RTT_COL_EDGE_START_NODE)
1010       {
1011 	  if (comma)
1012 	      sql = sqlite3_mprintf ("%s, start_node", prev);
1013 	  else
1014 	      sql = sqlite3_mprintf ("%s start_node", prev);
1015 	  comma = 1;
1016 	  sqlite3_free (prev);
1017 	  prev = sql;
1018       }
1019     if (fields & RTT_COL_EDGE_END_NODE)
1020       {
1021 	  if (comma)
1022 	      sql = sqlite3_mprintf ("%s, end_node", prev);
1023 	  else
1024 	      sql = sqlite3_mprintf ("%s end_node", prev);
1025 	  comma = 1;
1026 	  sqlite3_free (prev);
1027 	  prev = sql;
1028       }
1029     if (fields & RTT_COL_EDGE_FACE_LEFT)
1030       {
1031 	  if (comma)
1032 	      sql = sqlite3_mprintf ("%s, left_face", prev);
1033 	  else
1034 	      sql = sqlite3_mprintf ("%s left_face", prev);
1035 	  comma = 1;
1036 	  sqlite3_free (prev);
1037 	  prev = sql;
1038       }
1039     if (fields & RTT_COL_EDGE_FACE_RIGHT)
1040       {
1041 	  if (comma)
1042 	      sql = sqlite3_mprintf ("%s, right_face", prev);
1043 	  else
1044 	      sql = sqlite3_mprintf ("%s right_face", prev);
1045 	  comma = 1;
1046 	  sqlite3_free (prev);
1047 	  prev = sql;
1048       }
1049     if (fields & RTT_COL_EDGE_NEXT_LEFT)
1050       {
1051 	  if (comma)
1052 	      sql = sqlite3_mprintf ("%s, next_left_edge", prev);
1053 	  else
1054 	      sql = sqlite3_mprintf ("%s next_left_edge", prev);
1055 	  comma = 1;
1056 	  sqlite3_free (prev);
1057 	  prev = sql;
1058       }
1059     if (fields & RTT_COL_EDGE_NEXT_RIGHT)
1060       {
1061 	  if (comma)
1062 	      sql = sqlite3_mprintf ("%s, next_right_edge", prev);
1063 	  else
1064 	      sql = sqlite3_mprintf ("%s next_right_edge", prev);
1065 	  comma = 1;
1066 	  sqlite3_free (prev);
1067 	  prev = sql;
1068       }
1069     if (fields & RTT_COL_EDGE_GEOM)
1070       {
1071 	  if (comma)
1072 	      sql = sqlite3_mprintf ("%s, geom", prev);
1073 	  else
1074 	      sql = sqlite3_mprintf ("%s geom", prev);
1075 	  comma = 1;
1076 	  sqlite3_free (prev);
1077 	  prev = sql;
1078       }
1079     table = sqlite3_mprintf ("%s_edge", topology_name);
1080     xtable = gaiaDoubleQuotedSql (table);
1081     sqlite3_free (table);
1082     sql =
1083 	sqlite3_mprintf ("%s FROM MAIN.\"%s\" WHERE edge_id = ?", prev, xtable);
1084     free (xtable);
1085     sqlite3_free (prev);
1086     return sql;
1087 }
1088 
1089 static int
do_read_edge_row(sqlite3_stmt * stmt,struct topo_edges_list * list,int fields,const char * callback_name,char ** errmsg)1090 do_read_edge_row (sqlite3_stmt * stmt, struct topo_edges_list *list, int fields,
1091 		  const char *callback_name, char **errmsg)
1092 {
1093 /* reading an Edge Row out from the resultset */
1094     int icol = 0;
1095 
1096     int ok_id = 0;
1097     int ok_start = 0;
1098     int ok_end = 0;
1099     int ok_left = 0;
1100     int ok_right = 0;
1101     int ok_next_left = 0;
1102     int ok_next_right = 0;
1103     int ok_geom = 0;
1104     sqlite3_int64 edge_id;
1105     sqlite3_int64 start_node;
1106     sqlite3_int64 end_node;
1107     sqlite3_int64 face_left;
1108     sqlite3_int64 face_right;
1109     sqlite3_int64 next_left_edge;
1110     sqlite3_int64 next_right_edge;
1111     gaiaGeomCollPtr geom = NULL;
1112     gaiaLinestringPtr ln = NULL;
1113     /* unconditionally querying the Edge ID */
1114     if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
1115       {
1116 	  edge_id = sqlite3_column_int64 (stmt, icol);
1117 	  ok_id = 1;
1118       }
1119     icol++;
1120     if (fields & RTT_COL_EDGE_START_NODE)
1121       {
1122 	  if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
1123 	    {
1124 		start_node = sqlite3_column_int64 (stmt, icol);
1125 		ok_start = 1;
1126 	    }
1127 	  icol++;
1128       }
1129     else
1130 	ok_start = 1;
1131     if (fields & RTT_COL_EDGE_END_NODE)
1132       {
1133 	  if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
1134 	    {
1135 		end_node = sqlite3_column_int64 (stmt, icol);
1136 		ok_end = 1;
1137 	    }
1138 	  icol++;
1139       }
1140     else
1141 	ok_end = 1;
1142     if (fields & RTT_COL_EDGE_FACE_LEFT)
1143       {
1144 	  if (sqlite3_column_type (stmt, icol) == SQLITE_NULL)
1145 	    {
1146 		face_left = -1;
1147 		ok_left = 1;
1148 	    }
1149 	  if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
1150 	    {
1151 		face_left = sqlite3_column_int64 (stmt, icol);
1152 		ok_left = 1;
1153 	    }
1154 	  icol++;
1155       }
1156     else
1157 	ok_left = 1;
1158     if (fields & RTT_COL_EDGE_FACE_RIGHT)
1159       {
1160 	  if (sqlite3_column_type (stmt, icol) == SQLITE_NULL)
1161 	    {
1162 		face_right = -1;
1163 		ok_right = 1;
1164 	    }
1165 	  if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
1166 	    {
1167 		face_right = sqlite3_column_int64 (stmt, icol);
1168 		ok_right = 1;
1169 	    }
1170 	  icol++;
1171       }
1172     else
1173 	ok_right = 1;
1174     if (fields & RTT_COL_EDGE_NEXT_LEFT)
1175       {
1176 	  if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
1177 	    {
1178 		next_left_edge = sqlite3_column_int64 (stmt, icol);
1179 		ok_next_left = 1;
1180 	    }
1181 	  icol++;
1182       }
1183     else
1184 	ok_next_left = 1;
1185     if (fields & RTT_COL_EDGE_NEXT_RIGHT)
1186       {
1187 	  if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
1188 	    {
1189 		next_right_edge = sqlite3_column_int64 (stmt, icol);
1190 		ok_next_right = 1;
1191 	    }
1192 	  icol++;
1193       }
1194     else
1195 	ok_next_right = 1;
1196     if (fields & RTT_COL_EDGE_GEOM)
1197       {
1198 	  if (sqlite3_column_type (stmt, icol) == SQLITE_BLOB)
1199 	    {
1200 		const unsigned char *blob = sqlite3_column_blob (stmt, icol);
1201 		int blob_sz = sqlite3_column_bytes (stmt, icol);
1202 		geom = gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
1203 		if (geom != NULL)
1204 		  {
1205 		      if (geom->FirstPoint == NULL
1206 			  && geom->FirstPolygon == NULL
1207 			  && geom->FirstLinestring ==
1208 			  geom->LastLinestring && geom->FirstLinestring != NULL)
1209 			{
1210 			    ok_geom = 1;
1211 			    ln = geom->FirstLinestring;
1212 			}
1213 		  }
1214 	    }
1215 	  icol++;
1216       }
1217     else
1218 	ok_geom = 1;
1219     if (ok_id && ok_start && ok_end && ok_left && ok_right
1220 	&& ok_next_left && ok_next_right && ok_geom)
1221       {
1222 	  add_edge (list, edge_id, start_node, end_node,
1223 		    face_left, face_right, next_left_edge, next_right_edge, ln);
1224 	  if (geom != NULL)
1225 	    {
1226 		/* releasing ownership on Linestring */
1227 		geom->FirstLinestring = NULL;
1228 		geom->LastLinestring = NULL;
1229 		gaiaFreeGeomColl (geom);
1230 	    }
1231 	  *errmsg = NULL;
1232 	  return 1;
1233       }
1234 /* an invalid Edge has been found */
1235     if (geom != NULL)
1236 	gaiaFreeGeomColl (geom);
1237     *errmsg =
1238 	sqlite3_mprintf
1239 	("%s: found an invalid Edge \"%lld\"", callback_name, edge_id);
1240     return 0;
1241 }
1242 
1243 static int
do_read_edge(sqlite3_stmt * stmt,struct topo_edges_list * list,sqlite3_int64 edge_id,int fields,const char * callback_name,char ** errmsg)1244 do_read_edge (sqlite3_stmt * stmt, struct topo_edges_list *list,
1245 	      sqlite3_int64 edge_id, int fields, const char *callback_name,
1246 	      char **errmsg)
1247 {
1248 /* reading a single Edge out from the DBMS */
1249     int ret;
1250 
1251 /* setting up the prepared statement */
1252     sqlite3_reset (stmt);
1253     sqlite3_clear_bindings (stmt);
1254     sqlite3_bind_int64 (stmt, 1, edge_id);
1255 
1256     while (1)
1257       {
1258 	  /* scrolling the result set rows */
1259 	  ret = sqlite3_step (stmt);
1260 	  if (ret == SQLITE_DONE)
1261 	      break;		/* end of result set */
1262 	  if (ret == SQLITE_ROW)
1263 	    {
1264 		if (!do_read_edge_row
1265 		    (stmt, list, fields, callback_name, errmsg))
1266 		  {
1267 		      sqlite3_reset (stmt);
1268 		      return 0;
1269 		  }
1270 	    }
1271       }
1272     sqlite3_reset (stmt);
1273     return 1;
1274 }
1275 
1276 static int
do_read_edge_by_node(sqlite3_stmt * stmt,struct topo_edges_list * list,sqlite3_int64 node_id,int fields,const char * callback_name,char ** errmsg)1277 do_read_edge_by_node (sqlite3_stmt * stmt, struct topo_edges_list *list,
1278 		      sqlite3_int64 node_id, int fields,
1279 		      const char *callback_name, char **errmsg)
1280 {
1281 /* reading a single Edge out from the DBMS */
1282     int ret;
1283 
1284 /* setting up the prepared statement */
1285     sqlite3_reset (stmt);
1286     sqlite3_clear_bindings (stmt);
1287     sqlite3_bind_int64 (stmt, 1, node_id);
1288     sqlite3_bind_int64 (stmt, 2, node_id);
1289 
1290     while (1)
1291       {
1292 	  /* scrolling the result set rows */
1293 	  ret = sqlite3_step (stmt);
1294 	  if (ret == SQLITE_DONE)
1295 	      break;		/* end of result set */
1296 	  if (ret == SQLITE_ROW)
1297 	    {
1298 		if (!do_read_edge_row
1299 		    (stmt, list, fields, callback_name, errmsg))
1300 		  {
1301 		      sqlite3_reset (stmt);
1302 		      return 0;
1303 		  }
1304 	    }
1305       }
1306     sqlite3_reset (stmt);
1307     return 1;
1308 }
1309 
1310 static int
do_read_edge_by_face(sqlite3_stmt * stmt,struct topo_edges_list * list,sqlite3_int64 face_id,int fields,const RTGBOX * box,const char * callback_name,char ** errmsg)1311 do_read_edge_by_face (sqlite3_stmt * stmt, struct topo_edges_list *list,
1312 		      sqlite3_int64 face_id, int fields, const RTGBOX * box,
1313 		      const char *callback_name, char **errmsg)
1314 {
1315 /* reading a single Edge out from the DBMS */
1316     int ret;
1317 
1318 /* setting up the prepared statement */
1319     sqlite3_reset (stmt);
1320     sqlite3_clear_bindings (stmt);
1321     sqlite3_bind_int64 (stmt, 1, face_id);
1322     sqlite3_bind_int64 (stmt, 2, face_id);
1323     if (box != NULL)
1324       {
1325 	  sqlite3_bind_double (stmt, 3, box->xmin);
1326 	  sqlite3_bind_double (stmt, 4, box->ymin);
1327 	  sqlite3_bind_double (stmt, 5, box->xmax);
1328 	  sqlite3_bind_double (stmt, 6, box->ymax);
1329       }
1330 
1331     while (1)
1332       {
1333 	  /* scrolling the result set rows */
1334 	  ret = sqlite3_step (stmt);
1335 	  if (ret == SQLITE_DONE)
1336 	      break;		/* end of result set */
1337 	  if (ret == SQLITE_ROW)
1338 	    {
1339 		if (!do_read_edge_row
1340 		    (stmt, list, fields, callback_name, errmsg))
1341 		  {
1342 		      sqlite3_reset (stmt);
1343 		      return 0;
1344 		  }
1345 	    }
1346       }
1347     sqlite3_reset (stmt);
1348     return 1;
1349 }
1350 
1351 static int
do_read_face(sqlite3_stmt * stmt,struct topo_faces_list * list,sqlite3_int64 id,int fields,const char * callback_name,char ** errmsg)1352 do_read_face (sqlite3_stmt * stmt, struct topo_faces_list *list,
1353 	      sqlite3_int64 id, int fields, const char *callback_name,
1354 	      char **errmsg)
1355 {
1356 /* reading Faces out from the DBMS */
1357     int icol = 0;
1358     int ret;
1359 
1360 /* setting up the prepared statement */
1361     sqlite3_reset (stmt);
1362     sqlite3_clear_bindings (stmt);
1363     if (id <= 0)
1364 	sqlite3_bind_int64 (stmt, 1, 0);
1365     else
1366 	sqlite3_bind_int64 (stmt, 1, id);
1367 
1368     while (1)
1369       {
1370 	  /* scrolling the result set rows */
1371 	  ret = sqlite3_step (stmt);
1372 	  if (ret == SQLITE_DONE)
1373 	      break;		/* end of result set */
1374 	  if (ret == SQLITE_ROW)
1375 	    {
1376 		int ok_id = 0;
1377 		int ok_minx = 0;
1378 		int ok_miny = 0;
1379 		int ok_maxx = 0;
1380 		int ok_maxy = 0;
1381 		sqlite3_int64 face_id = -1;
1382 		double minx = 0.0;
1383 		double miny = 0.0;
1384 		double maxx = 0.0;
1385 		double maxy = 0.0;
1386 		if (fields & RTT_COL_FACE_FACE_ID)
1387 		  {
1388 		      if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
1389 			{
1390 			    face_id = sqlite3_column_int64 (stmt, icol);
1391 			    ok_id = 1;
1392 			}
1393 		      icol++;
1394 		  }
1395 		else
1396 		    ok_id = 1;
1397 		if (fields & RTT_COL_FACE_MBR)
1398 		  {
1399 		      if (id <= 0)
1400 			{
1401 			    ok_minx = 1;
1402 			    ok_miny = 1;
1403 			    ok_maxx = 1;
1404 			    ok_maxy = 1;
1405 			}
1406 		      else
1407 			{
1408 			    if (sqlite3_column_type (stmt, icol) ==
1409 				SQLITE_FLOAT)
1410 			      {
1411 				  minx = sqlite3_column_double (stmt, icol);
1412 				  ok_minx = 1;
1413 			      }
1414 			    icol++;
1415 			    if (sqlite3_column_type (stmt, icol) ==
1416 				SQLITE_FLOAT)
1417 			      {
1418 				  miny = sqlite3_column_double (stmt, icol);
1419 				  ok_miny = 1;
1420 			      }
1421 			    icol++;
1422 			    if (sqlite3_column_type (stmt, icol) ==
1423 				SQLITE_FLOAT)
1424 			      {
1425 				  maxx = sqlite3_column_double (stmt, icol);
1426 				  ok_maxx = 1;
1427 			      }
1428 			    icol++;
1429 			    if (sqlite3_column_type (stmt, icol) ==
1430 				SQLITE_FLOAT)
1431 			      {
1432 				  maxy = sqlite3_column_double (stmt, icol);
1433 				  ok_maxy = 1;
1434 			      }
1435 			    icol++;
1436 			}
1437 		  }
1438 		else
1439 		  {
1440 		      ok_minx = 1;
1441 		      ok_miny = 1;
1442 		      ok_maxx = 1;
1443 		      ok_maxy = 1;
1444 		  }
1445 		if (ok_id && ok_minx && ok_miny && ok_maxx && ok_maxy)
1446 		  {
1447 		      add_face (list, id, face_id, minx, miny, maxx, maxy);
1448 		      *errmsg = NULL;
1449 		      sqlite3_reset (stmt);
1450 		      return 1;
1451 		  }
1452 		/* an invalid Face has been found */
1453 		*errmsg =
1454 		    sqlite3_mprintf
1455 		    ("%s: found an invalid Face \"%lld\"", callback_name,
1456 		     face_id);
1457 		sqlite3_reset (stmt);
1458 		return 0;
1459 	    }
1460       }
1461     *errmsg = NULL;
1462     sqlite3_reset (stmt);
1463     return 1;
1464 }
1465 
1466 const char *
callback_lastErrorMessage(const RTT_BE_DATA * be)1467 callback_lastErrorMessage (const RTT_BE_DATA * be)
1468 {
1469     return gaiatopo_get_last_exception ((GaiaTopologyAccessorPtr) be);
1470 }
1471 
1472 RTT_BE_TOPOLOGY *
callback_loadTopologyByName(const RTT_BE_DATA * be,const char * name)1473 callback_loadTopologyByName (const RTT_BE_DATA * be, const char *name)
1474 {
1475 /* callback function: loadTopologyByName */
1476     struct gaia_topology *ptr = (struct gaia_topology *) be;
1477     char *topology_name;
1478     int srid;
1479     double tolerance;
1480     int has_z;
1481     struct splite_internal_cache *cache =
1482 	(struct splite_internal_cache *) ptr->cache;
1483     if (gaiaReadTopologyFromDBMS
1484 	(ptr->db_handle, name, &topology_name, &srid, &tolerance, &has_z))
1485       {
1486 	  ptr->topology_name = topology_name;
1487 	  ptr->srid = srid;
1488 	  ptr->tolerance = tolerance;
1489 	  ptr->has_z = has_z;
1490 	  /* registering into the Internal Cache double linked list */
1491 	  if (cache->firstTopology == NULL)
1492 	      cache->firstTopology = ptr;
1493 	  if (cache->lastTopology != NULL)
1494 	    {
1495 		struct gaia_topology *p2 =
1496 		    (struct gaia_topology *) (cache->lastTopology);
1497 		p2->next = ptr;
1498 	    }
1499 	  cache->lastTopology = ptr;
1500 	  return (RTT_BE_TOPOLOGY *) ptr;
1501       }
1502     else
1503 	return NULL;
1504 }
1505 
1506 int
callback_freeTopology(RTT_BE_TOPOLOGY * rtt_topo)1507 callback_freeTopology (RTT_BE_TOPOLOGY * rtt_topo)
1508 {
1509 /* callback function: freeTopology - does nothing */
1510     if (rtt_topo != NULL)
1511 	rtt_topo = NULL;	/* silencing stupid compiler warnings on unuse args */
1512     return 1;
1513 }
1514 
1515 RTT_ISO_NODE *
callback_getNodeById(const RTT_BE_TOPOLOGY * rtt_topo,const RTT_ELEMID * ids,int * numelems,int fields)1516 callback_getNodeById (const RTT_BE_TOPOLOGY * rtt_topo,
1517 		      const RTT_ELEMID * ids, int *numelems, int fields)
1518 {
1519 /* callback function: getNodeById */
1520     const RTCTX *ctx = NULL;
1521     struct splite_internal_cache *cache = NULL;
1522     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
1523     struct gaia_topology *accessor = (struct gaia_topology *) topo;
1524     sqlite3_stmt *stmt_aux = NULL;
1525     int ret;
1526     int i;
1527     char *sql;
1528     RTPOINTARRAY *pa;
1529     RTPOINT4D pt4d;
1530     struct topo_nodes_list *list = NULL;
1531     RTT_ISO_NODE *result = NULL;
1532     if (accessor == NULL)
1533       {
1534 	  *numelems = -1;
1535 	  return NULL;
1536       }
1537 
1538     cache = (struct splite_internal_cache *) accessor->cache;
1539     if (cache == NULL)
1540 	return NULL;
1541     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1542 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1543 	return NULL;
1544     ctx = cache->RTTOPO_handle;
1545     if (ctx == NULL)
1546 	return NULL;
1547 
1548     /* preparing the SQL statement */
1549     sql =
1550 	do_prepare_read_node (accessor->topology_name, fields, accessor->has_z);
1551     ret =
1552 	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt_aux,
1553 			    NULL);
1554     sqlite3_free (sql);
1555     if (ret != SQLITE_OK)
1556       {
1557 	  char *msg = sqlite3_mprintf ("Prepare_getNodeById AUX error: \"%s\"",
1558 				       sqlite3_errmsg (accessor->db_handle));
1559 	  gaiatopo_set_last_error_msg (topo, msg);
1560 	  sqlite3_free (msg);
1561 	  *numelems = -1;
1562 	  return NULL;
1563       }
1564 
1565     list = create_nodes_list ();
1566     for (i = 0; i < *numelems; i++)
1567       {
1568 	  char *msg;
1569 	  if (!do_read_node
1570 	      (stmt_aux, list, *(ids + i), fields, accessor->has_z,
1571 	       "callback_getNodeById", &msg))
1572 	    {
1573 		gaiatopo_set_last_error_msg (topo, msg);
1574 		sqlite3_free (msg);
1575 		goto error;
1576 	    }
1577       }
1578 
1579     if (list->count == 0)
1580       {
1581 	  /* no node was found */
1582 	  *numelems = list->count;
1583       }
1584     else
1585       {
1586 	  struct topo_node *p_nd;
1587 	  result = rtalloc (ctx, sizeof (RTT_ISO_NODE) * list->count);
1588 	  p_nd = list->first;
1589 	  i = 0;
1590 	  while (p_nd != NULL)
1591 	    {
1592 		RTT_ISO_NODE *nd = result + i;
1593 		if (fields & RTT_COL_NODE_NODE_ID)
1594 		    nd->node_id = p_nd->node_id;
1595 		if (fields & RTT_COL_NODE_CONTAINING_FACE)
1596 		    nd->containing_face = p_nd->containing_face;
1597 		if (fields & RTT_COL_NODE_GEOM)
1598 		  {
1599 		      pa = ptarray_construct (ctx, accessor->has_z, 0, 1);
1600 		      pt4d.x = p_nd->x;
1601 		      pt4d.y = p_nd->y;
1602 		      if (accessor->has_z)
1603 			  pt4d.z = p_nd->z;
1604 		      ptarray_set_point4d (ctx, pa, 0, &pt4d);
1605 		      nd->geom =
1606 			  rtpoint_construct (ctx, accessor->srid, NULL, pa);
1607 		  }
1608 		i++;
1609 		p_nd = p_nd->next;
1610 	    }
1611 	  *numelems = list->count;
1612       }
1613     sqlite3_finalize (stmt_aux);
1614     destroy_nodes_list (list);
1615     return result;
1616 
1617   error:
1618     if (stmt_aux != NULL)
1619 	sqlite3_finalize (stmt_aux);
1620     if (list != NULL)
1621 	destroy_nodes_list (list);
1622     *numelems = -1;
1623     return NULL;
1624 }
1625 
1626 RTT_ISO_NODE *
callback_getNodeWithinDistance2D(const RTT_BE_TOPOLOGY * rtt_topo,const RTPOINT * pt,double dist,int * numelems,int fields,int limit)1627 callback_getNodeWithinDistance2D (const RTT_BE_TOPOLOGY * rtt_topo,
1628 				  const RTPOINT * pt, double dist,
1629 				  int *numelems, int fields, int limit)
1630 {
1631 /* callback function: getNodeWithinDistance2D */
1632     const RTCTX *ctx = NULL;
1633     struct splite_internal_cache *cache = NULL;
1634     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
1635     struct gaia_topology *accessor = (struct gaia_topology *) topo;
1636     sqlite3_stmt *stmt;
1637     int ret;
1638     double cx;
1639     double cy;
1640     RTPOINTARRAY *pa;
1641     RTPOINT4D pt4d;
1642     int count = 0;
1643     sqlite3_stmt *stmt_aux = NULL;
1644     char *sql;
1645     struct topo_nodes_list *list = NULL;
1646     RTT_ISO_NODE *result = NULL;
1647     if (accessor == NULL)
1648       {
1649 	  *numelems = -1;
1650 	  return NULL;
1651       }
1652 
1653     stmt = accessor->stmt_getNodeWithinDistance2D;
1654     if (stmt == NULL)
1655       {
1656 	  *numelems = -1;
1657 	  return NULL;
1658       }
1659 
1660     cache = (struct splite_internal_cache *) accessor->cache;
1661     if (cache == NULL)
1662 	return NULL;
1663     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1664 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1665 	return NULL;
1666     ctx = cache->RTTOPO_handle;
1667     if (ctx == NULL)
1668 	return NULL;
1669 
1670     if (limit >= 0)
1671       {
1672 	  /* preparing the auxiliary SQL statement */
1673 	  sql =
1674 	      do_prepare_read_node (accessor->topology_name, fields,
1675 				    accessor->has_z);
1676 	  ret =
1677 	      sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
1678 				  &stmt_aux, NULL);
1679 	  sqlite3_free (sql);
1680 	  if (ret != SQLITE_OK)
1681 	    {
1682 		char *msg =
1683 		    sqlite3_mprintf
1684 		    ("Prepare_getNodeWithinDistance2D AUX error: \"%s\"",
1685 		     sqlite3_errmsg (accessor->db_handle));
1686 		gaiatopo_set_last_error_msg (topo, msg);
1687 		sqlite3_free (msg);
1688 		*numelems = -1;
1689 		return NULL;
1690 	    }
1691       }
1692 
1693 /* extracting X and Y from RTPOINT */
1694     pa = pt->point;
1695     rt_getPoint4d_p (ctx, pa, 0, &pt4d);
1696     cx = pt4d.x;
1697     cy = pt4d.y;
1698 
1699 /* setting up the prepared statement */
1700     sqlite3_reset (stmt);
1701     sqlite3_clear_bindings (stmt);
1702     sqlite3_bind_double (stmt, 1, cx);
1703     sqlite3_bind_double (stmt, 2, cy);
1704     sqlite3_bind_double (stmt, 3, dist);
1705     sqlite3_bind_double (stmt, 4, cx);
1706     sqlite3_bind_double (stmt, 5, cy);
1707     sqlite3_bind_double (stmt, 6, dist);
1708     list = create_nodes_list ();
1709 
1710     while (1)
1711       {
1712 	  /* scrolling the result set rows */
1713 	  ret = sqlite3_step (stmt);
1714 	  if (ret == SQLITE_DONE)
1715 	      break;		/* end of result set */
1716 	  if (ret == SQLITE_ROW)
1717 	    {
1718 		sqlite3_int64 node_id = sqlite3_column_int64 (stmt, 0);
1719 		if (stmt_aux != NULL)
1720 		  {
1721 		      char *msg;
1722 		      if (!do_read_node
1723 			  (stmt_aux, list, node_id, fields, accessor->has_z,
1724 			   "callback_getNodeWithinDistance2D", &msg))
1725 			{
1726 			    gaiatopo_set_last_error_msg (topo, msg);
1727 			    sqlite3_free (msg);
1728 			    goto error;
1729 			}
1730 		  }
1731 		count++;
1732 		if (limit > 0)
1733 		  {
1734 		      if (count > limit)
1735 			  break;
1736 		  }
1737 		if (limit < 0)
1738 		    break;
1739 	    }
1740 	  else
1741 	    {
1742 		char *msg =
1743 		    sqlite3_mprintf ("callback_getNodeWithinDistance2D: %s",
1744 				     sqlite3_errmsg (accessor->db_handle));
1745 		gaiatopo_set_last_error_msg (topo, msg);
1746 		sqlite3_free (msg);
1747 		goto error;
1748 	    }
1749       }
1750 
1751     if (limit < 0)
1752       {
1753 	  result = NULL;
1754 	  *numelems = count;
1755       }
1756     else
1757       {
1758 	  if (list->count <= 0)
1759 	    {
1760 		result = NULL;
1761 		*numelems = 0;
1762 	    }
1763 	  else
1764 	    {
1765 		int i = 0;
1766 		struct topo_node *p_nd;
1767 		result = rtalloc (ctx, sizeof (RTT_ISO_NODE) * list->count);
1768 		p_nd = list->first;
1769 		while (p_nd != NULL)
1770 		  {
1771 		      RTT_ISO_NODE *nd = result + i;
1772 		      if (fields & RTT_COL_NODE_NODE_ID)
1773 			  nd->node_id = p_nd->node_id;
1774 		      if (fields & RTT_COL_NODE_CONTAINING_FACE)
1775 			  nd->containing_face = p_nd->containing_face;
1776 		      if (fields & RTT_COL_NODE_GEOM)
1777 			{
1778 			    pa = ptarray_construct (ctx, accessor->has_z, 0, 1);
1779 			    pt4d.x = p_nd->x;
1780 			    pt4d.y = p_nd->y;
1781 			    if (accessor->has_z)
1782 				pt4d.z = p_nd->z;
1783 			    ptarray_set_point4d (ctx, pa, 0, &pt4d);
1784 			    nd->geom =
1785 				rtpoint_construct (ctx, accessor->srid, NULL,
1786 						   pa);
1787 			}
1788 		      i++;
1789 		      p_nd = p_nd->next;
1790 		  }
1791 		*numelems = list->count;
1792 	    }
1793       }
1794 
1795     if (stmt_aux != NULL)
1796 	sqlite3_finalize (stmt_aux);
1797     destroy_nodes_list (list);
1798     sqlite3_reset (stmt);
1799     return result;
1800 
1801   error:
1802     sqlite3_reset (stmt);
1803     if (stmt_aux != NULL)
1804 	sqlite3_finalize (stmt_aux);
1805     if (list != NULL)
1806 	destroy_nodes_list (list);
1807     *numelems = -1;
1808     return NULL;
1809 }
1810 
1811 int
callback_insertNodes(const RTT_BE_TOPOLOGY * rtt_topo,RTT_ISO_NODE * nodes,int numelems)1812 callback_insertNodes (const RTT_BE_TOPOLOGY * rtt_topo, RTT_ISO_NODE * nodes,
1813 		      int numelems)
1814 {
1815 /* callback function: insertNodes */
1816     const RTCTX *ctx = NULL;
1817     struct splite_internal_cache *cache = NULL;
1818     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
1819     struct gaia_topology *accessor = (struct gaia_topology *) topo;
1820     sqlite3_stmt *stmt;
1821     int ret;
1822     int i;
1823     double x;
1824     double y;
1825     double z;
1826     RTPOINTARRAY *pa;
1827     RTPOINT4D pt4d;
1828     gaiaGeomCollPtr geom;
1829     unsigned char *p_blob;
1830     int n_bytes;
1831     int gpkg_mode = 0;
1832     int tiny_point = 0;
1833     if (accessor == NULL)
1834 	return 0;
1835 
1836     stmt = accessor->stmt_insertNodes;
1837     if (stmt == NULL)
1838 	return 0;
1839 
1840     cache = (struct splite_internal_cache *) accessor->cache;
1841     if (cache == NULL)
1842 	return 0;
1843     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1844 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1845 	return 0;
1846     ctx = cache->RTTOPO_handle;
1847     if (ctx == NULL)
1848 	return 0;
1849 
1850     if (accessor->cache != NULL)
1851       {
1852 	  struct splite_internal_cache *cache =
1853 	      (struct splite_internal_cache *) (accessor->cache);
1854 	  gpkg_mode = cache->gpkg_mode;
1855 	  tiny_point = cache->tinyPointEnabled;
1856       }
1857 
1858     for (i = 0; i < numelems; i++)
1859       {
1860 	  RTT_ISO_NODE *nd = nodes + i;
1861 	  /* setting up the prepared statement */
1862 	  sqlite3_reset (stmt);
1863 	  sqlite3_clear_bindings (stmt);
1864 	  if (nd->node_id <= 0)
1865 	      sqlite3_bind_null (stmt, 1);
1866 	  else
1867 	      sqlite3_bind_int64 (stmt, 1, nd->node_id);
1868 	  if (nd->containing_face < 0)
1869 	      sqlite3_bind_null (stmt, 2);
1870 	  else
1871 	      sqlite3_bind_int64 (stmt, 2, nd->containing_face);
1872 	  if (accessor->has_z)
1873 	      geom = gaiaAllocGeomCollXYZ ();
1874 	  else
1875 	      geom = gaiaAllocGeomColl ();
1876 	  /* extracting X and Y from RTPOINT */
1877 	  pa = nd->geom->point;
1878 	  rt_getPoint4d_p (ctx, pa, 0, &pt4d);
1879 	  x = pt4d.x;
1880 	  y = pt4d.y;
1881 	  if (accessor->has_z)
1882 	    {
1883 		z = pt4d.z;
1884 		gaiaAddPointToGeomCollXYZ (geom, x, y, z);
1885 	    }
1886 	  else
1887 	      gaiaAddPointToGeomColl (geom, x, y);
1888 	  geom->Srid = accessor->srid;
1889 	  geom->DeclaredType = GAIA_POINT;
1890 	  gaiaToSpatiaLiteBlobWkbEx2 (geom, &p_blob, &n_bytes, gpkg_mode,
1891 				      tiny_point);
1892 	  gaiaFreeGeomColl (geom);
1893 	  sqlite3_bind_blob (stmt, 3, p_blob, n_bytes, free);
1894 	  ret = sqlite3_step (stmt);
1895 	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
1896 	    {
1897 		/* retrieving the PK value */
1898 		nd->node_id = sqlite3_last_insert_rowid (accessor->db_handle);
1899 	    }
1900 	  else
1901 	    {
1902 		char *msg = sqlite3_mprintf ("callback_insertNodes: \"%s\"",
1903 					     sqlite3_errmsg
1904 					     (accessor->db_handle));
1905 		gaiatopo_set_last_error_msg (topo, msg);
1906 		sqlite3_free (msg);
1907 		goto error;
1908 	    }
1909       }
1910     sqlite3_reset (stmt);
1911     return 1;
1912 
1913   error:
1914     sqlite3_reset (stmt);
1915     return 0;
1916 }
1917 
1918 RTT_ISO_EDGE *
callback_getEdgeById(const RTT_BE_TOPOLOGY * rtt_topo,const RTT_ELEMID * ids,int * numelems,int fields)1919 callback_getEdgeById (const RTT_BE_TOPOLOGY * rtt_topo,
1920 		      const RTT_ELEMID * ids, int *numelems, int fields)
1921 {
1922 /* callback function: getEdgeById */
1923     const RTCTX *ctx = NULL;
1924     struct splite_internal_cache *cache = NULL;
1925     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
1926     struct gaia_topology *accessor = (struct gaia_topology *) topo;
1927     int ret;
1928     int i;
1929     sqlite3_stmt *stmt_aux = NULL;
1930     char *sql;
1931     struct topo_edges_list *list = NULL;
1932     RTT_ISO_EDGE *result = NULL;
1933     if (accessor == NULL)
1934       {
1935 	  *numelems = -1;
1936 	  return NULL;
1937       }
1938 
1939     cache = (struct splite_internal_cache *) accessor->cache;
1940     if (cache == NULL)
1941 	return NULL;
1942     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1943 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1944 	return NULL;
1945     ctx = cache->RTTOPO_handle;
1946     if (ctx == NULL)
1947 	return NULL;
1948 
1949     /* preparing the SQL statement */
1950     sql = do_prepare_read_edge (accessor->topology_name, fields);
1951     ret =
1952 	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
1953 			    &stmt_aux, NULL);
1954     sqlite3_free (sql);
1955     if (ret != SQLITE_OK)
1956       {
1957 	  char *msg = sqlite3_mprintf ("Prepare_getEdgeById AUX error: \"%s\"",
1958 				       sqlite3_errmsg (accessor->db_handle));
1959 	  gaiatopo_set_last_error_msg (topo, msg);
1960 	  sqlite3_free (msg);
1961 	  *numelems = -1;
1962 	  return NULL;
1963       }
1964 
1965     list = create_edges_list ();
1966     for (i = 0; i < *numelems; i++)
1967       {
1968 	  char *msg;
1969 	  if (!do_read_edge
1970 	      (stmt_aux, list, *(ids + i), fields, "callback_getEdgeById",
1971 	       &msg))
1972 	    {
1973 		gaiatopo_set_last_error_msg (topo, msg);
1974 		sqlite3_free (msg);
1975 		goto error;
1976 	    }
1977       }
1978 
1979     if (list->count == 0)
1980       {
1981 	  /* no edge was found */
1982 	  *numelems = list->count;
1983       }
1984     else
1985       {
1986 	  struct topo_edge *p_ed;
1987 	  result = rtalloc (ctx, sizeof (RTT_ISO_EDGE) * list->count);
1988 	  p_ed = list->first;
1989 	  i = 0;
1990 	  while (p_ed != NULL)
1991 	    {
1992 		RTT_ISO_EDGE *ed = result + i;
1993 		if (fields & RTT_COL_EDGE_EDGE_ID)
1994 		    ed->edge_id = p_ed->edge_id;
1995 		if (fields & RTT_COL_EDGE_START_NODE)
1996 		    ed->start_node = p_ed->start_node;
1997 		if (fields & RTT_COL_EDGE_END_NODE)
1998 		    ed->end_node = p_ed->end_node;
1999 		if (fields & RTT_COL_EDGE_FACE_LEFT)
2000 		    ed->face_left = p_ed->face_left;
2001 		if (fields & RTT_COL_EDGE_FACE_RIGHT)
2002 		    ed->face_right = p_ed->face_right;
2003 		if (fields & RTT_COL_EDGE_NEXT_LEFT)
2004 		    ed->next_left = p_ed->next_left;
2005 		if (fields & RTT_COL_EDGE_NEXT_RIGHT)
2006 		    ed->next_right = p_ed->next_right;
2007 		if (fields & RTT_COL_EDGE_GEOM)
2008 		    ed->geom =
2009 			gaia_convert_linestring_to_rtline (ctx, p_ed->geom,
2010 							   accessor->srid,
2011 							   accessor->has_z);
2012 		i++;
2013 		p_ed = p_ed->next;
2014 	    }
2015 	  *numelems = list->count;
2016       }
2017     sqlite3_finalize (stmt_aux);
2018     destroy_edges_list (list);
2019     return result;
2020 
2021   error:
2022     if (stmt_aux != NULL)
2023 	sqlite3_finalize (stmt_aux);
2024     if (list != NULL)
2025 	destroy_edges_list (list);
2026     *numelems = -1;
2027     return NULL;
2028 }
2029 
2030 RTT_ISO_EDGE *
callback_getEdgeWithinDistance2D(const RTT_BE_TOPOLOGY * rtt_topo,const RTPOINT * pt,double dist,int * numelems,int fields,int limit)2031 callback_getEdgeWithinDistance2D (const RTT_BE_TOPOLOGY * rtt_topo,
2032 				  const RTPOINT * pt, double dist,
2033 				  int *numelems, int fields, int limit)
2034 {
2035 /* callback function: getEdgeWithinDistance2D */
2036     const RTCTX *ctx = NULL;
2037     struct splite_internal_cache *cache = NULL;
2038     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
2039     struct gaia_topology *accessor = (struct gaia_topology *) topo;
2040     sqlite3_stmt *stmt;
2041     int ret;
2042     double cx;
2043     double cy;
2044     RTPOINTARRAY *pa;
2045     RTPOINT4D pt4d;
2046     int count = 0;
2047     sqlite3_stmt *stmt_aux = NULL;
2048     char *sql;
2049     struct topo_edges_list *list = NULL;
2050     RTT_ISO_EDGE *result = NULL;
2051     if (accessor == NULL)
2052       {
2053 	  *numelems = -1;
2054 	  return NULL;
2055       }
2056 
2057     stmt = accessor->stmt_getEdgeWithinDistance2D;
2058     if (stmt == NULL)
2059       {
2060 	  *numelems = -1;
2061 	  return NULL;
2062       }
2063 
2064     cache = (struct splite_internal_cache *) accessor->cache;
2065     if (cache == NULL)
2066 	return 0;
2067     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2068 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2069 	return 0;
2070     ctx = cache->RTTOPO_handle;
2071     if (ctx == NULL)
2072 	return 0;
2073 
2074     cache = (struct splite_internal_cache *) accessor->cache;
2075     if (cache == NULL)
2076 	return NULL;
2077     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2078 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2079 	return NULL;
2080     ctx = cache->RTTOPO_handle;
2081     if (ctx == NULL)
2082 	return NULL;
2083 
2084     if (limit >= 0)
2085       {
2086 	  /* preparing the auxiliary SQL statement */
2087 	  sql = do_prepare_read_edge (accessor->topology_name, fields);
2088 	  ret =
2089 	      sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
2090 				  &stmt_aux, NULL);
2091 	  sqlite3_free (sql);
2092 	  if (ret != SQLITE_OK)
2093 	    {
2094 		char *msg =
2095 		    sqlite3_mprintf ("Prepare_getEdgeById AUX error: \"%s\"",
2096 				     sqlite3_errmsg (accessor->db_handle));
2097 		gaiatopo_set_last_error_msg (topo, msg);
2098 		sqlite3_free (msg);
2099 		*numelems = -1;
2100 		return NULL;
2101 	    }
2102       }
2103 
2104 /* extracting X and Y from RTPOINT */
2105     pa = pt->point;
2106     rt_getPoint4d_p (ctx, pa, 0, &pt4d);
2107     cx = pt4d.x;
2108     cy = pt4d.y;
2109 
2110 /* setting up the prepared statement */
2111     sqlite3_reset (stmt);
2112     sqlite3_clear_bindings (stmt);
2113     sqlite3_bind_double (stmt, 1, cx);
2114     sqlite3_bind_double (stmt, 2, cy);
2115     sqlite3_bind_double (stmt, 3, dist);
2116     sqlite3_bind_double (stmt, 4, cx);
2117     sqlite3_bind_double (stmt, 5, cy);
2118     sqlite3_bind_double (stmt, 6, dist);
2119     list = create_edges_list ();
2120 
2121     while (1)
2122       {
2123 	  /* scrolling the result set rows */
2124 	  ret = sqlite3_step (stmt);
2125 	  if (ret == SQLITE_DONE)
2126 	      break;		/* end of result set */
2127 	  if (ret == SQLITE_ROW)
2128 	    {
2129 		sqlite3_int64 edge_id = sqlite3_column_int64 (stmt, 0);
2130 		if (stmt_aux != NULL)
2131 		  {
2132 		      char *msg;
2133 		      if (!do_read_edge
2134 			  (stmt_aux, list, edge_id, fields,
2135 			   "callback_getEdgeWithinDistance2D", &msg))
2136 			{
2137 			    gaiatopo_set_last_error_msg (topo, msg);
2138 			    sqlite3_free (msg);
2139 			    goto error;
2140 			}
2141 		  }
2142 		count++;
2143 		if (limit > 0)
2144 		  {
2145 		      if (count > limit)
2146 			  break;
2147 		  }
2148 		if (limit < 0)
2149 		    break;
2150 	    }
2151 	  else
2152 	    {
2153 		char *msg =
2154 		    sqlite3_mprintf ("callback_getEdgeWithinDistance2D: %s",
2155 				     sqlite3_errmsg (accessor->db_handle));
2156 		gaiatopo_set_last_error_msg (topo, msg);
2157 		sqlite3_free (msg);
2158 		goto error;
2159 	    }
2160       }
2161 
2162     if (limit < 0)
2163       {
2164 	  result = NULL;
2165 	  *numelems = count;
2166       }
2167     else
2168       {
2169 	  if (list->count <= 0)
2170 	    {
2171 		result = NULL;
2172 		*numelems = 0;
2173 	    }
2174 	  else
2175 	    {
2176 		int i = 0;
2177 		struct topo_edge *p_ed;
2178 		result = rtalloc (ctx, sizeof (RTT_ISO_EDGE) * list->count);
2179 		p_ed = list->first;
2180 		while (p_ed != NULL)
2181 		  {
2182 		      RTT_ISO_EDGE *ed = result + i;
2183 		      if (fields & RTT_COL_EDGE_EDGE_ID)
2184 			  ed->edge_id = p_ed->edge_id;
2185 		      if (fields & RTT_COL_EDGE_START_NODE)
2186 			  ed->start_node = p_ed->start_node;
2187 		      if (fields & RTT_COL_EDGE_END_NODE)
2188 			  ed->end_node = p_ed->end_node;
2189 		      if (fields & RTT_COL_EDGE_FACE_LEFT)
2190 			  ed->face_left = p_ed->face_left;
2191 		      if (fields & RTT_COL_EDGE_FACE_RIGHT)
2192 			  ed->face_right = p_ed->face_right;
2193 		      if (fields & RTT_COL_EDGE_NEXT_LEFT)
2194 			  ed->next_left = p_ed->next_left;
2195 		      if (fields & RTT_COL_EDGE_NEXT_RIGHT)
2196 			  ed->next_right = p_ed->next_right;
2197 		      if (fields & RTT_COL_EDGE_GEOM)
2198 			  ed->geom =
2199 			      gaia_convert_linestring_to_rtline (ctx,
2200 								 p_ed->geom,
2201 								 accessor->srid,
2202 								 accessor->
2203 								 has_z);
2204 		      i++;
2205 		      p_ed = p_ed->next;
2206 		  }
2207 		*numelems = list->count;
2208 	    }
2209       }
2210     sqlite3_reset (stmt);
2211     if (stmt_aux != NULL)
2212 	sqlite3_finalize (stmt_aux);
2213     destroy_edges_list (list);
2214     return result;
2215 
2216   error:
2217     sqlite3_reset (stmt);
2218     if (stmt_aux != NULL)
2219 	sqlite3_finalize (stmt_aux);
2220     if (list != NULL)
2221 	destroy_edges_list (list);
2222     *numelems = -1;
2223     return NULL;
2224 }
2225 
2226 RTT_ELEMID
callback_getNextEdgeId(const RTT_BE_TOPOLOGY * rtt_topo)2227 callback_getNextEdgeId (const RTT_BE_TOPOLOGY * rtt_topo)
2228 {
2229 /* callback function: getNextEdgeId */
2230     const RTCTX *ctx = NULL;
2231     struct splite_internal_cache *cache = NULL;
2232     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
2233     struct gaia_topology *accessor = (struct gaia_topology *) topo;
2234     sqlite3_stmt *stmt_in;
2235     sqlite3_stmt *stmt_out;
2236     int ret;
2237     sqlite3_int64 edge_id = -1;
2238     if (accessor == NULL)
2239 	return -1;
2240 
2241     stmt_in = accessor->stmt_getNextEdgeId;
2242     if (stmt_in == NULL)
2243 	return -1;
2244     stmt_out = accessor->stmt_setNextEdgeId;
2245     if (stmt_out == NULL)
2246 	return -1;
2247 
2248     cache = (struct splite_internal_cache *) accessor->cache;
2249     if (cache == NULL)
2250 	return -1;
2251     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2252 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2253 	return -1;
2254     ctx = cache->RTTOPO_handle;
2255     if (ctx == NULL)
2256 	return -1;
2257 
2258 /* setting up the prepared statement */
2259     sqlite3_reset (stmt_in);
2260     sqlite3_clear_bindings (stmt_in);
2261 
2262     while (1)
2263       {
2264 	  /* scrolling the result set rows */
2265 	  ret = sqlite3_step (stmt_in);
2266 	  if (ret == SQLITE_DONE)
2267 	      break;		/* end of result set */
2268 	  if (ret == SQLITE_ROW)
2269 	    {
2270 		edge_id = sqlite3_column_int64 (stmt_in, 0);
2271 	    }
2272 	  else
2273 	    {
2274 		char *msg = sqlite3_mprintf ("callback_getNextEdgeId: %s",
2275 					     sqlite3_errmsg
2276 					     (accessor->db_handle));
2277 		gaiatopo_set_last_error_msg (topo, msg);
2278 		sqlite3_free (msg);
2279 		goto stop;
2280 	    }
2281       }
2282 
2283 /* updating next_edge_id */
2284     sqlite3_reset (stmt_out);
2285     sqlite3_clear_bindings (stmt_out);
2286     ret = sqlite3_step (stmt_out);
2287     if (ret == SQLITE_DONE || ret == SQLITE_ROW)
2288       {
2289 	  sqlite3_reset (stmt_in);
2290 	  sqlite3_reset (stmt_out);
2291 	  return edge_id;
2292       }
2293     else
2294       {
2295 	  char *msg = sqlite3_mprintf ("callback_setNextEdgeId: \"%s\"",
2296 				       sqlite3_errmsg (accessor->db_handle));
2297 	  gaiatopo_set_last_error_msg (topo, msg);
2298 	  sqlite3_free (msg);
2299 	  edge_id = -1;
2300       }
2301   stop:
2302     if (edge_id >= 0)
2303 	edge_id++;
2304     sqlite3_reset (stmt_in);
2305     sqlite3_reset (stmt_out);
2306     return edge_id;
2307 }
2308 
2309 int
callback_insertEdges(const RTT_BE_TOPOLOGY * rtt_topo,RTT_ISO_EDGE * edges,int numelems)2310 callback_insertEdges (const RTT_BE_TOPOLOGY * rtt_topo, RTT_ISO_EDGE * edges,
2311 		      int numelems)
2312 {
2313 /* callback function: insertEdges */
2314     const RTCTX *ctx = NULL;
2315     struct splite_internal_cache *cache = NULL;
2316     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
2317     struct gaia_topology *accessor = (struct gaia_topology *) topo;
2318     sqlite3_stmt *stmt;
2319     int ret;
2320     int i;
2321     gaiaGeomCollPtr geom;
2322     unsigned char *p_blob;
2323     int n_bytes;
2324     int gpkg_mode = 0;
2325     int tiny_point = 0;
2326     if (accessor == NULL)
2327 	return 0;
2328 
2329     stmt = accessor->stmt_insertEdges;
2330     if (stmt == NULL)
2331 	return 0;
2332 
2333     cache = (struct splite_internal_cache *) accessor->cache;
2334     if (cache == NULL)
2335 	return 0;
2336     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2337 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2338 	return 0;
2339     ctx = cache->RTTOPO_handle;
2340     if (ctx == NULL)
2341 	return 0;
2342 
2343     if (accessor->cache != NULL)
2344       {
2345 	  struct splite_internal_cache *cache =
2346 	      (struct splite_internal_cache *) (accessor->cache);
2347 	  gpkg_mode = cache->gpkg_mode;
2348 	  tiny_point = cache->tinyPointEnabled;
2349       }
2350 
2351     for (i = 0; i < numelems; i++)
2352       {
2353 	  RTT_ISO_EDGE *eg = edges + i;
2354 	  /* setting up the prepared statement */
2355 	  sqlite3_reset (stmt);
2356 	  sqlite3_clear_bindings (stmt);
2357 	  if (eg->edge_id <= 0)
2358 	      sqlite3_bind_null (stmt, 1);
2359 	  else
2360 	      sqlite3_bind_int64 (stmt, 1, eg->edge_id);
2361 	  sqlite3_bind_int64 (stmt, 2, eg->start_node);
2362 	  sqlite3_bind_int64 (stmt, 3, eg->end_node);
2363 	  if (eg->face_left < 0)
2364 	      sqlite3_bind_null (stmt, 4);
2365 	  else
2366 	      sqlite3_bind_int64 (stmt, 4, eg->face_left);
2367 	  if (eg->face_right < 0)
2368 	      sqlite3_bind_null (stmt, 5);
2369 	  else
2370 	      sqlite3_bind_int64 (stmt, 5, eg->face_right);
2371 	  sqlite3_bind_int64 (stmt, 6, eg->next_left);
2372 	  sqlite3_bind_int64 (stmt, 7, eg->next_right);
2373 	  /* transforming the RTLINE into a Geometry-Linestring */
2374 	  geom = do_rtline_to_geom (ctx, eg->geom, accessor->srid);
2375 	  gaiaToSpatiaLiteBlobWkbEx2 (geom, &p_blob, &n_bytes, gpkg_mode,
2376 				      tiny_point);
2377 	  gaiaFreeGeomColl (geom);
2378 	  sqlite3_bind_blob (stmt, 8, p_blob, n_bytes, free);
2379 	  ret = sqlite3_step (stmt);
2380 	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
2381 	    {
2382 		/* retrieving the PK value */
2383 		eg->edge_id = sqlite3_last_insert_rowid (accessor->db_handle);
2384 	    }
2385 	  else
2386 	    {
2387 		char *msg = sqlite3_mprintf ("callback_insertEdges: \"%s\"",
2388 					     sqlite3_errmsg
2389 					     (accessor->db_handle));
2390 		gaiatopo_set_last_error_msg (topo, msg);
2391 		sqlite3_free (msg);
2392 		goto error;
2393 	    }
2394       }
2395     sqlite3_reset (stmt);
2396     return 1;
2397 
2398   error:
2399     sqlite3_reset (stmt);
2400     return 0;
2401 }
2402 
2403 int
callback_updateEdges(const RTT_BE_TOPOLOGY * rtt_topo,const RTT_ISO_EDGE * sel_edge,int sel_fields,const RTT_ISO_EDGE * upd_edge,int upd_fields,const RTT_ISO_EDGE * exc_edge,int exc_fields)2404 callback_updateEdges (const RTT_BE_TOPOLOGY * rtt_topo,
2405 		      const RTT_ISO_EDGE * sel_edge, int sel_fields,
2406 		      const RTT_ISO_EDGE * upd_edge, int upd_fields,
2407 		      const RTT_ISO_EDGE * exc_edge, int exc_fields)
2408 {
2409 /* callback function: updateEdges */
2410     const RTCTX *ctx = NULL;
2411     struct splite_internal_cache *cache = NULL;
2412     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
2413     struct gaia_topology *accessor = (struct gaia_topology *) topo;
2414     sqlite3_stmt *stmt = NULL;
2415     int ret;
2416     char *sql;
2417     char *prev;
2418     int comma = 0;
2419     char *table;
2420     char *xtable;
2421     int icol = 1;
2422     unsigned char *p_blob;
2423     int n_bytes;
2424     int gpkg_mode = 0;
2425     int tiny_point = 0;
2426     int changed = 0;
2427     if (accessor == NULL)
2428 	return -1;
2429 
2430     cache = (struct splite_internal_cache *) accessor->cache;
2431     if (cache == NULL)
2432 	return 0;
2433     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2434 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2435 	return 0;
2436     ctx = cache->RTTOPO_handle;
2437     if (ctx == NULL)
2438 	return 0;
2439 
2440     if (accessor->cache != NULL)
2441       {
2442 	  struct splite_internal_cache *cache =
2443 	      (struct splite_internal_cache *) (accessor->cache);
2444 	  gpkg_mode = cache->gpkg_mode;
2445 	  tiny_point = cache->tinyPointEnabled;
2446       }
2447 
2448 /* composing the SQL prepared statement */
2449     table = sqlite3_mprintf ("%s_edge", accessor->topology_name);
2450     xtable = gaiaDoubleQuotedSql (table);
2451     sqlite3_free (table);
2452     sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET ", xtable);
2453     free (xtable);
2454     prev = sql;
2455     if (upd_fields & RTT_COL_EDGE_EDGE_ID)
2456       {
2457 	  if (comma)
2458 	      sql = sqlite3_mprintf ("%s, edge_id = ?", prev);
2459 	  else
2460 	      sql = sqlite3_mprintf ("%s edge_id = ?", prev);
2461 	  comma = 1;
2462 	  sqlite3_free (prev);
2463 	  prev = sql;
2464       }
2465     if (upd_fields & RTT_COL_EDGE_START_NODE)
2466       {
2467 	  if (comma)
2468 	      sql = sqlite3_mprintf ("%s, start_node = ?", prev);
2469 	  else
2470 	      sql = sqlite3_mprintf ("%s start_node = ?", prev);
2471 	  comma = 1;
2472 	  sqlite3_free (prev);
2473 	  prev = sql;
2474       }
2475     if (upd_fields & RTT_COL_EDGE_END_NODE)
2476       {
2477 	  if (comma)
2478 	      sql = sqlite3_mprintf ("%s, end_node = ?", prev);
2479 	  else
2480 	      sql = sqlite3_mprintf ("%s end_node = ?", prev);
2481 	  comma = 1;
2482 	  sqlite3_free (prev);
2483 	  prev = sql;
2484       }
2485     if (upd_fields & RTT_COL_EDGE_FACE_LEFT)
2486       {
2487 	  if (comma)
2488 	      sql = sqlite3_mprintf ("%s, left_face = ?", prev);
2489 	  else
2490 	      sql = sqlite3_mprintf ("%s left_face = ?", prev);
2491 	  comma = 1;
2492 	  sqlite3_free (prev);
2493 	  prev = sql;
2494       }
2495     if (upd_fields & RTT_COL_EDGE_FACE_RIGHT)
2496       {
2497 	  if (comma)
2498 	      sql = sqlite3_mprintf ("%s, right_face = ?", prev);
2499 	  else
2500 	      sql = sqlite3_mprintf ("%s right_face = ?", prev);
2501 	  comma = 1;
2502 	  sqlite3_free (prev);
2503 	  prev = sql;
2504       }
2505     if (upd_fields & RTT_COL_EDGE_NEXT_LEFT)
2506       {
2507 	  if (comma)
2508 	      sql = sqlite3_mprintf ("%s, next_left_edge = ?", prev);
2509 	  else
2510 	      sql = sqlite3_mprintf ("%s next_left_edge = ?", prev);
2511 	  comma = 1;
2512 	  sqlite3_free (prev);
2513 	  prev = sql;
2514       }
2515     if (upd_fields & RTT_COL_EDGE_NEXT_RIGHT)
2516       {
2517 	  if (comma)
2518 	      sql = sqlite3_mprintf ("%s, next_right_edge = ?", prev);
2519 	  else
2520 	      sql = sqlite3_mprintf ("%s next_right_edge = ?", prev);
2521 	  comma = 1;
2522 	  sqlite3_free (prev);
2523 	  prev = sql;
2524       }
2525     if (upd_fields & RTT_COL_EDGE_GEOM)
2526       {
2527 	  if (comma)
2528 	      sql = sqlite3_mprintf ("%s, geom = ?", prev);
2529 	  else
2530 	      sql = sqlite3_mprintf ("%s geom = ?", prev);
2531 	  comma = 1;
2532 	  sqlite3_free (prev);
2533 	  prev = sql;
2534       }
2535     if (exc_edge || sel_edge)
2536       {
2537 	  sql = sqlite3_mprintf ("%s WHERE", prev);
2538 	  sqlite3_free (prev);
2539 	  prev = sql;
2540 	  if (sel_edge)
2541 	    {
2542 		comma = 0;
2543 		if (sel_fields & RTT_COL_EDGE_EDGE_ID)
2544 		  {
2545 		      if (comma)
2546 			  sql = sqlite3_mprintf ("%s AND edge_id = ?", prev);
2547 		      else
2548 			  sql = sqlite3_mprintf ("%s edge_id = ?", prev);
2549 		      comma = 1;
2550 		      sqlite3_free (prev);
2551 		      prev = sql;
2552 		  }
2553 		if (sel_fields & RTT_COL_EDGE_START_NODE)
2554 		  {
2555 		      if (comma)
2556 			  sql = sqlite3_mprintf ("%s AND start_node = ?", prev);
2557 		      else
2558 			  sql = sqlite3_mprintf ("%s start_node = ?", prev);
2559 		      comma = 1;
2560 		      sqlite3_free (prev);
2561 		      prev = sql;
2562 		  }
2563 		if (sel_fields & RTT_COL_EDGE_END_NODE)
2564 		  {
2565 		      if (comma)
2566 			  sql = sqlite3_mprintf ("%s AND end_node = ?", prev);
2567 		      else
2568 			  sql = sqlite3_mprintf ("%s end_node = ?", prev);
2569 		      comma = 1;
2570 		      sqlite3_free (prev);
2571 		      prev = sql;
2572 		  }
2573 		if (sel_fields & RTT_COL_EDGE_FACE_LEFT)
2574 		  {
2575 		      if (sel_edge->face_left < 0)
2576 			{
2577 			    if (comma)
2578 				sql =
2579 				    sqlite3_mprintf ("%s AND left_face IS NULL",
2580 						     prev);
2581 			    else
2582 				sql =
2583 				    sqlite3_mprintf ("%s left_face IS NULL",
2584 						     prev);
2585 			}
2586 		      else
2587 			{
2588 			    if (comma)
2589 				sql =
2590 				    sqlite3_mprintf ("%s AND left_face = ?",
2591 						     prev);
2592 			    else
2593 				sql =
2594 				    sqlite3_mprintf ("%s left_face = ?", prev);
2595 			}
2596 		      comma = 1;
2597 		      sqlite3_free (prev);
2598 		      prev = sql;
2599 		  }
2600 		if (sel_fields & RTT_COL_EDGE_FACE_RIGHT)
2601 		  {
2602 		      if (sel_edge->face_right < 0)
2603 			{
2604 			    if (comma)
2605 				sql =
2606 				    sqlite3_mprintf
2607 				    ("%s AND right_face IS NULL", prev);
2608 			    else
2609 				sql =
2610 				    sqlite3_mprintf ("%s right_face IS NULL",
2611 						     prev);
2612 			}
2613 		      else
2614 			{
2615 			    if (comma)
2616 				sql =
2617 				    sqlite3_mprintf ("%s AND right_face = ?",
2618 						     prev);
2619 			    else
2620 				sql =
2621 				    sqlite3_mprintf ("%s right_face = ?", prev);
2622 			}
2623 		      comma = 1;
2624 		      sqlite3_free (prev);
2625 		      prev = sql;
2626 		  }
2627 		if (sel_fields & RTT_COL_EDGE_NEXT_LEFT)
2628 		  {
2629 		      if (comma)
2630 			  sql =
2631 			      sqlite3_mprintf
2632 			      ("%s AND next_left_edge = ?", prev);
2633 		      else
2634 			  sql = sqlite3_mprintf ("%s next_left_edge = ?", prev);
2635 		      comma = 1;
2636 		      sqlite3_free (prev);
2637 		      prev = sql;
2638 		  }
2639 		if (sel_fields & RTT_COL_EDGE_NEXT_RIGHT)
2640 		  {
2641 		      if (comma)
2642 			  sql =
2643 			      sqlite3_mprintf
2644 			      ("%s AND next_right_edge = ?", prev);
2645 		      else
2646 			  sql =
2647 			      sqlite3_mprintf ("%s next_right_edge = ?", prev);
2648 		      comma = 1;
2649 		      sqlite3_free (prev);
2650 		      prev = sql;
2651 		  }
2652 	    }
2653 	  if (exc_edge)
2654 	    {
2655 		if (sel_edge)
2656 		  {
2657 		      sql = sqlite3_mprintf ("%s AND", prev);
2658 		      sqlite3_free (prev);
2659 		      prev = sql;
2660 		  }
2661 		comma = 0;
2662 		if (exc_fields & RTT_COL_EDGE_EDGE_ID)
2663 		  {
2664 		      if (comma)
2665 			  sql = sqlite3_mprintf ("%s AND edge_id <> ?", prev);
2666 		      else
2667 			  sql = sqlite3_mprintf ("%s edge_id <> ?", prev);
2668 		      comma = 1;
2669 		      sqlite3_free (prev);
2670 		      prev = sql;
2671 		  }
2672 		if (exc_fields & RTT_COL_EDGE_START_NODE)
2673 		  {
2674 		      if (comma)
2675 			  sql =
2676 			      sqlite3_mprintf ("%s AND start_node <> ?", prev);
2677 		      else
2678 			  sql = sqlite3_mprintf ("%s start_node <> ?", prev);
2679 		      comma = 1;
2680 		      sqlite3_free (prev);
2681 		      prev = sql;
2682 		  }
2683 		if (exc_fields & RTT_COL_EDGE_END_NODE)
2684 		  {
2685 		      if (comma)
2686 			  sql = sqlite3_mprintf ("%s AND end_node <> ?", prev);
2687 		      else
2688 			  sql = sqlite3_mprintf ("%s end_node <> ?", prev);
2689 		      comma = 1;
2690 		      sqlite3_free (prev);
2691 		      prev = sql;
2692 		  }
2693 		if (exc_fields & RTT_COL_EDGE_FACE_LEFT)
2694 		  {
2695 		      if (exc_edge->face_left < 0)
2696 			{
2697 			    if (comma)
2698 				sql =
2699 				    sqlite3_mprintf
2700 				    ("%s AND left_face IS NOT NULL", prev);
2701 			    else
2702 				sql =
2703 				    sqlite3_mprintf ("%s left_face IS NOT NULL",
2704 						     prev);
2705 			}
2706 		      else
2707 			{
2708 			    if (comma)
2709 				sql =
2710 				    sqlite3_mprintf ("%s AND left_face <> ?",
2711 						     prev);
2712 			    else
2713 				sql =
2714 				    sqlite3_mprintf ("%s left_face <> ?", prev);
2715 			}
2716 		      comma = 1;
2717 		      sqlite3_free (prev);
2718 		      prev = sql;
2719 		  }
2720 		if (exc_fields & RTT_COL_EDGE_FACE_RIGHT)
2721 		  {
2722 		      if (exc_edge->face_right < 0)
2723 			{
2724 			    if (comma)
2725 				sql =
2726 				    sqlite3_mprintf
2727 				    ("%s AND right_face IS NOT NULL", prev);
2728 			    else
2729 				sql =
2730 				    sqlite3_mprintf
2731 				    ("%s right_face IS NOT NULL", prev);
2732 			}
2733 		      else
2734 			{
2735 			    if (comma)
2736 				sql =
2737 				    sqlite3_mprintf ("%s AND right_face <> ?",
2738 						     prev);
2739 			    else
2740 				sql =
2741 				    sqlite3_mprintf ("%s right_face <> ?",
2742 						     prev);
2743 			}
2744 		      comma = 1;
2745 		      sqlite3_free (prev);
2746 		      prev = sql;
2747 		  }
2748 		if (exc_fields & RTT_COL_EDGE_NEXT_LEFT)
2749 		  {
2750 		      if (comma)
2751 			  sql =
2752 			      sqlite3_mprintf
2753 			      ("%s AND next_left_edge <> ?", prev);
2754 		      else
2755 			  sql =
2756 			      sqlite3_mprintf ("%s next_left_edge <> ?", prev);
2757 		      comma = 1;
2758 		      sqlite3_free (prev);
2759 		      prev = sql;
2760 		  }
2761 		if (exc_fields & RTT_COL_EDGE_NEXT_RIGHT)
2762 		  {
2763 		      if (comma)
2764 			  sql =
2765 			      sqlite3_mprintf
2766 			      ("%s AND next_right_edge <> ?", prev);
2767 		      else
2768 			  sql =
2769 			      sqlite3_mprintf ("%s next_right_edge <> ?", prev);
2770 		      comma = 1;
2771 		      sqlite3_free (prev);
2772 		      prev = sql;
2773 		  }
2774 	    }
2775       }
2776     ret =
2777 	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt,
2778 			    NULL);
2779     sqlite3_free (sql);
2780     if (ret != SQLITE_OK)
2781       {
2782 	  char *msg = sqlite3_mprintf ("Prepare_updateEdges error: \"%s\"",
2783 				       sqlite3_errmsg (accessor->db_handle));
2784 	  gaiatopo_set_last_error_msg (topo, msg);
2785 	  sqlite3_free (msg);
2786 	  return -1;
2787       }
2788 
2789 /* parameter binding */
2790     sqlite3_reset (stmt);
2791     sqlite3_clear_bindings (stmt);
2792     if (upd_fields & RTT_COL_EDGE_EDGE_ID)
2793       {
2794 	  sqlite3_bind_int64 (stmt, icol, upd_edge->edge_id);
2795 	  icol++;
2796       }
2797     if (upd_fields & RTT_COL_EDGE_START_NODE)
2798       {
2799 	  sqlite3_bind_int64 (stmt, icol, upd_edge->start_node);
2800 	  icol++;
2801       }
2802     if (upd_fields & RTT_COL_EDGE_END_NODE)
2803       {
2804 	  sqlite3_bind_int64 (stmt, icol, upd_edge->end_node);
2805 	  icol++;
2806       }
2807     if (upd_fields & RTT_COL_EDGE_FACE_LEFT)
2808       {
2809 	  if (upd_edge->face_left < 0)
2810 	      sqlite3_bind_null (stmt, icol);
2811 	  else
2812 	      sqlite3_bind_int64 (stmt, icol, upd_edge->face_left);
2813 	  icol++;
2814       }
2815     if (upd_fields & RTT_COL_EDGE_FACE_RIGHT)
2816       {
2817 	  if (upd_edge->face_right < 0)
2818 	      sqlite3_bind_null (stmt, icol);
2819 	  else
2820 	      sqlite3_bind_int64 (stmt, icol, upd_edge->face_right);
2821 	  icol++;
2822       }
2823     if (upd_fields & RTT_COL_EDGE_NEXT_LEFT)
2824       {
2825 	  sqlite3_bind_int64 (stmt, icol, upd_edge->next_left);
2826 	  icol++;
2827       }
2828     if (upd_fields & RTT_COL_EDGE_NEXT_RIGHT)
2829       {
2830 	  sqlite3_bind_int64 (stmt, icol, upd_edge->next_right);
2831 	  icol++;
2832       }
2833     if (upd_fields & RTT_COL_EDGE_GEOM)
2834       {
2835 	  /* transforming the RTLINE into a Geometry-Linestring */
2836 	  gaiaGeomCollPtr geom =
2837 	      do_rtline_to_geom (ctx, upd_edge->geom, accessor->srid);
2838 	  gaiaToSpatiaLiteBlobWkbEx2 (geom, &p_blob, &n_bytes, gpkg_mode,
2839 				      tiny_point);
2840 	  gaiaFreeGeomColl (geom);
2841 	  sqlite3_bind_blob (stmt, icol, p_blob, n_bytes, free);
2842 	  icol++;
2843       }
2844     if (sel_edge)
2845       {
2846 	  if (sel_fields & RTT_COL_EDGE_EDGE_ID)
2847 	    {
2848 		sqlite3_bind_int64 (stmt, icol, sel_edge->edge_id);
2849 		icol++;
2850 	    }
2851 	  if (sel_fields & RTT_COL_EDGE_START_NODE)
2852 	    {
2853 		sqlite3_bind_int64 (stmt, icol, sel_edge->start_node);
2854 		icol++;
2855 	    }
2856 	  if (sel_fields & RTT_COL_EDGE_END_NODE)
2857 	    {
2858 		sqlite3_bind_int64 (stmt, icol, sel_edge->end_node);
2859 		icol++;
2860 	    }
2861 	  if (sel_fields & RTT_COL_EDGE_FACE_LEFT)
2862 	    {
2863 		if (sel_edge->face_left < 0)
2864 		    sqlite3_bind_null (stmt, icol);
2865 		else
2866 		    sqlite3_bind_int64 (stmt, icol, sel_edge->face_left);
2867 		icol++;
2868 	    }
2869 	  if (sel_fields & RTT_COL_EDGE_FACE_RIGHT)
2870 	    {
2871 		if (sel_edge->face_right < 0)
2872 		    sqlite3_bind_null (stmt, icol);
2873 		else
2874 		    sqlite3_bind_int64 (stmt, icol, sel_edge->face_right);
2875 		icol++;
2876 	    }
2877 	  if (sel_fields & RTT_COL_EDGE_NEXT_LEFT)
2878 	    {
2879 		sqlite3_bind_int64 (stmt, icol, sel_edge->next_left);
2880 		icol++;
2881 	    }
2882 	  if (sel_fields & RTT_COL_EDGE_NEXT_RIGHT)
2883 	    {
2884 		sqlite3_bind_int64 (stmt, icol, sel_edge->next_right);
2885 		icol++;
2886 	    }
2887       }
2888     if (exc_edge)
2889       {
2890 	  if (exc_fields & RTT_COL_EDGE_EDGE_ID)
2891 	    {
2892 		sqlite3_bind_int64 (stmt, icol, exc_edge->edge_id);
2893 		icol++;
2894 	    }
2895 	  if (exc_fields & RTT_COL_EDGE_START_NODE)
2896 	    {
2897 		sqlite3_bind_int64 (stmt, icol, exc_edge->start_node);
2898 		icol++;
2899 	    }
2900 	  if (exc_fields & RTT_COL_EDGE_END_NODE)
2901 	    {
2902 		sqlite3_bind_int64 (stmt, icol, exc_edge->end_node);
2903 		icol++;
2904 	    }
2905 	  if (exc_fields & RTT_COL_EDGE_FACE_LEFT)
2906 	    {
2907 		if (exc_edge->face_left < 0)
2908 		    sqlite3_bind_null (stmt, icol);
2909 		else
2910 		    sqlite3_bind_int64 (stmt, icol, exc_edge->face_left);
2911 		icol++;
2912 	    }
2913 	  if (exc_fields & RTT_COL_EDGE_FACE_RIGHT)
2914 	    {
2915 		if (exc_edge->face_right < 0)
2916 		    sqlite3_bind_null (stmt, icol);
2917 		else
2918 		    sqlite3_bind_int64 (stmt, icol, exc_edge->face_right);
2919 		icol++;
2920 	    }
2921 	  if (exc_fields & RTT_COL_EDGE_NEXT_LEFT)
2922 	    {
2923 		sqlite3_bind_int64 (stmt, icol, exc_edge->next_left);
2924 		icol++;
2925 	    }
2926 	  if (exc_fields & RTT_COL_EDGE_NEXT_RIGHT)
2927 	    {
2928 		sqlite3_bind_int64 (stmt, icol, exc_edge->next_right);
2929 		icol++;
2930 	    }
2931       }
2932     ret = sqlite3_step (stmt);
2933     if (ret == SQLITE_DONE || ret == SQLITE_ROW)
2934 	changed = sqlite3_changes (accessor->db_handle);
2935     else
2936       {
2937 	  char *msg = sqlite3_mprintf ("callback_updateEdges: \"%s\"",
2938 				       sqlite3_errmsg (accessor->db_handle));
2939 	  gaiatopo_set_last_error_msg (topo, msg);
2940 	  sqlite3_free (msg);
2941 	  goto error;
2942       }
2943     sqlite3_finalize (stmt);
2944     return changed;
2945 
2946   error:
2947     sqlite3_finalize (stmt);
2948     return -1;
2949 }
2950 
2951 RTT_ISO_FACE *
callback_getFaceById(const RTT_BE_TOPOLOGY * rtt_topo,const RTT_ELEMID * ids,int * numelems,int fields)2952 callback_getFaceById (const RTT_BE_TOPOLOGY * rtt_topo,
2953 		      const RTT_ELEMID * ids, int *numelems, int fields)
2954 {
2955 /* callback function: getFeceById */
2956     const RTCTX *ctx = NULL;
2957     struct splite_internal_cache *cache = NULL;
2958     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
2959     struct gaia_topology *accessor = (struct gaia_topology *) topo;
2960     sqlite3_stmt *stmt_aux = NULL;
2961     int ret;
2962     int i;
2963     char *sql;
2964     char *prev;
2965     char *table;
2966     char *xtable;
2967     int comma = 0;
2968     struct topo_faces_list *list = NULL;
2969     RTT_ISO_FACE *result = NULL;
2970     if (accessor == NULL)
2971       {
2972 	  *numelems = -1;
2973 	  return NULL;
2974       }
2975 
2976     cache = (struct splite_internal_cache *) accessor->cache;
2977     if (cache == NULL)
2978 	return 0;
2979     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2980 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2981 	return 0;
2982     ctx = cache->RTTOPO_handle;
2983     if (ctx == NULL)
2984 	return 0;
2985 
2986     /* preparing the SQL statement */
2987     sql = sqlite3_mprintf ("SELECT ");
2988     prev = sql;
2989     if (fields & RTT_COL_FACE_FACE_ID)
2990       {
2991 	  if (comma)
2992 	      sql = sqlite3_mprintf ("%s, face_id", prev);
2993 	  else
2994 	      sql = sqlite3_mprintf ("%s face_id", prev);
2995 	  comma = 1;
2996 	  sqlite3_free (prev);
2997 	  prev = sql;
2998       }
2999     if (fields & RTT_COL_FACE_MBR)
3000       {
3001 	  if (comma)
3002 	      sql =
3003 		  sqlite3_mprintf
3004 		  ("%s, MbrMinX(mbr), MbrMinY(mbr), MbrMaxX(mbr), MbrMaxY(mbr)",
3005 		   prev);
3006 	  else
3007 	      sql =
3008 		  sqlite3_mprintf
3009 		  ("%s MbrMinX(mbr), MbrMinY(mbr), MbrMaxX(mbr), MbrMaxY(mbr)",
3010 		   prev);
3011 	  comma = 1;
3012 	  sqlite3_free (prev);
3013 	  prev = sql;
3014       }
3015     table = sqlite3_mprintf ("%s_face", accessor->topology_name);
3016     xtable = gaiaDoubleQuotedSql (table);
3017     sqlite3_free (table);
3018     sql =
3019 	sqlite3_mprintf ("%s FROM MAIN.\"%s\" WHERE face_id = ?", prev, xtable);
3020     sqlite3_free (prev);
3021     free (xtable);
3022     ret =
3023 	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt_aux,
3024 			    NULL);
3025     sqlite3_free (sql);
3026     if (ret != SQLITE_OK)
3027       {
3028 	  char *msg = sqlite3_mprintf ("Prepare_getFaceById AUX error: \"%s\"",
3029 				       sqlite3_errmsg (accessor->db_handle));
3030 	  gaiatopo_set_last_error_msg (topo, msg);
3031 	  sqlite3_free (msg);
3032 	  *numelems = -1;
3033 	  return NULL;
3034       }
3035 
3036     list = create_faces_list ();
3037     for (i = 0; i < *numelems; i++)
3038       {
3039 	  char *msg;
3040 	  if (!do_read_face
3041 	      (stmt_aux, list, *(ids + i), fields, "callback_getFaceById",
3042 	       &msg))
3043 	    {
3044 		gaiatopo_set_last_error_msg (topo, msg);
3045 		sqlite3_free (msg);
3046 		goto error;
3047 	    }
3048       }
3049 
3050     if (list->count == 0)
3051       {
3052 	  /* no face was found */
3053 	  *numelems = list->count;
3054       }
3055     else
3056       {
3057 	  struct topo_face *p_fc;
3058 	  result = rtalloc (ctx, sizeof (RTT_ISO_FACE) * list->count);
3059 	  p_fc = list->first;
3060 	  i = 0;
3061 	  while (p_fc != NULL)
3062 	    {
3063 		RTT_ISO_FACE *fc = result + i;
3064 		if (fields & RTT_COL_FACE_FACE_ID)
3065 		    fc->face_id = p_fc->face_id;
3066 		if (fields & RTT_COL_FACE_MBR)
3067 		  {
3068 		      if (p_fc->id == 0)
3069 			  fc->mbr = NULL;
3070 		      else
3071 			{
3072 			    fc->mbr = gbox_new (ctx, 0);
3073 			    fc->mbr->xmin = p_fc->minx;
3074 			    fc->mbr->ymin = p_fc->miny;
3075 			    fc->mbr->xmax = p_fc->maxx;
3076 			    fc->mbr->ymax = p_fc->maxy;
3077 			}
3078 		  }
3079 		i++;
3080 		p_fc = p_fc->next;
3081 	    }
3082 	  *numelems = list->count;
3083       }
3084     sqlite3_finalize (stmt_aux);
3085     destroy_faces_list (list);
3086     return result;
3087 
3088   error:
3089     if (stmt_aux != NULL)
3090 	sqlite3_finalize (stmt_aux);
3091     if (list != NULL)
3092 	destroy_faces_list (list);
3093     *numelems = -1;
3094     return NULL;
3095 }
3096 
3097 RTT_ELEMID
callback_getFaceContainingPoint(const RTT_BE_TOPOLOGY * rtt_topo,const RTPOINT * pt)3098 callback_getFaceContainingPoint (const RTT_BE_TOPOLOGY * rtt_topo,
3099 				 const RTPOINT * pt)
3100 {
3101 /* callback function: getFaceContainingPoint */
3102     const RTCTX *ctx = NULL;
3103     struct splite_internal_cache *cache = NULL;
3104     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
3105     struct gaia_topology *accessor = (struct gaia_topology *) topo;
3106     sqlite3_stmt *stmt;
3107     sqlite3_stmt *stmt_aux;
3108     int ret;
3109     double cx;
3110     double cy;
3111     float fx;
3112     float fy;
3113     double tic;
3114     double tic2;
3115     RTPOINTARRAY *pa;
3116     RTPOINT4D pt4d;
3117     int count = 0;
3118     sqlite3_int64 face_id;
3119     if (accessor == NULL)
3120 	return -2;
3121 
3122     stmt = accessor->stmt_getFaceContainingPoint_1;
3123     if (stmt == NULL)
3124 	return -2;
3125     stmt_aux = accessor->stmt_getFaceContainingPoint_2;
3126     if (stmt_aux == NULL)
3127 	return -2;
3128 
3129     cache = (struct splite_internal_cache *) accessor->cache;
3130     if (cache == NULL)
3131 	return -1;
3132     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3133 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3134 	return -1;
3135     ctx = cache->RTTOPO_handle;
3136     if (ctx == NULL)
3137 	return -1;
3138 
3139 /* extracting X and Y from RTPOINT */
3140     pa = pt->point;
3141     rt_getPoint4d_p (ctx, pa, 0, &pt4d);
3142     cx = pt4d.x;
3143     cy = pt4d.y;
3144 
3145 /* adjusting the MBR so to compensate for DOUBLE/FLOAT truncations */
3146     fx = (float) cx;
3147     fy = (float) cy;
3148     tic = fabs (cx - fx);
3149     tic2 = fabs (cy - fy);
3150     if (tic2 > tic)
3151 	tic = tic2;
3152     tic2 = fabs (cx - fx);
3153     if (tic2 > tic)
3154 	tic = tic2;
3155     tic2 = fabs (cy - fy);
3156     if (tic2 > tic)
3157 	tic = tic2;
3158     tic *= 2.0;
3159 
3160 /* setting up the prepared statement */
3161     sqlite3_reset (stmt);
3162     sqlite3_clear_bindings (stmt);
3163     sqlite3_bind_double (stmt, 1, cx + tic);
3164     sqlite3_bind_double (stmt, 2, cx - tic);
3165     sqlite3_bind_double (stmt, 3, cy + tic);
3166     sqlite3_bind_double (stmt, 4, cy - tic);
3167 
3168     while (1)
3169       {
3170 	  /* scrolling the result set rows [R*Tree] */
3171 	  ret = sqlite3_step (stmt);
3172 	  if (ret == SQLITE_DONE)
3173 	      break;		/* end of result set */
3174 	  if (ret == SQLITE_ROW)
3175 	    {
3176 		sqlite3_int64 id = sqlite3_column_int64 (stmt, 0);
3177 		/* testing for real intersection */
3178 		sqlite3_reset (stmt_aux);
3179 		sqlite3_clear_bindings (stmt_aux);
3180 		sqlite3_bind_int64 (stmt_aux, 1, id);
3181 		sqlite3_bind_double (stmt_aux, 2, cx);
3182 		sqlite3_bind_double (stmt_aux, 3, cy);
3183 		while (1)
3184 		  {
3185 		      ret = sqlite3_step (stmt_aux);
3186 		      if (ret == SQLITE_DONE)
3187 			  break;	/* end of result set */
3188 		      if (ret == SQLITE_ROW)
3189 			{
3190 			    if (sqlite3_column_type (stmt_aux, 0) ==
3191 				SQLITE_INTEGER)
3192 			      {
3193 				  if (sqlite3_column_int (stmt_aux, 0) == 1)
3194 				    {
3195 					face_id = id;
3196 					count++;
3197 					break;
3198 				    }
3199 			      }
3200 			}
3201 		      else
3202 			{
3203 			    char *msg =
3204 				sqlite3_mprintf
3205 				("callback_getFaceContainingPoint #2: %s",
3206 				 sqlite3_errmsg (accessor->db_handle));
3207 			    gaiatopo_set_last_error_msg (topo, msg);
3208 			    sqlite3_free (msg);
3209 			    goto error;
3210 			}
3211 		  }
3212 		if (count > 0)
3213 		    break;
3214 	    }
3215 	  else
3216 	    {
3217 		char *msg =
3218 		    sqlite3_mprintf ("callback_getFaceContainingPoint #1: %s",
3219 				     sqlite3_errmsg (accessor->db_handle));
3220 		gaiatopo_set_last_error_msg (topo, msg);
3221 		sqlite3_free (msg);
3222 		goto error;
3223 	    }
3224       }
3225 
3226     sqlite3_reset (stmt);
3227     if (count == 0)
3228 	return -1;		/* none found */
3229     return face_id;
3230 
3231   error:
3232     sqlite3_reset (stmt);
3233     return -2;
3234 }
3235 
3236 int
callback_deleteEdges(const RTT_BE_TOPOLOGY * rtt_topo,const RTT_ISO_EDGE * sel_edge,int sel_fields)3237 callback_deleteEdges (const RTT_BE_TOPOLOGY * rtt_topo,
3238 		      const RTT_ISO_EDGE * sel_edge, int sel_fields)
3239 {
3240 /* callback function: deleteEdgest */
3241     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
3242     struct gaia_topology *accessor = (struct gaia_topology *) topo;
3243     sqlite3_stmt *stmt = NULL;
3244     int ret;
3245     char *sql;
3246     char *prev;
3247     int comma = 0;
3248     char *table;
3249     char *xtable;
3250     int icol = 1;
3251     int changed = 0;
3252     if (accessor == NULL)
3253 	return -1;
3254 
3255 /* composing the SQL prepared statement */
3256     table = sqlite3_mprintf ("%s_edge", accessor->topology_name);
3257     xtable = gaiaDoubleQuotedSql (table);
3258     sqlite3_free (table);
3259     sql = sqlite3_mprintf ("DELETE FROM MAIN.\"%s\" WHERE", xtable);
3260     free (xtable);
3261     prev = sql;
3262     if (sel_fields & RTT_COL_EDGE_EDGE_ID)
3263       {
3264 	  if (comma)
3265 	      sql = sqlite3_mprintf ("%s AND edge_id = ?", prev);
3266 	  else
3267 	      sql = sqlite3_mprintf ("%s edge_id = ?", prev);
3268 	  comma = 1;
3269 	  sqlite3_free (prev);
3270 	  prev = sql;
3271       }
3272     if (sel_fields & RTT_COL_EDGE_START_NODE)
3273       {
3274 	  if (comma)
3275 	      sql = sqlite3_mprintf ("%s AND start_node = ?", prev);
3276 	  else
3277 	      sql = sqlite3_mprintf ("%s start_node = ?", prev);
3278 	  comma = 1;
3279 	  sqlite3_free (prev);
3280 	  prev = sql;
3281       }
3282     if (sel_fields & RTT_COL_EDGE_END_NODE)
3283       {
3284 	  if (comma)
3285 	      sql = sqlite3_mprintf ("%s AND end_node = ?", prev);
3286 	  else
3287 	      sql = sqlite3_mprintf ("%s end_node = ?", prev);
3288 	  comma = 1;
3289 	  sqlite3_free (prev);
3290 	  prev = sql;
3291       }
3292     if (sel_fields & RTT_COL_EDGE_FACE_LEFT)
3293       {
3294 	  if (sel_edge->face_left < 0)
3295 	    {
3296 		if (comma)
3297 		    sql = sqlite3_mprintf ("%s AND left_face IS NULL", prev);
3298 		else
3299 		    sql = sqlite3_mprintf ("%s left_face IS NULL", prev);
3300 	    }
3301 	  else
3302 	    {
3303 		if (comma)
3304 		    sql = sqlite3_mprintf ("%s AND left_face = ?", prev);
3305 		else
3306 		    sql = sqlite3_mprintf ("%s left_face = ?", prev);
3307 	    }
3308 	  comma = 1;
3309 	  sqlite3_free (prev);
3310 	  prev = sql;
3311       }
3312     if (sel_fields & RTT_COL_EDGE_FACE_RIGHT)
3313       {
3314 	  if (sel_edge->face_right < 0)
3315 	    {
3316 		if (comma)
3317 		    sql = sqlite3_mprintf ("%s AND right_face IS NULL", prev);
3318 		else
3319 		    sql = sqlite3_mprintf ("%s right_face IS NULL", prev);
3320 	    }
3321 	  else
3322 	    {
3323 		if (comma)
3324 		    sql = sqlite3_mprintf ("%s AND right_face = ?", prev);
3325 		else
3326 		    sql = sqlite3_mprintf ("%s right_face = ?", prev);
3327 	    }
3328 	  comma = 1;
3329 	  sqlite3_free (prev);
3330 	  prev = sql;
3331       }
3332     if (sel_fields & RTT_COL_EDGE_NEXT_LEFT)
3333       {
3334 	  if (comma)
3335 	      sql = sqlite3_mprintf ("%s AND next_left_edge = ?", prev);
3336 	  else
3337 	      sql = sqlite3_mprintf ("%s next_left_edge = ?", prev);
3338 	  comma = 1;
3339 	  sqlite3_free (prev);
3340 	  prev = sql;
3341       }
3342     if (sel_fields & RTT_COL_EDGE_NEXT_RIGHT)
3343       {
3344 	  if (comma)
3345 	      sql = sqlite3_mprintf ("%s AND next_right_edge = ?", prev);
3346 	  else
3347 	      sql = sqlite3_mprintf ("%s next_right_edge = ?", prev);
3348 	  comma = 1;
3349 	  sqlite3_free (prev);
3350 	  prev = sql;
3351       }
3352     if (sel_fields & RTT_COL_EDGE_GEOM)
3353       {
3354 	  if (comma)
3355 	      sql = sqlite3_mprintf ("%s AND geom = ?", prev);
3356 	  else
3357 	      sql = sqlite3_mprintf ("%s geom = ?", prev);
3358 	  comma = 1;
3359 	  sqlite3_free (prev);
3360 	  prev = sql;
3361       }
3362     ret =
3363 	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt,
3364 			    NULL);
3365     sqlite3_free (sql);
3366     if (ret != SQLITE_OK)
3367       {
3368 	  char *msg = sqlite3_mprintf ("Prepare_deleteEdges error: \"%s\"",
3369 				       sqlite3_errmsg (accessor->db_handle));
3370 	  gaiatopo_set_last_error_msg (topo, msg);
3371 	  sqlite3_free (msg);
3372 	  return -1;
3373       }
3374 
3375 /* parameter binding */
3376     sqlite3_reset (stmt);
3377     sqlite3_clear_bindings (stmt);
3378     if (sel_fields & RTT_COL_EDGE_EDGE_ID)
3379       {
3380 	  sqlite3_bind_int64 (stmt, icol, sel_edge->edge_id);
3381 	  icol++;
3382       }
3383     if (sel_fields & RTT_COL_EDGE_START_NODE)
3384       {
3385 	  sqlite3_bind_int64 (stmt, icol, sel_edge->start_node);
3386 	  icol++;
3387       }
3388     if (sel_fields & RTT_COL_EDGE_END_NODE)
3389       {
3390 	  sqlite3_bind_int64 (stmt, icol, sel_edge->end_node);
3391 	  icol++;
3392       }
3393     if (sel_fields & RTT_COL_EDGE_FACE_LEFT)
3394       {
3395 	  if (sel_edge->face_left < 0)
3396 	      sqlite3_bind_null (stmt, icol);
3397 	  else
3398 	      sqlite3_bind_int64 (stmt, icol, sel_edge->face_left);
3399 	  icol++;
3400       }
3401     if (sel_fields & RTT_COL_EDGE_FACE_RIGHT)
3402       {
3403 	  if (sel_edge->face_right < 0)
3404 	      sqlite3_bind_null (stmt, icol);
3405 	  else
3406 	      sqlite3_bind_int64 (stmt, icol, sel_edge->face_right);
3407 	  icol++;
3408       }
3409     if (sel_fields & RTT_COL_EDGE_NEXT_LEFT)
3410       {
3411 	  sqlite3_bind_int64 (stmt, icol, sel_edge->next_left);
3412 	  icol++;
3413       }
3414     if (sel_fields & RTT_COL_EDGE_NEXT_RIGHT)
3415       {
3416 	  sqlite3_bind_int64 (stmt, icol, sel_edge->next_right);
3417 	  icol++;
3418       }
3419     ret = sqlite3_step (stmt);
3420     if (ret == SQLITE_DONE || ret == SQLITE_ROW)
3421 	changed = sqlite3_changes (accessor->db_handle);
3422     else
3423       {
3424 	  char *msg = sqlite3_mprintf ("callback_deleteEdges: \"%s\"",
3425 				       sqlite3_errmsg (accessor->db_handle));
3426 	  gaiatopo_set_last_error_msg (topo, msg);
3427 	  sqlite3_free (msg);
3428 	  goto error;
3429       }
3430     sqlite3_finalize (stmt);
3431     return changed;
3432 
3433   error:
3434     sqlite3_finalize (stmt);
3435     return -1;
3436 }
3437 
3438 RTT_ISO_NODE *
callback_getNodeWithinBox2D(const RTT_BE_TOPOLOGY * rtt_topo,const RTGBOX * box,int * numelems,int fields,int limit)3439 callback_getNodeWithinBox2D (const RTT_BE_TOPOLOGY * rtt_topo,
3440 			     const RTGBOX * box, int *numelems,
3441 			     int fields, int limit)
3442 {
3443 /* callback function: getNodeWithinBox2D */
3444     const RTCTX *ctx = NULL;
3445     struct splite_internal_cache *cache = NULL;
3446     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
3447     struct gaia_topology *accessor = (struct gaia_topology *) topo;
3448     sqlite3_stmt *stmt;
3449     int ret;
3450     RTPOINTARRAY *pa;
3451     RTPOINT4D pt4d;
3452     int count = 0;
3453     sqlite3_stmt *stmt_aux = NULL;
3454     char *sql;
3455     struct topo_nodes_list *list = NULL;
3456     RTT_ISO_NODE *result = NULL;
3457     if (accessor == NULL)
3458       {
3459 	  *numelems = -1;
3460 	  return NULL;
3461       }
3462 
3463     stmt = accessor->stmt_getNodeWithinBox2D;
3464     if (stmt == NULL)
3465       {
3466 	  *numelems = -1;
3467 	  return NULL;
3468       }
3469 
3470     cache = (struct splite_internal_cache *) accessor->cache;
3471     if (cache == NULL)
3472 	return NULL;
3473     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3474 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3475 	return NULL;
3476     ctx = cache->RTTOPO_handle;
3477     if (ctx == NULL)
3478 	return NULL;
3479 
3480     if (limit >= 0)
3481       {
3482 	  /* preparing the auxiliary SQL statement */
3483 	  sql =
3484 	      do_prepare_read_node (accessor->topology_name, fields,
3485 				    accessor->has_z);
3486 	  ret =
3487 	      sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
3488 				  &stmt_aux, NULL);
3489 	  sqlite3_free (sql);
3490 	  if (ret != SQLITE_OK)
3491 	    {
3492 		char *msg =
3493 		    sqlite3_mprintf
3494 		    ("Prepare_getNodeWithinBox2D AUX error: \"%s\"",
3495 		     sqlite3_errmsg (accessor->db_handle));
3496 		gaiatopo_set_last_error_msg (topo, msg);
3497 		sqlite3_free (msg);
3498 		*numelems = -1;
3499 		return NULL;
3500 	    }
3501       }
3502 
3503 /* setting up the prepared statement */
3504     sqlite3_reset (stmt);
3505     sqlite3_clear_bindings (stmt);
3506     sqlite3_bind_double (stmt, 1, box->xmin);
3507     sqlite3_bind_double (stmt, 2, box->ymin);
3508     sqlite3_bind_double (stmt, 3, box->xmax);
3509     sqlite3_bind_double (stmt, 4, box->ymax);
3510     list = create_nodes_list ();
3511 
3512     while (1)
3513       {
3514 	  /* scrolling the result set rows */
3515 	  ret = sqlite3_step (stmt);
3516 	  if (ret == SQLITE_DONE)
3517 	      break;		/* end of result set */
3518 	  if (ret == SQLITE_ROW)
3519 	    {
3520 		sqlite3_int64 node_id = sqlite3_column_int64 (stmt, 0);
3521 		if (stmt_aux != NULL)
3522 		  {
3523 		      char *msg;
3524 		      if (!do_read_node
3525 			  (stmt_aux, list, node_id, fields, accessor->has_z,
3526 			   "callback_getNodeWithinBox2D", &msg))
3527 			{
3528 			    gaiatopo_set_last_error_msg (topo, msg);
3529 			    sqlite3_free (msg);
3530 			    goto error;
3531 			}
3532 		  }
3533 		count++;
3534 		if (limit > 0)
3535 		  {
3536 		      if (count > limit)
3537 			  break;
3538 		  }
3539 		if (limit < 0)
3540 		    break;
3541 	    }
3542 	  else
3543 	    {
3544 		char *msg = sqlite3_mprintf ("callback_getNodeWithinBox2D: %s",
3545 					     sqlite3_errmsg
3546 					     (accessor->db_handle));
3547 		gaiatopo_set_last_error_msg (topo, msg);
3548 		sqlite3_free (msg);
3549 		goto error;
3550 	    }
3551       }
3552 
3553     if (limit < 0)
3554       {
3555 	  result = NULL;
3556 	  *numelems = count;
3557       }
3558     else
3559       {
3560 	  if (list->count <= 0)
3561 	    {
3562 		result = NULL;
3563 		*numelems = 0;
3564 	    }
3565 	  else
3566 	    {
3567 		int i = 0;
3568 		struct topo_node *p_nd;
3569 		result = rtalloc (ctx, sizeof (RTT_ISO_NODE) * list->count);
3570 		p_nd = list->first;
3571 		while (p_nd != NULL)
3572 		  {
3573 		      RTT_ISO_NODE *nd = result + i;
3574 		      if (fields & RTT_COL_NODE_NODE_ID)
3575 			  nd->node_id = p_nd->node_id;
3576 		      if (fields & RTT_COL_NODE_CONTAINING_FACE)
3577 			  nd->containing_face = p_nd->containing_face;
3578 		      if (fields & RTT_COL_NODE_GEOM)
3579 			{
3580 			    pa = ptarray_construct (ctx, accessor->has_z, 0, 1);
3581 			    pt4d.x = p_nd->x;
3582 			    pt4d.y = p_nd->y;
3583 			    if (accessor->has_z)
3584 				pt4d.z = p_nd->z;
3585 			    ptarray_set_point4d (ctx, pa, 0, &pt4d);
3586 			    nd->geom =
3587 				rtpoint_construct (ctx, accessor->srid, NULL,
3588 						   pa);
3589 			}
3590 		      i++;
3591 		      p_nd = p_nd->next;
3592 		  }
3593 		*numelems = list->count;
3594 	    }
3595       }
3596 
3597     sqlite3_reset (stmt);
3598     if (stmt_aux != NULL)
3599 	sqlite3_finalize (stmt_aux);
3600     destroy_nodes_list (list);
3601     return result;
3602 
3603   error:
3604     sqlite3_reset (stmt);
3605     if (stmt_aux != NULL)
3606 	sqlite3_finalize (stmt_aux);
3607     if (list != NULL)
3608 	destroy_nodes_list (list);
3609     *numelems = 1;
3610     return NULL;
3611 }
3612 
3613 RTT_ISO_EDGE *
callback_getEdgeWithinBox2D(const RTT_BE_TOPOLOGY * rtt_topo,const RTGBOX * box,int * numelems,int fields,int limit)3614 callback_getEdgeWithinBox2D (const RTT_BE_TOPOLOGY * rtt_topo,
3615 			     const RTGBOX * box, int *numelems,
3616 			     int fields, int limit)
3617 {
3618 /* callback function: getEdgeWithinBox2D */
3619     const RTCTX *ctx = NULL;
3620     struct splite_internal_cache *cache = NULL;
3621     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
3622     struct gaia_topology *accessor = (struct gaia_topology *) topo;
3623     sqlite3_stmt *stmt;
3624     int ret;
3625     int count = 0;
3626     sqlite3_stmt *stmt_aux = NULL;
3627     char *sql;
3628     struct topo_edges_list *list = NULL;
3629     RTT_ISO_EDGE *result = NULL;
3630 
3631     if (box == NULL)
3632       {
3633 	  /* special case - ignoring the Spatial Index and returning ALL edges */
3634 	  return callback_getAllEdges (rtt_topo, numelems, fields, limit);
3635       }
3636 
3637     if (accessor == NULL)
3638       {
3639 	  *numelems = -1;
3640 	  return NULL;
3641       }
3642 
3643     stmt = accessor->stmt_getEdgeWithinBox2D;
3644     if (stmt == NULL)
3645       {
3646 	  *numelems = -1;
3647 	  return NULL;
3648       }
3649 
3650     cache = (struct splite_internal_cache *) accessor->cache;
3651     if (cache == NULL)
3652 	return NULL;
3653     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3654 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3655 	return NULL;
3656     ctx = cache->RTTOPO_handle;
3657     if (ctx == NULL)
3658 	return NULL;
3659 
3660     if (limit >= 0)
3661       {
3662 	  /* preparing the auxiliary SQL statement */
3663 	  sql = do_prepare_read_edge (accessor->topology_name, fields);
3664 	  ret =
3665 	      sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
3666 				  &stmt_aux, NULL);
3667 	  sqlite3_free (sql);
3668 	  if (ret != SQLITE_OK)
3669 	    {
3670 		char *msg =
3671 		    sqlite3_mprintf
3672 		    ("Prepare_getEdgeWithinBox2D AUX error: \"%s\"",
3673 		     sqlite3_errmsg (accessor->db_handle));
3674 		gaiatopo_set_last_error_msg (topo, msg);
3675 		sqlite3_free (msg);
3676 		*numelems = -1;
3677 		return NULL;
3678 	    }
3679       }
3680 
3681 /* setting up the prepared statement */
3682     sqlite3_reset (stmt);
3683     sqlite3_clear_bindings (stmt);
3684     sqlite3_bind_double (stmt, 1, box->xmin);
3685     sqlite3_bind_double (stmt, 2, box->ymin);
3686     sqlite3_bind_double (stmt, 3, box->xmax);
3687     sqlite3_bind_double (stmt, 4, box->ymax);
3688     list = create_edges_list ();
3689 
3690     while (1)
3691       {
3692 	  /* scrolling the result set rows */
3693 	  ret = sqlite3_step (stmt);
3694 	  if (ret == SQLITE_DONE)
3695 	      break;		/* end of result set */
3696 	  if (ret == SQLITE_ROW)
3697 	    {
3698 		sqlite3_int64 edge_id = sqlite3_column_int64 (stmt, 0);
3699 		if (stmt_aux != NULL)
3700 		  {
3701 		      char *msg;
3702 		      if (!do_read_edge
3703 			  (stmt_aux, list, edge_id, fields,
3704 			   "callback_getEdgeWithinBox2D", &msg))
3705 			{
3706 			    gaiatopo_set_last_error_msg (topo, msg);
3707 			    sqlite3_free (msg);
3708 			    goto error;
3709 			}
3710 		  }
3711 		count++;
3712 		if (limit > 0)
3713 		  {
3714 		      if (count > limit)
3715 			  break;
3716 		  }
3717 		if (limit < 0)
3718 		    break;
3719 	    }
3720 	  else
3721 	    {
3722 		char *msg = sqlite3_mprintf ("callback_getEdgeWithinBox2D: %s",
3723 					     sqlite3_errmsg
3724 					     (accessor->db_handle));
3725 		gaiatopo_set_last_error_msg (topo, msg);
3726 		sqlite3_free (msg);
3727 		goto error;
3728 	    }
3729       }
3730 
3731     if (limit < 0)
3732       {
3733 	  result = NULL;
3734 	  *numelems = count;
3735       }
3736     else
3737       {
3738 	  if (list->count <= 0)
3739 	    {
3740 		result = NULL;
3741 		*numelems = 0;
3742 	    }
3743 	  else
3744 	    {
3745 		int i = 0;
3746 		struct topo_edge *p_ed;
3747 		result = rtalloc (ctx, sizeof (RTT_ISO_EDGE) * list->count);
3748 		p_ed = list->first;
3749 		while (p_ed != NULL)
3750 		  {
3751 		      RTT_ISO_EDGE *ed = result + i;
3752 		      if (fields & RTT_COL_EDGE_EDGE_ID)
3753 			  ed->edge_id = p_ed->edge_id;
3754 		      if (fields & RTT_COL_EDGE_START_NODE)
3755 			  ed->start_node = p_ed->start_node;
3756 		      if (fields & RTT_COL_EDGE_END_NODE)
3757 			  ed->end_node = p_ed->end_node;
3758 		      if (fields & RTT_COL_EDGE_FACE_LEFT)
3759 			  ed->face_left = p_ed->face_left;
3760 		      if (fields & RTT_COL_EDGE_FACE_RIGHT)
3761 			  ed->face_right = p_ed->face_right;
3762 		      if (fields & RTT_COL_EDGE_NEXT_LEFT)
3763 			  ed->next_left = p_ed->next_left;
3764 		      if (fields & RTT_COL_EDGE_NEXT_RIGHT)
3765 			  ed->next_right = p_ed->next_right;
3766 		      if (fields & RTT_COL_EDGE_GEOM)
3767 			  ed->geom =
3768 			      gaia_convert_linestring_to_rtline (ctx,
3769 								 p_ed->geom,
3770 								 accessor->srid,
3771 								 accessor->
3772 								 has_z);
3773 		      i++;
3774 		      p_ed = p_ed->next;
3775 		  }
3776 		*numelems = list->count;
3777 	    }
3778       }
3779     sqlite3_reset (stmt);
3780     if (stmt_aux != NULL)
3781 	sqlite3_finalize (stmt_aux);
3782     destroy_edges_list (list);
3783     return result;
3784 
3785   error:
3786     sqlite3_reset (stmt);
3787     if (stmt_aux != NULL)
3788 	sqlite3_finalize (stmt_aux);
3789     if (list != NULL)
3790 	destroy_edges_list (list);
3791     *numelems = -1;
3792     return NULL;
3793 }
3794 
3795 RTT_ISO_EDGE *
callback_getAllEdges(const RTT_BE_TOPOLOGY * rtt_topo,int * numelems,int fields,int limit)3796 callback_getAllEdges (const RTT_BE_TOPOLOGY * rtt_topo, int *numelems,
3797 		      int fields, int limit)
3798 {
3799 /* callback function: getAllEdges */
3800     const RTCTX *ctx = NULL;
3801     struct splite_internal_cache *cache = NULL;
3802     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
3803     struct gaia_topology *accessor = (struct gaia_topology *) topo;
3804     sqlite3_stmt *stmt;
3805     int ret;
3806     char *table;
3807     char *xtable;
3808     char *sql;
3809     int i;
3810     char **results;
3811     int rows;
3812     int columns;
3813     char *errMsg = NULL;
3814     int count = 0;
3815     RTT_ISO_EDGE *result = NULL;
3816     if (accessor == NULL)
3817       {
3818 	  *numelems = -1;
3819 	  return NULL;
3820       }
3821 
3822     stmt = accessor->stmt_getAllEdges;
3823     if (stmt == NULL)
3824       {
3825 	  *numelems = -1;
3826 	  return NULL;
3827       }
3828 
3829     cache = (struct splite_internal_cache *) accessor->cache;
3830     if (cache == NULL)
3831 	return NULL;
3832     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3833 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
3834 	return NULL;
3835     ctx = cache->RTTOPO_handle;
3836     if (ctx == NULL)
3837 	return NULL;
3838 
3839 /* counting how many EDGEs are there */
3840     table = sqlite3_mprintf ("%s_edge", accessor->topology_name);
3841     xtable = gaiaDoubleQuotedSql (table);
3842     sqlite3_free (table);
3843     sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.\"%s\"", xtable);
3844     free (xtable);
3845     ret =
3846 	sqlite3_get_table (accessor->db_handle, sql, &results, &rows, &columns,
3847 			   &errMsg);
3848     sqlite3_free (sql);
3849     if (ret != SQLITE_OK)
3850       {
3851 	  sqlite3_free (errMsg);
3852 	  return NULL;
3853       }
3854     for (i = 1; i <= rows; i++)
3855 	count = atoi (results[(i * columns) + 0]);
3856     sqlite3_free_table (results);
3857 
3858     if (limit < 0)
3859       {
3860 	  if (count <= 0)
3861 	      *numelems = 0;
3862 	  else
3863 	      *numelems = 1;
3864 	  return NULL;
3865       }
3866     if (count <= 0)
3867       {
3868 	  *numelems = 0;
3869 	  return NULL;
3870       }
3871 
3872 /* allocating an Edge's array */
3873     if (limit > 0)
3874       {
3875 	  if (limit > count)
3876 	      *numelems = count;
3877 	  else
3878 	      *numelems = limit;
3879       }
3880     else
3881 	*numelems = count;
3882     result = rtalloc (ctx, sizeof (RTT_ISO_EDGE) * *numelems);
3883 
3884     sqlite3_reset (stmt);
3885     i = 0;
3886     while (1)
3887       {
3888 	  /* scrolling the result set rows */
3889 	  ret = sqlite3_step (stmt);
3890 	  if (ret == SQLITE_DONE)
3891 	      break;		/* end of result set */
3892 	  if (ret == SQLITE_ROW)
3893 	    {
3894 		RTT_ISO_EDGE *ed = result + i;
3895 		if (fields & RTT_COL_EDGE_EDGE_ID)
3896 		    ed->edge_id = sqlite3_column_int64 (stmt, 0);
3897 		if (fields & RTT_COL_EDGE_START_NODE)
3898 		    ed->start_node = sqlite3_column_int64 (stmt, 1);
3899 		if (fields & RTT_COL_EDGE_END_NODE)
3900 		    ed->end_node = sqlite3_column_int64 (stmt, 2);
3901 		if (fields & RTT_COL_EDGE_FACE_LEFT)
3902 		  {
3903 		      if (sqlite3_column_type (stmt, 3) == SQLITE_NULL)
3904 			  ed->face_left = -1;
3905 		      else
3906 			  ed->face_left = sqlite3_column_int64 (stmt, 3);
3907 		  }
3908 		if (fields & RTT_COL_EDGE_FACE_RIGHT)
3909 		  {
3910 		      if (sqlite3_column_type (stmt, 4) == SQLITE_NULL)
3911 			  ed->face_right = -1;
3912 		      else
3913 			  ed->face_right = sqlite3_column_int64 (stmt, 4);
3914 		  }
3915 		if (fields & RTT_COL_EDGE_NEXT_LEFT)
3916 		    ed->next_left = sqlite3_column_int64 (stmt, 5);
3917 		if (fields & RTT_COL_EDGE_NEXT_RIGHT)
3918 		    ed->next_right = sqlite3_column_int64 (stmt, 6);
3919 		if (fields & RTT_COL_EDGE_GEOM)
3920 		  {
3921 		      if (sqlite3_column_type (stmt, 7) == SQLITE_BLOB)
3922 			{
3923 			    const unsigned char *blob =
3924 				sqlite3_column_blob (stmt, 7);
3925 			    int blob_sz = sqlite3_column_bytes (stmt, 7);
3926 			    gaiaGeomCollPtr geom =
3927 				gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
3928 			    if (geom != NULL)
3929 			      {
3930 				  if (geom->FirstPoint == NULL
3931 				      && geom->FirstPolygon == NULL
3932 				      && geom->FirstLinestring ==
3933 				      geom->LastLinestring
3934 				      && geom->FirstLinestring != NULL)
3935 				    {
3936 					gaiaLinestringPtr ln =
3937 					    geom->FirstLinestring;
3938 					ed->geom =
3939 					    gaia_convert_linestring_to_rtline
3940 					    (ctx, ln, accessor->srid,
3941 					     accessor->has_z);
3942 				    }
3943 				  gaiaFreeGeomColl (geom);
3944 			      }
3945 			}
3946 		  }
3947 		i++;
3948 		if (limit > 0 && i >= limit)
3949 		    break;
3950 	    }
3951 	  else
3952 	    {
3953 		char *msg = sqlite3_mprintf ("callback_getAllEdges: %s",
3954 					     sqlite3_errmsg
3955 					     (accessor->db_handle));
3956 		gaiatopo_set_last_error_msg (topo, msg);
3957 		sqlite3_free (msg);
3958 		goto error;
3959 	    }
3960       }
3961     sqlite3_reset (stmt);
3962     return result;
3963 
3964   error:
3965     sqlite3_reset (stmt);
3966     *numelems = -1;
3967     return NULL;
3968 }
3969 
3970 RTT_ISO_EDGE *
callback_getEdgeByNode(const RTT_BE_TOPOLOGY * rtt_topo,const RTT_ELEMID * ids,int * numelems,int fields)3971 callback_getEdgeByNode (const RTT_BE_TOPOLOGY * rtt_topo,
3972 			const RTT_ELEMID * ids, int *numelems, int fields)
3973 {
3974 /* callback function: getEdgeByNode */
3975     const RTCTX *ctx = NULL;
3976     struct splite_internal_cache *cache = NULL;
3977     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
3978     struct gaia_topology *accessor = (struct gaia_topology *) topo;
3979     int ret;
3980     char *sql;
3981     char *prev;
3982     char *table;
3983     char *xtable;
3984     int comma = 0;
3985     int i;
3986     sqlite3_stmt *stmt_aux = NULL;
3987     struct topo_edges_list *list = NULL;
3988     RTT_ISO_EDGE *result = NULL;
3989     if (accessor == NULL)
3990       {
3991 	  *numelems = -1;
3992 	  return NULL;
3993       }
3994 
3995     cache = (struct splite_internal_cache *) accessor->cache;
3996     if (cache == NULL)
3997 	return NULL;
3998     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
3999 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
4000 	return NULL;
4001     ctx = cache->RTTOPO_handle;
4002     if (ctx == NULL)
4003 	return NULL;
4004 
4005     /* preparing the SQL statement */
4006     sql = sqlite3_mprintf ("SELECT ");
4007     prev = sql;
4008     /* unconditionally querying the Edge ID */
4009     if (comma)
4010 	sql = sqlite3_mprintf ("%s, edge_id", prev);
4011     else
4012 	sql = sqlite3_mprintf ("%s edge_id", prev);
4013     comma = 1;
4014     sqlite3_free (prev);
4015     prev = sql;
4016     if (fields & RTT_COL_EDGE_START_NODE)
4017       {
4018 	  if (comma)
4019 	      sql = sqlite3_mprintf ("%s, start_node", prev);
4020 	  else
4021 	      sql = sqlite3_mprintf ("%s start_node", prev);
4022 	  comma = 1;
4023 	  sqlite3_free (prev);
4024 	  prev = sql;
4025       }
4026     if (fields & RTT_COL_EDGE_END_NODE)
4027       {
4028 	  if (comma)
4029 	      sql = sqlite3_mprintf ("%s, end_node", prev);
4030 	  else
4031 	      sql = sqlite3_mprintf ("%s end_node", prev);
4032 	  comma = 1;
4033 	  sqlite3_free (prev);
4034 	  prev = sql;
4035       }
4036     if (fields & RTT_COL_EDGE_FACE_LEFT)
4037       {
4038 	  if (comma)
4039 	      sql = sqlite3_mprintf ("%s, left_face", prev);
4040 	  else
4041 	      sql = sqlite3_mprintf ("%s left_face", prev);
4042 	  comma = 1;
4043 	  sqlite3_free (prev);
4044 	  prev = sql;
4045       }
4046     if (fields & RTT_COL_EDGE_FACE_RIGHT)
4047       {
4048 	  if (comma)
4049 	      sql = sqlite3_mprintf ("%s, right_face", prev);
4050 	  else
4051 	      sql = sqlite3_mprintf ("%s right_face", prev);
4052 	  comma = 1;
4053 	  sqlite3_free (prev);
4054 	  prev = sql;
4055       }
4056     if (fields & RTT_COL_EDGE_NEXT_LEFT)
4057       {
4058 	  if (comma)
4059 	      sql = sqlite3_mprintf ("%s, next_left_edge", prev);
4060 	  else
4061 	      sql = sqlite3_mprintf ("%s next_left_edge", prev);
4062 	  comma = 1;
4063 	  sqlite3_free (prev);
4064 	  prev = sql;
4065       }
4066     if (fields & RTT_COL_EDGE_NEXT_RIGHT)
4067       {
4068 	  if (comma)
4069 	      sql = sqlite3_mprintf ("%s, next_right_edge", prev);
4070 	  else
4071 	      sql = sqlite3_mprintf ("%s next_right_edge", prev);
4072 	  comma = 1;
4073 	  sqlite3_free (prev);
4074 	  prev = sql;
4075       }
4076     if (fields & RTT_COL_EDGE_GEOM)
4077       {
4078 	  if (comma)
4079 	      sql = sqlite3_mprintf ("%s, geom", prev);
4080 	  else
4081 	      sql = sqlite3_mprintf ("%s geom", prev);
4082 	  comma = 1;
4083 	  sqlite3_free (prev);
4084 	  prev = sql;
4085       }
4086     table = sqlite3_mprintf ("%s_edge", accessor->topology_name);
4087     xtable = gaiaDoubleQuotedSql (table);
4088     sqlite3_free (table);
4089     sql =
4090 	sqlite3_mprintf
4091 	("%s FROM MAIN.\"%s\" WHERE start_node = ? OR end_node = ?", prev,
4092 	 xtable);
4093     free (xtable);
4094     sqlite3_free (prev);
4095     ret =
4096 	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
4097 			    &stmt_aux, NULL);
4098     sqlite3_free (sql);
4099     if (ret != SQLITE_OK)
4100       {
4101 	  char *msg =
4102 	      sqlite3_mprintf ("Prepare_getEdgeByNode AUX error: \"%s\"",
4103 			       sqlite3_errmsg (accessor->db_handle));
4104 	  gaiatopo_set_last_error_msg (topo, msg);
4105 	  sqlite3_free (msg);
4106 	  *numelems = -1;
4107 	  return NULL;
4108       }
4109 
4110     list = create_edges_list ();
4111     for (i = 0; i < *numelems; i++)
4112       {
4113 	  char *msg;
4114 	  if (!do_read_edge_by_node
4115 	      (stmt_aux, list, *(ids + i), fields, "callback_getEdgeByNode",
4116 	       &msg))
4117 	    {
4118 		gaiatopo_set_last_error_msg (topo, msg);
4119 		sqlite3_free (msg);
4120 		goto error;
4121 	    }
4122       }
4123 
4124     if (list->count == 0)
4125       {
4126 	  /* no edge was found */
4127 	  *numelems = list->count;
4128       }
4129     else
4130       {
4131 	  struct topo_edge *p_ed;
4132 	  result = rtalloc (ctx, sizeof (RTT_ISO_EDGE) * list->count);
4133 	  p_ed = list->first;
4134 	  i = 0;
4135 	  while (p_ed != NULL)
4136 	    {
4137 		RTT_ISO_EDGE *ed = result + i;
4138 		if (fields & RTT_COL_EDGE_EDGE_ID)
4139 		    ed->edge_id = p_ed->edge_id;
4140 		if (fields & RTT_COL_EDGE_START_NODE)
4141 		    ed->start_node = p_ed->start_node;
4142 		if (fields & RTT_COL_EDGE_END_NODE)
4143 		    ed->end_node = p_ed->end_node;
4144 		if (fields & RTT_COL_EDGE_FACE_LEFT)
4145 		    ed->face_left = p_ed->face_left;
4146 		if (fields & RTT_COL_EDGE_FACE_RIGHT)
4147 		    ed->face_right = p_ed->face_right;
4148 		if (fields & RTT_COL_EDGE_NEXT_LEFT)
4149 		    ed->next_left = p_ed->next_left;
4150 		if (fields & RTT_COL_EDGE_NEXT_RIGHT)
4151 		    ed->next_right = p_ed->next_right;
4152 		if (fields & RTT_COL_EDGE_GEOM)
4153 		    ed->geom =
4154 			gaia_convert_linestring_to_rtline (ctx, p_ed->geom,
4155 							   accessor->srid,
4156 							   accessor->has_z);
4157 		i++;
4158 		p_ed = p_ed->next;
4159 	    }
4160 	  *numelems = list->count;
4161       }
4162     sqlite3_finalize (stmt_aux);
4163     destroy_edges_list (list);
4164     return result;
4165 
4166   error:
4167     if (stmt_aux != NULL)
4168 	sqlite3_finalize (stmt_aux);
4169     if (list != NULL)
4170 	destroy_edges_list (list);
4171     *numelems = -1;
4172     return NULL;
4173 }
4174 
4175 int
callback_updateNodes(const RTT_BE_TOPOLOGY * rtt_topo,const RTT_ISO_NODE * sel_node,int sel_fields,const RTT_ISO_NODE * upd_node,int upd_fields,const RTT_ISO_NODE * exc_node,int exc_fields)4176 callback_updateNodes (const RTT_BE_TOPOLOGY * rtt_topo,
4177 		      const RTT_ISO_NODE * sel_node, int sel_fields,
4178 		      const RTT_ISO_NODE * upd_node, int upd_fields,
4179 		      const RTT_ISO_NODE * exc_node, int exc_fields)
4180 {
4181 /* callback function: updateNodes */
4182     const RTCTX *ctx = NULL;
4183     struct splite_internal_cache *cache = NULL;
4184     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
4185     struct gaia_topology *accessor = (struct gaia_topology *) topo;
4186     sqlite3_stmt *stmt = NULL;
4187     int ret;
4188     char *sql;
4189     char *prev;
4190     int comma = 0;
4191     char *table;
4192     char *xtable;
4193     int icol = 1;
4194     int changed = 0;
4195     RTPOINTARRAY *pa;
4196     RTPOINT4D pt4d;
4197     double x;
4198     double y;
4199     double z;
4200     if (accessor == NULL)
4201 	return -1;
4202 
4203     cache = (struct splite_internal_cache *) accessor->cache;
4204     if (cache == NULL)
4205 	return 0;
4206     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
4207 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
4208 	return 0;
4209     ctx = cache->RTTOPO_handle;
4210     if (ctx == NULL)
4211 	return 0;
4212 
4213 /* composing the SQL prepared statement */
4214     table = sqlite3_mprintf ("%s_node", accessor->topology_name);
4215     xtable = gaiaDoubleQuotedSql (table);
4216     sqlite3_free (table);
4217     sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET ", xtable);
4218     free (xtable);
4219     prev = sql;
4220     if (upd_fields & RTT_COL_NODE_NODE_ID)
4221       {
4222 	  if (comma)
4223 	      sql = sqlite3_mprintf ("%s, node_id = ?", prev);
4224 	  else
4225 	      sql = sqlite3_mprintf ("%s node_id = ?", prev);
4226 	  comma = 1;
4227 	  sqlite3_free (prev);
4228 	  prev = sql;
4229       }
4230     if (upd_fields & RTT_COL_NODE_CONTAINING_FACE)
4231       {
4232 	  if (comma)
4233 	      sql = sqlite3_mprintf ("%s, containing_face = ?", prev);
4234 	  else
4235 	      sql = sqlite3_mprintf ("%s containing_face = ?", prev);
4236 	  comma = 1;
4237 	  sqlite3_free (prev);
4238 	  prev = sql;
4239       }
4240     if (upd_fields & RTT_COL_NODE_GEOM)
4241       {
4242 	  if (accessor->has_z)
4243 	    {
4244 		if (comma)
4245 		    sql =
4246 			sqlite3_mprintf ("%s, geom = MakePointZ(?, ?, ?, %d)",
4247 					 prev, accessor->srid);
4248 		else
4249 		    sql =
4250 			sqlite3_mprintf ("%s geom = MakePointZ(?, ?, ?, %d)",
4251 					 prev, accessor->srid);
4252 	    }
4253 	  else
4254 	    {
4255 		if (comma)
4256 		    sql =
4257 			sqlite3_mprintf ("%s, geom = MakePoint(?, ?, %d)", prev,
4258 					 accessor->srid);
4259 		else
4260 		    sql =
4261 			sqlite3_mprintf ("%s geom = MakePoint(?, ?, %d)", prev,
4262 					 accessor->srid);
4263 	    }
4264 	  comma = 1;
4265 	  sqlite3_free (prev);
4266 	  prev = sql;
4267       }
4268     if (exc_node || sel_node)
4269       {
4270 	  sql = sqlite3_mprintf ("%s WHERE", prev);
4271 	  sqlite3_free (prev);
4272 	  prev = sql;
4273 	  if (sel_node)
4274 	    {
4275 		comma = 0;
4276 		if (sel_fields & RTT_COL_NODE_NODE_ID)
4277 		  {
4278 		      if (comma)
4279 			  sql = sqlite3_mprintf ("%s AND node_id = ?", prev);
4280 		      else
4281 			  sql = sqlite3_mprintf ("%s node_id = ?", prev);
4282 		      comma = 1;
4283 		      sqlite3_free (prev);
4284 		      prev = sql;
4285 		  }
4286 		if (sel_fields & RTT_COL_NODE_CONTAINING_FACE)
4287 		  {
4288 		      if (sel_node->containing_face < 0)
4289 			{
4290 			    if (comma)
4291 				sql =
4292 				    sqlite3_mprintf
4293 				    ("%s AND containing_face IS NULL", prev);
4294 			    else
4295 				sql =
4296 				    sqlite3_mprintf
4297 				    ("%s containing_face IS NULL", prev);
4298 			}
4299 		      else
4300 			{
4301 			    if (comma)
4302 				sql =
4303 				    sqlite3_mprintf
4304 				    ("%s AND containing_face = ?", prev);
4305 			    else
4306 				sql =
4307 				    sqlite3_mprintf ("%s containing_face = ?",
4308 						     prev);
4309 			}
4310 		      comma = 1;
4311 		      sqlite3_free (prev);
4312 		      prev = sql;
4313 		  }
4314 	    }
4315 	  if (exc_node)
4316 	    {
4317 		if (sel_node)
4318 		  {
4319 		      sql = sqlite3_mprintf ("%s AND", prev);
4320 		      sqlite3_free (prev);
4321 		      prev = sql;
4322 		  }
4323 		comma = 0;
4324 		if (exc_fields & RTT_COL_NODE_NODE_ID)
4325 		  {
4326 		      if (comma)
4327 			  sql = sqlite3_mprintf ("%s AND node_id <> ?", prev);
4328 		      else
4329 			  sql = sqlite3_mprintf ("%s node_id <> ?", prev);
4330 		      comma = 1;
4331 		      sqlite3_free (prev);
4332 		      prev = sql;
4333 		  }
4334 		if (exc_fields & RTT_COL_NODE_CONTAINING_FACE)
4335 		  {
4336 		      if (exc_node->containing_face < 0)
4337 			{
4338 			    if (comma)
4339 				sql =
4340 				    sqlite3_mprintf
4341 				    ("%s AND containing_face IS NOT NULL",
4342 				     prev);
4343 			    else
4344 				sql =
4345 				    sqlite3_mprintf
4346 				    ("%s containing_face IS NOT NULL", prev);
4347 			}
4348 		      else
4349 			{
4350 			    if (comma)
4351 				sql =
4352 				    sqlite3_mprintf
4353 				    ("%s AND containing_face <> ?", prev);
4354 			    else
4355 				sql =
4356 				    sqlite3_mprintf ("%s containing_face <> ?",
4357 						     prev);
4358 			}
4359 		      comma = 1;
4360 		      sqlite3_free (prev);
4361 		      prev = sql;
4362 		  }
4363 	    }
4364       }
4365     ret =
4366 	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt,
4367 			    NULL);
4368     sqlite3_free (sql);
4369     if (ret != SQLITE_OK)
4370       {
4371 	  char *msg = sqlite3_mprintf ("Prepare_updateNodes error: \"%s\"",
4372 				       sqlite3_errmsg (accessor->db_handle));
4373 	  gaiatopo_set_last_error_msg (topo, msg);
4374 	  sqlite3_free (msg);
4375 	  return -1;
4376       }
4377 
4378 /* parameter binding */
4379     sqlite3_reset (stmt);
4380     sqlite3_clear_bindings (stmt);
4381     if (upd_fields & RTT_COL_NODE_NODE_ID)
4382       {
4383 	  sqlite3_bind_int64 (stmt, icol, upd_node->node_id);
4384 	  icol++;
4385       }
4386     if (upd_fields & RTT_COL_NODE_CONTAINING_FACE)
4387       {
4388 	  if (upd_node->containing_face < 0)
4389 	      sqlite3_bind_null (stmt, icol);
4390 	  else
4391 	      sqlite3_bind_int64 (stmt, icol, upd_node->containing_face);
4392 	  icol++;
4393       }
4394     if (upd_fields & RTT_COL_NODE_GEOM)
4395       {
4396 	  /* extracting X and Y from RTTOPO */
4397 	  pa = upd_node->geom->point;
4398 	  rt_getPoint4d_p (ctx, pa, 0, &pt4d);
4399 	  x = pt4d.x;
4400 	  y = pt4d.y;
4401 	  if (accessor->has_z)
4402 	      z = pt4d.z;
4403 	  sqlite3_bind_double (stmt, icol, x);
4404 	  icol++;
4405 	  sqlite3_bind_double (stmt, icol, y);
4406 	  icol++;
4407 	  if (accessor->has_z)
4408 	    {
4409 		sqlite3_bind_double (stmt, icol, z);
4410 		icol++;
4411 	    }
4412       }
4413     if (sel_node)
4414       {
4415 	  if (sel_fields & RTT_COL_NODE_NODE_ID)
4416 	    {
4417 		sqlite3_bind_int64 (stmt, icol, sel_node->node_id);
4418 		icol++;
4419 	    }
4420 	  if (sel_fields & RTT_COL_NODE_CONTAINING_FACE)
4421 	    {
4422 		if (sel_node->containing_face < 0)
4423 		    ;
4424 		else
4425 		  {
4426 		      sqlite3_bind_int64 (stmt, icol,
4427 					  sel_node->containing_face);
4428 		      icol++;
4429 		  }
4430 	    }
4431       }
4432     if (exc_node)
4433       {
4434 	  if (exc_fields & RTT_COL_NODE_NODE_ID)
4435 	    {
4436 		sqlite3_bind_int64 (stmt, icol, exc_node->node_id);
4437 		icol++;
4438 	    }
4439 	  if (exc_fields & RTT_COL_NODE_CONTAINING_FACE)
4440 	    {
4441 		if (exc_node->containing_face < 0)
4442 		    ;
4443 		else
4444 		  {
4445 		      sqlite3_bind_int64 (stmt, icol,
4446 					  exc_node->containing_face);
4447 		      icol++;
4448 		  }
4449 	    }
4450       }
4451     ret = sqlite3_step (stmt);
4452     if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4453 	changed = sqlite3_changes (accessor->db_handle);
4454     else
4455       {
4456 	  char *msg = sqlite3_mprintf ("callback_updateNodes: \"%s\"",
4457 				       sqlite3_errmsg (accessor->db_handle));
4458 	  gaiatopo_set_last_error_msg (topo, msg);
4459 	  sqlite3_free (msg);
4460 	  goto error;
4461       }
4462     sqlite3_finalize (stmt);
4463     return changed;
4464 
4465   error:
4466     sqlite3_finalize (stmt);
4467     return -1;
4468 }
4469 
4470 int
callback_insertFaces(const RTT_BE_TOPOLOGY * rtt_topo,RTT_ISO_FACE * faces,int numelems)4471 callback_insertFaces (const RTT_BE_TOPOLOGY * rtt_topo, RTT_ISO_FACE * faces,
4472 		      int numelems)
4473 {
4474 /* callback function: insertFaces */
4475     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
4476     struct gaia_topology *accessor = (struct gaia_topology *) topo;
4477     int ret;
4478     int i;
4479     int count = 0;
4480     sqlite3_stmt *stmt;
4481     if (accessor == NULL)
4482 	return -1;
4483 
4484     stmt = accessor->stmt_insertFaces;
4485     if (stmt == NULL)
4486 	return -1;
4487 
4488     for (i = 0; i < numelems; i++)
4489       {
4490 	  RTT_ISO_FACE *fc = faces + i;
4491 	  sqlite3_reset (stmt);
4492 	  sqlite3_clear_bindings (stmt);
4493 	  if (fc->face_id <= 0)
4494 	      sqlite3_bind_null (stmt, 1);
4495 	  else
4496 	      sqlite3_bind_int64 (stmt, 1, fc->face_id);
4497 	  sqlite3_bind_double (stmt, 2, fc->mbr->xmin);
4498 	  sqlite3_bind_double (stmt, 3, fc->mbr->ymin);
4499 	  sqlite3_bind_double (stmt, 4, fc->mbr->xmax);
4500 	  sqlite3_bind_double (stmt, 5, fc->mbr->ymax);
4501 	  ret = sqlite3_step (stmt);
4502 	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4503 	    {
4504 		if (fc->face_id <= 0)
4505 		    fc->face_id =
4506 			sqlite3_last_insert_rowid (accessor->db_handle);
4507 		count++;
4508 	    }
4509 	  else
4510 	    {
4511 		char *msg = sqlite3_mprintf ("callback_insertFaces: \"%s\"",
4512 					     sqlite3_errmsg
4513 					     (accessor->db_handle));
4514 		gaiatopo_set_last_error_msg (topo, msg);
4515 		sqlite3_free (msg);
4516 		goto error;
4517 	    }
4518       }
4519     sqlite3_reset (stmt);
4520     return count;
4521 
4522   error:
4523     sqlite3_reset (stmt);
4524     return -1;
4525 }
4526 
4527 int
callback_updateFacesById(const RTT_BE_TOPOLOGY * rtt_topo,const RTT_ISO_FACE * faces,int numfaces)4528 callback_updateFacesById (const RTT_BE_TOPOLOGY * rtt_topo,
4529 			  const RTT_ISO_FACE * faces, int numfaces)
4530 {
4531 /* callback function: updateFacesById */
4532     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
4533     struct gaia_topology *accessor = (struct gaia_topology *) topo;
4534     sqlite3_stmt *stmt = NULL;
4535     int ret;
4536     int i;
4537     int changed = 0;
4538     if (accessor == NULL)
4539 	return -1;
4540 
4541     stmt = accessor->stmt_updateFacesById;
4542     if (stmt == NULL)
4543 	return -1;
4544 
4545     for (i = 0; i < numfaces; i++)
4546       {
4547 	  /* parameter binding */
4548 	  const RTT_ISO_FACE *fc = faces + i;
4549 	  sqlite3_reset (stmt);
4550 	  sqlite3_clear_bindings (stmt);
4551 	  sqlite3_bind_double (stmt, 1, fc->mbr->xmin);
4552 	  sqlite3_bind_double (stmt, 2, fc->mbr->ymin);
4553 	  sqlite3_bind_double (stmt, 3, fc->mbr->xmax);
4554 	  sqlite3_bind_double (stmt, 4, fc->mbr->ymax);
4555 	  sqlite3_bind_int64 (stmt, 5, fc->face_id);
4556 	  ret = sqlite3_step (stmt);
4557 	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4558 	      changed += sqlite3_changes (accessor->db_handle);
4559 	  else
4560 	    {
4561 		char *msg = sqlite3_mprintf ("callback_updateFacesById: \"%s\"",
4562 					     sqlite3_errmsg
4563 					     (accessor->db_handle));
4564 		gaiatopo_set_last_error_msg (topo, msg);
4565 		sqlite3_free (msg);
4566 		goto error;
4567 	    }
4568       }
4569     return changed;
4570 
4571   error:
4572     return -1;
4573 }
4574 
4575 int
callback_deleteFacesById(const RTT_BE_TOPOLOGY * rtt_topo,const RTT_ELEMID * ids,int numelems)4576 callback_deleteFacesById (const RTT_BE_TOPOLOGY * rtt_topo,
4577 			  const RTT_ELEMID * ids, int numelems)
4578 {
4579 /* callback function: deleteFacesById */
4580     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
4581     struct gaia_topology *accessor = (struct gaia_topology *) topo;
4582     sqlite3_stmt *stmt = NULL;
4583     int ret;
4584     int i;
4585     int changed = 0;
4586     if (accessor == NULL)
4587 	return -1;
4588 
4589     stmt = accessor->stmt_deleteFacesById;
4590     if (stmt == NULL)
4591 	return -1;
4592 
4593     for (i = 0; i < numelems; i++)
4594       {
4595 	  /* parameter binding */
4596 	  sqlite3_int64 id = *(ids + i);
4597 	  sqlite3_reset (stmt);
4598 	  sqlite3_clear_bindings (stmt);
4599 	  sqlite3_bind_int64 (stmt, 1, id);
4600 	  ret = sqlite3_step (stmt);
4601 	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4602 	    {
4603 		changed += sqlite3_changes (accessor->db_handle);
4604 	    }
4605 	  else
4606 	    {
4607 		char *msg = sqlite3_mprintf ("callback_deleteFacesById: \"%s\"",
4608 					     sqlite3_errmsg
4609 					     (accessor->db_handle));
4610 		gaiatopo_set_last_error_msg (topo, msg);
4611 		sqlite3_free (msg);
4612 		goto error;
4613 	    }
4614       }
4615     sqlite3_reset (stmt);
4616     return changed;
4617 
4618   error:
4619     sqlite3_reset (stmt);
4620     return -1;
4621 }
4622 
4623 int
callback_deleteNodesById(const RTT_BE_TOPOLOGY * rtt_topo,const RTT_ELEMID * ids,int numelems)4624 callback_deleteNodesById (const RTT_BE_TOPOLOGY * rtt_topo,
4625 			  const RTT_ELEMID * ids, int numelems)
4626 {
4627 /* callback function: deleteNodesById */
4628     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
4629     struct gaia_topology *accessor = (struct gaia_topology *) topo;
4630     sqlite3_stmt *stmt = NULL;
4631     int ret;
4632     int i;
4633     int changed = 0;
4634     if (accessor == NULL)
4635 	return -1;
4636 
4637     stmt = accessor->stmt_deleteNodesById;
4638     if (stmt == NULL)
4639 	return -1;
4640 
4641     for (i = 0; i < numelems; i++)
4642       {
4643 	  /* parameter binding */
4644 	  sqlite3_int64 id = *(ids + i);
4645 	  sqlite3_reset (stmt);
4646 	  sqlite3_clear_bindings (stmt);
4647 	  sqlite3_bind_int64 (stmt, 1, id);
4648 	  ret = sqlite3_step (stmt);
4649 	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4650 	    {
4651 		changed += sqlite3_changes (accessor->db_handle);
4652 	    }
4653 	  else
4654 	    {
4655 		char *msg = sqlite3_mprintf ("callback_deleteNodesById: \"%s\"",
4656 					     sqlite3_errmsg
4657 					     (accessor->db_handle));
4658 		gaiatopo_set_last_error_msg (topo, msg);
4659 		sqlite3_free (msg);
4660 		goto error;
4661 	    }
4662       }
4663     sqlite3_reset (stmt);
4664     return changed;
4665 
4666   error:
4667     sqlite3_reset (stmt);
4668     return -1;
4669 }
4670 
4671 RTT_ELEMID *
callback_getRingEdges(const RTT_BE_TOPOLOGY * rtt_topo,RTT_ELEMID edge,int * numedges,int limit)4672 callback_getRingEdges (const RTT_BE_TOPOLOGY * rtt_topo,
4673 		       RTT_ELEMID edge, int *numedges, int limit)
4674 {
4675 /* callback function: getRingEdges */
4676     const RTCTX *ctx = NULL;
4677     struct splite_internal_cache *cache = NULL;
4678     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
4679     struct gaia_topology *accessor = (struct gaia_topology *) topo;
4680     int ret;
4681     int i;
4682     int count = 0;
4683     sqlite3_stmt *stmt;
4684 
4685     struct topo_edges_list *list = NULL;
4686     RTT_ELEMID *result = NULL;
4687     if (accessor == NULL)
4688       {
4689 	  *numedges = -1;
4690 	  return NULL;
4691       }
4692 
4693     stmt = accessor->stmt_getRingEdges;
4694     if (stmt == NULL)
4695       {
4696 	  *numedges = -1;
4697 	  return NULL;
4698       }
4699 
4700     cache = (struct splite_internal_cache *) accessor->cache;
4701     if (cache == NULL)
4702 	return NULL;
4703     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
4704 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
4705 	return NULL;
4706     ctx = cache->RTTOPO_handle;
4707     if (ctx == NULL)
4708 	return NULL;
4709 
4710 /* setting up the prepared statement */
4711     sqlite3_reset (stmt);
4712     sqlite3_clear_bindings (stmt);
4713     sqlite3_bind_double (stmt, 1, edge);
4714     sqlite3_bind_double (stmt, 2, edge);
4715     list = create_edges_list ();
4716 
4717     while (1)
4718       {
4719 	  /* scrolling the result set rows */
4720 	  ret = sqlite3_step (stmt);
4721 	  if (ret == SQLITE_DONE)
4722 	      break;		/* end of result set */
4723 	  if (ret == SQLITE_ROW)
4724 	    {
4725 		sqlite3_int64 edge_id = sqlite3_column_int64 (stmt, 0);
4726 		add_edge (list, edge_id, -1, -1, -1, -1, -1, -1, NULL);
4727 		count++;
4728 		if (limit > 0)
4729 		  {
4730 		      if (count > limit)
4731 			  break;
4732 		  }
4733 	    }
4734 	  else
4735 	    {
4736 		char *msg =
4737 		    sqlite3_mprintf ("callback_getNodeWithinDistance2D: %s",
4738 				     sqlite3_errmsg (accessor->db_handle));
4739 		gaiatopo_set_last_error_msg (topo, msg);
4740 		sqlite3_free (msg);
4741 		goto error;
4742 	    }
4743       }
4744 
4745     if (limit < 0)
4746       {
4747 	  result = NULL;
4748 	  *numedges = count;
4749       }
4750     else
4751       {
4752 	  if (list->count == 0)
4753 	    {
4754 		/* no edge was found */
4755 		*numedges = 0;
4756 	    }
4757 	  else
4758 	    {
4759 		struct topo_edge *p_ed;
4760 		result = rtalloc (ctx, sizeof (RTT_ELEMID) * list->count);
4761 		p_ed = list->first;
4762 		i = 0;
4763 		while (p_ed != NULL)
4764 		  {
4765 		      *(result + i) = p_ed->edge_id;
4766 		      i++;
4767 		      p_ed = p_ed->next;
4768 		  }
4769 		*numedges = list->count;
4770 	    }
4771       }
4772     destroy_edges_list (list);
4773     sqlite3_reset (stmt);
4774     return result;
4775 
4776   error:
4777     if (list != NULL)
4778 	destroy_edges_list (list);
4779     *numedges = -1;
4780     sqlite3_reset (stmt);
4781     return NULL;
4782 }
4783 
4784 int
callback_updateEdgesById(const RTT_BE_TOPOLOGY * rtt_topo,const RTT_ISO_EDGE * edges,int numedges,int upd_fields)4785 callback_updateEdgesById (const RTT_BE_TOPOLOGY * rtt_topo,
4786 			  const RTT_ISO_EDGE * edges, int numedges,
4787 			  int upd_fields)
4788 {
4789 /* callback function: updateEdgesById */
4790     const RTCTX *ctx = NULL;
4791     struct splite_internal_cache *cache = NULL;
4792     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
4793     struct gaia_topology *accessor = (struct gaia_topology *) topo;
4794     sqlite3_stmt *stmt = NULL;
4795     int ret;
4796     char *sql;
4797     char *prev;
4798     int comma = 0;
4799     char *table;
4800     char *xtable;
4801     int i;
4802     int changed = 0;
4803     unsigned char *p_blob;
4804     int n_bytes;
4805     int gpkg_mode = 0;
4806     int tiny_point = 0;
4807     if (accessor == NULL)
4808 	return -1;
4809 
4810     cache = (struct splite_internal_cache *) accessor->cache;
4811     if (cache == NULL)
4812 	return 0;
4813     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
4814 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
4815 	return 0;
4816     ctx = cache->RTTOPO_handle;
4817     if (ctx == NULL)
4818 	return 0;
4819 
4820     if (accessor->cache != NULL)
4821       {
4822 	  struct splite_internal_cache *cache =
4823 	      (struct splite_internal_cache *) (accessor->cache);
4824 	  gpkg_mode = cache->gpkg_mode;
4825 	  tiny_point = cache->tinyPointEnabled;
4826       }
4827 
4828 /* composing the SQL prepared statement */
4829     table = sqlite3_mprintf ("%s_edge", accessor->topology_name);
4830     xtable = gaiaDoubleQuotedSql (table);
4831     sqlite3_free (table);
4832     sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET", xtable);
4833     free (xtable);
4834     prev = sql;
4835     if (upd_fields & RTT_COL_EDGE_EDGE_ID)
4836       {
4837 	  if (comma)
4838 	      sql = sqlite3_mprintf ("%s, edge_id = ?", prev);
4839 	  else
4840 	      sql = sqlite3_mprintf ("%s edge_id = ?", prev);
4841 	  comma = 1;
4842 	  sqlite3_free (prev);
4843 	  prev = sql;
4844       }
4845     if (upd_fields & RTT_COL_EDGE_START_NODE)
4846       {
4847 	  if (comma)
4848 	      sql = sqlite3_mprintf ("%s, start_node = ?", prev);
4849 	  else
4850 	      sql = sqlite3_mprintf ("%s start_node = ?", prev);
4851 	  comma = 1;
4852 	  sqlite3_free (prev);
4853 	  prev = sql;
4854       }
4855     if (upd_fields & RTT_COL_EDGE_END_NODE)
4856       {
4857 	  if (comma)
4858 	      sql = sqlite3_mprintf ("%s, end_node = ?", prev);
4859 	  else
4860 	      sql = sqlite3_mprintf ("%s end_node = ?", prev);
4861 	  comma = 1;
4862 	  sqlite3_free (prev);
4863 	  prev = sql;
4864       }
4865     if (upd_fields & RTT_COL_EDGE_FACE_LEFT)
4866       {
4867 	  if (comma)
4868 	      sql = sqlite3_mprintf ("%s, left_face = ?", prev);
4869 	  else
4870 	      sql = sqlite3_mprintf ("%s left_face = ?", prev);
4871 	  comma = 1;
4872 	  sqlite3_free (prev);
4873 	  prev = sql;
4874       }
4875     if (upd_fields & RTT_COL_EDGE_FACE_RIGHT)
4876       {
4877 	  if (comma)
4878 	      sql = sqlite3_mprintf ("%s, right_face = ?", prev);
4879 	  else
4880 	      sql = sqlite3_mprintf ("%s right_face = ?", prev);
4881 	  comma = 1;
4882 	  sqlite3_free (prev);
4883 	  prev = sql;
4884       }
4885     if (upd_fields & RTT_COL_EDGE_NEXT_LEFT)
4886       {
4887 	  if (comma)
4888 	      sql = sqlite3_mprintf ("%s, next_left_edge = ?", prev);
4889 	  else
4890 	      sql = sqlite3_mprintf ("%s next_left_edge = ?", prev);
4891 	  comma = 1;
4892 	  sqlite3_free (prev);
4893 	  prev = sql;
4894       }
4895     if (upd_fields & RTT_COL_EDGE_NEXT_RIGHT)
4896       {
4897 	  if (comma)
4898 	      sql = sqlite3_mprintf ("%s, next_right_edge = ?", prev);
4899 	  else
4900 	      sql = sqlite3_mprintf ("%s next_right_edge = ?", prev);
4901 	  comma = 1;
4902 	  sqlite3_free (prev);
4903 	  prev = sql;
4904       }
4905     if (upd_fields & RTT_COL_EDGE_GEOM)
4906       {
4907 	  if (comma)
4908 	      sql = sqlite3_mprintf ("%s, geom = ?", prev);
4909 	  else
4910 	      sql = sqlite3_mprintf ("%s geom = ?", prev);
4911 	  comma = 1;
4912 	  sqlite3_free (prev);
4913 	  prev = sql;
4914       }
4915     sql = sqlite3_mprintf ("%s WHERE edge_id = ?", prev);
4916     sqlite3_free (prev);
4917     ret =
4918 	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt,
4919 			    NULL);
4920     sqlite3_free (sql);
4921     if (ret != SQLITE_OK)
4922       {
4923 	  char *msg = sqlite3_mprintf ("Prepare_updateEdgesById error: \"%s\"",
4924 				       sqlite3_errmsg (accessor->db_handle));
4925 	  gaiatopo_set_last_error_msg (topo, msg);
4926 	  sqlite3_free (msg);
4927 	  return -1;
4928       }
4929 
4930     for (i = 0; i < numedges; i++)
4931       {
4932 	  /* parameter binding */
4933 	  int icol = 1;
4934 	  const RTT_ISO_EDGE *upd_edge = edges + i;
4935 	  sqlite3_reset (stmt);
4936 	  sqlite3_clear_bindings (stmt);
4937 	  if (upd_fields & RTT_COL_EDGE_EDGE_ID)
4938 	    {
4939 		sqlite3_bind_int64 (stmt, icol, upd_edge->edge_id);
4940 		icol++;
4941 	    }
4942 	  if (upd_fields & RTT_COL_EDGE_START_NODE)
4943 	    {
4944 		sqlite3_bind_int64 (stmt, icol, upd_edge->start_node);
4945 		icol++;
4946 	    }
4947 	  if (upd_fields & RTT_COL_EDGE_END_NODE)
4948 	    {
4949 		sqlite3_bind_int64 (stmt, icol, upd_edge->end_node);
4950 		icol++;
4951 	    }
4952 	  if (upd_fields & RTT_COL_EDGE_FACE_LEFT)
4953 	    {
4954 		if (upd_edge->face_left < 0)
4955 		    sqlite3_bind_null (stmt, icol);
4956 		else
4957 		    sqlite3_bind_int64 (stmt, icol, upd_edge->face_left);
4958 		icol++;
4959 	    }
4960 	  if (upd_fields & RTT_COL_EDGE_FACE_RIGHT)
4961 	    {
4962 		if (upd_edge->face_right < 0)
4963 		    sqlite3_bind_null (stmt, icol);
4964 		else
4965 		    sqlite3_bind_int64 (stmt, icol, upd_edge->face_right);
4966 		icol++;
4967 	    }
4968 	  if (upd_fields & RTT_COL_EDGE_NEXT_LEFT)
4969 	    {
4970 		sqlite3_bind_int64 (stmt, icol, upd_edge->next_left);
4971 		icol++;
4972 	    }
4973 	  if (upd_fields & RTT_COL_EDGE_NEXT_RIGHT)
4974 	    {
4975 		sqlite3_bind_int64 (stmt, icol, upd_edge->next_right);
4976 		icol++;
4977 	    }
4978 	  if (upd_fields & RTT_COL_EDGE_GEOM)
4979 	    {
4980 		/* transforming the RTLINE into a Geometry-Linestring */
4981 		gaiaGeomCollPtr geom =
4982 		    do_rtline_to_geom (ctx, upd_edge->geom, accessor->srid);
4983 		gaiaToSpatiaLiteBlobWkbEx2 (geom, &p_blob, &n_bytes, gpkg_mode,
4984 					    tiny_point);
4985 		gaiaFreeGeomColl (geom);
4986 		sqlite3_bind_blob (stmt, icol, p_blob, n_bytes, free);
4987 		icol++;
4988 	    }
4989 	  sqlite3_bind_int64 (stmt, icol, upd_edge->edge_id);
4990 	  ret = sqlite3_step (stmt);
4991 	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4992 	      changed += sqlite3_changes (accessor->db_handle);
4993 	  else
4994 	    {
4995 		char *msg = sqlite3_mprintf ("callback_updateEdgesById: \"%s\"",
4996 					     sqlite3_errmsg
4997 					     (accessor->db_handle));
4998 		gaiatopo_set_last_error_msg (topo, msg);
4999 		sqlite3_free (msg);
5000 		goto error;
5001 	    }
5002       }
5003     sqlite3_finalize (stmt);
5004     return changed;
5005 
5006   error:
5007     sqlite3_finalize (stmt);
5008     return -1;
5009 }
5010 
5011 RTT_ISO_EDGE *
callback_getEdgeByFace(const RTT_BE_TOPOLOGY * rtt_topo,const RTT_ELEMID * ids,int * numelems,int fields,const RTGBOX * box)5012 callback_getEdgeByFace (const RTT_BE_TOPOLOGY * rtt_topo,
5013 			const RTT_ELEMID * ids, int *numelems, int fields,
5014 			const RTGBOX * box)
5015 {
5016 /* callback function: getEdgeByFace */
5017     const RTCTX *ctx = NULL;
5018     struct splite_internal_cache *cache = NULL;
5019     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
5020     struct gaia_topology *accessor = (struct gaia_topology *) topo;
5021     int ret;
5022     char *sql;
5023     char *prev;
5024     char *table;
5025     char *xtable;
5026     int comma = 0;
5027     int i;
5028     sqlite3_stmt *stmt_aux = NULL;
5029     struct topo_edges_list *list = NULL;
5030     RTT_ISO_EDGE *result = NULL;
5031     if (accessor == NULL)
5032       {
5033 	  *numelems = -1;
5034 	  return NULL;
5035       }
5036 
5037     cache = (struct splite_internal_cache *) accessor->cache;
5038     if (cache == NULL)
5039 	return NULL;
5040     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
5041 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
5042 	return NULL;
5043     ctx = cache->RTTOPO_handle;
5044     if (ctx == NULL)
5045 	return NULL;
5046 
5047     /* preparing the SQL statement */
5048     sql = sqlite3_mprintf ("SELECT ");
5049     prev = sql;
5050     /* unconditionally querying the Edge ID */
5051     if (comma)
5052 	sql = sqlite3_mprintf ("%s, edge_id", prev);
5053     else
5054 	sql = sqlite3_mprintf ("%s edge_id", prev);
5055     comma = 1;
5056     sqlite3_free (prev);
5057     prev = sql;
5058     if (fields & RTT_COL_EDGE_START_NODE)
5059       {
5060 	  if (comma)
5061 	      sql = sqlite3_mprintf ("%s, start_node", prev);
5062 	  else
5063 	      sql = sqlite3_mprintf ("%s start_node", prev);
5064 	  comma = 1;
5065 	  sqlite3_free (prev);
5066 	  prev = sql;
5067       }
5068     if (fields & RTT_COL_EDGE_END_NODE)
5069       {
5070 	  if (comma)
5071 	      sql = sqlite3_mprintf ("%s, end_node", prev);
5072 	  else
5073 	      sql = sqlite3_mprintf ("%s end_node", prev);
5074 	  comma = 1;
5075 	  sqlite3_free (prev);
5076 	  prev = sql;
5077       }
5078     if (fields & RTT_COL_EDGE_FACE_LEFT)
5079       {
5080 	  if (comma)
5081 	      sql = sqlite3_mprintf ("%s, left_face", prev);
5082 	  else
5083 	      sql = sqlite3_mprintf ("%s left_face", prev);
5084 	  comma = 1;
5085 	  sqlite3_free (prev);
5086 	  prev = sql;
5087       }
5088     if (fields & RTT_COL_EDGE_FACE_RIGHT)
5089       {
5090 	  if (comma)
5091 	      sql = sqlite3_mprintf ("%s, right_face", prev);
5092 	  else
5093 	      sql = sqlite3_mprintf ("%s right_face", prev);
5094 	  comma = 1;
5095 	  sqlite3_free (prev);
5096 	  prev = sql;
5097       }
5098     if (fields & RTT_COL_EDGE_NEXT_LEFT)
5099       {
5100 	  if (comma)
5101 	      sql = sqlite3_mprintf ("%s, next_left_edge", prev);
5102 	  else
5103 	      sql = sqlite3_mprintf ("%s next_left_edge", prev);
5104 	  comma = 1;
5105 	  sqlite3_free (prev);
5106 	  prev = sql;
5107       }
5108     if (fields & RTT_COL_EDGE_NEXT_RIGHT)
5109       {
5110 	  if (comma)
5111 	      sql = sqlite3_mprintf ("%s, next_right_edge", prev);
5112 	  else
5113 	      sql = sqlite3_mprintf ("%s next_right_edge", prev);
5114 	  comma = 1;
5115 	  sqlite3_free (prev);
5116 	  prev = sql;
5117       }
5118     if (fields & RTT_COL_EDGE_GEOM)
5119       {
5120 	  if (comma)
5121 	      sql = sqlite3_mprintf ("%s, geom", prev);
5122 	  else
5123 	      sql = sqlite3_mprintf ("%s geom", prev);
5124 	  comma = 1;
5125 	  sqlite3_free (prev);
5126 	  prev = sql;
5127       }
5128     table = sqlite3_mprintf ("%s_edge", accessor->topology_name);
5129     xtable = gaiaDoubleQuotedSql (table);
5130     sqlite3_free (table);
5131     sql =
5132 	sqlite3_mprintf
5133 	("%s FROM MAIN.\"%s\" WHERE (left_face = ? OR right_face = ?)", prev,
5134 	 xtable);
5135     free (xtable);
5136     sqlite3_free (prev);
5137     if (box != NULL)
5138       {
5139 	  table = sqlite3_mprintf ("%s_edge", accessor->topology_name);
5140 	  prev = sql;
5141 	  sql =
5142 	      sqlite3_mprintf
5143 	      ("%s AND ROWID IN (SELECT ROWID FROM SpatialIndex WHERE "
5144 	       "f_table_name = %Q AND f_geometry_column = 'geom' AND search_frame = BuildMBR(?, ?, ?, ?))",
5145 	       sql, table);
5146 	  sqlite3_free (table);
5147 	  sqlite3_free (prev);
5148       }
5149     ret =
5150 	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
5151 			    &stmt_aux, NULL);
5152     sqlite3_free (sql);
5153     if (ret != SQLITE_OK)
5154       {
5155 	  char *msg =
5156 	      sqlite3_mprintf ("Prepare_getEdgeByFace AUX error: \"%s\"",
5157 			       sqlite3_errmsg (accessor->db_handle));
5158 	  gaiatopo_set_last_error_msg (topo, msg);
5159 	  sqlite3_free (msg);
5160 	  *numelems = -1;
5161 	  return NULL;
5162       }
5163 
5164     list = create_edges_list ();
5165     for (i = 0; i < *numelems; i++)
5166       {
5167 	  char *msg;
5168 	  if (!do_read_edge_by_face
5169 	      (stmt_aux, list, *(ids + i), fields, box,
5170 	       "callback_getEdgeByFace", &msg))
5171 	    {
5172 		gaiatopo_set_last_error_msg (topo, msg);
5173 		sqlite3_free (msg);
5174 		goto error;
5175 	    }
5176       }
5177 
5178     if (list->count == 0)
5179       {
5180 	  /* no edge was found */
5181 	  *numelems = list->count;
5182       }
5183     else
5184       {
5185 	  struct topo_edge *p_ed;
5186 	  result = rtalloc (ctx, sizeof (RTT_ISO_EDGE) * list->count);
5187 	  p_ed = list->first;
5188 	  i = 0;
5189 	  while (p_ed != NULL)
5190 	    {
5191 		RTT_ISO_EDGE *ed = result + i;
5192 		if (fields & RTT_COL_EDGE_EDGE_ID)
5193 		    ed->edge_id = p_ed->edge_id;
5194 		if (fields & RTT_COL_EDGE_START_NODE)
5195 		    ed->start_node = p_ed->start_node;
5196 		if (fields & RTT_COL_EDGE_END_NODE)
5197 		    ed->end_node = p_ed->end_node;
5198 		if (fields & RTT_COL_EDGE_FACE_LEFT)
5199 		    ed->face_left = p_ed->face_left;
5200 		if (fields & RTT_COL_EDGE_FACE_RIGHT)
5201 		    ed->face_right = p_ed->face_right;
5202 		if (fields & RTT_COL_EDGE_NEXT_LEFT)
5203 		    ed->next_left = p_ed->next_left;
5204 		if (fields & RTT_COL_EDGE_NEXT_RIGHT)
5205 		    ed->next_right = p_ed->next_right;
5206 		if (fields & RTT_COL_EDGE_GEOM)
5207 		    ed->geom =
5208 			gaia_convert_linestring_to_rtline (ctx, p_ed->geom,
5209 							   accessor->srid,
5210 							   accessor->has_z);
5211 		i++;
5212 		p_ed = p_ed->next;
5213 	    }
5214 	  *numelems = list->count;
5215       }
5216     sqlite3_finalize (stmt_aux);
5217     destroy_edges_list (list);
5218     return result;
5219 
5220   error:
5221     if (stmt_aux != NULL)
5222 	sqlite3_finalize (stmt_aux);
5223     if (list != NULL)
5224 	destroy_edges_list (list);
5225     *numelems = -1;
5226     return NULL;
5227 }
5228 
5229 RTT_ISO_NODE *
callback_getNodeByFace(const RTT_BE_TOPOLOGY * rtt_topo,const RTT_ELEMID * faces,int * numelems,int fields,const RTGBOX * box)5230 callback_getNodeByFace (const RTT_BE_TOPOLOGY * rtt_topo,
5231 			const RTT_ELEMID * faces, int *numelems, int fields,
5232 			const RTGBOX * box)
5233 {
5234 /* callback function: getNodeByFace */
5235     const RTCTX *ctx = NULL;
5236     struct splite_internal_cache *cache = NULL;
5237     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
5238     struct gaia_topology *accessor = (struct gaia_topology *) topo;
5239     sqlite3_stmt *stmt_aux = NULL;
5240     int ret;
5241     int i;
5242     char *sql;
5243     char *prev;
5244     char *table;
5245     char *xtable;
5246     int comma = 0;
5247     RTPOINTARRAY *pa;
5248     RTPOINT4D pt4d;
5249     struct topo_nodes_list *list = NULL;
5250     RTT_ISO_NODE *result = NULL;
5251     if (accessor == NULL)
5252       {
5253 	  *numelems = -1;
5254 	  return NULL;
5255       }
5256 
5257     cache = (struct splite_internal_cache *) accessor->cache;
5258     if (cache == NULL)
5259 	return NULL;
5260     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
5261 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
5262 	return NULL;
5263     ctx = cache->RTTOPO_handle;
5264     if (ctx == NULL)
5265 	return NULL;
5266 
5267     /* preparing the SQL statement */
5268     sql = sqlite3_mprintf ("SELECT ");
5269     prev = sql;
5270     if (fields & RTT_COL_NODE_NODE_ID)
5271       {
5272 	  if (comma)
5273 	      sql = sqlite3_mprintf ("%s, node_id", prev);
5274 	  else
5275 	      sql = sqlite3_mprintf ("%s node_id", prev);
5276 	  comma = 1;
5277 	  sqlite3_free (prev);
5278 	  prev = sql;
5279       }
5280     if (fields & RTT_COL_NODE_CONTAINING_FACE)
5281       {
5282 	  if (comma)
5283 	      sql = sqlite3_mprintf ("%s, containing_face", prev);
5284 	  else
5285 	      sql = sqlite3_mprintf ("%s containing_face", prev);
5286 	  comma = 1;
5287 	  sqlite3_free (prev);
5288 	  prev = sql;
5289       }
5290     if (fields & RTT_COL_NODE_GEOM)
5291       {
5292 	  if (comma)
5293 	      sql = sqlite3_mprintf ("%s, ST_X(geom), ST_Y(geom)", prev);
5294 	  else
5295 	      sql = sqlite3_mprintf ("%s ST_X(geom), ST_Y(geom)", prev);
5296 	  comma = 1;
5297 	  sqlite3_free (prev);
5298 	  prev = sql;
5299 	  if (accessor->has_z)
5300 	    {
5301 		sql = sqlite3_mprintf ("%s, ST_Z(geom)", prev);
5302 		sqlite3_free (prev);
5303 		prev = sql;
5304 	    }
5305       }
5306     table = sqlite3_mprintf ("%s_node", accessor->topology_name);
5307     xtable = gaiaDoubleQuotedSql (table);
5308     sqlite3_free (table);
5309     sql =
5310 	sqlite3_mprintf ("%s FROM MAIN.\"%s\" WHERE containing_face = ?", prev,
5311 			 xtable);
5312     free (xtable);
5313     sqlite3_free (prev);
5314     if (box != NULL)
5315       {
5316 	  table = sqlite3_mprintf ("%s_node", accessor->topology_name);
5317 	  prev = sql;
5318 	  sql =
5319 	      sqlite3_mprintf
5320 	      ("%s AND ROWID IN (SELECT ROWID FROM SpatialIndex WHERE "
5321 	       "f_table_name = %Q AND f_geometry_column = 'geom' AND search_frame = BuildMBR(?, ?, ?, ?))",
5322 	       sql, table);
5323 	  sqlite3_free (table);
5324 	  sqlite3_free (prev);
5325       }
5326     ret =
5327 	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt_aux,
5328 			    NULL);
5329     sqlite3_free (sql);
5330     if (ret != SQLITE_OK)
5331       {
5332 	  char *msg =
5333 	      sqlite3_mprintf ("Prepare_getNodeByFace AUX error: \"%s\"",
5334 			       sqlite3_errmsg (accessor->db_handle));
5335 	  gaiatopo_set_last_error_msg (topo, msg);
5336 	  sqlite3_free (msg);
5337 	  *numelems = -1;
5338 	  return NULL;
5339       }
5340 
5341     list = create_nodes_list ();
5342     for (i = 0; i < *numelems; i++)
5343       {
5344 	  char *msg;
5345 	  if (!do_read_node_by_face
5346 	      (stmt_aux, list, *(faces + i), fields, box, accessor->has_z,
5347 	       "callback_getNodeByFace", &msg))
5348 	    {
5349 		gaiatopo_set_last_error_msg (topo, msg);
5350 		sqlite3_free (msg);
5351 		goto error;
5352 	    }
5353       }
5354 
5355     if (list->count == 0)
5356       {
5357 	  /* no node was found */
5358 	  *numelems = list->count;
5359       }
5360     else
5361       {
5362 	  struct topo_node *p_nd;
5363 	  result = rtalloc (ctx, sizeof (RTT_ISO_NODE) * list->count);
5364 	  p_nd = list->first;
5365 	  i = 0;
5366 	  while (p_nd != NULL)
5367 	    {
5368 		RTT_ISO_NODE *nd = result + i;
5369 		if (fields & RTT_COL_NODE_NODE_ID)
5370 		    nd->node_id = p_nd->node_id;
5371 		if (fields & RTT_COL_NODE_CONTAINING_FACE)
5372 		    nd->containing_face = p_nd->containing_face;
5373 		if (fields & RTT_COL_NODE_GEOM)
5374 		  {
5375 		      pa = ptarray_construct (ctx, accessor->has_z, 0, 1);
5376 		      pt4d.x = p_nd->x;
5377 		      pt4d.y = p_nd->y;
5378 		      if (accessor->has_z)
5379 			  pt4d.z = p_nd->z;
5380 		      ptarray_set_point4d (ctx, pa, 0, &pt4d);
5381 		      nd->geom =
5382 			  rtpoint_construct (ctx, accessor->srid, NULL, pa);
5383 		  }
5384 		i++;
5385 		p_nd = p_nd->next;
5386 	    }
5387 	  *numelems = list->count;
5388       }
5389     sqlite3_finalize (stmt_aux);
5390     destroy_nodes_list (list);
5391     return result;
5392 
5393   error:
5394     if (stmt_aux != NULL)
5395 	sqlite3_finalize (stmt_aux);
5396     if (list != NULL)
5397 	destroy_nodes_list (list);
5398     *numelems = -1;
5399     return NULL;
5400 }
5401 
5402 int
callback_updateNodesById(const RTT_BE_TOPOLOGY * rtt_topo,const RTT_ISO_NODE * nodes,int numnodes,int upd_fields)5403 callback_updateNodesById (const RTT_BE_TOPOLOGY * rtt_topo,
5404 			  const RTT_ISO_NODE * nodes, int numnodes,
5405 			  int upd_fields)
5406 {
5407 /* callback function: updateNodesById */
5408     const RTCTX *ctx = NULL;
5409     struct splite_internal_cache *cache = NULL;
5410     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
5411     struct gaia_topology *accessor = (struct gaia_topology *) topo;
5412     sqlite3_stmt *stmt = NULL;
5413     int ret;
5414     char *sql;
5415     char *prev;
5416     int comma = 0;
5417     char *table;
5418     char *xtable;
5419     int icol = 1;
5420     int i;
5421     int changed = 0;
5422     if (accessor == NULL)
5423 	return -1;
5424 
5425     cache = (struct splite_internal_cache *) accessor->cache;
5426     if (cache == NULL)
5427 	return 0;
5428     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
5429 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
5430 	return 0;
5431     ctx = cache->RTTOPO_handle;
5432     if (ctx == NULL)
5433 	return 0;
5434 
5435 /* composing the SQL prepared statement */
5436     table = sqlite3_mprintf ("%s_node", accessor->topology_name);
5437     xtable = gaiaDoubleQuotedSql (table);
5438     sqlite3_free (table);
5439     sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET", xtable);
5440     free (xtable);
5441     prev = sql;
5442     if (upd_fields & RTT_COL_NODE_NODE_ID)
5443       {
5444 	  if (comma)
5445 	      sql = sqlite3_mprintf ("%s, node_id = ?", prev);
5446 	  else
5447 	      sql = sqlite3_mprintf ("%s node_id = ?", prev);
5448 	  comma = 1;
5449 	  sqlite3_free (prev);
5450 	  prev = sql;
5451       }
5452     if (upd_fields & RTT_COL_NODE_CONTAINING_FACE)
5453       {
5454 	  if (comma)
5455 	      sql = sqlite3_mprintf ("%s, containing_face = ?", prev);
5456 	  else
5457 	      sql = sqlite3_mprintf ("%s containing_face = ?", prev);
5458 	  comma = 1;
5459 	  sqlite3_free (prev);
5460 	  prev = sql;
5461       }
5462     if (upd_fields & RTT_COL_NODE_GEOM)
5463       {
5464 	  if (accessor->has_z)
5465 	    {
5466 		if (comma)
5467 		    sql =
5468 			sqlite3_mprintf ("%s, geom = MakePointZ(?, ?. ?, %d)",
5469 					 prev, accessor->srid);
5470 		else
5471 		    sql =
5472 			sqlite3_mprintf ("%s geom = MakePointZ(?, ?, ?, %d)",
5473 					 prev, accessor->srid);
5474 	    }
5475 	  else
5476 	    {
5477 		if (comma)
5478 		    sql =
5479 			sqlite3_mprintf ("%s, geom = MakePoint(?, ?, %d)", prev,
5480 					 accessor->srid);
5481 		else
5482 		    sql =
5483 			sqlite3_mprintf ("%s geom = MakePoint(?, ?, %d)", prev,
5484 					 accessor->srid);
5485 	    }
5486 	  comma = 1;
5487 	  sqlite3_free (prev);
5488 	  prev = sql;
5489       }
5490     sql = sqlite3_mprintf ("%s WHERE node_id = ?", prev);
5491     sqlite3_free (prev);
5492     ret =
5493 	sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt,
5494 			    NULL);
5495     sqlite3_free (sql);
5496     if (ret != SQLITE_OK)
5497       {
5498 	  char *msg = sqlite3_mprintf ("Prepare_updateNodesById error: \"%s\"",
5499 				       sqlite3_errmsg (accessor->db_handle));
5500 	  gaiatopo_set_last_error_msg (topo, msg);
5501 	  sqlite3_free (msg);
5502 	  return -1;
5503       }
5504 
5505     for (i = 0; i < numnodes; i++)
5506       {
5507 	  /* parameter binding */
5508 	  const RTT_ISO_NODE *nd = nodes + i;
5509 	  icol = 1;
5510 	  sqlite3_reset (stmt);
5511 	  sqlite3_clear_bindings (stmt);
5512 	  if (upd_fields & RTT_COL_NODE_NODE_ID)
5513 	    {
5514 		sqlite3_bind_int64 (stmt, icol, nd->node_id);
5515 		icol++;
5516 	    }
5517 	  if (upd_fields & RTT_COL_NODE_CONTAINING_FACE)
5518 	    {
5519 		if (nd->containing_face < 0)
5520 		    sqlite3_bind_null (stmt, icol);
5521 		else
5522 		    sqlite3_bind_int64 (stmt, icol, nd->containing_face);
5523 		icol++;
5524 	    }
5525 	  if (upd_fields & RTT_COL_NODE_GEOM)
5526 	    {
5527 		RTPOINTARRAY *pa;
5528 		RTPOINT4D pt4d;
5529 		double x;
5530 		double y;
5531 		double z;
5532 		/* extracting X and Y from RTPOINT */
5533 		pa = nd->geom->point;
5534 		rt_getPoint4d_p (ctx, pa, 0, &pt4d);
5535 		x = pt4d.x;
5536 		y = pt4d.y;
5537 		if (accessor->has_z)
5538 		    z = pt4d.z;
5539 		sqlite3_bind_double (stmt, icol, x);
5540 		icol++;
5541 		sqlite3_bind_double (stmt, icol, y);
5542 		icol++;
5543 		if (accessor->has_z)
5544 		  {
5545 		      sqlite3_bind_double (stmt, icol, z);
5546 		      icol++;
5547 		  }
5548 	    }
5549 	  sqlite3_bind_int64 (stmt, icol, nd->node_id);
5550 	  ret = sqlite3_step (stmt);
5551 	  if (ret == SQLITE_DONE || ret == SQLITE_ROW)
5552 	      changed += sqlite3_changes (accessor->db_handle);
5553 	  else
5554 	    {
5555 		char *msg = sqlite3_mprintf ("callback_updateNodesById: \"%s\"",
5556 					     sqlite3_errmsg
5557 					     (accessor->db_handle));
5558 		gaiatopo_set_last_error_msg (topo, msg);
5559 		sqlite3_free (msg);
5560 		goto error;
5561 	    }
5562       }
5563     sqlite3_finalize (stmt);
5564     return changed;
5565 
5566   error:
5567     sqlite3_finalize (stmt);
5568     return -1;
5569 }
5570 
5571 RTT_ISO_FACE *
callback_getFaceWithinBox2D(const RTT_BE_TOPOLOGY * rtt_topo,const RTGBOX * box,int * numelems,int fields,int limit)5572 callback_getFaceWithinBox2D (const RTT_BE_TOPOLOGY * rtt_topo,
5573 			     const RTGBOX * box, int *numelems, int fields,
5574 			     int limit)
5575 {
5576 /* callback function: getFaceWithinBox2D */
5577     const RTCTX *ctx = NULL;
5578     struct splite_internal_cache *cache = NULL;
5579     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
5580     struct gaia_topology *accessor = (struct gaia_topology *) topo;
5581     sqlite3_stmt *stmt;
5582     int ret;
5583     int count = 0;
5584     struct topo_faces_list *list = NULL;
5585     RTT_ISO_FACE *result = NULL;
5586     if (accessor == NULL)
5587       {
5588 	  *numelems = -1;
5589 	  return NULL;
5590       }
5591 
5592     stmt = accessor->stmt_getFaceWithinBox2D;
5593     if (stmt == NULL)
5594       {
5595 	  *numelems = -1;
5596 	  return NULL;
5597       }
5598 
5599     cache = (struct splite_internal_cache *) accessor->cache;
5600     if (cache == NULL)
5601 	return NULL;
5602     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
5603 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
5604 	return NULL;
5605     ctx = cache->RTTOPO_handle;
5606     if (ctx == NULL)
5607 	return NULL;
5608 
5609 /* setting up the prepared statement */
5610     sqlite3_reset (stmt);
5611     sqlite3_clear_bindings (stmt);
5612     sqlite3_bind_double (stmt, 1, box->xmax);
5613     sqlite3_bind_double (stmt, 2, box->xmin);
5614     sqlite3_bind_double (stmt, 3, box->ymax);
5615     sqlite3_bind_double (stmt, 4, box->ymin);
5616     list = create_faces_list ();
5617 
5618     while (1)
5619       {
5620 	  /* scrolling the result set rows */
5621 	  ret = sqlite3_step (stmt);
5622 	  if (ret == SQLITE_DONE)
5623 	      break;		/* end of result set */
5624 	  if (ret == SQLITE_ROW)
5625 	    {
5626 		sqlite3_int64 face_id = sqlite3_column_int64 (stmt, 0);
5627 		double minx = sqlite3_column_double (stmt, 1);
5628 		double miny = sqlite3_column_double (stmt, 2);
5629 		double maxx = sqlite3_column_double (stmt, 3);
5630 		double maxy = sqlite3_column_double (stmt, 4);
5631 		add_face (list, face_id, face_id, minx, miny, maxx, maxy);
5632 		count++;
5633 		if (limit > 0)
5634 		  {
5635 		      if (count > limit)
5636 			  break;
5637 		  }
5638 		if (limit < 0)
5639 		    break;
5640 	    }
5641 	  else
5642 	    {
5643 		char *msg = sqlite3_mprintf ("callback_getFaceWithinBox2D: %s",
5644 					     sqlite3_errmsg
5645 					     (accessor->db_handle));
5646 		gaiatopo_set_last_error_msg (topo, msg);
5647 		sqlite3_free (msg);
5648 		goto error;
5649 	    }
5650       }
5651 
5652     if (limit < 0)
5653       {
5654 	  result = NULL;
5655 	  *numelems = count;
5656       }
5657     else
5658       {
5659 	  if (list->count <= 0)
5660 	    {
5661 		result = NULL;
5662 		*numelems = 0;
5663 	    }
5664 	  else
5665 	    {
5666 		int i = 0;
5667 		struct topo_face *p_fc;
5668 		result = rtalloc (ctx, sizeof (RTT_ISO_FACE) * list->count);
5669 		p_fc = list->first;
5670 		while (p_fc != NULL)
5671 		  {
5672 		      RTT_ISO_FACE *fc = result + i;
5673 		      if (fields & RTT_COL_FACE_FACE_ID)
5674 			  fc->face_id = p_fc->face_id;
5675 		      if (fields & RTT_COL_FACE_MBR)
5676 			{
5677 			    fc->mbr = gbox_new (ctx, 0);
5678 			    fc->mbr->xmin = p_fc->minx;
5679 			    fc->mbr->ymin = p_fc->miny;
5680 			    fc->mbr->xmax = p_fc->maxx;
5681 			    fc->mbr->ymax = p_fc->maxy;
5682 			}
5683 		      i++;
5684 		      p_fc = p_fc->next;
5685 		  }
5686 		*numelems = list->count;
5687 	    }
5688       }
5689     destroy_faces_list (list);
5690     sqlite3_reset (stmt);
5691     return result;
5692 
5693   error:
5694     if (list != NULL)
5695 	destroy_faces_list (list);
5696     *numelems = -1;
5697     sqlite3_reset (stmt);
5698     return NULL;
5699 }
5700 
5701 int
callback_updateTopoGeomEdgeSplit(const RTT_BE_TOPOLOGY * topo,RTT_ELEMID split_edge,RTT_ELEMID new_edge1,RTT_ELEMID new_edge2)5702 callback_updateTopoGeomEdgeSplit (const RTT_BE_TOPOLOGY * topo,
5703 				  RTT_ELEMID split_edge, RTT_ELEMID new_edge1,
5704 				  RTT_ELEMID new_edge2)
5705 {
5706 /* does nothing */
5707     if (topo != NULL && split_edge == 0 && new_edge1 == 0 && new_edge2 == 0)
5708 	topo = NULL;		/* silencing stupid compiler warnings on unused args */
5709     return 1;
5710 }
5711 
5712 int
callback_updateTopoGeomFaceSplit(const RTT_BE_TOPOLOGY * topo,RTT_ELEMID split_face,RTT_ELEMID new_face1,RTT_ELEMID new_face2)5713 callback_updateTopoGeomFaceSplit (const RTT_BE_TOPOLOGY * topo,
5714 				  RTT_ELEMID split_face,
5715 				  RTT_ELEMID new_face1, RTT_ELEMID new_face2)
5716 {
5717 /* does nothing */
5718     if (topo != NULL && split_face == 0 && new_face1 == 0 && new_face2 == 0)
5719 	topo = NULL;		/* silencing stupid compiler warnings on unused args */
5720     return 1;
5721 }
5722 
5723 int
callback_checkTopoGeomRemEdge(const RTT_BE_TOPOLOGY * topo,RTT_ELEMID rem_edge,RTT_ELEMID face_left,RTT_ELEMID face_right)5724 callback_checkTopoGeomRemEdge (const RTT_BE_TOPOLOGY * topo,
5725 			       RTT_ELEMID rem_edge, RTT_ELEMID face_left,
5726 			       RTT_ELEMID face_right)
5727 {
5728 /* does nothing */
5729     if (topo != NULL && rem_edge == 0 && face_left == 0 && face_right == 0)
5730 	topo = NULL;		/* silencing stupid compiler warnings on unused args */
5731     return 1;
5732 }
5733 
5734 int
callback_updateTopoGeomFaceHeal(const RTT_BE_TOPOLOGY * topo,RTT_ELEMID face1,RTT_ELEMID face2,RTT_ELEMID newface)5735 callback_updateTopoGeomFaceHeal (const RTT_BE_TOPOLOGY * topo, RTT_ELEMID face1,
5736 				 RTT_ELEMID face2, RTT_ELEMID newface)
5737 {
5738 /* does nothing */
5739     if (topo != NULL && face1 == 0 && face2 == 0 && newface == 0)
5740 	topo = NULL;		/* silencing stupid compiler warnings on unused args */
5741     return 1;
5742 }
5743 
5744 int
callback_checkTopoGeomRemNode(const RTT_BE_TOPOLOGY * topo,RTT_ELEMID rem_node,RTT_ELEMID e1,RTT_ELEMID e2)5745 callback_checkTopoGeomRemNode (const RTT_BE_TOPOLOGY * topo,
5746 			       RTT_ELEMID rem_node, RTT_ELEMID e1,
5747 			       RTT_ELEMID e2)
5748 {
5749 /* does nothing */
5750     if (topo != NULL && rem_node == 0 && e1 == 0 && e2 == 0)
5751 	topo = NULL;		/* silencing stupid compiler warnings on unused args */
5752     return 1;
5753 }
5754 
5755 int
callback_updateTopoGeomEdgeHeal(const RTT_BE_TOPOLOGY * topo,RTT_ELEMID edge1,RTT_ELEMID edge2,RTT_ELEMID newedge)5756 callback_updateTopoGeomEdgeHeal (const RTT_BE_TOPOLOGY * topo, RTT_ELEMID edge1,
5757 				 RTT_ELEMID edge2, RTT_ELEMID newedge)
5758 {
5759 /* does nothing */
5760     if (topo != NULL && edge1 == 0 && edge2 == 0 && newedge == 0)
5761 	topo = NULL;		/* silencing stupid compiler warnings on unused args */
5762     return 1;
5763 }
5764 
5765 int
callback_topoGetSRID(const RTT_BE_TOPOLOGY * rtt_topo)5766 callback_topoGetSRID (const RTT_BE_TOPOLOGY * rtt_topo)
5767 {
5768 /* callback function: topoGetSRID */
5769     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
5770     struct gaia_topology *accessor = (struct gaia_topology *) topo;
5771     if (accessor == NULL)
5772 	return -1;
5773 
5774     return accessor->srid;
5775 }
5776 
5777 double
callback_topoGetPrecision(const RTT_BE_TOPOLOGY * rtt_topo)5778 callback_topoGetPrecision (const RTT_BE_TOPOLOGY * rtt_topo)
5779 {
5780 /* callback function: topoGetPrecision */
5781     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
5782     struct gaia_topology *accessor = (struct gaia_topology *) topo;
5783     if (accessor == NULL)
5784 	return 0.0;
5785 
5786     return accessor->tolerance;
5787 }
5788 
5789 int
callback_topoHasZ(const RTT_BE_TOPOLOGY * rtt_topo)5790 callback_topoHasZ (const RTT_BE_TOPOLOGY * rtt_topo)
5791 {
5792 /* callback function: topoHasZ */
5793     GaiaTopologyAccessorPtr topo = (GaiaTopologyAccessorPtr) rtt_topo;
5794     struct gaia_topology *accessor = (struct gaia_topology *) topo;
5795     if (accessor == NULL)
5796 	return 0;
5797 
5798     return accessor->has_z;
5799 }
5800 
5801 #endif /* end ENABLE_RTTOPO conditionals */
5802