1 /*
2
3 net_callbacks.c -- implementation of Topology-Network 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 #include <stdlib.h>
47 #include <stdio.h>
48 #include <string.h>
49
50 #if defined(_WIN32) && !defined(__MINGW32__)
51 #include "config-msvc.h"
52 #else
53 #include "config.h"
54 #endif
55
56 #ifdef ENABLE_RTTOPO /* only if RTTOPO is enabled */
57
58 #include <spatialite/sqlite.h>
59 #include <spatialite/debug.h>
60 #include <spatialite/gaiageo.h>
61 #include <spatialite/gaia_network.h>
62 #include <spatialite/gaiaaux.h>
63
64 #include <spatialite.h>
65 #include <spatialite_private.h>
66
67 #include <librttopo.h>
68 #include <lwn_network.h>
69
70 #include "network_private.h"
71
72 struct net_node
73 {
74 /* a struct wrapping a Network Node */
75 sqlite3_int64 node_id;
76 double x;
77 double y;
78 double z;
79 int has_z;
80 int is_null;
81 struct net_node *next;
82 };
83
84 struct net_nodes_list
85 {
86 /* a struct wrapping a list of Network Nodes */
87 struct net_node *first;
88 struct net_node *last;
89 int count;
90 };
91
92 struct net_link
93 {
94 /* a struct wrapping a Network Link */
95 sqlite3_int64 link_id;
96 sqlite3_int64 start_node;
97 sqlite3_int64 end_node;
98 gaiaLinestringPtr geom;
99 struct net_link *next;
100 };
101
102 struct net_links_list
103 {
104 /* a struct wrapping a list of Network Links */
105 struct net_link *first;
106 struct net_link *last;
107 int count;
108 };
109
110 static struct net_node *
create_net_node(sqlite3_int64 node_id,double x,double y,double z,int has_z)111 create_net_node (sqlite3_int64 node_id, double x, double y, double z, int has_z)
112 {
113 /* creating a Network Node */
114 struct net_node *ptr = malloc (sizeof (struct net_node));
115 ptr->node_id = node_id;
116 ptr->x = x;
117 ptr->y = y;
118 ptr->z = z;
119 ptr->has_z = has_z;
120 ptr->is_null = 0;
121 ptr->next = NULL;
122 return ptr;
123 }
124
125 static struct net_node *
create_net_node_null(sqlite3_int64 node_id)126 create_net_node_null (sqlite3_int64 node_id)
127 {
128 /* creating a Network Node - NULL */
129 struct net_node *ptr = malloc (sizeof (struct net_node));
130 ptr->node_id = node_id;
131 ptr->is_null = 1;
132 ptr->next = NULL;
133 return ptr;
134 }
135
136 static void
destroy_net_node(struct net_node * ptr)137 destroy_net_node (struct net_node *ptr)
138 {
139 /* destroying a Network Node */
140 if (ptr == NULL)
141 return;
142 free (ptr);
143 }
144
145 static struct net_link *
create_net_link(sqlite3_int64 link_id,sqlite3_int64 start_node,sqlite3_int64 end_node,gaiaLinestringPtr ln)146 create_net_link (sqlite3_int64 link_id, sqlite3_int64 start_node,
147 sqlite3_int64 end_node, gaiaLinestringPtr ln)
148 {
149 /* creating a Network Link */
150 struct net_link *ptr = malloc (sizeof (struct net_link));
151 ptr->link_id = link_id;
152 ptr->start_node = start_node;
153 ptr->end_node = end_node;
154 ptr->geom = ln;
155 ptr->next = NULL;
156 return ptr;
157 }
158
159 static void
destroy_net_link(struct net_link * ptr)160 destroy_net_link (struct net_link *ptr)
161 {
162 /* destroying a Network Link */
163 if (ptr == NULL)
164 return;
165 if (ptr->geom != NULL)
166 gaiaFreeLinestring (ptr->geom);
167 free (ptr);
168 }
169
170 static struct net_nodes_list *
create_nodes_list(void)171 create_nodes_list (void)
172 {
173 /* creating an empty list of Network Nodes */
174 struct net_nodes_list *ptr = malloc (sizeof (struct net_nodes_list));
175 ptr->first = NULL;
176 ptr->last = NULL;
177 ptr->count = 0;
178 return ptr;
179 }
180
181 static void
destroy_net_nodes_list(struct net_nodes_list * ptr)182 destroy_net_nodes_list (struct net_nodes_list *ptr)
183 {
184 /* destroying a list of Network Nodes */
185 struct net_node *p;
186 struct net_node *pn;
187 if (ptr == NULL)
188 return;
189
190 p = ptr->first;
191 while (p != NULL)
192 {
193 pn = p->next;
194 destroy_net_node (p);
195 p = pn;
196 }
197 free (ptr);
198 }
199
200 static void
add_node_2D(struct net_nodes_list * list,sqlite3_int64 node_id,double x,double y)201 add_node_2D (struct net_nodes_list *list, sqlite3_int64 node_id,
202 double x, double y)
203 {
204 /* inserting a Network Node 2D into the list */
205 struct net_node *ptr;
206 if (list == NULL)
207 return;
208
209 ptr = create_net_node (node_id, x, y, 0.0, 0);
210 if (list->first == NULL)
211 list->first = ptr;
212 if (list->last != NULL)
213 list->last->next = ptr;
214 list->last = ptr;
215 list->count++;
216 }
217
218 static void
add_node_3D(struct net_nodes_list * list,sqlite3_int64 node_id,double x,double y,double z)219 add_node_3D (struct net_nodes_list *list, sqlite3_int64 node_id,
220 double x, double y, double z)
221 {
222 /* inserting a Network Node 3D into the list */
223 struct net_node *ptr;
224 if (list == NULL)
225 return;
226
227 ptr = create_net_node (node_id, x, y, z, 1);
228 if (list->first == NULL)
229 list->first = ptr;
230 if (list->last != NULL)
231 list->last->next = ptr;
232 list->last = ptr;
233 list->count++;
234 }
235
236 static void
add_node_null(struct net_nodes_list * list,sqlite3_int64 node_id)237 add_node_null (struct net_nodes_list *list, sqlite3_int64 node_id)
238 {
239 /* inserting a Network Node (NULL) into the list */
240 struct net_node *ptr;
241 if (list == NULL)
242 return;
243
244 ptr = create_net_node_null (node_id);
245 if (list->first == NULL)
246 list->first = ptr;
247 if (list->last != NULL)
248 list->last->next = ptr;
249 list->last = ptr;
250 list->count++;
251 }
252
253 static struct net_links_list *
create_links_list(void)254 create_links_list (void)
255 {
256 /* creating an empty list of Network Links */
257 struct net_links_list *ptr = malloc (sizeof (struct net_links_list));
258 ptr->first = NULL;
259 ptr->last = NULL;
260 ptr->count = 0;
261 return ptr;
262 }
263
264 static void
destroy_links_list(struct net_links_list * ptr)265 destroy_links_list (struct net_links_list *ptr)
266 {
267 /* destroying a list of Network Links */
268 struct net_link *p;
269 struct net_link *pn;
270 if (ptr == NULL)
271 return;
272
273 p = ptr->first;
274 while (p != NULL)
275 {
276 pn = p->next;
277 destroy_net_link (p);
278 p = pn;
279 }
280 free (ptr);
281 }
282
283 static void
add_link(struct net_links_list * list,sqlite3_int64 link_id,sqlite3_int64 start_node,sqlite3_int64 end_node,gaiaLinestringPtr ln)284 add_link (struct net_links_list *list, sqlite3_int64 link_id,
285 sqlite3_int64 start_node, sqlite3_int64 end_node,
286 gaiaLinestringPtr ln)
287 {
288 /* inserting a Network Link into the list */
289 struct net_link *ptr;
290 if (list == NULL)
291 return;
292
293 ptr = create_net_link (link_id, start_node, end_node, ln);
294 if (list->first == NULL)
295 list->first = ptr;
296 if (list->last != NULL)
297 list->last->next = ptr;
298 list->last = ptr;
299 list->count++;
300 }
301
302 static char *
do_prepare_read_net_node(const char * network_name,int fields,int spatial,int has_z)303 do_prepare_read_net_node (const char *network_name, int fields, int spatial,
304 int has_z)
305 {
306 /* preparing the auxiliary "read_node" SQL statement */
307 char *sql;
308 char *prev;
309 char *table;
310 char *xtable;
311 int comma = 0;
312
313 sql = sqlite3_mprintf ("SELECT ");
314 prev = sql;
315 if (fields & LWN_COL_NODE_NODE_ID)
316 {
317 if (comma)
318 sql = sqlite3_mprintf ("%s, node_id", prev);
319 else
320 sql = sqlite3_mprintf ("%s node_id", prev);
321 comma = 1;
322 sqlite3_free (prev);
323 prev = sql;
324 }
325 if (fields & LWN_COL_NODE_GEOM && spatial)
326 {
327 if (comma)
328 sql =
329 sqlite3_mprintf ("%s, ST_X(geometry), ST_Y(geometry)", prev);
330 else
331 sql = sqlite3_mprintf ("%s ST_X(geometry), ST_Y(geometry)", prev);
332 comma = 1;
333 sqlite3_free (prev);
334 prev = sql;
335 if (has_z)
336 {
337 sql = sqlite3_mprintf ("%s, ST_Z(geometry)", prev);
338 sqlite3_free (prev);
339 prev = sql;
340 }
341 }
342 table = sqlite3_mprintf ("%s_node", network_name);
343 xtable = gaiaDoubleQuotedSql (table);
344 sqlite3_free (table);
345 sql =
346 sqlite3_mprintf ("%s FROM MAIN.\"%s\" WHERE node_id = ?", prev, xtable);
347 sqlite3_free (prev);
348 free (xtable);
349 return sql;
350 }
351
352 static int
do_read_net_node(sqlite3_stmt * stmt,struct net_nodes_list * list,sqlite3_int64 id,int fields,int spatial,int has_z,const char * callback_name,char ** errmsg)353 do_read_net_node (sqlite3_stmt * stmt, struct net_nodes_list *list,
354 sqlite3_int64 id, int fields, int spatial, int has_z,
355 const char *callback_name, char **errmsg)
356 {
357 /* reading Nodes out from the DBMS */
358 int icol = 0;
359 int ret;
360
361 /* setting up the prepared statement */
362 sqlite3_reset (stmt);
363 sqlite3_clear_bindings (stmt);
364 sqlite3_bind_int64 (stmt, 1, id);
365
366 while (1)
367 {
368 /* scrolling the result set rows */
369 ret = sqlite3_step (stmt);
370 if (ret == SQLITE_DONE)
371 break; /* end of result set */
372 if (ret == SQLITE_ROW)
373 {
374 int ok_id = 0;
375 int ok_x = 0;
376 int ok_y = 0;
377 int ok_z = 0;
378 sqlite3_int64 node_id = -1;
379 double x = 0.0;
380 double y = 0.0;
381 double z = 0.0;
382 if (fields & LWN_COL_NODE_NODE_ID)
383 {
384 if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
385 {
386 node_id = sqlite3_column_int64 (stmt, icol);
387 ok_id = 1;
388 }
389 icol++;
390 }
391 else
392 ok_id = 1;
393 if (fields & LWN_COL_NODE_GEOM && spatial)
394 {
395 if (sqlite3_column_type (stmt, icol) == SQLITE_FLOAT)
396 {
397 x = sqlite3_column_double (stmt, icol);
398 ok_x = 1;
399 }
400 icol++;
401 if (sqlite3_column_type (stmt, icol) == SQLITE_FLOAT)
402 {
403 y = sqlite3_column_double (stmt, icol);
404 ok_y = 1;
405 }
406 icol++;
407 if (has_z)
408 {
409 if (sqlite3_column_type (stmt, icol) ==
410 SQLITE_FLOAT)
411 {
412 z = sqlite3_column_double (stmt, icol);
413 ok_z = 1;
414 }
415 }
416 }
417 else
418 {
419 ok_x = 1;
420 ok_y = 1;
421 ok_z = 1;
422 }
423 if (!spatial)
424 {
425 add_node_null (list, node_id);
426 *errmsg = NULL;
427 sqlite3_reset (stmt);
428 return 1;
429 }
430 else
431 {
432 if (has_z)
433 {
434 if (ok_id && ok_x && ok_y && ok_z)
435 {
436 add_node_3D (list, node_id, x, y, z);
437 *errmsg = NULL;
438 sqlite3_reset (stmt);
439 return 1;
440 }
441 }
442 else
443 {
444 if (ok_id && ok_x && ok_y)
445 {
446 add_node_2D (list, node_id, x, y);
447 *errmsg = NULL;
448 sqlite3_reset (stmt);
449 return 1;
450 }
451 }
452 }
453 /* an invalid Node has been found */
454 *errmsg =
455 sqlite3_mprintf
456 ("%s: found an invalid Node \"%lld\"", callback_name,
457 node_id);
458 sqlite3_reset (stmt);
459 return 0;
460 }
461 }
462 *errmsg = NULL;
463 sqlite3_reset (stmt);
464 return 1;
465 }
466
467 static char *
do_prepare_read_link(const char * network_name,int fields)468 do_prepare_read_link (const char *network_name, int fields)
469 {
470 /* preparing the auxiliary "read_link" SQL statement */
471 char *sql;
472 char *prev;
473 char *table;
474 char *xtable;
475 int comma = 0;
476
477 sql = sqlite3_mprintf ("SELECT ");
478 prev = sql;
479 if (fields & LWN_COL_LINK_LINK_ID)
480 {
481 if (comma)
482 sql = sqlite3_mprintf ("%s, link_id", prev);
483 else
484 sql = sqlite3_mprintf ("%s link_id", prev);
485 comma = 1;
486 sqlite3_free (prev);
487 prev = sql;
488 }
489 if (fields & LWN_COL_LINK_START_NODE)
490 {
491 if (comma)
492 sql = sqlite3_mprintf ("%s, start_node", prev);
493 else
494 sql = sqlite3_mprintf ("%s start_node", prev);
495 comma = 1;
496 sqlite3_free (prev);
497 prev = sql;
498 }
499 if (fields & LWN_COL_LINK_END_NODE)
500 {
501 if (comma)
502 sql = sqlite3_mprintf ("%s, end_node", prev);
503 else
504 sql = sqlite3_mprintf ("%s end_node", prev);
505 comma = 1;
506 sqlite3_free (prev);
507 prev = sql;
508 }
509 if (fields & LWN_COL_LINK_GEOM)
510 {
511 if (comma)
512 sql = sqlite3_mprintf ("%s, geometry", prev);
513 else
514 sql = sqlite3_mprintf ("%s geometry", prev);
515 comma = 1;
516 sqlite3_free (prev);
517 prev = sql;
518 }
519 table = sqlite3_mprintf ("%s_link", network_name);
520 xtable = gaiaDoubleQuotedSql (table);
521 sqlite3_free (table);
522 sql =
523 sqlite3_mprintf ("%s FROM MAIN.\"%s\" WHERE link_id = ?", prev, xtable);
524 free (xtable);
525 sqlite3_free (prev);
526 return sql;
527 }
528
529 static int
do_read_link_row(sqlite3_stmt * stmt,struct net_links_list * list,int fields,const char * callback_name,char ** errmsg)530 do_read_link_row (sqlite3_stmt * stmt, struct net_links_list *list, int fields,
531 const char *callback_name, char **errmsg)
532 {
533 /* reading a Link Row out from the resultset */
534 int icol = 0;
535
536 int ok_id = 0;
537 int ok_start = 0;
538 int ok_end = 0;
539 int ok_geom = 0;
540 sqlite3_int64 link_id = -1;
541 sqlite3_int64 start_node = -1;
542 sqlite3_int64 end_node = -1;
543 gaiaGeomCollPtr geom = NULL;
544 gaiaLinestringPtr ln = NULL;
545 if (fields & LWN_COL_LINK_LINK_ID)
546 {
547 if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
548 {
549 link_id = sqlite3_column_int64 (stmt, icol);
550 ok_id = 1;
551 }
552 icol++;
553 }
554 else
555 ok_id = 1;
556 if (fields & LWN_COL_LINK_START_NODE)
557 {
558 if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
559 {
560 start_node = sqlite3_column_int64 (stmt, icol);
561 ok_start = 1;
562 }
563 icol++;
564 }
565 else
566 ok_start = 1;
567 if (fields & LWN_COL_LINK_END_NODE)
568 {
569 if (sqlite3_column_type (stmt, icol) == SQLITE_INTEGER)
570 {
571 end_node = sqlite3_column_int64 (stmt, icol);
572 ok_end = 1;
573 }
574 icol++;
575 }
576 else
577 ok_end = 1;
578 if (fields & LWN_COL_LINK_GEOM)
579 {
580 if (sqlite3_column_type (stmt, icol) == SQLITE_NULL)
581 {
582 ln = NULL;
583 ok_geom = 1;
584 }
585 if (sqlite3_column_type (stmt, icol) == SQLITE_BLOB)
586 {
587 const unsigned char *blob = sqlite3_column_blob (stmt, icol);
588 int blob_sz = sqlite3_column_bytes (stmt, icol);
589 geom = gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
590 if (geom != NULL)
591 {
592 if (geom->FirstPoint == NULL
593 && geom->FirstPolygon == NULL
594 && geom->FirstLinestring ==
595 geom->LastLinestring && geom->FirstLinestring != NULL)
596 {
597 ln = geom->FirstLinestring;
598 ok_geom = 1;
599 /* releasing ownership on Linestring */
600 geom->FirstLinestring = NULL;
601 geom->LastLinestring = NULL;
602 }
603 gaiaFreeGeomColl (geom);
604 }
605 }
606 icol++;
607 }
608 else
609 ok_geom = 1;
610 if (ok_id && ok_start && ok_end && ok_geom)
611 {
612 add_link (list, link_id, start_node, end_node, ln);
613 *errmsg = NULL;
614 return 1;
615 }
616 /* an invalid Link has been found */
617 if (geom != NULL)
618 gaiaFreeGeomColl (geom);
619 *errmsg =
620 sqlite3_mprintf
621 ("%s: found an invalid Link \"%lld\"", callback_name, link_id);
622 return 0;
623 }
624
625 static int
do_read_link(sqlite3_stmt * stmt,struct net_links_list * list,sqlite3_int64 link_id,int fields,const char * callback_name,char ** errmsg)626 do_read_link (sqlite3_stmt * stmt, struct net_links_list *list,
627 sqlite3_int64 link_id, int fields, const char *callback_name,
628 char **errmsg)
629 {
630 /* reading a single Link out from the DBMS */
631 int ret;
632
633 /* setting up the prepared statement */
634 sqlite3_reset (stmt);
635 sqlite3_clear_bindings (stmt);
636 sqlite3_bind_int64 (stmt, 1, link_id);
637
638 while (1)
639 {
640 /* scrolling the result set rows */
641 ret = sqlite3_step (stmt);
642 if (ret == SQLITE_DONE)
643 break; /* end of result set */
644 if (ret == SQLITE_ROW)
645 {
646 if (!do_read_link_row
647 (stmt, list, fields, callback_name, errmsg))
648 {
649 sqlite3_reset (stmt);
650 return 0;
651 }
652 }
653 }
654 sqlite3_reset (stmt);
655 return 1;
656 }
657
658 static int
do_read_link_by_net_node(sqlite3_stmt * stmt,struct net_links_list * list,sqlite3_int64 node_id,int fields,const char * callback_name,char ** errmsg)659 do_read_link_by_net_node (sqlite3_stmt * stmt, struct net_links_list *list,
660 sqlite3_int64 node_id, int fields,
661 const char *callback_name, char **errmsg)
662 {
663 /* reading a single Link out from the DBMS */
664 int ret;
665
666 /* setting up the prepared statement */
667 sqlite3_reset (stmt);
668 sqlite3_clear_bindings (stmt);
669 sqlite3_bind_int64 (stmt, 1, node_id);
670 sqlite3_bind_int64 (stmt, 2, node_id);
671
672 while (1)
673 {
674 /* scrolling the result set rows */
675 ret = sqlite3_step (stmt);
676 if (ret == SQLITE_DONE)
677 break; /* end of result set */
678 if (ret == SQLITE_ROW)
679 {
680 if (!do_read_link_row
681 (stmt, list, fields, callback_name, errmsg))
682 {
683 sqlite3_reset (stmt);
684 return 0;
685 }
686 }
687 }
688 sqlite3_reset (stmt);
689 return 1;
690 }
691
692 const char *
netcallback_lastErrorMessage(const LWN_BE_DATA * be)693 netcallback_lastErrorMessage (const LWN_BE_DATA * be)
694 {
695 return gaianet_get_last_exception ((GaiaNetworkAccessorPtr) be);
696 }
697
698 LWN_BE_NETWORK *
netcallback_loadNetworkByName(const LWN_BE_DATA * be,const char * name)699 netcallback_loadNetworkByName (const LWN_BE_DATA * be, const char *name)
700 {
701 /* callback function: loadNetworkByName */
702 struct gaia_network *ptr = (struct gaia_network *) be;
703 char *network_name;
704 int spatial;
705 int srid;
706 int has_z;
707 int allow_coincident;
708 struct splite_internal_cache *cache =
709 (struct splite_internal_cache *) ptr->cache;
710
711 if (gaiaReadNetworkFromDBMS
712 (ptr->db_handle, name, &network_name, &spatial, &srid, &has_z,
713 &allow_coincident))
714 {
715 ptr->network_name = network_name;
716 ptr->srid = srid;
717 ptr->has_z = has_z;
718 ptr->spatial = spatial;
719 ptr->allow_coincident = allow_coincident;
720 /* registering into the Internal Cache double linked list */
721 if (cache->firstNetwork == NULL)
722 cache->firstNetwork = ptr;
723 if (cache->lastNetwork != NULL)
724 {
725 struct gaia_network *p2 =
726 (struct gaia_network *) (cache->lastNetwork);
727 p2->next = ptr;
728 }
729 cache->lastNetwork = ptr;
730 return (LWN_BE_NETWORK *) ptr;
731 }
732 else
733 return NULL;
734 }
735
736 int
netcallback_freeNetwork(LWN_BE_NETWORK * lwn_net)737 netcallback_freeNetwork (LWN_BE_NETWORK * lwn_net)
738 {
739 /* callback function: freeNetwork - does nothing */
740 if (lwn_net != NULL)
741 lwn_net = NULL; /* silencing stupid compiler warnings on unuse args */
742 return 1;
743 }
744
745 static gaiaGeomCollPtr
do_convert_lwnline_to_geom(LWN_LINE * line,int srid)746 do_convert_lwnline_to_geom (LWN_LINE * line, int srid)
747 {
748 /* converting an LWN_LINE into a Linestring */
749 int iv;
750 double ox;
751 double oy;
752 int normalized_points = 0;
753 gaiaLinestringPtr ln;
754 gaiaGeomCollPtr geom;
755 if (line->has_z)
756 geom = gaiaAllocGeomCollXYZ ();
757 else
758 geom = gaiaAllocGeomColl ();
759 for (iv = 0; iv < line->points; iv++)
760 {
761 /* counting how many duplicate points are there */
762 double x = line->x[iv];
763 double y = line->y[iv];
764 if (iv == 0)
765 normalized_points++;
766 else
767 {
768 if (x == ox && y == oy)
769 ;
770 else
771 normalized_points++;
772 }
773 ox = x;
774 oy = y;
775 }
776 ln = gaiaAddLinestringToGeomColl (geom, normalized_points);
777 normalized_points = 0;
778 for (iv = 0; iv < line->points; iv++)
779 {
780 double x = line->x[iv];
781 double y = line->y[iv];
782 double z;
783 if (iv == 0)
784 ;
785 else
786 {
787 if (x == ox && y == oy)
788 continue; /* discarding duplicate points */
789 }
790 ox = x;
791 oy = y;
792 if (line->has_z)
793 z = line->z[iv];
794 if (line->has_z)
795 {
796 gaiaSetPointXYZ (ln->Coords, normalized_points, x, y, z);
797 }
798 else
799 {
800 gaiaSetPoint (ln->Coords, normalized_points, x, y);
801 }
802 normalized_points++;
803 }
804 geom->DeclaredType = GAIA_LINESTRING;
805 geom->Srid = srid;
806
807 return geom;
808 }
809
810 LWN_NET_NODE *
netcallback_getNetNodeWithinDistance2D(const LWN_BE_NETWORK * lwn_net,const LWN_POINT * pt,double dist,int * numelems,int fields,int limit)811 netcallback_getNetNodeWithinDistance2D (const LWN_BE_NETWORK * lwn_net,
812 const LWN_POINT * pt, double dist,
813 int *numelems, int fields, int limit)
814 {
815 /* callback function: getNodeWithinDistance2D */
816 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
817 struct gaia_network *accessor = (struct gaia_network *) net;
818 sqlite3_stmt *stmt;
819 int ret;
820 int count = 0;
821 sqlite3_stmt *stmt_aux = NULL;
822 char *sql;
823 struct net_nodes_list *list = NULL;
824 LWN_NET_NODE *result = NULL;
825 if (accessor == NULL)
826 {
827 *numelems = -1;
828 return NULL;
829 }
830 if (pt == NULL)
831 {
832 *numelems = 0;
833 return NULL;
834 }
835
836 stmt = accessor->stmt_getNetNodeWithinDistance2D;
837 if (stmt == NULL)
838 {
839 *numelems = -1;
840 return NULL;
841 }
842
843 if (limit >= 0)
844 {
845 /* preparing the auxiliary SQL statement */
846 sql =
847 do_prepare_read_net_node (accessor->network_name, fields,
848 accessor->spatial, accessor->has_z);
849 ret =
850 sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
851 &stmt_aux, NULL);
852 sqlite3_free (sql);
853 if (ret != SQLITE_OK)
854 {
855 char *msg =
856 sqlite3_mprintf
857 ("Prepare_getNetNodeWithinDistance2D AUX error: \"%s\"",
858 sqlite3_errmsg (accessor->db_handle));
859 gaianet_set_last_error_msg (net, msg);
860 sqlite3_free (msg);
861 *numelems = -1;
862 return NULL;
863 }
864 }
865
866 /* setting up the prepared statement */
867 sqlite3_reset (stmt);
868 sqlite3_clear_bindings (stmt);
869 sqlite3_bind_double (stmt, 1, pt->x);
870 sqlite3_bind_double (stmt, 2, pt->y);
871 sqlite3_bind_double (stmt, 3, dist);
872 sqlite3_bind_double (stmt, 4, pt->x);
873 sqlite3_bind_double (stmt, 5, pt->y);
874 sqlite3_bind_double (stmt, 6, dist);
875 list = create_nodes_list ();
876
877 while (1)
878 {
879 /* scrolling the result set rows */
880 ret = sqlite3_step (stmt);
881 if (ret == SQLITE_DONE)
882 break; /* end of result set */
883 if (ret == SQLITE_ROW)
884 {
885 sqlite3_int64 node_id = sqlite3_column_int64 (stmt, 0);
886 if (stmt_aux != NULL)
887 {
888 char *msg;
889 if (!do_read_net_node
890 (stmt_aux, list, node_id, fields, accessor->spatial,
891 accessor->has_z,
892 "netcallback_getNetNodeWithinDistance2D", &msg))
893 {
894 gaianet_set_last_error_msg (net, msg);
895 sqlite3_free (msg);
896 goto error;
897 }
898 }
899 count++;
900 if (limit > 0)
901 {
902 if (count > limit)
903 break;
904 }
905 if (limit < 0)
906 break;
907 }
908 else
909 {
910 char *msg =
911 sqlite3_mprintf ("netcallback_getNodeWithinDistance2D: %s",
912 sqlite3_errmsg (accessor->db_handle));
913 gaianet_set_last_error_msg (net, msg);
914 sqlite3_free (msg);
915 goto error;
916 }
917 }
918
919 if (limit < 0)
920 {
921 result = NULL;
922 *numelems = count;
923 }
924 else
925 {
926 if (list->count <= 0)
927 {
928 result = NULL;
929 *numelems = 0;
930 }
931 else
932 {
933 int i = 0;
934 struct net_node *p_nd;
935 result = malloc (sizeof (LWN_NET_NODE) * list->count);
936 p_nd = list->first;
937 while (p_nd != NULL)
938 {
939 LWN_NET_NODE *nd = result + i;
940 nd->geom = NULL;
941 if (fields & LWN_COL_NODE_NODE_ID)
942 nd->node_id = p_nd->node_id;
943 if (fields & LWN_COL_NODE_GEOM)
944 {
945 if (p_nd->is_null)
946 ;
947 else
948 {
949 if (accessor->has_z)
950 nd->geom =
951 lwn_create_point3d (accessor->srid,
952 p_nd->x, p_nd->y,
953 p_nd->z);
954 else
955 nd->geom =
956 lwn_create_point2d (accessor->srid,
957 p_nd->x, p_nd->y);
958 }
959 }
960 i++;
961 p_nd = p_nd->next;
962 }
963 *numelems = list->count;
964 }
965 }
966
967 if (stmt_aux != NULL)
968 sqlite3_finalize (stmt_aux);
969 destroy_net_nodes_list (list);
970 sqlite3_reset (stmt);
971 return result;
972
973 error:
974 if (stmt_aux != NULL)
975 sqlite3_finalize (stmt_aux);
976 if (list != NULL)
977 destroy_net_nodes_list (list);
978 *numelems = -1;
979 sqlite3_reset (stmt);
980 return NULL;
981 }
982
983 LWN_NET_NODE *
netcallback_getNetNodeById(const LWN_BE_NETWORK * lwn_net,const LWN_ELEMID * ids,int * numelems,int fields)984 netcallback_getNetNodeById (const LWN_BE_NETWORK * lwn_net,
985 const LWN_ELEMID * ids, int *numelems, int fields)
986 {
987 /* callback function: getNetNodeById */
988 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
989 struct gaia_network *accessor = (struct gaia_network *) net;
990 sqlite3_stmt *stmt_aux = NULL;
991 int ret;
992 int i;
993 char *sql;
994 struct net_nodes_list *list = NULL;
995 LWN_NET_NODE *result = NULL;
996 if (accessor == NULL)
997 {
998 *numelems = -1;
999 return NULL;
1000 }
1001
1002 /* preparing the SQL statement */
1003 sql =
1004 do_prepare_read_net_node (accessor->network_name, fields,
1005 accessor->spatial, accessor->has_z);
1006 ret =
1007 sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt_aux,
1008 NULL);
1009 sqlite3_free (sql);
1010 if (ret != SQLITE_OK)
1011 {
1012 char *msg =
1013 sqlite3_mprintf ("Prepare_getNetNodeById AUX error: \"%s\"",
1014 sqlite3_errmsg (accessor->db_handle));
1015 gaianet_set_last_error_msg (net, msg);
1016 sqlite3_free (msg);
1017 *numelems = -1;
1018 return NULL;
1019 }
1020
1021 list = create_nodes_list ();
1022 for (i = 0; i < *numelems; i++)
1023 {
1024 char *msg;
1025 if (!do_read_net_node
1026 (stmt_aux, list, *(ids + i), fields, accessor->spatial,
1027 accessor->has_z, "netcallback_getNetNodeById", &msg))
1028 {
1029 gaianet_set_last_error_msg (net, msg);
1030 sqlite3_free (msg);
1031 goto error;
1032 }
1033 }
1034
1035 if (list->count == 0)
1036 {
1037 /* no node was found */
1038 *numelems = list->count;
1039 }
1040 else
1041 {
1042 struct net_node *p_nd;
1043 result = malloc (sizeof (LWN_NET_NODE) * list->count);
1044 p_nd = list->first;
1045 i = 0;
1046 while (p_nd != NULL)
1047 {
1048 LWN_NET_NODE *nd = result + i;
1049 nd->geom = NULL;
1050 if (fields & LWN_COL_NODE_NODE_ID)
1051 nd->node_id = p_nd->node_id;
1052 if (fields & LWN_COL_NODE_GEOM)
1053 {
1054 if (p_nd->is_null)
1055 ;
1056 else
1057 {
1058 if (accessor->has_z)
1059 nd->geom =
1060 lwn_create_point3d (accessor->srid, p_nd->x,
1061 p_nd->y, p_nd->z);
1062 else
1063 nd->geom =
1064 lwn_create_point2d (accessor->srid, p_nd->x,
1065 p_nd->y);
1066 }
1067 }
1068 i++;
1069 p_nd = p_nd->next;
1070 }
1071 *numelems = list->count;
1072 }
1073 sqlite3_finalize (stmt_aux);
1074 destroy_net_nodes_list (list);
1075 return result;
1076
1077 error:
1078 if (stmt_aux != NULL)
1079 sqlite3_finalize (stmt_aux);
1080 if (list != NULL)
1081 destroy_net_nodes_list (list);
1082 *numelems = -1;
1083 return NULL;
1084 }
1085
1086 LWN_LINK *
netcallback_getLinkWithinDistance2D(const LWN_BE_NETWORK * lwn_net,const LWN_POINT * pt,double dist,int * numelems,int fields,int limit)1087 netcallback_getLinkWithinDistance2D (const LWN_BE_NETWORK * lwn_net,
1088 const LWN_POINT * pt, double dist,
1089 int *numelems, int fields, int limit)
1090 {
1091 /* callback function: getLinkWithinDistance2D */
1092 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
1093 struct gaia_network *accessor = (struct gaia_network *) net;
1094 sqlite3_stmt *stmt;
1095 int ret;
1096 int count = 0;
1097 sqlite3_stmt *stmt_aux = NULL;
1098 char *sql;
1099 struct net_links_list *list = NULL;
1100 LWN_LINK *result = NULL;
1101 if (accessor == NULL)
1102 {
1103 *numelems = -1;
1104 return NULL;
1105 }
1106 if (pt == NULL)
1107 {
1108 *numelems = 0;
1109 return NULL;
1110 }
1111
1112 stmt = accessor->stmt_getLinkWithinDistance2D;
1113 if (stmt == NULL)
1114 {
1115 *numelems = -1;
1116 return NULL;
1117 }
1118
1119 if (limit >= 0)
1120 {
1121 /* preparing the auxiliary SQL statement */
1122 sql = do_prepare_read_link (accessor->network_name, fields);
1123 ret =
1124 sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
1125 &stmt_aux, NULL);
1126 sqlite3_free (sql);
1127 if (ret != SQLITE_OK)
1128 {
1129 char *msg =
1130 sqlite3_mprintf ("Prepare_getLinkById AUX error: \"%s\"",
1131 sqlite3_errmsg (accessor->db_handle));
1132 gaianet_set_last_error_msg (net, msg);
1133 sqlite3_free (msg);
1134 *numelems = -1;
1135 return NULL;
1136 }
1137 }
1138
1139 /* setting up the prepared statement */
1140 sqlite3_reset (stmt);
1141 sqlite3_clear_bindings (stmt);
1142 sqlite3_bind_double (stmt, 1, pt->x);
1143 sqlite3_bind_double (stmt, 2, pt->y);
1144 sqlite3_bind_double (stmt, 3, dist);
1145 sqlite3_bind_double (stmt, 4, pt->x);
1146 sqlite3_bind_double (stmt, 5, pt->y);
1147 sqlite3_bind_double (stmt, 6, dist);
1148 list = create_links_list ();
1149
1150 while (1)
1151 {
1152 /* scrolling the result set rows */
1153 ret = sqlite3_step (stmt);
1154 if (ret == SQLITE_DONE)
1155 break; /* end of result set */
1156 if (ret == SQLITE_ROW)
1157 {
1158 sqlite3_int64 link_id = sqlite3_column_int64 (stmt, 0);
1159 if (stmt_aux != NULL)
1160 {
1161 char *msg;
1162 if (!do_read_link
1163 (stmt_aux, list, link_id, fields,
1164 "netcallback_getLinkWithinDistance2D", &msg))
1165 {
1166 gaianet_set_last_error_msg (net, msg);
1167 sqlite3_free (msg);
1168 goto error;
1169 }
1170 }
1171 count++;
1172 if (limit > 0)
1173 {
1174 if (count > limit)
1175 break;
1176 }
1177 if (limit < 0)
1178 break;
1179 }
1180 else
1181 {
1182 char *msg =
1183 sqlite3_mprintf ("netcallback_getLinkWithinDistance2D: %s",
1184 sqlite3_errmsg (accessor->db_handle));
1185 gaianet_set_last_error_msg (net, msg);
1186 sqlite3_free (msg);
1187 goto error;
1188 }
1189 }
1190
1191 if (limit < 0)
1192 {
1193 result = NULL;
1194 *numelems = count;
1195 }
1196 else
1197 {
1198 if (list->count <= 0)
1199 {
1200 result = NULL;
1201 *numelems = 0;
1202 }
1203 else
1204 {
1205 int i = 0;
1206 struct net_link *p_lnk;
1207 result = malloc (sizeof (LWN_LINK) * list->count);
1208 p_lnk = list->first;
1209 while (p_lnk != NULL)
1210 {
1211 LWN_LINK *lnk = result + i;
1212 if (fields & LWN_COL_LINK_LINK_ID)
1213 lnk->link_id = p_lnk->link_id;
1214 if (fields & LWN_COL_LINK_START_NODE)
1215 lnk->start_node = p_lnk->start_node;
1216 if (fields & LWN_COL_LINK_END_NODE)
1217 lnk->end_node = p_lnk->end_node;
1218 if (fields & LWN_COL_LINK_GEOM)
1219 lnk->geom =
1220 gaianet_convert_linestring_to_lwnline
1221 (p_lnk->geom, accessor->srid, accessor->has_z);
1222 else
1223 lnk->geom = NULL;
1224 i++;
1225 p_lnk = p_lnk->next;
1226 }
1227 *numelems = list->count;
1228 }
1229 }
1230 if (stmt_aux != NULL)
1231 sqlite3_finalize (stmt_aux);
1232 destroy_links_list (list);
1233 sqlite3_reset (stmt);
1234 return result;
1235
1236 error:
1237 if (stmt_aux != NULL)
1238 sqlite3_finalize (stmt_aux);
1239 if (list != NULL)
1240 destroy_links_list (list);
1241 *numelems = -1;
1242 sqlite3_reset (stmt);
1243 return NULL;
1244 }
1245
1246 int
netcallback_insertNetNodes(const LWN_BE_NETWORK * lwn_net,LWN_NET_NODE * nodes,int numelems)1247 netcallback_insertNetNodes (const LWN_BE_NETWORK * lwn_net,
1248 LWN_NET_NODE * nodes, int numelems)
1249 {
1250 /* callback function: insertNetNodes */
1251 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
1252 struct gaia_network *accessor = (struct gaia_network *) net;
1253 sqlite3_stmt *stmt;
1254 int ret;
1255 int i;
1256 unsigned char *p_blob;
1257 int n_bytes;
1258 gaiaGeomCollPtr geom = NULL;
1259 int gpkg_mode = 0;
1260 int tiny_point = 0;
1261 if (accessor == NULL)
1262 return 0;
1263
1264 stmt = accessor->stmt_insertNetNodes;
1265 if (stmt == NULL)
1266 return 0;
1267
1268 if (accessor->cache != NULL)
1269 {
1270 struct splite_internal_cache *cache =
1271 (struct splite_internal_cache *) (accessor->cache);
1272 gpkg_mode = cache->gpkg_mode;
1273 tiny_point = cache->tinyPointEnabled;
1274 }
1275
1276 for (i = 0; i < numelems; i++)
1277 {
1278 LWN_NET_NODE *nd = nodes + i;
1279 /* setting up the prepared statement */
1280 sqlite3_reset (stmt);
1281 sqlite3_clear_bindings (stmt);
1282 if (nd->node_id <= 0)
1283 sqlite3_bind_null (stmt, 1);
1284 else
1285 sqlite3_bind_int64 (stmt, 1, nd->node_id);
1286 if (nd->geom == NULL)
1287 sqlite3_bind_null (stmt, 2);
1288 else
1289 {
1290 if (accessor->has_z)
1291 geom = gaiaAllocGeomCollXYZ ();
1292 else
1293 geom = gaiaAllocGeomColl ();
1294 if (accessor->has_z)
1295 gaiaAddPointToGeomCollXYZ (geom, nd->geom->x, nd->geom->y,
1296 nd->geom->z);
1297 else
1298 gaiaAddPointToGeomColl (geom, nd->geom->x, nd->geom->y);
1299 geom->Srid = accessor->srid;
1300 geom->DeclaredType = GAIA_POINT;
1301 gaiaToSpatiaLiteBlobWkbEx2 (geom, &p_blob, &n_bytes, gpkg_mode,
1302 tiny_point);
1303 gaiaFreeGeomColl (geom);
1304 sqlite3_bind_blob (stmt, 2, p_blob, n_bytes, free);
1305 }
1306 ret = sqlite3_step (stmt);
1307 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
1308 {
1309 /* retrieving the PK value */
1310 nd->node_id = sqlite3_last_insert_rowid (accessor->db_handle);
1311 }
1312 else
1313 {
1314 char *msg =
1315 sqlite3_mprintf ("netcallback_insertNetNodes: \"%s\"",
1316 sqlite3_errmsg (accessor->db_handle));
1317 gaianet_set_last_error_msg (net, msg);
1318 sqlite3_free (msg);
1319 goto error;
1320 }
1321 }
1322 sqlite3_reset (stmt);
1323 return 1;
1324
1325 error:
1326 sqlite3_reset (stmt);
1327 return 0;
1328 }
1329
1330 int
netcallback_updateNetNodesById(const LWN_BE_NETWORK * lwn_net,const LWN_NET_NODE * nodes,int numnodes,int upd_fields)1331 netcallback_updateNetNodesById (const LWN_BE_NETWORK * lwn_net,
1332 const LWN_NET_NODE * nodes, int numnodes,
1333 int upd_fields)
1334 {
1335 /* callback function: updateNetNodesById */
1336 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
1337 struct gaia_network *accessor = (struct gaia_network *) net;
1338 sqlite3_stmt *stmt = NULL;
1339 int ret;
1340 char *sql;
1341 char *prev;
1342 int comma = 0;
1343 char *table;
1344 char *xtable;
1345 int icol = 1;
1346 int i;
1347 int changed = 0;
1348 if (accessor == NULL)
1349 return -1;
1350
1351 /* composing the SQL prepared statement */
1352 table = sqlite3_mprintf ("%s_node", accessor->network_name);
1353 xtable = gaiaDoubleQuotedSql (table);
1354 sqlite3_free (table);
1355 sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET", xtable);
1356 free (xtable);
1357 prev = sql;
1358 if (upd_fields & LWN_COL_NODE_NODE_ID)
1359 {
1360 if (comma)
1361 sql = sqlite3_mprintf ("%s, node_id = ?", prev);
1362 else
1363 sql = sqlite3_mprintf ("%s node_id = ?", prev);
1364 comma = 1;
1365 sqlite3_free (prev);
1366 prev = sql;
1367 }
1368 if (upd_fields & LWN_COL_NODE_GEOM)
1369 {
1370 if (accessor->has_z)
1371 {
1372 if (comma)
1373 sql =
1374 sqlite3_mprintf
1375 ("%s, geometry = MakePointZ(?, ?. ?, %d)", prev,
1376 accessor->srid);
1377 else
1378 sql =
1379 sqlite3_mprintf
1380 ("%s geometry = MakePointZ(?, ?, ?, %d)", prev,
1381 accessor->srid);
1382 }
1383 else
1384 {
1385 if (comma)
1386 sql =
1387 sqlite3_mprintf ("%s, geometry = MakePoint(?, ?, %d)",
1388 prev, accessor->srid);
1389 else
1390 sql =
1391 sqlite3_mprintf ("%s geometry = MakePoint(?, ?, %d)",
1392 prev, accessor->srid);
1393 }
1394 comma = 1;
1395 sqlite3_free (prev);
1396 prev = sql;
1397 }
1398 sql = sqlite3_mprintf ("%s WHERE node_id = ?", prev);
1399 sqlite3_free (prev);
1400 ret =
1401 sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt,
1402 NULL);
1403 sqlite3_free (sql);
1404 if (ret != SQLITE_OK)
1405 {
1406 char *msg =
1407 sqlite3_mprintf ("Prepare_updateNetNodesById error: \"%s\"",
1408 sqlite3_errmsg (accessor->db_handle));
1409 gaianet_set_last_error_msg (net, msg);
1410 sqlite3_free (msg);
1411 return -1;
1412 }
1413
1414 for (i = 0; i < numnodes; i++)
1415 {
1416 /* parameter binding */
1417 const LWN_NET_NODE *nd = nodes + i;
1418 icol = 1;
1419 sqlite3_reset (stmt);
1420 sqlite3_clear_bindings (stmt);
1421 if (upd_fields & LWN_COL_NODE_NODE_ID)
1422 {
1423 sqlite3_bind_int64 (stmt, icol, nd->node_id);
1424 icol++;
1425 }
1426 if (upd_fields & LWN_COL_NODE_GEOM)
1427 {
1428 if (accessor->spatial)
1429 {
1430 sqlite3_bind_double (stmt, icol, nd->geom->x);
1431 icol++;
1432 sqlite3_bind_double (stmt, icol, nd->geom->y);
1433 icol++;
1434 if (accessor->has_z)
1435 {
1436 sqlite3_bind_double (stmt, icol, nd->geom->z);
1437 icol++;
1438 }
1439 }
1440 else
1441 {
1442 icol += 2;
1443 if (accessor->has_z)
1444 icol++;
1445 }
1446 }
1447 sqlite3_bind_int64 (stmt, icol, nd->node_id);
1448 ret = sqlite3_step (stmt);
1449 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
1450 changed += sqlite3_changes (accessor->db_handle);
1451 else
1452 {
1453 char *msg =
1454 sqlite3_mprintf ("netcallback_updateNetNodesById: \"%s\"",
1455 sqlite3_errmsg (accessor->db_handle));
1456 gaianet_set_last_error_msg (net, msg);
1457 sqlite3_free (msg);
1458 goto error;
1459 }
1460 }
1461 sqlite3_finalize (stmt);
1462 return changed;
1463
1464 error:
1465 sqlite3_finalize (stmt);
1466 return -1;
1467 }
1468
1469 int
netcallback_insertLinks(const LWN_BE_NETWORK * lwn_net,LWN_LINK * links,int numelems)1470 netcallback_insertLinks (const LWN_BE_NETWORK * lwn_net, LWN_LINK * links,
1471 int numelems)
1472 {
1473 /* callback function: insertLinks */
1474 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
1475 struct gaia_network *accessor = (struct gaia_network *) net;
1476 sqlite3_stmt *stmt;
1477 int ret;
1478 int i;
1479 gaiaGeomCollPtr geom;
1480 unsigned char *p_blob;
1481 int n_bytes;
1482 int gpkg_mode = 0;
1483 int tiny_point = 0;
1484 if (accessor == NULL)
1485 return 0;
1486
1487 stmt = accessor->stmt_insertLinks;
1488 if (stmt == NULL)
1489 return 0;
1490
1491 if (accessor->cache != NULL)
1492 {
1493 struct splite_internal_cache *cache =
1494 (struct splite_internal_cache *) (accessor->cache);
1495 gpkg_mode = cache->gpkg_mode;
1496 tiny_point = cache->tinyPointEnabled;
1497 }
1498
1499 for (i = 0; i < numelems; i++)
1500 {
1501 LWN_LINK *lnk = links + i;
1502 /* setting up the prepared statement */
1503 sqlite3_reset (stmt);
1504 sqlite3_clear_bindings (stmt);
1505 if (lnk->link_id <= 0)
1506 sqlite3_bind_null (stmt, 1);
1507 else
1508 sqlite3_bind_int64 (stmt, 1, lnk->link_id);
1509 sqlite3_bind_int64 (stmt, 2, lnk->start_node);
1510 sqlite3_bind_int64 (stmt, 3, lnk->end_node);
1511 if (lnk->geom == NULL)
1512 sqlite3_bind_null (stmt, 4);
1513 else
1514 {
1515 /* transforming the LWN_LINE into a Geometry-Linestring */
1516 geom = do_convert_lwnline_to_geom (lnk->geom, accessor->srid);
1517 gaiaToSpatiaLiteBlobWkbEx2 (geom, &p_blob, &n_bytes, gpkg_mode,
1518 tiny_point);
1519 gaiaFreeGeomColl (geom);
1520 sqlite3_bind_blob (stmt, 4, p_blob, n_bytes, free);
1521 }
1522 ret = sqlite3_step (stmt);
1523 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
1524 {
1525 /* retrieving the PK value */
1526 lnk->link_id = sqlite3_last_insert_rowid (accessor->db_handle);
1527 }
1528 else
1529 {
1530 char *msg = sqlite3_mprintf ("netcallback_inserLinks: \"%s\"",
1531 sqlite3_errmsg
1532 (accessor->db_handle));
1533 gaianet_set_last_error_msg (net, msg);
1534 sqlite3_free (msg);
1535 goto error;
1536 }
1537 }
1538 sqlite3_reset (stmt);
1539 return 1;
1540
1541 error:
1542 sqlite3_reset (stmt);
1543 return 0;
1544 }
1545
1546 LWN_LINK *
netcallback_getLinkByNetNode(const LWN_BE_NETWORK * lwn_net,const LWN_ELEMID * ids,int * numelems,int fields)1547 netcallback_getLinkByNetNode (const LWN_BE_NETWORK * lwn_net,
1548 const LWN_ELEMID * ids, int *numelems, int fields)
1549 {
1550 /* callback function: getLinkByNetNode */
1551 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
1552 struct gaia_network *accessor = (struct gaia_network *) net;
1553 int ret;
1554 char *sql;
1555 char *prev;
1556 char *table;
1557 char *xtable;
1558 int comma = 0;
1559 int i;
1560 sqlite3_stmt *stmt_aux = NULL;
1561 struct net_links_list *list = NULL;
1562 LWN_LINK *result = NULL;
1563 if (accessor == NULL)
1564 {
1565 *numelems = -1;
1566 return NULL;
1567 }
1568
1569 /* preparing the SQL statement */
1570 sql = sqlite3_mprintf ("SELECT ");
1571 prev = sql;
1572 if (fields & LWN_COL_LINK_LINK_ID)
1573 {
1574 if (comma)
1575 sql = sqlite3_mprintf ("%s, link_id", prev);
1576 else
1577 sql = sqlite3_mprintf ("%s link_id", prev);
1578 comma = 1;
1579 sqlite3_free (prev);
1580 prev = sql;
1581 }
1582 if (fields & LWN_COL_LINK_START_NODE)
1583 {
1584 if (comma)
1585 sql = sqlite3_mprintf ("%s, start_node", prev);
1586 else
1587 sql = sqlite3_mprintf ("%s start_node", prev);
1588 comma = 1;
1589 sqlite3_free (prev);
1590 prev = sql;
1591 }
1592 if (fields & LWN_COL_LINK_END_NODE)
1593 {
1594 if (comma)
1595 sql = sqlite3_mprintf ("%s, end_node", prev);
1596 else
1597 sql = sqlite3_mprintf ("%s end_node", prev);
1598 comma = 1;
1599 sqlite3_free (prev);
1600 prev = sql;
1601 }
1602 if (fields & LWN_COL_LINK_GEOM)
1603 {
1604 if (comma)
1605 sql = sqlite3_mprintf ("%s, geometry", prev);
1606 else
1607 sql = sqlite3_mprintf ("%s geometry", prev);
1608 comma = 1;
1609 sqlite3_free (prev);
1610 prev = sql;
1611 }
1612 table = sqlite3_mprintf ("%s_link", accessor->network_name);
1613 xtable = gaiaDoubleQuotedSql (table);
1614 sqlite3_free (table);
1615 sql =
1616 sqlite3_mprintf
1617 ("%s FROM MAIN.\"%s\" WHERE start_node = ? OR end_node = ?", prev,
1618 xtable);
1619 free (xtable);
1620 sqlite3_free (prev);
1621 ret =
1622 sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
1623 &stmt_aux, NULL);
1624 sqlite3_free (sql);
1625 if (ret != SQLITE_OK)
1626 {
1627 char *msg =
1628 sqlite3_mprintf ("Prepare_getLinkByNetNode AUX error: \"%s\"",
1629 sqlite3_errmsg (accessor->db_handle));
1630 gaianet_set_last_error_msg (net, msg);
1631 sqlite3_free (msg);
1632 *numelems = -1;
1633 return NULL;
1634 }
1635
1636 list = create_links_list ();
1637 for (i = 0; i < *numelems; i++)
1638 {
1639 char *msg;
1640 if (!do_read_link_by_net_node
1641 (stmt_aux, list, *(ids + i), fields,
1642 "netcallback_getLinkByNetNode", &msg))
1643 {
1644 gaianet_set_last_error_msg (net, msg);
1645 sqlite3_free (msg);
1646 goto error;
1647 }
1648 }
1649
1650 if (list->count == 0)
1651 {
1652 /* no link was found */
1653 *numelems = list->count;
1654 }
1655 else
1656 {
1657 struct net_link *p_lnk;
1658 result = malloc (sizeof (LWN_LINK) * list->count);
1659 p_lnk = list->first;
1660 i = 0;
1661 while (p_lnk != NULL)
1662 {
1663 LWN_LINK *lnk = result + i;
1664 lnk->geom = NULL;
1665 if (fields & LWN_COL_LINK_LINK_ID)
1666 lnk->link_id = p_lnk->link_id;
1667 if (fields & LWN_COL_LINK_START_NODE)
1668 lnk->start_node = p_lnk->start_node;
1669 if (fields & LWN_COL_LINK_END_NODE)
1670 lnk->end_node = p_lnk->end_node;
1671 if (fields & LWN_COL_LINK_GEOM)
1672 lnk->geom =
1673 gaianet_convert_linestring_to_lwnline (p_lnk->geom,
1674 accessor->srid,
1675 accessor->has_z);
1676 i++;
1677 p_lnk = p_lnk->next;
1678 }
1679 *numelems = list->count;
1680 }
1681 sqlite3_finalize (stmt_aux);
1682 destroy_links_list (list);
1683 return result;
1684
1685 error:
1686 if (stmt_aux != NULL)
1687 sqlite3_finalize (stmt_aux);
1688 if (list != NULL)
1689 destroy_links_list (list);
1690 *numelems = -1;
1691 return NULL;
1692 }
1693
1694 int
netcallback_deleteNetNodesById(const LWN_BE_NETWORK * lwn_net,const LWN_ELEMID * ids,int numelems)1695 netcallback_deleteNetNodesById (const LWN_BE_NETWORK * lwn_net,
1696 const LWN_ELEMID * ids, int numelems)
1697 {
1698 /* callback function: deleteNetNodesById */
1699 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
1700 struct gaia_network *accessor = (struct gaia_network *) net;
1701 sqlite3_stmt *stmt = NULL;
1702 int ret;
1703 int i;
1704 int changed = 0;
1705 if (accessor == NULL)
1706 return -1;
1707
1708 stmt = accessor->stmt_deleteNetNodesById;
1709 if (stmt == NULL)
1710 return -1;
1711
1712 for (i = 0; i < numelems; i++)
1713 {
1714 /* parameter binding */
1715 sqlite3_int64 id = *(ids + i);
1716 sqlite3_reset (stmt);
1717 sqlite3_clear_bindings (stmt);
1718 sqlite3_bind_int64 (stmt, 1, id);
1719 ret = sqlite3_step (stmt);
1720 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
1721 {
1722 changed += sqlite3_changes (accessor->db_handle);
1723 }
1724 else
1725 {
1726 char *msg =
1727 sqlite3_mprintf ("netcallback_deleteNetNodesById: \"%s\"",
1728 sqlite3_errmsg (accessor->db_handle));
1729 gaianet_set_last_error_msg (net, msg);
1730 sqlite3_free (msg);
1731 goto error;
1732 }
1733 }
1734 sqlite3_reset (stmt);
1735 return changed;
1736
1737 error:
1738 sqlite3_reset (stmt);
1739 return -1;
1740 }
1741
1742 LWN_NET_NODE *
netcallback_getNetNodeWithinBox2D(const LWN_BE_NETWORK * lwn_net,const LWN_BBOX * box,int * numelems,int fields,int limit)1743 netcallback_getNetNodeWithinBox2D (const LWN_BE_NETWORK * lwn_net,
1744 const LWN_BBOX * box, int *numelems,
1745 int fields, int limit)
1746 {
1747 /* callback function: getNetNodeWithinBox2D */
1748 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
1749 struct gaia_network *accessor = (struct gaia_network *) net;
1750 sqlite3_stmt *stmt;
1751 int ret;
1752 int count = 0;
1753 sqlite3_stmt *stmt_aux = NULL;
1754 char *sql;
1755 struct net_nodes_list *list = NULL;
1756 LWN_NET_NODE *result = NULL;
1757 if (accessor == NULL)
1758 {
1759 *numelems = -1;
1760 return NULL;
1761 }
1762
1763 stmt = accessor->stmt_getNetNodeWithinBox2D;
1764 if (stmt == NULL)
1765 {
1766 *numelems = -1;
1767 return NULL;
1768 }
1769
1770 if (limit >= 0)
1771 {
1772 /* preparing the auxiliary SQL statement */
1773 sql =
1774 do_prepare_read_net_node (accessor->network_name, fields,
1775 accessor->spatial, accessor->has_z);
1776 ret =
1777 sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql),
1778 &stmt_aux, NULL);
1779 sqlite3_free (sql);
1780 if (ret != SQLITE_OK)
1781 {
1782 char *msg =
1783 sqlite3_mprintf
1784 ("Prepare_getNetNodeWithinBox2D AUX error: \"%s\"",
1785 sqlite3_errmsg (accessor->db_handle));
1786 gaianet_set_last_error_msg (net, msg);
1787 sqlite3_free (msg);
1788 *numelems = -1;
1789 return NULL;
1790 }
1791 }
1792
1793 /* setting up the prepared statement */
1794 sqlite3_reset (stmt);
1795 sqlite3_clear_bindings (stmt);
1796 sqlite3_bind_double (stmt, 1, box->min_x);
1797 sqlite3_bind_double (stmt, 2, box->min_y);
1798 sqlite3_bind_double (stmt, 3, box->max_x);
1799 sqlite3_bind_double (stmt, 4, box->max_y);
1800 list = create_nodes_list ();
1801
1802 while (1)
1803 {
1804 /* scrolling the result set rows */
1805 ret = sqlite3_step (stmt);
1806 if (ret == SQLITE_DONE)
1807 break; /* end of result set */
1808 if (ret == SQLITE_ROW)
1809 {
1810 sqlite3_int64 node_id = sqlite3_column_int64 (stmt, 0);
1811 if (stmt_aux != NULL)
1812 {
1813 char *msg;
1814 if (!do_read_net_node
1815 (stmt_aux, list, node_id, fields, accessor->spatial,
1816 accessor->has_z, "netcallback_getNetNodeWithinBox2D",
1817 &msg))
1818 {
1819 gaianet_set_last_error_msg (net, msg);
1820 sqlite3_free (msg);
1821 goto error;
1822 }
1823 }
1824 count++;
1825 if (limit > 0)
1826 {
1827 if (count > limit)
1828 break;
1829 }
1830 if (limit < 0)
1831 break;
1832 }
1833 else
1834 {
1835 char *msg =
1836 sqlite3_mprintf ("netcallback_getNetNodeWithinBox2D: %s",
1837 sqlite3_errmsg (accessor->db_handle));
1838 gaianet_set_last_error_msg (net, msg);
1839 sqlite3_free (msg);
1840 goto error;
1841 }
1842 }
1843
1844 if (limit < 0)
1845 {
1846 result = NULL;
1847 *numelems = count;
1848 }
1849 else
1850 {
1851 if (list->count <= 0)
1852 {
1853 result = NULL;
1854 *numelems = 0;
1855 }
1856 else
1857 {
1858 int i = 0;
1859 struct net_node *p_nd;
1860 result = malloc (sizeof (LWN_NET_NODE) * list->count);
1861 p_nd = list->first;
1862 while (p_nd != NULL)
1863 {
1864 LWN_NET_NODE *nd = result + i;
1865 nd->geom = NULL;
1866 if (fields & LWN_COL_NODE_NODE_ID)
1867 nd->node_id = p_nd->node_id;
1868 if (fields & LWN_COL_NODE_GEOM)
1869 {
1870 if (p_nd->is_null)
1871 ;
1872 else
1873 {
1874 if (accessor->has_z)
1875 nd->geom =
1876 lwn_create_point3d (accessor->srid,
1877 p_nd->x, p_nd->y,
1878 p_nd->z);
1879 else
1880 nd->geom =
1881 lwn_create_point2d (accessor->srid,
1882 p_nd->x, p_nd->y);
1883 }
1884 }
1885 i++;
1886 p_nd = p_nd->next;
1887 }
1888 *numelems = list->count;
1889 }
1890 }
1891
1892 if (stmt_aux != NULL)
1893 sqlite3_finalize (stmt_aux);
1894 destroy_net_nodes_list (list);
1895 sqlite3_reset (stmt);
1896 return result;
1897
1898 error:
1899 if (stmt_aux != NULL)
1900 sqlite3_finalize (stmt_aux);
1901 if (list != NULL)
1902 destroy_net_nodes_list (list);
1903 *numelems = 1;
1904 sqlite3_reset (stmt);
1905 return NULL;
1906 }
1907
1908 LWN_ELEMID
netcallback_getNextLinkId(const LWN_BE_NETWORK * lwn_net)1909 netcallback_getNextLinkId (const LWN_BE_NETWORK * lwn_net)
1910 {
1911 /* callback function: getNextLinkId */
1912 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
1913 struct gaia_network *accessor = (struct gaia_network *) net;
1914 sqlite3_stmt *stmt_in;
1915 sqlite3_stmt *stmt_out;
1916 int ret;
1917 sqlite3_int64 link_id = -1;
1918 if (accessor == NULL)
1919 return -1;
1920
1921 stmt_in = accessor->stmt_getNextLinkId;
1922 if (stmt_in == NULL)
1923 return -1;
1924 stmt_out = accessor->stmt_setNextLinkId;
1925 if (stmt_out == NULL)
1926 return -1;
1927
1928 /* setting up the prepared statement */
1929 sqlite3_reset (stmt_in);
1930 sqlite3_clear_bindings (stmt_in);
1931
1932 while (1)
1933 {
1934 /* scrolling the result set rows */
1935 ret = sqlite3_step (stmt_in);
1936 if (ret == SQLITE_DONE)
1937 break; /* end of result set */
1938 if (ret == SQLITE_ROW)
1939 link_id = sqlite3_column_int64 (stmt_in, 0);
1940 else
1941 {
1942 char *msg = sqlite3_mprintf ("netcallback_getNextLinkId: %s",
1943 sqlite3_errmsg
1944 (accessor->db_handle));
1945 gaianet_set_last_error_msg (net, msg);
1946 sqlite3_free (msg);
1947 goto stop;
1948 }
1949 }
1950
1951 /* updating next_link_id */
1952 sqlite3_reset (stmt_out);
1953 sqlite3_clear_bindings (stmt_out);
1954 ret = sqlite3_step (stmt_out);
1955 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
1956 {
1957 sqlite3_reset (stmt_in);
1958 sqlite3_reset (stmt_out);
1959 return link_id;
1960 }
1961 else
1962 {
1963 char *msg = sqlite3_mprintf ("netcallback_setNextLinkId: \"%s\"",
1964 sqlite3_errmsg (accessor->db_handle));
1965 gaianet_set_last_error_msg (net, msg);
1966 sqlite3_free (msg);
1967 link_id = -1;
1968 }
1969 stop:
1970 sqlite3_reset (stmt_in);
1971 sqlite3_reset (stmt_out);
1972 if (link_id >= 0)
1973 link_id++;
1974 return link_id;
1975 }
1976
1977 int
netcallback_updateLinksById(const LWN_BE_NETWORK * lwn_net,const LWN_LINK * links,int numlinks,int upd_fields)1978 netcallback_updateLinksById (const LWN_BE_NETWORK * lwn_net,
1979 const LWN_LINK * links, int numlinks,
1980 int upd_fields)
1981 {
1982 /* callback function: updateLinksById */
1983 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
1984 struct gaia_network *accessor = (struct gaia_network *) net;
1985 sqlite3_stmt *stmt = NULL;
1986 gaiaGeomCollPtr geom;
1987 int ret;
1988 char *sql;
1989 char *prev;
1990 int comma = 0;
1991 char *table;
1992 char *xtable;
1993 int i;
1994 int changed = 0;
1995 unsigned char *p_blob;
1996 int n_bytes;
1997 int gpkg_mode = 0;
1998 int tiny_point = 0;
1999 if (accessor == NULL)
2000 return -1;
2001
2002 if (accessor->cache != NULL)
2003 {
2004 struct splite_internal_cache *cache =
2005 (struct splite_internal_cache *) (accessor->cache);
2006 gpkg_mode = cache->gpkg_mode;
2007 tiny_point = cache->tinyPointEnabled;
2008 }
2009
2010 /* composing the SQL prepared statement */
2011 table = sqlite3_mprintf ("%s_link", accessor->network_name);
2012 xtable = gaiaDoubleQuotedSql (table);
2013 sqlite3_free (table);
2014 sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET", xtable);
2015 free (xtable);
2016 prev = sql;
2017 if (upd_fields & LWN_COL_LINK_LINK_ID)
2018 {
2019 if (comma)
2020 sql = sqlite3_mprintf ("%s, link_id = ?", prev);
2021 else
2022 sql = sqlite3_mprintf ("%s link_id = ?", prev);
2023 comma = 1;
2024 sqlite3_free (prev);
2025 prev = sql;
2026 }
2027 if (upd_fields & LWN_COL_LINK_START_NODE)
2028 {
2029 if (comma)
2030 sql = sqlite3_mprintf ("%s, start_node = ?", prev);
2031 else
2032 sql = sqlite3_mprintf ("%s start_node = ?", prev);
2033 comma = 1;
2034 sqlite3_free (prev);
2035 prev = sql;
2036 }
2037 if (upd_fields & LWN_COL_LINK_END_NODE)
2038 {
2039 if (comma)
2040 sql = sqlite3_mprintf ("%s, end_node = ?", prev);
2041 else
2042 sql = sqlite3_mprintf ("%s end_node = ?", prev);
2043 comma = 1;
2044 sqlite3_free (prev);
2045 prev = sql;
2046 }
2047 if (upd_fields & LWN_COL_LINK_GEOM)
2048 {
2049 if (comma)
2050 sql = sqlite3_mprintf ("%s, geometry = ?", prev);
2051 else
2052 sql = sqlite3_mprintf ("%s geometry = ?", prev);
2053 comma = 1;
2054 sqlite3_free (prev);
2055 prev = sql;
2056 }
2057 sql = sqlite3_mprintf ("%s WHERE link_id = ?", prev);
2058 sqlite3_free (prev);
2059 ret =
2060 sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt,
2061 NULL);
2062 sqlite3_free (sql);
2063 if (ret != SQLITE_OK)
2064 {
2065 char *msg = sqlite3_mprintf ("Prepare_updateLinksById error: \"%s\"",
2066 sqlite3_errmsg (accessor->db_handle));
2067 gaianet_set_last_error_msg (net, msg);
2068 sqlite3_free (msg);
2069 return -1;
2070 }
2071
2072 for (i = 0; i < numlinks; i++)
2073 {
2074 /* parameter binding */
2075 int icol = 1;
2076 const LWN_LINK *upd_link = links + i;
2077 sqlite3_reset (stmt);
2078 sqlite3_clear_bindings (stmt);
2079 if (upd_fields & LWN_COL_LINK_LINK_ID)
2080 {
2081 sqlite3_bind_int64 (stmt, icol, upd_link->link_id);
2082 icol++;
2083 }
2084 if (upd_fields & LWN_COL_LINK_START_NODE)
2085 {
2086 sqlite3_bind_int64 (stmt, icol, upd_link->start_node);
2087 icol++;
2088 }
2089 if (upd_fields & LWN_COL_LINK_END_NODE)
2090 {
2091 sqlite3_bind_int64 (stmt, icol, upd_link->end_node);
2092 icol++;
2093 }
2094 if (upd_fields & LWN_COL_LINK_GEOM)
2095 {
2096 if (upd_link->geom == NULL)
2097 sqlite3_bind_null (stmt, icol);
2098 else
2099 {
2100 /* transforming the LWN_LINE into a Geometry-Linestring */
2101 geom =
2102 do_convert_lwnline_to_geom (upd_link->geom,
2103 accessor->srid);
2104 gaiaToSpatiaLiteBlobWkbEx2 (geom, &p_blob, &n_bytes,
2105 gpkg_mode, tiny_point);
2106 gaiaFreeGeomColl (geom);
2107 sqlite3_bind_blob (stmt, icol, p_blob, n_bytes, free);
2108 }
2109 icol++;
2110 }
2111 sqlite3_bind_int64 (stmt, icol, upd_link->link_id);
2112 ret = sqlite3_step (stmt);
2113 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
2114 changed += sqlite3_changes (accessor->db_handle);
2115 else
2116 {
2117 char *msg =
2118 sqlite3_mprintf ("netcallback_updateLinksById: \"%s\"",
2119 sqlite3_errmsg (accessor->db_handle));
2120 gaianet_set_last_error_msg (net, msg);
2121 sqlite3_free (msg);
2122 goto error;
2123 }
2124 }
2125 sqlite3_finalize (stmt);
2126 return changed;
2127
2128 error:
2129 sqlite3_finalize (stmt);
2130 return -1;
2131 }
2132
2133 LWN_LINK *
netcallback_getLinkById(const LWN_BE_NETWORK * lwn_net,const LWN_ELEMID * ids,int * numelems,int fields)2134 netcallback_getLinkById (const LWN_BE_NETWORK * lwn_net,
2135 const LWN_ELEMID * ids, int *numelems, int fields)
2136 {
2137 /* callback function: getLinkById */
2138 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
2139 struct gaia_network *accessor = (struct gaia_network *) net;
2140 sqlite3_stmt *stmt_aux = NULL;
2141 int ret;
2142 int i;
2143 char *sql;
2144 struct net_links_list *list = NULL;
2145 LWN_LINK *result = NULL;
2146 if (accessor == NULL)
2147 {
2148 *numelems = -1;
2149 return NULL;
2150 }
2151
2152 /* preparing the SQL statement */
2153 sql = do_prepare_read_link (accessor->network_name, fields);
2154 ret =
2155 sqlite3_prepare_v2 (accessor->db_handle, sql, strlen (sql), &stmt_aux,
2156 NULL);
2157 sqlite3_free (sql);
2158 if (ret != SQLITE_OK)
2159 {
2160 char *msg = sqlite3_mprintf ("Prepare_getLinkById AUX error: \"%s\"",
2161 sqlite3_errmsg (accessor->db_handle));
2162 gaianet_set_last_error_msg (net, msg);
2163 sqlite3_free (msg);
2164 *numelems = -1;
2165 return NULL;
2166 }
2167
2168 list = create_links_list ();
2169 for (i = 0; i < *numelems; i++)
2170 {
2171 char *msg;
2172 if (!do_read_link
2173 (stmt_aux, list, *(ids + i), fields, "netcallback_getLinkById",
2174 &msg))
2175 {
2176 gaianet_set_last_error_msg (net, msg);
2177 sqlite3_free (msg);
2178 goto error;
2179 }
2180 }
2181
2182 if (list->count == 0)
2183 {
2184 /* no link was found */
2185 *numelems = list->count;
2186 }
2187 else
2188 {
2189 struct net_link *p_lnk;
2190 result = malloc (sizeof (LWN_LINK) * list->count);
2191 p_lnk = list->first;
2192 i = 0;
2193 while (p_lnk != NULL)
2194 {
2195 LWN_LINK *lnk = result + i;
2196 lnk->geom = NULL;
2197 if (fields & LWN_COL_LINK_LINK_ID)
2198 lnk->link_id = p_lnk->link_id;
2199 if (fields & LWN_COL_LINK_START_NODE)
2200 lnk->start_node = p_lnk->start_node;
2201 if (fields & LWN_COL_LINK_END_NODE)
2202 lnk->end_node = p_lnk->end_node;
2203 if (fields & LWN_COL_LINK_GEOM)
2204 {
2205 if (p_lnk->geom == NULL)
2206 lnk->geom = NULL;
2207 else
2208 lnk->geom =
2209 gaianet_convert_linestring_to_lwnline
2210 (p_lnk->geom, accessor->srid, accessor->has_z);
2211 }
2212 i++;
2213 p_lnk = p_lnk->next;
2214 }
2215 *numelems = list->count;
2216 }
2217 sqlite3_finalize (stmt_aux);
2218 destroy_links_list (list);
2219 return result;
2220
2221 error:
2222 if (stmt_aux != NULL)
2223 sqlite3_finalize (stmt_aux);
2224 if (list != NULL)
2225 destroy_links_list (list);
2226 *numelems = -1;
2227 return NULL;
2228 }
2229
2230 int
netcallback_deleteLinksById(const LWN_BE_NETWORK * lwn_net,const LWN_ELEMID * ids,int numelems)2231 netcallback_deleteLinksById (const LWN_BE_NETWORK * lwn_net,
2232 const LWN_ELEMID * ids, int numelems)
2233 {
2234 /* callback function: deleteLinksById */
2235 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
2236 struct gaia_network *accessor = (struct gaia_network *) net;
2237 sqlite3_stmt *stmt = NULL;
2238 int ret;
2239 int i;
2240 int changed = 0;
2241 if (accessor == NULL)
2242 return -1;
2243
2244 stmt = accessor->stmt_deleteLinksById;
2245 if (stmt == NULL)
2246 return -1;
2247
2248 for (i = 0; i < numelems; i++)
2249 {
2250 /* parameter binding */
2251 sqlite3_int64 id = *(ids + i);
2252 sqlite3_reset (stmt);
2253 sqlite3_clear_bindings (stmt);
2254 sqlite3_bind_int64 (stmt, 1, id);
2255 ret = sqlite3_step (stmt);
2256 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
2257 {
2258 changed += sqlite3_changes (accessor->db_handle);
2259 }
2260 else
2261 {
2262 char *msg =
2263 sqlite3_mprintf ("netcallback_deleteLinksById: \"%s\"",
2264 sqlite3_errmsg (accessor->db_handle));
2265 gaianet_set_last_error_msg (net, msg);
2266 sqlite3_free (msg);
2267 goto error;
2268 }
2269 }
2270 sqlite3_reset (stmt);
2271 return changed;
2272
2273 error:
2274 sqlite3_reset (stmt);
2275 return -1;
2276 }
2277
2278 int
netcallback_netGetSRID(const LWN_BE_NETWORK * lwn_net)2279 netcallback_netGetSRID (const LWN_BE_NETWORK * lwn_net)
2280 {
2281 /* callback function: netGetSRID */
2282 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
2283 struct gaia_network *accessor = (struct gaia_network *) net;
2284 if (accessor == NULL)
2285 return -1;
2286
2287 return accessor->srid;
2288 }
2289
2290 int
netcallback_netHasZ(const LWN_BE_NETWORK * lwn_net)2291 netcallback_netHasZ (const LWN_BE_NETWORK * lwn_net)
2292 {
2293 /* callback function: netHasZ */
2294 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
2295 struct gaia_network *accessor = (struct gaia_network *) net;
2296 if (accessor == NULL)
2297 return 0;
2298
2299 return accessor->has_z;
2300 }
2301
2302 int
netcallback_netIsSpatial(const LWN_BE_NETWORK * lwn_net)2303 netcallback_netIsSpatial (const LWN_BE_NETWORK * lwn_net)
2304 {
2305 /* callback function: netIsSpatial */
2306 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
2307 struct gaia_network *accessor = (struct gaia_network *) net;
2308 if (accessor == NULL)
2309 return 0;
2310
2311 return accessor->spatial;
2312 }
2313
2314 int
netcallback_netAllowCoincident(const LWN_BE_NETWORK * lwn_net)2315 netcallback_netAllowCoincident (const LWN_BE_NETWORK * lwn_net)
2316 {
2317 /* callback function: netAllowCoincident */
2318 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
2319 struct gaia_network *accessor = (struct gaia_network *) net;
2320 if (accessor == NULL)
2321 return 0;
2322
2323 return accessor->allow_coincident;
2324 }
2325
2326 const void *
netcallback_netGetGEOS(const LWN_BE_NETWORK * lwn_net)2327 netcallback_netGetGEOS (const LWN_BE_NETWORK * lwn_net)
2328 {
2329 /* callback function: netGetGEOS */
2330 const struct splite_internal_cache *cache;
2331 GaiaNetworkAccessorPtr net = (GaiaNetworkAccessorPtr) lwn_net;
2332 struct gaia_network *accessor = (struct gaia_network *) net;
2333 if (accessor == NULL)
2334 return NULL;
2335 if (accessor->cache == NULL)
2336 return NULL;
2337
2338 cache = (const struct splite_internal_cache *) (accessor->cache);
2339 return cache->GEOS_handle;
2340 }
2341
2342 #endif /* end RTTOPO conditionals */
2343