1 /*
2
3 gaia_auxnet.c -- implementation of the Topology-Network module methods
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/gaia_topology.h>
63 #include <spatialite/gaiaaux.h>
64
65 #include <spatialite.h>
66 #include <spatialite_private.h>
67
68 #include <librttopo.h>
69
70 #include <lwn_network.h>
71
72 #include "network_private.h"
73 #include "topology_private.h"
74
75 #ifdef _WIN32
76 #define strcasecmp _stricmp
77 #endif /* not WIN32 */
78
79 #define GAIA_UNUSED() if (argc || argv) argc = argc;
80
81 SPATIALITE_PRIVATE void
free_internal_cache_networks(void * firstNetwork)82 free_internal_cache_networks (void *firstNetwork)
83 {
84 /* destroying all Networks registered into the Internal Connection Cache */
85 struct gaia_network *p_net = (struct gaia_network *) firstNetwork;
86 struct gaia_network *p_net_n;
87
88 while (p_net != NULL)
89 {
90 p_net_n = p_net->next;
91 gaiaNetworkDestroy ((GaiaNetworkAccessorPtr) p_net);
92 p_net = p_net_n;
93 }
94 }
95
96 SPATIALITE_PRIVATE void
drop_networks_triggers(void * sqlite_handle)97 drop_networks_triggers (void *sqlite_handle)
98 {
99 /* dropping all "networks" triggers */
100 char *sql;
101 int ret;
102 char *err_msg = NULL;
103 char **results;
104 int rows;
105 int columns;
106 int i;
107 sqlite3 *sqlite = (sqlite3 *) sqlite_handle;
108
109 /* checking for existing tables */
110 sql =
111 "SELECT name FROM sqlite_master WHERE type = 'trigger' AND tbl_name = 'networks'";
112 ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, &err_msg);
113 if (ret != SQLITE_OK)
114 {
115 spatialite_e ("SQL error: %s\n", err_msg);
116 sqlite3_free (err_msg);
117 return;
118 }
119 for (i = 1; i <= rows; i++)
120 {
121 const char *name = results[(i * columns) + 0];
122 sql = sqlite3_mprintf ("DROP TRIGGER %s", name);
123 ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
124 if (ret != SQLITE_OK)
125 {
126 spatialite_e ("SQL error: %s\n", err_msg);
127 sqlite3_free (err_msg);
128 return;
129 }
130 sqlite3_free (sql);
131 }
132 sqlite3_free_table (results);
133 }
134
135 SPATIALITE_PRIVATE int
do_create_networks_triggers(void * sqlite_handle)136 do_create_networks_triggers (void *sqlite_handle)
137 {
138 /* attempting to create the Networks triggers */
139 const char *sql;
140 char *err_msg = NULL;
141 int ret;
142 char **results;
143 int rows;
144 int columns;
145 int i;
146 sqlite3 *handle = (sqlite3 *) sqlite_handle;
147 int ok_networks = 0;
148
149 /* checking for existing networks */
150 sql =
151 "SELECT tbl_name FROM sqlite_master WHERE type = 'table' AND tbl_name = 'networks'";
152 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, &err_msg);
153 if (ret != SQLITE_OK)
154 {
155 spatialite_e ("SQL error: %s\n", err_msg);
156 sqlite3_free (err_msg);
157 return 0;
158 }
159 for (i = 1; i <= rows; i++)
160 {
161 const char *name = results[(i * columns) + 0];
162 if (strcasecmp (name, "networks") == 0)
163 ok_networks = 1;
164 }
165 sqlite3_free_table (results);
166
167 if (ok_networks)
168 {
169 /* creating Networks triggers */
170 sql = "CREATE TRIGGER IF NOT EXISTS network_name_insert\n"
171 "BEFORE INSERT ON 'networks'\nFOR EACH ROW BEGIN\n"
172 "SELECT RAISE(ABORT,'insert on networks violates constraint: "
173 "network_name value must not contain a single quote')\n"
174 "WHERE NEW.network_name LIKE ('%''%');\n"
175 "SELECT RAISE(ABORT,'insert on networks violates constraint: "
176 "network_name value must not contain a double quote')\n"
177 "WHERE NEW.network_name LIKE ('%\"%');\n"
178 "SELECT RAISE(ABORT,'insert on networks violates constraint: "
179 "network_name value must be lower case')\n"
180 "WHERE NEW.network_name <> lower(NEW.network_name);\nEND";
181 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
182 if (ret != SQLITE_OK)
183 {
184 spatialite_e ("SQL error: %s\n", err_msg);
185 sqlite3_free (err_msg);
186 return 0;
187 }
188 sql = "CREATE TRIGGER IF NOT EXISTS network_name_update\n"
189 "BEFORE UPDATE OF 'network_name' ON 'networks'\nFOR EACH ROW BEGIN\n"
190 "SELECT RAISE(ABORT,'update on networks violates constraint: "
191 "network_name value must not contain a single quote')\n"
192 "WHERE NEW.network_name LIKE ('%''%');\n"
193 "SELECT RAISE(ABORT,'update on networks violates constraint: "
194 "network_name value must not contain a double quote')\n"
195 "WHERE NEW.network_name LIKE ('%\"%');\n"
196 "SELECT RAISE(ABORT,'update on networks violates constraint: "
197 "network_name value must be lower case')\n"
198 "WHERE NEW.network_name <> lower(NEW.network_name);\nEND";
199 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
200 if (ret != SQLITE_OK)
201 {
202 spatialite_e ("SQL error: %s\n", err_msg);
203 sqlite3_free (err_msg);
204 return 0;
205 }
206 }
207
208 return 1;
209 }
210
211 SPATIALITE_PRIVATE int
do_create_networks(void * sqlite_handle)212 do_create_networks (void *sqlite_handle)
213 {
214 /* attempting to create the Networks table (if not already existing) */
215 const char *sql;
216 char *err_msg = NULL;
217 int ret;
218 sqlite3 *handle = (sqlite3 *) sqlite_handle;
219
220 sql = "CREATE TABLE IF NOT EXISTS networks (\n"
221 "\tnetwork_name TEXT NOT NULL PRIMARY KEY,\n"
222 "\tspatial INTEGER NOT NULL,\n"
223 "\tsrid INTEGER NOT NULL,\n"
224 "\thas_z INTEGER NOT NULL,\n"
225 "\tallow_coincident INTEGER NOT NULL,\n"
226 "\tnext_node_id INTEGER NOT NULL DEFAULT 1,\n"
227 "\tnext_link_id INTEGER NOT NULL DEFAULT 1,\n"
228 "\tCONSTRAINT net_srid_fk FOREIGN KEY (srid) "
229 "REFERENCES spatial_ref_sys (srid))";
230 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
231 if (ret != SQLITE_OK)
232 {
233 spatialite_e ("CREATE TABLE networks - error: %s\n", err_msg);
234 sqlite3_free (err_msg);
235 return 0;
236 }
237
238 if (!do_create_networks_triggers (handle))
239 return 0;
240 return 1;
241 }
242
243 static int
check_new_network(sqlite3 * handle,const char * network_name)244 check_new_network (sqlite3 * handle, const char *network_name)
245 {
246 /* testing if some already defined DB object forbids creating the new Network */
247 char *sql;
248 char *prev;
249 char *table;
250 int ret;
251 int i;
252 char **results;
253 int rows;
254 int columns;
255 const char *value;
256 int error = 0;
257
258 /* testing if the same Network is already defined */
259 sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.networks WHERE "
260 "Lower(network_name) = Lower(%Q)", network_name);
261 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
262 sqlite3_free (sql);
263 if (ret != SQLITE_OK)
264 return 0;
265 if (rows < 1)
266 ;
267 else
268 {
269 for (i = 1; i <= rows; i++)
270 {
271 value = results[(i * columns) + 0];
272 if (atoi (value) != 0)
273 error = 1;
274 }
275 }
276 sqlite3_free_table (results);
277 if (error)
278 return 0;
279
280 /* testing if some table/geom is already defined in geometry_columns */
281 sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.geometry_columns WHERE");
282 prev = sql;
283 table = sqlite3_mprintf ("%s_node", network_name);
284 sql =
285 sqlite3_mprintf
286 ("%s (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geometry')",
287 prev, table);
288 sqlite3_free (table);
289 sqlite3_free (prev);
290 prev = sql;
291 table = sqlite3_mprintf ("%s_link", network_name);
292 sql =
293 sqlite3_mprintf
294 ("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geometry')",
295 prev, table);
296 sqlite3_free (table);
297 sqlite3_free (prev);
298 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
299 sqlite3_free (sql);
300 if (ret != SQLITE_OK)
301 return 0;
302 if (rows < 1)
303 ;
304 else
305 {
306 for (i = 1; i <= rows; i++)
307 {
308 value = results[(i * columns) + 0];
309 if (atoi (value) != 0)
310 error = 1;
311 }
312 }
313 sqlite3_free_table (results);
314 if (error)
315 return 0;
316
317 /* testing if some table is already defined */
318 sql = sqlite3_mprintf ("SELECT Count(*) FROM sqlite_master WHERE");
319 prev = sql;
320 table = sqlite3_mprintf ("%s_node", network_name);
321 sql = sqlite3_mprintf ("%s Lower(name) = Lower(%Q)", prev, table);
322 sqlite3_free (table);
323 sqlite3_free (prev);
324 prev = sql;
325 table = sqlite3_mprintf ("%s_link", network_name);
326 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
327 sqlite3_free (table);
328 sqlite3_free (prev);
329 prev = sql;
330 table = sqlite3_mprintf ("idx_%s_node_geometry", network_name);
331 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
332 sqlite3_free (table);
333 sqlite3_free (prev);
334 prev = sql;
335 table = sqlite3_mprintf ("idx_%s_link_geometry", network_name);
336 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
337 sqlite3_free (table);
338 sqlite3_free (prev);
339 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
340 sqlite3_free (sql);
341 if (ret != SQLITE_OK)
342 return 0;
343 if (rows < 1)
344 ;
345 else
346 {
347 for (i = 1; i <= rows; i++)
348 {
349 value = results[(i * columns) + 0];
350 if (atoi (value) != 0)
351 error = 1;
352 }
353 }
354 sqlite3_free_table (results);
355 if (error)
356 return 0;
357
358 return 1;
359 }
360
361 NETWORK_PRIVATE LWN_LINE *
gaianet_convert_linestring_to_lwnline(gaiaLinestringPtr ln,int srid,int has_z)362 gaianet_convert_linestring_to_lwnline (gaiaLinestringPtr ln, int srid,
363 int has_z)
364 {
365 /* converting a Linestring into an LWN_LINE */
366 int iv;
367 LWN_LINE *line = lwn_alloc_line (ln->Points, srid, has_z);
368 for (iv = 0; iv < ln->Points; iv++)
369 {
370 double x;
371 double y;
372 double z;
373 double m;
374 if (ln->DimensionModel == GAIA_XY_Z)
375 {
376 gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
377 }
378 else if (ln->DimensionModel == GAIA_XY_M)
379 {
380 gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
381 }
382 else if (ln->DimensionModel == GAIA_XY_Z_M)
383 {
384 gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
385 }
386 else
387 {
388 gaiaGetPoint (ln->Coords, iv, &x, &y);
389 }
390 line->x[iv] = x;
391 line->y[iv] = y;
392 if (has_z)
393 line->z[iv] = z;
394 }
395 return line;
396 }
397
398 static int
do_create_node(sqlite3 * handle,const char * network_name,int srid,int has_z)399 do_create_node (sqlite3 * handle, const char *network_name, int srid, int has_z)
400 {
401 /* attempting to create the Network Node table */
402 char *sql;
403 char *table;
404 char *xtable;
405 char *trigger;
406 char *xtrigger;
407 char *err_msg = NULL;
408 int ret;
409
410 /* creating the main table */
411 table = sqlite3_mprintf ("%s_node", network_name);
412 xtable = gaiaDoubleQuotedSql (table);
413 sqlite3_free (table);
414 sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
415 "\tnode_id INTEGER PRIMARY KEY AUTOINCREMENT)",
416 xtable);
417 free (xtable);
418 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
419 sqlite3_free (sql);
420 if (ret != SQLITE_OK)
421 {
422 spatialite_e ("CREATE TABLE network-NODE - error: %s\n", err_msg);
423 sqlite3_free (err_msg);
424 return 0;
425 }
426
427 /* adding the "next_node_ins" trigger */
428 trigger = sqlite3_mprintf ("%s_node_next_ins", network_name);
429 xtrigger = gaiaDoubleQuotedSql (trigger);
430 sqlite3_free (trigger);
431 table = sqlite3_mprintf ("%s_node", network_name);
432 xtable = gaiaDoubleQuotedSql (table);
433 sqlite3_free (table);
434 sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER INSERT ON \"%s\"\n"
435 "FOR EACH ROW BEGIN\n"
436 "\tUPDATE networks SET next_node_id = NEW.node_id + 1 "
437 "WHERE Lower(network_name) = Lower(%Q) AND next_node_id < NEW.node_id + 1;\n"
438 "END", xtrigger, xtable, network_name);
439 free (xtrigger);
440 free (xtable);
441 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
442 sqlite3_free (sql);
443 if (ret != SQLITE_OK)
444 {
445 spatialite_e
446 ("CREATE TRIGGER network-NODE next INSERT - error: %s\n",
447 err_msg);
448 sqlite3_free (err_msg);
449 return 0;
450 }
451
452 /* adding the "next_node_upd" trigger */
453 trigger = sqlite3_mprintf ("%s_node_next_upd", network_name);
454 xtrigger = gaiaDoubleQuotedSql (trigger);
455 sqlite3_free (trigger);
456 table = sqlite3_mprintf ("%s_node", network_name);
457 xtable = gaiaDoubleQuotedSql (table);
458 sqlite3_free (table);
459 sql =
460 sqlite3_mprintf
461 ("CREATE TRIGGER \"%s\" AFTER UPDATE OF node_id ON \"%s\"\n"
462 "FOR EACH ROW BEGIN\n"
463 "\tUPDATE networks SET next_node_id = NEW.node_id + 1 "
464 "WHERE Lower(network_name) = Lower(%Q) AND next_node_id < NEW.node_id + 1;\n"
465 "END", xtrigger, xtable, network_name);
466 free (xtrigger);
467 free (xtable);
468 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
469 sqlite3_free (sql);
470 if (ret != SQLITE_OK)
471 {
472 spatialite_e
473 ("CREATE TRIGGER network-NODE next UPDATE - error: %s\n",
474 err_msg);
475 sqlite3_free (err_msg);
476 return 0;
477 }
478
479 /* creating the Node Geometry */
480 table = sqlite3_mprintf ("%s_node", network_name);
481 sql =
482 sqlite3_mprintf
483 ("SELECT AddGeometryColumn(%Q, 'geometry', %d, 'POINT', %Q)", table,
484 srid, has_z ? "XYZ" : "XY");
485 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
486 sqlite3_free (table);
487 sqlite3_free (sql);
488 if (ret != SQLITE_OK)
489 {
490 spatialite_e
491 ("AddGeometryColumn network-NODE - error: %s\n", err_msg);
492 sqlite3_free (err_msg);
493 return 0;
494 }
495
496 /* creating a Spatial Index supporting Node Geometry */
497 table = sqlite3_mprintf ("%s_node", network_name);
498 sql = sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, 'geometry')", table);
499 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
500 sqlite3_free (table);
501 sqlite3_free (sql);
502 if (ret != SQLITE_OK)
503 {
504 spatialite_e
505 ("CreateSpatialIndex network-NODE - error: %s\n", err_msg);
506 sqlite3_free (err_msg);
507 return 0;
508 }
509
510 return 1;
511 }
512
513 static int
do_create_link(sqlite3 * handle,const char * network_name,int srid,int has_z)514 do_create_link (sqlite3 * handle, const char *network_name, int srid, int has_z)
515 {
516 /* attempting to create the Network Link table */
517 char *sql;
518 char *table;
519 char *xtable;
520 char *xconstraint1;
521 char *xconstraint2;
522 char *xnodes;
523 char *trigger;
524 char *xtrigger;
525 char *err_msg = NULL;
526 int ret;
527
528 /* creating the main table */
529 table = sqlite3_mprintf ("%s_link", network_name);
530 xtable = gaiaDoubleQuotedSql (table);
531 sqlite3_free (table);
532 table = sqlite3_mprintf ("%s_link_node_start_fk", network_name);
533 xconstraint1 = gaiaDoubleQuotedSql (table);
534 sqlite3_free (table);
535 table = sqlite3_mprintf ("%s_link_node_end_fk", network_name);
536 xconstraint2 = gaiaDoubleQuotedSql (table);
537 sqlite3_free (table);
538 table = sqlite3_mprintf ("%s_node", network_name);
539 xnodes = gaiaDoubleQuotedSql (table);
540 sqlite3_free (table);
541 sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
542 "\tlink_id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
543 "\tstart_node INTEGER NOT NULL,\n"
544 "\tend_node INTEGER NOT NULL,\n"
545 "\ttimestamp DATETIME,\n"
546 "\tCONSTRAINT \"%s\" FOREIGN KEY (start_node) "
547 "REFERENCES \"%s\" (node_id),\n"
548 "\tCONSTRAINT \"%s\" FOREIGN KEY (end_node) "
549 "REFERENCES \"%s\" (node_id))",
550 xtable, xconstraint1, xnodes, xconstraint2, xnodes);
551 free (xtable);
552 free (xconstraint1);
553 free (xconstraint2);
554 free (xnodes);
555 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
556 sqlite3_free (sql);
557 if (ret != SQLITE_OK)
558 {
559 spatialite_e ("CREATE TABLE network-LINK - error: %s\n", err_msg);
560 sqlite3_free (err_msg);
561 return 0;
562 }
563
564 /* adding the "next_link_ins" trigger */
565 trigger = sqlite3_mprintf ("%s_link_next_ins", network_name);
566 xtrigger = gaiaDoubleQuotedSql (trigger);
567 sqlite3_free (trigger);
568 table = sqlite3_mprintf ("%s_link", network_name);
569 xtable = gaiaDoubleQuotedSql (table);
570 sqlite3_free (table);
571 sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER INSERT ON \"%s\"\n"
572 "FOR EACH ROW BEGIN\n"
573 "\tUPDATE networks SET next_link_id = NEW.link_id + 1 "
574 "WHERE Lower(network_name) = Lower(%Q) AND next_link_id < NEW.link_id + 1;\n"
575 "\tUPDATE \"%s\" SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
576 "WHERE link_id = NEW.link_id;"
577 "END", xtrigger, xtable, network_name, xtable);
578 free (xtrigger);
579 free (xtable);
580 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
581 sqlite3_free (sql);
582 if (ret != SQLITE_OK)
583 {
584 spatialite_e
585 ("CREATE TRIGGER network-LINK next INSERT - error: %s\n",
586 err_msg);
587 sqlite3_free (err_msg);
588 return 0;
589 }
590
591 /* adding the "link_update" trigger */
592 trigger = sqlite3_mprintf ("%s_link_update", network_name);
593 xtrigger = gaiaDoubleQuotedSql (trigger);
594 sqlite3_free (trigger);
595 table = sqlite3_mprintf ("%s_link", network_name);
596 xtable = gaiaDoubleQuotedSql (table);
597 sqlite3_free (table);
598 sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER UPDATE ON \"%s\"\n"
599 "FOR EACH ROW BEGIN\n"
600 "\tUPDATE \"%s\" SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
601 "WHERE link_id = NEW.link_id;"
602 "END", xtrigger, xtable, xtable);
603 free (xtrigger);
604 free (xtable);
605 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
606 sqlite3_free (sql);
607 if (ret != SQLITE_OK)
608 {
609 spatialite_e
610 ("CREATE TRIGGER topology-LINK next INSERT - error: %s\n",
611 err_msg);
612 sqlite3_free (err_msg);
613 return 0;
614 }
615
616 /* adding the "next_link_upd" trigger */
617 trigger = sqlite3_mprintf ("%s_link_next_upd", network_name);
618 xtrigger = gaiaDoubleQuotedSql (trigger);
619 sqlite3_free (trigger);
620 table = sqlite3_mprintf ("%s_link", network_name);
621 xtable = gaiaDoubleQuotedSql (table);
622 sqlite3_free (table);
623 sql =
624 sqlite3_mprintf
625 ("CREATE TRIGGER \"%s\" AFTER UPDATE OF link_id ON \"%s\"\n"
626 "FOR EACH ROW BEGIN\n"
627 "\tUPDATE networks SET next_link_id = NEW.link_id + 1 "
628 "WHERE Lower(network_name) = Lower(%Q) AND next_link_id < NEW.link_id + 1;\n"
629 "END", xtrigger, xtable, network_name);
630 free (xtrigger);
631 free (xtable);
632 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
633 sqlite3_free (sql);
634 if (ret != SQLITE_OK)
635 {
636 spatialite_e
637 ("CREATE TRIGGER network-LINK next UPDATE - error: %s\n",
638 err_msg);
639 sqlite3_free (err_msg);
640 return 0;
641 }
642
643 /* creating the Link Geometry */
644 table = sqlite3_mprintf ("%s_link", network_name);
645 sql =
646 sqlite3_mprintf
647 ("SELECT AddGeometryColumn(%Q, 'geometry', %d, 'LINESTRING', %Q)",
648 table, srid, has_z ? "XYZ" : "XY");
649 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
650 sqlite3_free (table);
651 sqlite3_free (sql);
652 if (ret != SQLITE_OK)
653 {
654 spatialite_e
655 ("AddGeometryColumn network-LINK - error: %s\n", err_msg);
656 sqlite3_free (err_msg);
657 return 0;
658 }
659
660 /* creating a Spatial Index supporting Link Geometry */
661 table = sqlite3_mprintf ("%s_link", network_name);
662 sql = sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, 'geometry')", table);
663 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
664 sqlite3_free (table);
665 sqlite3_free (sql);
666 if (ret != SQLITE_OK)
667 {
668 spatialite_e
669 ("CreateSpatialIndex network-LINK - error: %s\n", err_msg);
670 sqlite3_free (err_msg);
671 return 0;
672 }
673
674 /* creating an Index supporting "start_node" */
675 table = sqlite3_mprintf ("%s_link", network_name);
676 xtable = gaiaDoubleQuotedSql (table);
677 sqlite3_free (table);
678 table = sqlite3_mprintf ("idx_%s_start_node", network_name);
679 xconstraint1 = gaiaDoubleQuotedSql (table);
680 sqlite3_free (table);
681 sql =
682 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (start_node)",
683 xconstraint1, xtable);
684 free (xtable);
685 free (xconstraint1);
686 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
687 sqlite3_free (sql);
688 if (ret != SQLITE_OK)
689 {
690 spatialite_e ("CREATE INDEX link-startnode - error: %s\n", err_msg);
691 sqlite3_free (err_msg);
692 return 0;
693 }
694
695 /* creating an Index supporting "end_node" */
696 table = sqlite3_mprintf ("%s_link", network_name);
697 xtable = gaiaDoubleQuotedSql (table);
698 sqlite3_free (table);
699 table = sqlite3_mprintf ("idx_%s_end_node", network_name);
700 xconstraint1 = gaiaDoubleQuotedSql (table);
701 sqlite3_free (table);
702 sql =
703 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (end_node)",
704 xconstraint1, xtable);
705 free (xtable);
706 free (xconstraint1);
707 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
708 sqlite3_free (sql);
709 if (ret != SQLITE_OK)
710 {
711 spatialite_e ("CREATE INDEX link-endnode - error: %s\n", err_msg);
712 sqlite3_free (err_msg);
713 return 0;
714 }
715
716 /* creating an Index supporting "timestamp" */
717 table = sqlite3_mprintf ("%s_link", network_name);
718 xtable = gaiaDoubleQuotedSql (table);
719 sqlite3_free (table);
720 table = sqlite3_mprintf ("idx_%s_timestamp", network_name);
721 xconstraint1 = gaiaDoubleQuotedSql (table);
722 sqlite3_free (table);
723 sql =
724 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (timestamp)",
725 xconstraint1, xtable);
726 free (xtable);
727 free (xconstraint1);
728 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
729 sqlite3_free (sql);
730 if (ret != SQLITE_OK)
731 {
732 spatialite_e ("CREATE INDEX link-timestamps - error: %s\n", err_msg);
733 sqlite3_free (err_msg);
734 return 0;
735 }
736
737 return 1;
738 }
739
740 static int
do_create_seeds(sqlite3 * handle,const char * network_name,int srid,int has_z)741 do_create_seeds (sqlite3 * handle, const char *network_name, int srid,
742 int has_z)
743 {
744 /* attempting to create the Network Seeds table */
745 char *sql;
746 char *table;
747 char *xtable;
748 char *xconstraint;
749 char *xlinks;
750 char *trigger;
751 char *xtrigger;
752 char *err_msg = NULL;
753 int ret;
754
755 /* creating the main table */
756 table = sqlite3_mprintf ("%s_seeds", network_name);
757 xtable = gaiaDoubleQuotedSql (table);
758 sqlite3_free (table);
759 table = sqlite3_mprintf ("%s_seeds_link_fk", network_name);
760 xconstraint = gaiaDoubleQuotedSql (table);
761 sqlite3_free (table);
762 table = sqlite3_mprintf ("%s_link", network_name);
763 xlinks = gaiaDoubleQuotedSql (table);
764 sqlite3_free (table);
765 sql = sqlite3_mprintf ("CREATE TABLE \"%s\" (\n"
766 "\tseed_id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
767 "\tlink_id INTEGER NOT NULL,\n"
768 "\ttimestamp DATETIME,\n"
769 "\tCONSTRAINT \"%s\" FOREIGN KEY (link_id) "
770 "REFERENCES \"%s\" (link_id) ON DELETE CASCADE)",
771 xtable, xconstraint, xlinks);
772 free (xtable);
773 free (xconstraint);
774 free (xlinks);
775 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
776 sqlite3_free (sql);
777 if (ret != SQLITE_OK)
778 {
779 spatialite_e ("CREATE TABLE network-SEEDS - error: %s\n", err_msg);
780 sqlite3_free (err_msg);
781 return 0;
782 }
783
784 /* adding the "seeds_ins" trigger */
785 trigger = sqlite3_mprintf ("%s_seeds_ins", network_name);
786 xtrigger = gaiaDoubleQuotedSql (trigger);
787 sqlite3_free (trigger);
788 table = sqlite3_mprintf ("%s_seeds", network_name);
789 xtable = gaiaDoubleQuotedSql (table);
790 sqlite3_free (table);
791 sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER INSERT ON \"%s\"\n"
792 "FOR EACH ROW BEGIN\n"
793 "\tUPDATE \"%s\" SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
794 "WHERE seed_id = NEW.seed_id;"
795 "END", xtrigger, xtable, xtable);
796 free (xtrigger);
797 free (xtable);
798 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
799 sqlite3_free (sql);
800 if (ret != SQLITE_OK)
801 {
802 spatialite_e
803 ("CREATE TRIGGER network-SEEDS next INSERT - error: %s\n",
804 err_msg);
805 sqlite3_free (err_msg);
806 return 0;
807 }
808
809 /* adding the "seeds_update" trigger */
810 trigger = sqlite3_mprintf ("%s_seeds_update", network_name);
811 xtrigger = gaiaDoubleQuotedSql (trigger);
812 sqlite3_free (trigger);
813 table = sqlite3_mprintf ("%s_seeds", network_name);
814 xtable = gaiaDoubleQuotedSql (table);
815 sqlite3_free (table);
816 sql = sqlite3_mprintf ("CREATE TRIGGER \"%s\" AFTER UPDATE ON \"%s\"\n"
817 "FOR EACH ROW BEGIN\n"
818 "\tUPDATE \"%s\" SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
819 "WHERE seed_id = NEW.seed_id;"
820 "END", xtrigger, xtable, xtable);
821 free (xtrigger);
822 free (xtable);
823 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
824 sqlite3_free (sql);
825 if (ret != SQLITE_OK)
826 {
827 spatialite_e
828 ("CREATE TRIGGER network-SEED next INSERT - error: %s\n",
829 err_msg);
830 sqlite3_free (err_msg);
831 return 0;
832 }
833
834 /* creating the Seeds Geometry */
835 table = sqlite3_mprintf ("%s_seeds", network_name);
836 sql =
837 sqlite3_mprintf
838 ("SELECT AddGeometryColumn(%Q, 'geometry', %d, 'POINT', %Q, 1)",
839 table, srid, has_z ? "XYZ" : "XY");
840 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
841 sqlite3_free (table);
842 sqlite3_free (sql);
843 if (ret != SQLITE_OK)
844 {
845 spatialite_e
846 ("AddGeometryColumn network-SEEDS - error: %s\n", err_msg);
847 sqlite3_free (err_msg);
848 return 0;
849 }
850
851 /* creating a Spatial Index supporting Seeds Geometry */
852 table = sqlite3_mprintf ("%s_seeds", network_name);
853 sql = sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, 'geometry')", table);
854 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
855 sqlite3_free (table);
856 sqlite3_free (sql);
857 if (ret != SQLITE_OK)
858 {
859 spatialite_e
860 ("CreateSpatialIndex network-SEEDS - error: %s\n", err_msg);
861 sqlite3_free (err_msg);
862 return 0;
863 }
864
865 /* creating an Index supporting "link_id" */
866 table = sqlite3_mprintf ("%s_seeds", network_name);
867 xtable = gaiaDoubleQuotedSql (table);
868 sqlite3_free (table);
869 table = sqlite3_mprintf ("idx_%s_link", network_name);
870 xconstraint = gaiaDoubleQuotedSql (table);
871 sqlite3_free (table);
872 sql =
873 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (link_id)",
874 xconstraint, xtable);
875 free (xtable);
876 free (xconstraint);
877 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
878 sqlite3_free (sql);
879 if (ret != SQLITE_OK)
880 {
881 spatialite_e ("CREATE INDEX seeds-link - error: %s\n", err_msg);
882 sqlite3_free (err_msg);
883 return 0;
884 }
885
886 /* creating an Index supporting "timestamp" */
887 table = sqlite3_mprintf ("%s_seeds", network_name);
888 xtable = gaiaDoubleQuotedSql (table);
889 sqlite3_free (table);
890 table = sqlite3_mprintf ("idx_%s_seeds_timestamp", network_name);
891 xconstraint = gaiaDoubleQuotedSql (table);
892 sqlite3_free (table);
893 sql =
894 sqlite3_mprintf ("CREATE INDEX \"%s\" ON \"%s\" (timestamp)",
895 xconstraint, xtable);
896 free (xtable);
897 free (xconstraint);
898 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
899 sqlite3_free (sql);
900 if (ret != SQLITE_OK)
901 {
902 spatialite_e ("CREATE INDEX seeds-timestamps - error: %s\n", err_msg);
903 sqlite3_free (err_msg);
904 return 0;
905 }
906
907 return 1;
908 }
909
910 GAIANET_DECLARE int
gaiaNetworkCreate(sqlite3 * handle,const char * network_name,int spatial,int srid,int has_z,int allow_coincident)911 gaiaNetworkCreate (sqlite3 * handle, const char *network_name, int spatial,
912 int srid, int has_z, int allow_coincident)
913 {
914 /* attempting to create a new Network */
915 int ret;
916 char *sql;
917
918 /* creating the Networks table (just in case) */
919 if (!do_create_networks (handle))
920 return 0;
921
922 /* testing for forbidding objects */
923 if (!check_new_network (handle, network_name))
924 return 0;
925
926 /* creating the Network own Tables */
927 if (!do_create_node (handle, network_name, srid, has_z))
928 goto error;
929 if (!do_create_link (handle, network_name, srid, has_z))
930 goto error;
931 if (!do_create_seeds (handle, network_name, srid, has_z))
932 goto error;
933
934 /* registering the Network */
935 sql = sqlite3_mprintf ("INSERT INTO MAIN.networks (network_name, "
936 "spatial, srid, has_z, allow_coincident) VALUES (Lower(%Q), %d, %d, %d, %d)",
937 network_name, spatial, srid, has_z,
938 allow_coincident);
939 ret = sqlite3_exec (handle, sql, NULL, NULL, NULL);
940 sqlite3_free (sql);
941 if (ret != SQLITE_OK)
942 goto error;
943
944 return 1;
945
946 error:
947 return 0;
948 }
949
950 static int
check_existing_network(sqlite3 * handle,const char * network_name,int full_check)951 check_existing_network (sqlite3 * handle, const char *network_name,
952 int full_check)
953 {
954 /* testing if a Network is already defined */
955 char *sql;
956 char *prev;
957 char *table;
958 int ret;
959 int i;
960 char **results;
961 int rows;
962 int columns;
963 const char *value;
964 int error = 0;
965
966 /* testing if the Network is already defined */
967 sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.networks WHERE "
968 "Lower(network_name) = Lower(%Q)", network_name);
969 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
970 sqlite3_free (sql);
971 if (ret != SQLITE_OK)
972 return 0;
973 if (rows < 1)
974 ;
975 else
976 {
977 for (i = 1; i <= rows; i++)
978 {
979 value = results[(i * columns) + 0];
980 if (atoi (value) != 1)
981 error = 1;
982 }
983 }
984 sqlite3_free_table (results);
985 if (error)
986 return 0;
987 if (!full_check)
988 return 1;
989
990 /* testing if all table/geom are correctly defined in geometry_columns */
991 sql = sqlite3_mprintf ("SELECT Count(*) FROM MAIN.geometry_columns WHERE");
992 prev = sql;
993 table = sqlite3_mprintf ("%s_node", network_name);
994 sql =
995 sqlite3_mprintf
996 ("%s (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geometry')",
997 prev, table);
998 sqlite3_free (table);
999 sqlite3_free (prev);
1000 prev = sql;
1001 table = sqlite3_mprintf ("%s_link", network_name);
1002 sql =
1003 sqlite3_mprintf
1004 ("%s OR (Lower(f_table_name) = Lower(%Q) AND f_geometry_column = 'geometry')",
1005 prev, table);
1006 sqlite3_free (table);
1007 sqlite3_free (prev);
1008 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
1009 sqlite3_free (sql);
1010 if (ret != SQLITE_OK)
1011 return 0;
1012 if (rows < 1)
1013 ;
1014 else
1015 {
1016 for (i = 1; i <= rows; i++)
1017 {
1018 value = results[(i * columns) + 0];
1019 if (atoi (value) != 2)
1020 error = 1;
1021 }
1022 }
1023 sqlite3_free_table (results);
1024 if (error)
1025 return 0;
1026
1027 /* testing if all tables are already defined */
1028 sql =
1029 sqlite3_mprintf
1030 ("SELECT Count(*) FROM sqlite_master WHERE type = 'table' AND (");
1031 prev = sql;
1032 table = sqlite3_mprintf ("%s_node", network_name);
1033 sql = sqlite3_mprintf ("%s Lower(name) = Lower(%Q)", prev, table);
1034 sqlite3_free (table);
1035 sqlite3_free (prev);
1036 prev = sql;
1037 table = sqlite3_mprintf ("%s_link", network_name);
1038 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
1039 sqlite3_free (table);
1040 sqlite3_free (prev);
1041 prev = sql;
1042 table = sqlite3_mprintf ("idx_%s_node_geometry", network_name);
1043 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q)", prev, table);
1044 sqlite3_free (table);
1045 sqlite3_free (prev);
1046 prev = sql;
1047 table = sqlite3_mprintf ("idx_%s_link_geometry", network_name);
1048 sql = sqlite3_mprintf ("%s OR Lower(name) = Lower(%Q))", prev, table);
1049 sqlite3_free (table);
1050 sqlite3_free (prev);
1051 ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
1052 sqlite3_free (sql);
1053 if (ret != SQLITE_OK)
1054 return 0;
1055 if (rows < 1)
1056 ;
1057 else
1058 {
1059 for (i = 1; i <= rows; i++)
1060 {
1061 value = results[(i * columns) + 0];
1062 if (atoi (value) != 4)
1063 error = 1;
1064 }
1065 }
1066 sqlite3_free_table (results);
1067 if (error)
1068 return 0;
1069
1070 return 1;
1071 }
1072
1073 static int
do_drop_network_table(sqlite3 * handle,const char * network_name,const char * which)1074 do_drop_network_table (sqlite3 * handle, const char *network_name,
1075 const char *which)
1076 {
1077 /* attempting to drop some Network table */
1078 char *sql;
1079 char *table;
1080 char *xtable;
1081 char *err_msg = NULL;
1082 int ret;
1083
1084 /* disabling the corresponding Spatial Index */
1085 table = sqlite3_mprintf ("%s_%s", network_name, which);
1086 sql = sqlite3_mprintf ("SELECT DisableSpatialIndex(%Q, 'geometry')", table);
1087 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1088 sqlite3_free (table);
1089 sqlite3_free (sql);
1090 if (ret != SQLITE_OK)
1091 {
1092 spatialite_e
1093 ("DisableSpatialIndex network-%s - error: %s\n", which, err_msg);
1094 sqlite3_free (err_msg);
1095 return 0;
1096 }
1097
1098 /* discarding the Geometry column */
1099 table = sqlite3_mprintf ("%s_%s", network_name, which);
1100 sql =
1101 sqlite3_mprintf ("SELECT DiscardGeometryColumn(%Q, 'geometry')", table);
1102 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1103 sqlite3_free (table);
1104 sqlite3_free (sql);
1105 if (ret != SQLITE_OK)
1106 {
1107 spatialite_e
1108 ("DisableGeometryColumn network-%s - error: %s\n", which,
1109 err_msg);
1110 sqlite3_free (err_msg);
1111 return 0;
1112 }
1113
1114 /* dropping the main table */
1115 table = sqlite3_mprintf ("%s_%s", network_name, which);
1116 xtable = gaiaDoubleQuotedSql (table);
1117 sqlite3_free (table);
1118 sql = sqlite3_mprintf ("DROP TABLE IF EXISTS \"%s\"", xtable);
1119 free (xtable);
1120 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1121 sqlite3_free (sql);
1122 if (ret != SQLITE_OK)
1123 {
1124 spatialite_e ("DROP network-%s - error: %s\n", which, err_msg);
1125 sqlite3_free (err_msg);
1126 return 0;
1127 }
1128
1129 /* dropping the corresponding Spatial Index */
1130 table = sqlite3_mprintf ("idx_%s_%s_geometry", network_name, which);
1131 sql = sqlite3_mprintf ("DROP TABLE IF EXISTS \"%s\"", table);
1132 ret = sqlite3_exec (handle, sql, NULL, NULL, &err_msg);
1133 sqlite3_free (table);
1134 sqlite3_free (sql);
1135 if (ret != SQLITE_OK)
1136 {
1137 spatialite_e
1138 ("DROP SpatialIndex network-%s - error: %s\n", which, err_msg);
1139 sqlite3_free (err_msg);
1140 return 0;
1141 }
1142
1143 return 1;
1144 }
1145
1146 static int
do_get_network(sqlite3 * handle,const char * net_name,char ** network_name,int * spatial,int * srid,int * has_z,int * allow_coincident)1147 do_get_network (sqlite3 * handle, const char *net_name, char **network_name,
1148 int *spatial, int *srid, int *has_z, int *allow_coincident)
1149 {
1150 /* retrieving a Network configuration */
1151 char *sql;
1152 int ret;
1153 sqlite3_stmt *stmt = NULL;
1154 int ok = 0;
1155 char *xnetwork_name = NULL;
1156 int xsrid;
1157 int xhas_z;
1158 int xspatial;
1159 int xallow_coincident;
1160
1161 /* preparing the SQL query */
1162 sql =
1163 sqlite3_mprintf
1164 ("SELECT network_name, spatial, srid, has_z, allow_coincident "
1165 "FROM MAIN.networks WHERE Lower(network_name) = Lower(%Q)", net_name);
1166 ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
1167 sqlite3_free (sql);
1168 if (ret != SQLITE_OK)
1169 {
1170 spatialite_e ("SELECT FROM networks error: \"%s\"\n",
1171 sqlite3_errmsg (handle));
1172 return 0;
1173 }
1174
1175 while (1)
1176 {
1177 /* scrolling the result set rows */
1178 ret = sqlite3_step (stmt);
1179 if (ret == SQLITE_DONE)
1180 break; /* end of result set */
1181 if (ret == SQLITE_ROW)
1182 {
1183 int ok_name = 0;
1184 int ok_srid = 0;
1185 int ok_z = 0;
1186 int ok_spatial = 0;
1187 int ok_allow_coincident = 0;
1188 if (sqlite3_column_type (stmt, 0) == SQLITE_TEXT)
1189 {
1190 const char *str =
1191 (const char *) sqlite3_column_text (stmt, 0);
1192 if (xnetwork_name != NULL)
1193 free (xnetwork_name);
1194 xnetwork_name = malloc (strlen (str) + 1);
1195 strcpy (xnetwork_name, str);
1196 ok_name = 1;
1197 }
1198 if (sqlite3_column_type (stmt, 1) == SQLITE_INTEGER)
1199 {
1200 xspatial = sqlite3_column_int (stmt, 1);
1201 ok_spatial = 1;
1202 }
1203 if (sqlite3_column_type (stmt, 2) == SQLITE_INTEGER)
1204 {
1205 xsrid = sqlite3_column_int (stmt, 2);
1206 ok_srid = 1;
1207 }
1208 if (sqlite3_column_type (stmt, 3) == SQLITE_INTEGER)
1209 {
1210 xhas_z = sqlite3_column_int (stmt, 3);
1211 ok_z = 1;
1212 }
1213 if (sqlite3_column_type (stmt, 4) == SQLITE_INTEGER)
1214 {
1215 xallow_coincident = sqlite3_column_int (stmt, 4);
1216 ok_allow_coincident = 1;
1217 }
1218 if (ok_name && ok_spatial && ok_srid && ok_z
1219 && ok_allow_coincident)
1220 {
1221 ok = 1;
1222 break;
1223 }
1224 }
1225 else
1226 {
1227 spatialite_e
1228 ("step: SELECT FROM networks error: \"%s\"\n",
1229 sqlite3_errmsg (handle));
1230 sqlite3_finalize (stmt);
1231 return 0;
1232 }
1233 }
1234 sqlite3_finalize (stmt);
1235
1236 if (ok)
1237 {
1238 *network_name = xnetwork_name;
1239 *srid = xsrid;
1240 *has_z = xhas_z;
1241 *spatial = xspatial;
1242 *allow_coincident = xallow_coincident;
1243 return 1;
1244 }
1245
1246 if (xnetwork_name != NULL)
1247 free (xnetwork_name);
1248 return 0;
1249 }
1250
1251 GAIANET_DECLARE GaiaNetworkAccessorPtr
gaiaGetNetwork(sqlite3 * handle,const void * cache,const char * network_name)1252 gaiaGetNetwork (sqlite3 * handle, const void *cache, const char *network_name)
1253 {
1254 /* attempting to get a reference to some Network Accessor Object */
1255 GaiaNetworkAccessorPtr accessor;
1256
1257 /* attempting to retrieve an alredy cached definition */
1258 accessor = gaiaNetworkFromCache (cache, network_name);
1259 if (accessor != NULL)
1260 return accessor;
1261
1262 /* attempting to create a new Network Accessor */
1263 accessor = gaiaNetworkFromDBMS (handle, cache, network_name);
1264 return accessor;
1265 }
1266
1267 GAIANET_DECLARE GaiaNetworkAccessorPtr
gaiaNetworkFromCache(const void * p_cache,const char * network_name)1268 gaiaNetworkFromCache (const void *p_cache, const char *network_name)
1269 {
1270 /* attempting to retrieve an already defined Network Accessor Object from the Connection Cache */
1271 struct gaia_network *ptr;
1272 struct splite_internal_cache *cache =
1273 (struct splite_internal_cache *) p_cache;
1274 if (cache == 0)
1275 return NULL;
1276
1277 ptr = (struct gaia_network *) (cache->firstNetwork);
1278 while (ptr != NULL)
1279 {
1280 /* checking for an already registered Network */
1281 if (strcasecmp (network_name, ptr->network_name) == 0)
1282 return (GaiaNetworkAccessorPtr) ptr;
1283 ptr = ptr->next;
1284 }
1285 return NULL;
1286 }
1287
1288 GAIANET_DECLARE int
gaiaReadNetworkFromDBMS(sqlite3 * handle,const char * net_name,char ** network_name,int * spatial,int * srid,int * has_z,int * allow_coincident)1289 gaiaReadNetworkFromDBMS (sqlite3 *
1290 handle,
1291 const char
1292 *net_name, char **network_name, int *spatial,
1293 int *srid, int *has_z, int *allow_coincident)
1294 {
1295 /* testing for existing DBMS objects */
1296 if (!check_existing_network (handle, net_name, 1))
1297 return 0;
1298
1299 /* retrieving the Network configuration */
1300 if (!do_get_network
1301 (handle, net_name, network_name, spatial, srid, has_z,
1302 allow_coincident))
1303 return 0;
1304 return 1;
1305 }
1306
1307 GAIANET_DECLARE GaiaNetworkAccessorPtr
gaiaNetworkFromDBMS(sqlite3 * handle,const void * p_cache,const char * network_name)1308 gaiaNetworkFromDBMS (sqlite3 * handle, const void *p_cache,
1309 const char *network_name)
1310 {
1311 /* attempting to create a Network Accessor Object into the Connection Cache */
1312 const RTCTX *ctx = NULL;
1313 LWN_BE_CALLBACKS *callbacks;
1314 struct gaia_network *ptr;
1315 struct splite_internal_cache *cache =
1316 (struct splite_internal_cache *) p_cache;
1317 if (cache == 0)
1318 return NULL;
1319 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1320 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1321 return NULL;
1322 ctx = cache->RTTOPO_handle;
1323 if (ctx == NULL)
1324 return NULL;
1325
1326 /* allocating and initializing the opaque object */
1327 ptr = malloc (sizeof (struct gaia_network));
1328 ptr->db_handle = handle;
1329 ptr->cache = cache;
1330 ptr->network_name = NULL;
1331 ptr->srid = -1;
1332 ptr->has_z = 0;
1333 ptr->spatial = 0;
1334 ptr->allow_coincident = 0;
1335 ptr->last_error_message = NULL;
1336 ptr->lwn_iface = lwn_CreateBackendIface (ctx, (const LWN_BE_DATA *) ptr);
1337 ptr->prev = cache->lastNetwork;
1338 ptr->next = NULL;
1339
1340 callbacks = malloc (sizeof (LWN_BE_CALLBACKS));
1341 callbacks->netGetSRID = netcallback_netGetSRID;
1342 callbacks->netHasZ = netcallback_netHasZ;
1343 callbacks->netIsSpatial = netcallback_netIsSpatial;
1344 callbacks->netAllowCoincident = netcallback_netAllowCoincident;
1345 callbacks->netGetGEOS = netcallback_netGetGEOS;
1346 callbacks->createNetwork = NULL;
1347 callbacks->loadNetworkByName = netcallback_loadNetworkByName;
1348 callbacks->freeNetwork = netcallback_freeNetwork;
1349 callbacks->getNetNodeWithinDistance2D =
1350 netcallback_getNetNodeWithinDistance2D;
1351 callbacks->getLinkWithinDistance2D = netcallback_getLinkWithinDistance2D;
1352 callbacks->insertNetNodes = netcallback_insertNetNodes;
1353 callbacks->getNetNodeById = netcallback_getNetNodeById;
1354 callbacks->updateNetNodesById = netcallback_updateNetNodesById;
1355 callbacks->deleteNetNodesById = netcallback_deleteNetNodesById;
1356 callbacks->getLinkByNetNode = netcallback_getLinkByNetNode;
1357 callbacks->getNextLinkId = netcallback_getNextLinkId;
1358 callbacks->getNetNodeWithinBox2D = netcallback_getNetNodeWithinBox2D;
1359 callbacks->getNextLinkId = netcallback_getNextLinkId;
1360 callbacks->insertLinks = netcallback_insertLinks;
1361 callbacks->updateLinksById = netcallback_updateLinksById;
1362 callbacks->getLinkById = netcallback_getLinkById;
1363 callbacks->deleteLinksById = netcallback_deleteLinksById;
1364 ptr->callbacks = callbacks;
1365
1366 lwn_BackendIfaceRegisterCallbacks (ptr->lwn_iface, callbacks);
1367 ptr->lwn_network = lwn_LoadNetwork (ptr->lwn_iface, network_name);
1368
1369 ptr->stmt_getNetNodeWithinDistance2D = NULL;
1370 ptr->stmt_getLinkWithinDistance2D = NULL;
1371 ptr->stmt_insertNetNodes = NULL;
1372 ptr->stmt_deleteNetNodesById = NULL;
1373 ptr->stmt_getNetNodeWithinBox2D = NULL;
1374 ptr->stmt_getNextLinkId = NULL;
1375 ptr->stmt_setNextLinkId = NULL;
1376 ptr->stmt_insertLinks = NULL;
1377 ptr->stmt_deleteLinksById = NULL;
1378 if (ptr->lwn_network == NULL)
1379 goto invalid;
1380
1381 /* creating the SQL prepared statements */
1382 create_toponet_prepared_stmts ((GaiaNetworkAccessorPtr) ptr);
1383 return (GaiaNetworkAccessorPtr) ptr;
1384
1385 invalid:
1386 gaiaNetworkDestroy ((GaiaNetworkAccessorPtr) ptr);
1387 return NULL;
1388 }
1389
1390 GAIANET_DECLARE void
gaiaNetworkDestroy(GaiaNetworkAccessorPtr net_ptr)1391 gaiaNetworkDestroy (GaiaNetworkAccessorPtr net_ptr)
1392 {
1393 /* destroying a Network Accessor Object */
1394 struct gaia_network *prev;
1395 struct gaia_network *next;
1396 struct splite_internal_cache *cache;
1397 struct gaia_network *ptr = (struct gaia_network *) net_ptr;
1398 if (ptr == NULL)
1399 return;
1400
1401 prev = ptr->prev;
1402 next = ptr->next;
1403 cache = (struct splite_internal_cache *) (ptr->cache);
1404 if (ptr->lwn_network != NULL)
1405 lwn_FreeNetwork ((LWN_NETWORK *) (ptr->lwn_network));
1406 if (ptr->lwn_iface != NULL)
1407 lwn_FreeBackendIface ((LWN_BE_IFACE *) (ptr->lwn_iface));
1408 if (ptr->callbacks != NULL)
1409 free (ptr->callbacks);
1410 if (ptr->network_name != NULL)
1411 free (ptr->network_name);
1412 if (ptr->last_error_message != NULL)
1413 free (ptr->last_error_message);
1414
1415 finalize_toponet_prepared_stmts (net_ptr);
1416 free (ptr);
1417
1418 /* unregistering from the Internal Cache double linked list */
1419 if (prev != NULL)
1420 prev->next = next;
1421 if (next != NULL)
1422 next->prev = prev;
1423 if (cache->firstNetwork == ptr)
1424 cache->firstNetwork = next;
1425 if (cache->lastNetwork == ptr)
1426 cache->lastNetwork = prev;
1427 }
1428
1429 NETWORK_PRIVATE void
finalize_toponet_prepared_stmts(GaiaNetworkAccessorPtr accessor)1430 finalize_toponet_prepared_stmts (GaiaNetworkAccessorPtr accessor)
1431 {
1432 /* finalizing the SQL prepared statements */
1433 struct gaia_network *ptr = (struct gaia_network *) accessor;
1434 if (ptr->stmt_getNetNodeWithinDistance2D != NULL)
1435 sqlite3_finalize (ptr->stmt_getNetNodeWithinDistance2D);
1436 if (ptr->stmt_getLinkWithinDistance2D != NULL)
1437 sqlite3_finalize (ptr->stmt_getLinkWithinDistance2D);
1438 if (ptr->stmt_insertNetNodes != NULL)
1439 sqlite3_finalize (ptr->stmt_insertNetNodes);
1440 if (ptr->stmt_deleteNetNodesById != NULL)
1441 sqlite3_finalize (ptr->stmt_deleteNetNodesById);
1442 if (ptr->stmt_getNetNodeWithinBox2D != NULL)
1443 sqlite3_finalize (ptr->stmt_getNetNodeWithinBox2D);
1444 if (ptr->stmt_getNextLinkId != NULL)
1445 sqlite3_finalize (ptr->stmt_getNextLinkId);
1446 if (ptr->stmt_setNextLinkId != NULL)
1447 sqlite3_finalize (ptr->stmt_setNextLinkId);
1448 if (ptr->stmt_insertLinks != NULL)
1449 sqlite3_finalize (ptr->stmt_insertLinks);
1450 if (ptr->stmt_deleteLinksById != NULL)
1451 sqlite3_finalize (ptr->stmt_deleteLinksById);
1452 ptr->stmt_getNetNodeWithinDistance2D = NULL;
1453 ptr->stmt_getLinkWithinDistance2D = NULL;
1454 ptr->stmt_insertNetNodes = NULL;
1455 ptr->stmt_deleteNetNodesById = NULL;
1456 ptr->stmt_getNetNodeWithinBox2D = NULL;
1457 ptr->stmt_getNextLinkId = NULL;
1458 ptr->stmt_setNextLinkId = NULL;
1459 ptr->stmt_insertLinks = NULL;
1460 ptr->stmt_deleteLinksById = NULL;
1461 }
1462
1463 NETWORK_PRIVATE void
create_toponet_prepared_stmts(GaiaNetworkAccessorPtr accessor)1464 create_toponet_prepared_stmts (GaiaNetworkAccessorPtr accessor)
1465 {
1466 /* creating the SQL prepared statements */
1467 struct gaia_network *ptr = (struct gaia_network *) accessor;
1468 finalize_toponet_prepared_stmts (accessor);
1469 ptr->stmt_getNetNodeWithinDistance2D =
1470 do_create_stmt_getNetNodeWithinDistance2D (accessor);
1471 ptr->stmt_getLinkWithinDistance2D =
1472 do_create_stmt_getLinkWithinDistance2D (accessor);
1473 ptr->stmt_deleteNetNodesById = do_create_stmt_deleteNetNodesById (accessor);
1474 ptr->stmt_insertNetNodes = do_create_stmt_insertNetNodes (accessor);
1475 ptr->stmt_getNetNodeWithinBox2D =
1476 do_create_stmt_getNetNodeWithinBox2D (accessor);
1477 ptr->stmt_getNextLinkId = do_create_stmt_getNextLinkId (accessor);
1478 ptr->stmt_setNextLinkId = do_create_stmt_setNextLinkId (accessor);
1479 ptr->stmt_insertLinks = do_create_stmt_insertLinks (accessor);
1480 ptr->stmt_deleteLinksById = do_create_stmt_deleteLinksById (accessor);
1481 }
1482
1483 NETWORK_PRIVATE void
gaianet_reset_last_error_msg(GaiaNetworkAccessorPtr accessor)1484 gaianet_reset_last_error_msg (GaiaNetworkAccessorPtr accessor)
1485 {
1486 /* resets the last Network error message */
1487 struct gaia_network *net = (struct gaia_network *) accessor;
1488 if (net == NULL)
1489 return;
1490
1491 if (net->last_error_message != NULL)
1492 free (net->last_error_message);
1493 net->last_error_message = NULL;
1494 }
1495
1496 NETWORK_PRIVATE void
gaianet_set_last_error_msg(GaiaNetworkAccessorPtr accessor,const char * msg)1497 gaianet_set_last_error_msg (GaiaNetworkAccessorPtr accessor, const char *msg)
1498 {
1499 /* sets the last Network error message */
1500 int len;
1501 struct gaia_network *net = (struct gaia_network *) accessor;
1502 if (msg == NULL)
1503 msg = "no message available";
1504
1505 spatialite_e ("%s\n", msg);
1506 if (net == NULL)
1507 return;
1508
1509 if (net->last_error_message != NULL)
1510 return;
1511
1512 len = strlen (msg);
1513 net->last_error_message = malloc (len + 1);
1514 strcpy (net->last_error_message, msg);
1515 }
1516
1517 NETWORK_PRIVATE const char *
gaianet_get_last_exception(GaiaNetworkAccessorPtr accessor)1518 gaianet_get_last_exception (GaiaNetworkAccessorPtr accessor)
1519 {
1520 /* returns the last Network error message */
1521 struct gaia_network *net = (struct gaia_network *) accessor;
1522 if (net == NULL)
1523 return NULL;
1524
1525 return net->last_error_message;
1526 }
1527
1528 GAIANET_DECLARE int
gaiaNetworkDrop(sqlite3 * handle,const char * network_name)1529 gaiaNetworkDrop (sqlite3 * handle, const char *network_name)
1530 {
1531 /* attempting to drop an already existing Network */
1532 int ret;
1533 char *sql;
1534
1535 /* creating the Networks table (just in case) */
1536 if (!do_create_networks (handle))
1537 return 0;
1538
1539 /* testing for existing DBMS objects */
1540 if (!check_existing_network (handle, network_name, 0))
1541 return 0;
1542
1543 /* dropping the Network own Tables */
1544 if (!do_drop_network_table (handle, network_name, "seeds"))
1545 goto error;
1546 if (!do_drop_network_table (handle, network_name, "link"))
1547 goto error;
1548 if (!do_drop_network_table (handle, network_name, "node"))
1549 goto error;
1550
1551 /* unregistering the Network */
1552 sql =
1553 sqlite3_mprintf
1554 ("DELETE FROM MAIN.networks WHERE Lower(network_name) = Lower(%Q)",
1555 network_name);
1556 ret = sqlite3_exec (handle, sql, NULL, NULL, NULL);
1557 sqlite3_free (sql);
1558 if (ret != SQLITE_OK)
1559 goto error;
1560
1561 return 1;
1562
1563 error:
1564 return 0;
1565 }
1566
1567 GAIANET_DECLARE sqlite3_int64
gaiaAddIsoNetNode(GaiaNetworkAccessorPtr accessor,gaiaPointPtr pt)1568 gaiaAddIsoNetNode (GaiaNetworkAccessorPtr accessor, gaiaPointPtr pt)
1569 {
1570 /* LWN wrapper - AddIsoNetNode */
1571 sqlite3_int64 ret;
1572 LWN_POINT *point = NULL;
1573 struct gaia_network *network = (struct gaia_network *) accessor;
1574 if (network == NULL)
1575 return 0;
1576
1577 if (pt != NULL)
1578 {
1579 if (pt->DimensionModel == GAIA_XY_Z
1580 || pt->DimensionModel == GAIA_XY_Z_M)
1581 point = lwn_create_point3d (network->srid, pt->X, pt->Y, pt->Z);
1582 else
1583 point = lwn_create_point2d (network->srid, pt->X, pt->Y);
1584 }
1585 lwn_ResetErrorMsg (network->lwn_iface);
1586 ret = lwn_AddIsoNetNode ((LWN_NETWORK *) (network->lwn_network), point);
1587 lwn_free_point (point);
1588
1589 return ret;
1590 }
1591
1592 GAIANET_DECLARE int
gaiaMoveIsoNetNode(GaiaNetworkAccessorPtr accessor,sqlite3_int64 node,gaiaPointPtr pt)1593 gaiaMoveIsoNetNode (GaiaNetworkAccessorPtr accessor,
1594 sqlite3_int64 node, gaiaPointPtr pt)
1595 {
1596 /* LWN wrapper - MoveIsoNetNode */
1597 int ret;
1598 LWN_POINT *point = NULL;
1599 struct gaia_network *network = (struct gaia_network *) accessor;
1600 if (network == NULL)
1601 return 0;
1602
1603 if (pt != NULL)
1604 {
1605 if (pt->DimensionModel == GAIA_XY_Z
1606 || pt->DimensionModel == GAIA_XY_Z_M)
1607 point = lwn_create_point3d (network->srid, pt->X, pt->Y, pt->Z);
1608 else
1609 point = lwn_create_point2d (network->srid, pt->X, pt->Y);
1610 }
1611 lwn_ResetErrorMsg (network->lwn_iface);
1612 ret =
1613 lwn_MoveIsoNetNode ((LWN_NETWORK *) (network->lwn_network), node,
1614 point);
1615 lwn_free_point (point);
1616
1617 if (ret == 0)
1618 return 1;
1619 return 0;
1620 }
1621
1622 GAIANET_DECLARE int
gaiaRemIsoNetNode(GaiaNetworkAccessorPtr accessor,sqlite3_int64 node)1623 gaiaRemIsoNetNode (GaiaNetworkAccessorPtr accessor, sqlite3_int64 node)
1624 {
1625 /* LWN wrapper - RemIsoNetNode */
1626 int ret;
1627 struct gaia_network *network = (struct gaia_network *) accessor;
1628 if (network == NULL)
1629 return 0;
1630
1631 lwn_ResetErrorMsg (network->lwn_iface);
1632 ret = lwn_RemIsoNetNode ((LWN_NETWORK *) (network->lwn_network), node);
1633
1634 if (ret == 0)
1635 return 1;
1636 return 0;
1637 }
1638
1639 GAIANET_DECLARE sqlite3_int64
gaiaAddLink(GaiaNetworkAccessorPtr accessor,sqlite3_int64 start_node,sqlite3_int64 end_node,gaiaLinestringPtr ln)1640 gaiaAddLink (GaiaNetworkAccessorPtr accessor,
1641 sqlite3_int64 start_node, sqlite3_int64 end_node,
1642 gaiaLinestringPtr ln)
1643 {
1644 /* LWN wrapper - AddLink */
1645 sqlite3_int64 ret;
1646 LWN_LINE *lwn_line = NULL;
1647 struct gaia_network *network = (struct gaia_network *) accessor;
1648 if (network == NULL)
1649 return 0;
1650
1651 if (ln != NULL)
1652 {
1653 lwn_line =
1654 gaianet_convert_linestring_to_lwnline (ln, network->srid,
1655 network->has_z);
1656 }
1657
1658 lwn_ResetErrorMsg (network->lwn_iface);
1659 ret =
1660 lwn_AddLink ((LWN_NETWORK *) (network->lwn_network), start_node,
1661 end_node, lwn_line);
1662
1663 lwn_free_line (lwn_line);
1664 return ret;
1665 }
1666
1667 GAIANET_DECLARE int
gaiaChangeLinkGeom(GaiaNetworkAccessorPtr accessor,sqlite3_int64 link_id,gaiaLinestringPtr ln)1668 gaiaChangeLinkGeom (GaiaNetworkAccessorPtr accessor,
1669 sqlite3_int64 link_id, gaiaLinestringPtr ln)
1670 {
1671 /* LWN wrapper - ChangeLinkGeom */
1672 int ret;
1673 LWN_LINE *lwn_line = NULL;
1674 struct gaia_network *network = (struct gaia_network *) accessor;
1675 if (network == NULL)
1676 return 0;
1677
1678 if (ln != NULL)
1679 {
1680 lwn_line =
1681 gaianet_convert_linestring_to_lwnline (ln, network->srid,
1682 network->has_z);
1683 }
1684
1685 lwn_ResetErrorMsg (network->lwn_iface);
1686 ret =
1687 lwn_ChangeLinkGeom ((LWN_NETWORK *) (network->lwn_network), link_id,
1688 lwn_line);
1689 lwn_free_line (lwn_line);
1690
1691 if (ret == 0)
1692 return 1;
1693 return 0;
1694 }
1695
1696 GAIANET_DECLARE int
gaiaRemoveLink(GaiaNetworkAccessorPtr accessor,sqlite3_int64 link)1697 gaiaRemoveLink (GaiaNetworkAccessorPtr accessor, sqlite3_int64 link)
1698 {
1699 /* LWN wrapper - RemoveLink */
1700 int ret;
1701 struct gaia_network *network = (struct gaia_network *) accessor;
1702 if (network == NULL)
1703 return 0;
1704
1705 lwn_ResetErrorMsg (network->lwn_iface);
1706 ret = lwn_RemoveLink ((LWN_NETWORK *) (network->lwn_network), link);
1707
1708 if (ret == 0)
1709 return 1;
1710 return 0;
1711 }
1712
1713 GAIANET_DECLARE sqlite3_int64
gaiaNewLogLinkSplit(GaiaNetworkAccessorPtr accessor,sqlite3_int64 link)1714 gaiaNewLogLinkSplit (GaiaNetworkAccessorPtr accessor, sqlite3_int64 link)
1715 {
1716 /* LWN wrapper - NewLogLinkSplit */
1717 sqlite3_int64 ret;
1718 struct gaia_network *network = (struct gaia_network *) accessor;
1719 if (network == NULL)
1720 return 0;
1721
1722 lwn_ResetErrorMsg (network->lwn_iface);
1723 ret = lwn_NewLogLinkSplit ((LWN_NETWORK *) (network->lwn_network), link);
1724 return ret;
1725 }
1726
1727 GAIANET_DECLARE sqlite3_int64
gaiaModLogLinkSplit(GaiaNetworkAccessorPtr accessor,sqlite3_int64 link)1728 gaiaModLogLinkSplit (GaiaNetworkAccessorPtr accessor, sqlite3_int64 link)
1729 {
1730 /* LWN wrapper - ModLogLinkSplit */
1731 sqlite3_int64 ret;
1732 struct gaia_network *network = (struct gaia_network *) accessor;
1733 if (network == NULL)
1734 return 0;
1735
1736 lwn_ResetErrorMsg (network->lwn_iface);
1737 ret = lwn_ModLogLinkSplit ((LWN_NETWORK *) (network->lwn_network), link);
1738 return ret;
1739 }
1740
1741 GAIANET_DECLARE sqlite3_int64
gaiaNewGeoLinkSplit(GaiaNetworkAccessorPtr accessor,sqlite3_int64 link,gaiaPointPtr pt)1742 gaiaNewGeoLinkSplit (GaiaNetworkAccessorPtr accessor, sqlite3_int64 link,
1743 gaiaPointPtr pt)
1744 {
1745 /* LWN wrapper - NewGeoLinkSplit */
1746 sqlite3_int64 ret;
1747 LWN_POINT *point = NULL;
1748 struct gaia_network *network = (struct gaia_network *) accessor;
1749 if (network == NULL)
1750 return 0;
1751
1752 if (pt != NULL)
1753 {
1754 if (pt->DimensionModel == GAIA_XY_Z
1755 || pt->DimensionModel == GAIA_XY_Z_M)
1756 point = lwn_create_point3d (network->srid, pt->X, pt->Y, pt->Z);
1757 else
1758 point = lwn_create_point2d (network->srid, pt->X, pt->Y);
1759 }
1760 lwn_ResetErrorMsg (network->lwn_iface);
1761 ret =
1762 lwn_NewGeoLinkSplit ((LWN_NETWORK *) (network->lwn_network), link,
1763 point);
1764 lwn_free_point (point);
1765 return ret;
1766 }
1767
1768 GAIANET_DECLARE sqlite3_int64
gaiaModGeoLinkSplit(GaiaNetworkAccessorPtr accessor,sqlite3_int64 link,gaiaPointPtr pt)1769 gaiaModGeoLinkSplit (GaiaNetworkAccessorPtr accessor, sqlite3_int64 link,
1770 gaiaPointPtr pt)
1771 {
1772 /* LWN wrapper - ModGeoLinkSplit */
1773 sqlite3_int64 ret;
1774 LWN_POINT *point = NULL;
1775 struct gaia_network *network = (struct gaia_network *) accessor;
1776 if (network == NULL)
1777 return 0;
1778
1779 if (pt != NULL)
1780 {
1781 if (pt->DimensionModel == GAIA_XY_Z
1782 || pt->DimensionModel == GAIA_XY_Z_M)
1783 point = lwn_create_point3d (network->srid, pt->X, pt->Y, pt->Z);
1784 else
1785 point = lwn_create_point2d (network->srid, pt->X, pt->Y);
1786 }
1787 lwn_ResetErrorMsg (network->lwn_iface);
1788 ret =
1789 lwn_ModGeoLinkSplit ((LWN_NETWORK *) (network->lwn_network), link,
1790 point);
1791 lwn_free_point (point);
1792 return ret;
1793 }
1794
1795 GAIANET_DECLARE sqlite3_int64
gaiaNewLinkHeal(GaiaNetworkAccessorPtr accessor,sqlite3_int64 link,sqlite3_int64 anotherlink)1796 gaiaNewLinkHeal (GaiaNetworkAccessorPtr accessor, sqlite3_int64 link,
1797 sqlite3_int64 anotherlink)
1798 {
1799 /* LWN wrapper - NewLinkHeal */
1800 sqlite3_int64 ret;
1801 struct gaia_network *network = (struct gaia_network *) accessor;
1802 if (network == NULL)
1803 return 0;
1804
1805 lwn_ResetErrorMsg (network->lwn_iface);
1806 ret =
1807 lwn_NewLinkHeal ((LWN_NETWORK *) (network->lwn_network), link,
1808 anotherlink);
1809
1810 return ret;
1811 }
1812
1813 GAIANET_DECLARE sqlite3_int64
gaiaModLinkHeal(GaiaNetworkAccessorPtr accessor,sqlite3_int64 link,sqlite3_int64 anotherlink)1814 gaiaModLinkHeal (GaiaNetworkAccessorPtr accessor, sqlite3_int64 link,
1815 sqlite3_int64 anotherlink)
1816 {
1817 /* LWN wrapper - ModLinkHeal */
1818 sqlite3_int64 ret;
1819 struct gaia_network *network = (struct gaia_network *) accessor;
1820 if (network == NULL)
1821 return 0;
1822
1823 lwn_ResetErrorMsg (network->lwn_iface);
1824 ret =
1825 lwn_ModLinkHeal ((LWN_NETWORK *) (network->lwn_network), link,
1826 anotherlink);
1827
1828 return ret;
1829 }
1830
1831 GAIANET_DECLARE sqlite3_int64
gaiaGetNetNodeByPoint(GaiaNetworkAccessorPtr accessor,gaiaPointPtr pt,double tolerance)1832 gaiaGetNetNodeByPoint (GaiaNetworkAccessorPtr accessor, gaiaPointPtr pt,
1833 double tolerance)
1834 {
1835 /* LWN wrapper - GetNetNodeByPoint */
1836 sqlite3_int64 ret;
1837 LWN_POINT *point = NULL;
1838 struct gaia_network *network = (struct gaia_network *) accessor;
1839 if (network == NULL)
1840 return 0;
1841
1842 if (pt != NULL)
1843 {
1844 if (pt->DimensionModel == GAIA_XY_Z
1845 || pt->DimensionModel == GAIA_XY_Z_M)
1846 point = lwn_create_point3d (network->srid, pt->X, pt->Y, pt->Z);
1847 else
1848 point = lwn_create_point2d (network->srid, pt->X, pt->Y);
1849 }
1850 lwn_ResetErrorMsg (network->lwn_iface);
1851
1852 ret =
1853 lwn_GetNetNodeByPoint ((LWN_NETWORK *) (network->lwn_network), point,
1854 tolerance);
1855
1856 lwn_free_point (point);
1857 return ret;
1858 }
1859
1860 GAIANET_DECLARE sqlite3_int64
gaiaGetLinkByPoint(GaiaNetworkAccessorPtr accessor,gaiaPointPtr pt,double tolerance)1861 gaiaGetLinkByPoint (GaiaNetworkAccessorPtr accessor, gaiaPointPtr pt,
1862 double tolerance)
1863 {
1864 /* LWN wrapper - GetLinkByPoint */
1865 sqlite3_int64 ret;
1866 LWN_POINT *point = NULL;
1867 struct gaia_network *network = (struct gaia_network *) accessor;
1868 if (network == NULL)
1869 return 0;
1870
1871 if (pt != NULL)
1872 {
1873 if (pt->DimensionModel == GAIA_XY_Z
1874 || pt->DimensionModel == GAIA_XY_Z_M)
1875 point = lwn_create_point3d (network->srid, pt->X, pt->Y, pt->Z);
1876 else
1877 point = lwn_create_point2d (network->srid, pt->X, pt->Y);
1878 }
1879 lwn_ResetErrorMsg (network->lwn_iface);
1880
1881 ret =
1882 lwn_GetLinkByPoint ((LWN_NETWORK *) (network->lwn_network), point,
1883 tolerance);
1884
1885 lwn_free_point (point);
1886 return ret;
1887 }
1888
1889 static int
do_check_create_valid_logicalnet_table(GaiaNetworkAccessorPtr accessor)1890 do_check_create_valid_logicalnet_table (GaiaNetworkAccessorPtr accessor)
1891 {
1892 /* attemtping to create or validate the target table */
1893 char *sql;
1894 char *table;
1895 char *xtable;
1896 int ret;
1897 char *errMsg = NULL;
1898 struct gaia_network *net = (struct gaia_network *) accessor;
1899
1900 /* finalizing all prepared Statements */
1901 finalize_all_topo_prepared_stmts (net->cache);
1902
1903 /* attempting to drop the table (just in case if it already exists) */
1904 table = sqlite3_mprintf ("%s_valid_logicalnet", net->network_name);
1905 xtable = gaiaDoubleQuotedSql (table);
1906 sqlite3_free (table);
1907 sql = sqlite3_mprintf ("DROP TABLE IF EXISTS TEMP.\"%s\"", xtable);
1908 free (xtable);
1909 ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
1910 sqlite3_free (sql);
1911 create_all_topo_prepared_stmts (net->cache); /* recreating prepared stsms */
1912 if (ret != SQLITE_OK)
1913 {
1914 char *msg =
1915 sqlite3_mprintf ("ST_ValidLogicalNet exception: %s", errMsg);
1916 gaianet_set_last_error_msg (accessor, msg);
1917 sqlite3_free (msg);
1918 sqlite3_free (errMsg);
1919 return 0;
1920 }
1921
1922 /* attempting to create the table */
1923 table = sqlite3_mprintf ("%s_valid_logicalnet", net->network_name);
1924 xtable = gaiaDoubleQuotedSql (table);
1925 sqlite3_free (table);
1926 sql =
1927 sqlite3_mprintf
1928 ("CREATE TEMP TABLE \"%s\" (\n\terror TEXT,\n"
1929 "\tprimitive1 INTEGER,\n\tprimitive2 INTEGER)", xtable);
1930 free (xtable);
1931 ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
1932 sqlite3_free (sql);
1933 if (ret != SQLITE_OK)
1934 {
1935 char *msg =
1936 sqlite3_mprintf ("ST_ValidLogicalNet exception: %s", errMsg);
1937 gaianet_set_last_error_msg (accessor, msg);
1938 sqlite3_free (msg);
1939 sqlite3_free (errMsg);
1940 return 0;
1941 }
1942
1943 return 1;
1944 }
1945
1946 static int
do_loginet_check_nodes(GaiaNetworkAccessorPtr accessor,sqlite3_stmt * stmt)1947 do_loginet_check_nodes (GaiaNetworkAccessorPtr accessor, sqlite3_stmt * stmt)
1948 {
1949 /* checking for nodes with geometry */
1950 char *sql;
1951 char *table;
1952 char *xtable;
1953 int ret;
1954 sqlite3_stmt *stmt_in = NULL;
1955 struct gaia_network *net = (struct gaia_network *) accessor;
1956
1957 table = sqlite3_mprintf ("%s_node", net->network_name);
1958 xtable = gaiaDoubleQuotedSql (table);
1959 sqlite3_free (table);
1960 sql =
1961 sqlite3_mprintf
1962 ("SELECT node_id FROM MAIN.\"%s\" WHERE geometry IS NOT NULL", xtable);
1963 free (xtable);
1964 ret =
1965 sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_in, NULL);
1966 sqlite3_free (sql);
1967 if (ret != SQLITE_OK)
1968 {
1969 char *msg =
1970 sqlite3_mprintf ("ST_ValidLogicalNet() - Nodes error: \"%s\"",
1971 sqlite3_errmsg (net->db_handle));
1972 gaianet_set_last_error_msg (accessor, msg);
1973 sqlite3_free (msg);
1974 goto error;
1975 }
1976
1977 sqlite3_reset (stmt_in);
1978 sqlite3_clear_bindings (stmt_in);
1979 while (1)
1980 {
1981 /* scrolling the result set rows */
1982 ret = sqlite3_step (stmt_in);
1983 if (ret == SQLITE_DONE)
1984 break; /* end of result set */
1985 if (ret == SQLITE_ROW)
1986 {
1987 sqlite3_int64 node_id = sqlite3_column_int64 (stmt_in, 0);
1988 /* reporting the error */
1989 sqlite3_reset (stmt);
1990 sqlite3_clear_bindings (stmt);
1991 sqlite3_bind_text (stmt, 1, "node has geometry", -1,
1992 SQLITE_STATIC);
1993 sqlite3_bind_int64 (stmt, 2, node_id);
1994 sqlite3_bind_null (stmt, 3);
1995 ret = sqlite3_step (stmt);
1996 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
1997 ;
1998 else
1999 {
2000 char *msg =
2001 sqlite3_mprintf
2002 ("ST_ValidLogicalNet() insert error: \"%s\"",
2003 sqlite3_errmsg (net->db_handle));
2004 gaianet_set_last_error_msg (accessor, msg);
2005 sqlite3_free (msg);
2006 goto error;
2007 }
2008 }
2009 else
2010 {
2011 char *msg =
2012 sqlite3_mprintf
2013 ("ST_ValidLogicalNet() - Nodes step error: %s",
2014 sqlite3_errmsg (net->db_handle));
2015 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
2016 sqlite3_free (msg);
2017 goto error;
2018 }
2019 }
2020 sqlite3_finalize (stmt_in);
2021
2022 return 1;
2023
2024 error:
2025 if (stmt_in == NULL)
2026 sqlite3_finalize (stmt_in);
2027 return 0;
2028 }
2029
2030 static int
do_loginet_check_links(GaiaNetworkAccessorPtr accessor,sqlite3_stmt * stmt)2031 do_loginet_check_links (GaiaNetworkAccessorPtr accessor, sqlite3_stmt * stmt)
2032 {
2033 /* checking for links with geometry */
2034 char *sql;
2035 char *table;
2036 char *xtable;
2037 int ret;
2038 sqlite3_stmt *stmt_in = NULL;
2039 struct gaia_network *net = (struct gaia_network *) accessor;
2040
2041 table = sqlite3_mprintf ("%s_link", net->network_name);
2042 xtable = gaiaDoubleQuotedSql (table);
2043 sqlite3_free (table);
2044 sql =
2045 sqlite3_mprintf
2046 ("SELECT link_id FROM MAIN.\"%s\" WHERE geometry IS NOT NULL", xtable);
2047 free (xtable);
2048 ret =
2049 sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_in, NULL);
2050 sqlite3_free (sql);
2051 if (ret != SQLITE_OK)
2052 {
2053 char *msg =
2054 sqlite3_mprintf ("ST_ValidLogicalNet() - Links error: \"%s\"",
2055 sqlite3_errmsg (net->db_handle));
2056 gaianet_set_last_error_msg (accessor, msg);
2057 sqlite3_free (msg);
2058 goto error;
2059 }
2060
2061 sqlite3_reset (stmt_in);
2062 sqlite3_clear_bindings (stmt_in);
2063 while (1)
2064 {
2065 /* scrolling the result set rows */
2066 ret = sqlite3_step (stmt_in);
2067 if (ret == SQLITE_DONE)
2068 break; /* end of result set */
2069 if (ret == SQLITE_ROW)
2070 {
2071 sqlite3_int64 link_id = sqlite3_column_int64 (stmt_in, 0);
2072 /* reporting the error */
2073 sqlite3_reset (stmt);
2074 sqlite3_clear_bindings (stmt);
2075 sqlite3_bind_text (stmt, 1, "link has geometry", -1,
2076 SQLITE_STATIC);
2077 sqlite3_bind_int64 (stmt, 2, link_id);
2078 sqlite3_bind_null (stmt, 3);
2079 ret = sqlite3_step (stmt);
2080 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
2081 ;
2082 else
2083 {
2084 char *msg =
2085 sqlite3_mprintf
2086 ("ST_ValidLogicalNet() insert error: \"%s\"",
2087 sqlite3_errmsg (net->db_handle));
2088 gaianet_set_last_error_msg (accessor, msg);
2089 sqlite3_free (msg);
2090 goto error;
2091 }
2092 }
2093 else
2094 {
2095 char *msg =
2096 sqlite3_mprintf
2097 ("ST_ValidLogicalNet() - Links step error: %s",
2098 sqlite3_errmsg (net->db_handle));
2099 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
2100 sqlite3_free (msg);
2101 goto error;
2102 }
2103 }
2104 sqlite3_finalize (stmt_in);
2105
2106 return 1;
2107
2108 error:
2109 if (stmt_in == NULL)
2110 sqlite3_finalize (stmt_in);
2111 return 0;
2112 }
2113
2114 GAIANET_DECLARE int
gaiaValidLogicalNet(GaiaNetworkAccessorPtr accessor)2115 gaiaValidLogicalNet (GaiaNetworkAccessorPtr accessor)
2116 {
2117 /* generating a validity report for a given Logical Network */
2118 char *table;
2119 char *xtable;
2120 char *sql;
2121 int ret;
2122 sqlite3_stmt *stmt = NULL;
2123 struct gaia_network *net = (struct gaia_network *) accessor;
2124 if (net == NULL)
2125 return 0;
2126
2127 if (!do_check_create_valid_logicalnet_table (accessor))
2128 return 0;
2129
2130 table = sqlite3_mprintf ("%s_valid_logicalnet", net->network_name);
2131 xtable = gaiaDoubleQuotedSql (table);
2132 sqlite3_free (table);
2133 sql =
2134 sqlite3_mprintf
2135 ("INSERT INTO TEMP.\"%s\" (error, primitive1, primitive2) VALUES (?, ?, ?)",
2136 xtable);
2137 free (xtable);
2138 ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
2139 sqlite3_free (sql);
2140 if (ret != SQLITE_OK)
2141 {
2142 char *msg = sqlite3_mprintf ("ST_ValidLogicalNet error: \"%s\"",
2143 sqlite3_errmsg (net->db_handle));
2144 gaianet_set_last_error_msg (accessor, msg);
2145 sqlite3_free (msg);
2146 goto error;
2147 }
2148
2149 if (!do_loginet_check_nodes (accessor, stmt))
2150 goto error;
2151
2152 if (!do_loginet_check_links (accessor, stmt))
2153 goto error;
2154
2155 sqlite3_finalize (stmt);
2156 return 1;
2157
2158 error:
2159 if (stmt != NULL)
2160 sqlite3_finalize (stmt);
2161 return 0;
2162 }
2163
2164 static int
do_check_create_valid_spatialnet_table(GaiaNetworkAccessorPtr accessor)2165 do_check_create_valid_spatialnet_table (GaiaNetworkAccessorPtr accessor)
2166 {
2167 /* attemtping to create or validate the target table */
2168 char *sql;
2169 char *table;
2170 char *xtable;
2171 int ret;
2172 char *errMsg;
2173 struct gaia_network *net = (struct gaia_network *) accessor;
2174
2175 /* attempting to drop the table (just in case if it already exists) */
2176 table = sqlite3_mprintf ("%s_valid_spatialnet", net->network_name);
2177 xtable = gaiaDoubleQuotedSql (table);
2178 sqlite3_free (table);
2179 sql = sqlite3_mprintf ("DROP TABLE IF EXISTS temp.\"%s\"", xtable);
2180 free (xtable);
2181 ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
2182 sqlite3_free (sql);
2183 if (ret != SQLITE_OK)
2184 {
2185 char *msg =
2186 sqlite3_mprintf ("ST_ValidSpatialNet exception: %s", errMsg);
2187 gaianet_set_last_error_msg (accessor, msg);
2188 sqlite3_free (msg);
2189 sqlite3_free (errMsg);
2190 return 0;
2191 }
2192
2193 /* attempting to create the table */
2194 table = sqlite3_mprintf ("%s_valid_spatialnet", net->network_name);
2195 xtable = gaiaDoubleQuotedSql (table);
2196 sqlite3_free (table);
2197 sql =
2198 sqlite3_mprintf
2199 ("CREATE TEMP TABLE \"%s\" (\n\terror TEXT,\n"
2200 "\tprimitive1 INTEGER,\n\tprimitive2 INTEGER)", xtable);
2201 free (xtable);
2202 ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
2203 sqlite3_free (sql);
2204 if (ret != SQLITE_OK)
2205 {
2206 char *msg =
2207 sqlite3_mprintf ("ST_ValidSpatialNet exception: %s", errMsg);
2208 gaianet_set_last_error_msg (accessor, msg);
2209 sqlite3_free (msg);
2210 sqlite3_free (errMsg);
2211 return 0;
2212 }
2213
2214 return 1;
2215 }
2216
2217 static int
do_spatnet_check_nodes(GaiaNetworkAccessorPtr accessor,sqlite3_stmt * stmt)2218 do_spatnet_check_nodes (GaiaNetworkAccessorPtr accessor, sqlite3_stmt * stmt)
2219 {
2220 /* checking for nodes without geometry */
2221 char *sql;
2222 char *table;
2223 char *xtable;
2224 int ret;
2225 sqlite3_stmt *stmt_in = NULL;
2226 struct gaia_network *net = (struct gaia_network *) accessor;
2227
2228 table = sqlite3_mprintf ("%s_node", net->network_name);
2229 xtable = gaiaDoubleQuotedSql (table);
2230 sqlite3_free (table);
2231 sql =
2232 sqlite3_mprintf
2233 ("SELECT node_id FROM MAIN.\"%s\" WHERE geometry IS NULL", xtable);
2234 free (xtable);
2235 ret =
2236 sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_in, NULL);
2237 sqlite3_free (sql);
2238 if (ret != SQLITE_OK)
2239 {
2240 char *msg =
2241 sqlite3_mprintf ("ST_ValidSpatialNet() - Nodes error: \"%s\"",
2242 sqlite3_errmsg (net->db_handle));
2243 gaianet_set_last_error_msg (accessor, msg);
2244 sqlite3_free (msg);
2245 goto error;
2246 }
2247
2248 sqlite3_reset (stmt_in);
2249 sqlite3_clear_bindings (stmt_in);
2250 while (1)
2251 {
2252 /* scrolling the result set rows */
2253 ret = sqlite3_step (stmt_in);
2254 if (ret == SQLITE_DONE)
2255 break; /* end of result set */
2256 if (ret == SQLITE_ROW)
2257 {
2258 sqlite3_int64 node_id = sqlite3_column_int64 (stmt_in, 0);
2259 /* reporting the error */
2260 sqlite3_reset (stmt);
2261 sqlite3_clear_bindings (stmt);
2262 sqlite3_bind_text (stmt, 1, "missing node geometry", -1,
2263 SQLITE_STATIC);
2264 sqlite3_bind_int64 (stmt, 2, node_id);
2265 sqlite3_bind_null (stmt, 3);
2266 ret = sqlite3_step (stmt);
2267 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
2268 ;
2269 else
2270 {
2271 char *msg =
2272 sqlite3_mprintf
2273 ("ST_ValidSpatialNet() insert error: \"%s\"",
2274 sqlite3_errmsg (net->db_handle));
2275 gaianet_set_last_error_msg (accessor, msg);
2276 sqlite3_free (msg);
2277 goto error;
2278 }
2279 }
2280 else
2281 {
2282 char *msg =
2283 sqlite3_mprintf
2284 ("ST_ValidSpatialNet() - Nodes step error: %s",
2285 sqlite3_errmsg (net->db_handle));
2286 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
2287 sqlite3_free (msg);
2288 goto error;
2289 }
2290 }
2291 sqlite3_finalize (stmt_in);
2292
2293 return 1;
2294
2295 error:
2296 if (stmt_in == NULL)
2297 sqlite3_finalize (stmt_in);
2298 return 0;
2299 }
2300
2301 static int
do_spatnet_check_links(GaiaNetworkAccessorPtr accessor,sqlite3_stmt * stmt)2302 do_spatnet_check_links (GaiaNetworkAccessorPtr accessor, sqlite3_stmt * stmt)
2303 {
2304 /* checking for links without geometry */
2305 char *sql;
2306 char *table;
2307 char *xtable;
2308 int ret;
2309 sqlite3_stmt *stmt_in = NULL;
2310 struct gaia_network *net = (struct gaia_network *) accessor;
2311
2312 table = sqlite3_mprintf ("%s_link", net->network_name);
2313 xtable = gaiaDoubleQuotedSql (table);
2314 sqlite3_free (table);
2315 sql =
2316 sqlite3_mprintf
2317 ("SELECT link_id FROM MAIN.\"%s\" WHERE geometry IS NULL", xtable);
2318 free (xtable);
2319 ret =
2320 sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_in, NULL);
2321 sqlite3_free (sql);
2322 if (ret != SQLITE_OK)
2323 {
2324 char *msg =
2325 sqlite3_mprintf ("ST_ValidSpatialNet() - Links error: \"%s\"",
2326 sqlite3_errmsg (net->db_handle));
2327 gaianet_set_last_error_msg (accessor, msg);
2328 sqlite3_free (msg);
2329 goto error;
2330 }
2331
2332 sqlite3_reset (stmt_in);
2333 sqlite3_clear_bindings (stmt_in);
2334 while (1)
2335 {
2336 /* scrolling the result set rows */
2337 ret = sqlite3_step (stmt_in);
2338 if (ret == SQLITE_DONE)
2339 break; /* end of result set */
2340 if (ret == SQLITE_ROW)
2341 {
2342 sqlite3_int64 link_id = sqlite3_column_int64 (stmt_in, 0);
2343 /* reporting the error */
2344 sqlite3_reset (stmt);
2345 sqlite3_clear_bindings (stmt);
2346 sqlite3_bind_text (stmt, 1, "missing link geometry", -1,
2347 SQLITE_STATIC);
2348 sqlite3_bind_int64 (stmt, 2, link_id);
2349 sqlite3_bind_null (stmt, 3);
2350 ret = sqlite3_step (stmt);
2351 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
2352 ;
2353 else
2354 {
2355 char *msg =
2356 sqlite3_mprintf
2357 ("ST_ValidSpatialNet() insert error: \"%s\"",
2358 sqlite3_errmsg (net->db_handle));
2359 gaianet_set_last_error_msg (accessor, msg);
2360 sqlite3_free (msg);
2361 goto error;
2362 }
2363 }
2364 else
2365 {
2366 char *msg =
2367 sqlite3_mprintf
2368 ("ST_ValidSpatialNet() - Links step error: %s",
2369 sqlite3_errmsg (net->db_handle));
2370 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
2371 sqlite3_free (msg);
2372 goto error;
2373 }
2374 }
2375 sqlite3_finalize (stmt_in);
2376
2377 return 1;
2378
2379 error:
2380 if (stmt_in == NULL)
2381 sqlite3_finalize (stmt_in);
2382 return 0;
2383 }
2384
2385 static int
do_spatnet_check_start_nodes(GaiaNetworkAccessorPtr accessor,sqlite3_stmt * stmt)2386 do_spatnet_check_start_nodes (GaiaNetworkAccessorPtr accessor,
2387 sqlite3_stmt * stmt)
2388 {
2389 /* checking for links mismatching start nodes */
2390 char *sql;
2391 char *table;
2392 char *xtable1;
2393 char *xtable2;
2394 int ret;
2395 sqlite3_stmt *stmt_in = NULL;
2396 struct gaia_network *net = (struct gaia_network *) accessor;
2397
2398 table = sqlite3_mprintf ("%s_link", net->network_name);
2399 xtable1 = gaiaDoubleQuotedSql (table);
2400 sqlite3_free (table);
2401 table = sqlite3_mprintf ("%s_node", net->network_name);
2402 xtable2 = gaiaDoubleQuotedSql (table);
2403 sqlite3_free (table);
2404 sql =
2405 sqlite3_mprintf ("SELECT l.link_id, l.start_node FROM MAIN.\"%s\" AS l "
2406 "JOIN MAIN.\"%s\" AS n ON (l.start_node = n.node_id) "
2407 "WHERE ST_Disjoint(ST_StartPoint(l.geometry), n.geometry) = 1",
2408 xtable1, xtable2);
2409 free (xtable1);
2410 free (xtable2);
2411 ret =
2412 sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_in, NULL);
2413 sqlite3_free (sql);
2414 if (ret != SQLITE_OK)
2415 {
2416 char *msg =
2417 sqlite3_mprintf
2418 ("ST_ValidSpatialNet() - StartNodes error: \"%s\"",
2419 sqlite3_errmsg (net->db_handle));
2420 gaianet_set_last_error_msg (accessor, msg);
2421 sqlite3_free (msg);
2422 goto error;
2423 }
2424
2425 sqlite3_reset (stmt_in);
2426 sqlite3_clear_bindings (stmt_in);
2427 while (1)
2428 {
2429 /* scrolling the result set rows */
2430 ret = sqlite3_step (stmt_in);
2431 if (ret == SQLITE_DONE)
2432 break; /* end of result set */
2433 if (ret == SQLITE_ROW)
2434 {
2435 sqlite3_int64 link_id = sqlite3_column_int64 (stmt_in, 0);
2436 sqlite3_int64 node_id = sqlite3_column_int64 (stmt_in, 1);
2437 /* reporting the error */
2438 sqlite3_reset (stmt);
2439 sqlite3_clear_bindings (stmt);
2440 sqlite3_bind_text (stmt, 1, "geometry start mismatch", -1,
2441 SQLITE_STATIC);
2442 sqlite3_bind_int64 (stmt, 2, link_id);
2443 sqlite3_bind_int64 (stmt, 3, node_id);
2444 ret = sqlite3_step (stmt);
2445 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
2446 ;
2447 else
2448 {
2449 char *msg =
2450 sqlite3_mprintf
2451 ("ST_ValidSpatialNet() insert error: \"%s\"",
2452 sqlite3_errmsg (net->db_handle));
2453 gaianet_set_last_error_msg (accessor, msg);
2454 sqlite3_free (msg);
2455 goto error;
2456 }
2457 }
2458 else
2459 {
2460 char *msg =
2461 sqlite3_mprintf
2462 ("ST_ValidSpatialNet() - StartNodes step error: %s",
2463 sqlite3_errmsg (net->db_handle));
2464 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
2465 sqlite3_free (msg);
2466 goto error;
2467 }
2468 }
2469 sqlite3_finalize (stmt_in);
2470
2471 return 1;
2472
2473 error:
2474 if (stmt_in == NULL)
2475 sqlite3_finalize (stmt_in);
2476 return 0;
2477 }
2478
2479 static int
do_spatnet_check_end_nodes(GaiaNetworkAccessorPtr accessor,sqlite3_stmt * stmt)2480 do_spatnet_check_end_nodes (GaiaNetworkAccessorPtr accessor,
2481 sqlite3_stmt * stmt)
2482 {
2483 /* checking for links mismatching end nodes */
2484 char *sql;
2485 char *table;
2486 char *xtable1;
2487 char *xtable2;
2488 int ret;
2489 sqlite3_stmt *stmt_in = NULL;
2490 struct gaia_network *net = (struct gaia_network *) accessor;
2491
2492 table = sqlite3_mprintf ("%s_link", net->network_name);
2493 xtable1 = gaiaDoubleQuotedSql (table);
2494 sqlite3_free (table);
2495 table = sqlite3_mprintf ("%s_node", net->network_name);
2496 xtable2 = gaiaDoubleQuotedSql (table);
2497 sqlite3_free (table);
2498 sql = sqlite3_mprintf ("SELECT l.link_id, l.end_node FROM MAIN.\"%s\" AS l "
2499 "JOIN MAIN.\"%s\" AS n ON (l.end_node = n.node_id) "
2500 "WHERE ST_Disjoint(ST_EndPoint(l.geometry), n.geometry) = 1",
2501 xtable1, xtable2);
2502 free (xtable1);
2503 free (xtable2);
2504 ret =
2505 sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_in, NULL);
2506 sqlite3_free (sql);
2507 if (ret != SQLITE_OK)
2508 {
2509 char *msg =
2510 sqlite3_mprintf ("ST_ValidSpatialNet() - EndNodes error: \"%s\"",
2511 sqlite3_errmsg (net->db_handle));
2512 gaianet_set_last_error_msg (accessor, msg);
2513 sqlite3_free (msg);
2514 goto error;
2515 }
2516
2517 sqlite3_reset (stmt_in);
2518 sqlite3_clear_bindings (stmt_in);
2519 while (1)
2520 {
2521 /* scrolling the result set rows */
2522 ret = sqlite3_step (stmt_in);
2523 if (ret == SQLITE_DONE)
2524 break; /* end of result set */
2525 if (ret == SQLITE_ROW)
2526 {
2527 sqlite3_int64 link_id = sqlite3_column_int64 (stmt_in, 0);
2528 sqlite3_int64 node_id = sqlite3_column_int64 (stmt_in, 1);
2529 /* reporting the error */
2530 sqlite3_reset (stmt);
2531 sqlite3_clear_bindings (stmt);
2532 sqlite3_bind_text (stmt, 1, "geometry end mismatch", -1,
2533 SQLITE_STATIC);
2534 sqlite3_bind_int64 (stmt, 2, link_id);
2535 sqlite3_bind_int64 (stmt, 3, node_id);
2536 ret = sqlite3_step (stmt);
2537 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
2538 ;
2539 else
2540 {
2541 char *msg =
2542 sqlite3_mprintf
2543 ("ST_ValidSpatialNet() insert error: \"%s\"",
2544 sqlite3_errmsg (net->db_handle));
2545 gaianet_set_last_error_msg (accessor, msg);
2546 sqlite3_free (msg);
2547 goto error;
2548 }
2549 }
2550 else
2551 {
2552 char *msg =
2553 sqlite3_mprintf
2554 ("ST_ValidSpatialNet() - EndNodes step error: %s",
2555 sqlite3_errmsg (net->db_handle));
2556 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
2557 sqlite3_free (msg);
2558 goto error;
2559 }
2560 }
2561 sqlite3_finalize (stmt_in);
2562
2563 return 1;
2564
2565 error:
2566 if (stmt_in == NULL)
2567 sqlite3_finalize (stmt_in);
2568 return 0;
2569 }
2570
2571 GAIANET_DECLARE int
gaiaValidSpatialNet(GaiaNetworkAccessorPtr accessor)2572 gaiaValidSpatialNet (GaiaNetworkAccessorPtr accessor)
2573 {
2574 /* generating a validity report for a given Spatial Network */
2575 char *table;
2576 char *xtable;
2577 char *sql;
2578 int ret;
2579 sqlite3_stmt *stmt = NULL;
2580 struct gaia_network *net = (struct gaia_network *) accessor;
2581 if (net == NULL)
2582 return 0;
2583
2584 if (!do_check_create_valid_spatialnet_table (accessor))
2585 return 0;
2586
2587 table = sqlite3_mprintf ("%s_valid_spatialnet", net->network_name);
2588 xtable = gaiaDoubleQuotedSql (table);
2589 sqlite3_free (table);
2590 sql =
2591 sqlite3_mprintf
2592 ("INSERT INTO TEMP.\"%s\" (error, primitive1, primitive2) VALUES (?, ?, ?)",
2593 xtable);
2594 free (xtable);
2595 ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
2596 sqlite3_free (sql);
2597 if (ret != SQLITE_OK)
2598 {
2599 char *msg = sqlite3_mprintf ("ST_ValidSpatialNet error: \"%s\"",
2600 sqlite3_errmsg (net->db_handle));
2601 gaianet_set_last_error_msg (accessor, msg);
2602 sqlite3_free (msg);
2603 goto error;
2604 }
2605
2606 if (!do_spatnet_check_nodes (accessor, stmt))
2607 goto error;
2608
2609 if (!do_spatnet_check_links (accessor, stmt))
2610 goto error;
2611
2612 if (!do_spatnet_check_start_nodes (accessor, stmt))
2613 goto error;
2614
2615 if (!do_spatnet_check_end_nodes (accessor, stmt))
2616 goto error;
2617
2618 sqlite3_finalize (stmt);
2619 return 1;
2620
2621 error:
2622 if (stmt != NULL)
2623 sqlite3_finalize (stmt);
2624 return 0;
2625 }
2626
2627 NETWORK_PRIVATE int
auxnet_insert_into_network(GaiaNetworkAccessorPtr accessor,gaiaGeomCollPtr geom)2628 auxnet_insert_into_network (GaiaNetworkAccessorPtr accessor,
2629 gaiaGeomCollPtr geom)
2630 {
2631 /* processing all individual geometry items */
2632 sqlite3_int64 ret;
2633 gaiaLinestringPtr ln;
2634 gaiaPoint pt;
2635 struct gaia_network *network = (struct gaia_network *) accessor;
2636 if (network == NULL)
2637 return 0;
2638
2639 ln = geom->FirstLinestring;
2640 while (ln != NULL)
2641 {
2642 /* looping on Linestrings items */
2643 int last = ln->Points - 1;
2644 double x;
2645 double y;
2646 double z = 0.0;
2647 double m = 0.0;
2648 sqlite3_int64 start_node;
2649 sqlite3_int64 end_node;
2650 LWN_LINE *lwn_line;
2651 lwn_ResetErrorMsg (network->lwn_iface);
2652
2653 /* attempting to retrieve or insert the Start Node */
2654 if (geom->DimensionModel == GAIA_XY_Z)
2655 {
2656 gaiaGetPointXYZ (ln->Coords, 0, &x, &y, &z);
2657 }
2658 else if (geom->DimensionModel == GAIA_XY_Z_M)
2659 {
2660 gaiaGetPointXYZM (ln->Coords, 0, &x, &y, &z, &m);
2661 }
2662 else if (geom->DimensionModel == GAIA_XY_M)
2663 {
2664 gaiaGetPointXYM (ln->Coords, 0, &x, &y, &m);
2665 }
2666 else
2667 {
2668 gaiaGetPoint (ln->Coords, 0, &x, &y);
2669 }
2670 if (network->has_z)
2671 {
2672 pt.DimensionModel = GAIA_XY_Z;
2673 pt.X = x;
2674 pt.Y = y;
2675 pt.Z = z;
2676 }
2677 else
2678 {
2679 pt.DimensionModel = GAIA_XY;
2680 pt.X = x;
2681 pt.Y = y;
2682 }
2683 start_node = gaiaGetNetNodeByPoint (accessor, &pt, 0.0);
2684 if (start_node < 0)
2685 start_node = gaiaAddIsoNetNode (accessor, &pt);
2686 if (start_node < 0)
2687 {
2688 const char *msg = lwn_GetErrorMsg (network->lwn_iface);
2689 gaianet_set_last_error_msg (accessor, msg);
2690 goto error;
2691 }
2692
2693 /* attempting to retrieve or insert the End Node */
2694 if (geom->DimensionModel == GAIA_XY_Z)
2695 {
2696 gaiaGetPointXYZ (ln->Coords, last, &x, &y, &z);
2697 }
2698 else if (geom->DimensionModel == GAIA_XY_Z_M)
2699 {
2700 gaiaGetPointXYZM (ln->Coords, last, &x, &y, &z, &m);
2701 }
2702 else if (geom->DimensionModel == GAIA_XY_M)
2703 {
2704 gaiaGetPointXYM (ln->Coords, last, &x, &y, &m);
2705 }
2706 else
2707 {
2708 gaiaGetPoint (ln->Coords, last, &x, &y);
2709 }
2710 if (network->has_z)
2711 {
2712 pt.DimensionModel = GAIA_XY_Z;
2713 pt.X = x;
2714 pt.Y = y;
2715 pt.Z = z;
2716 }
2717 else
2718 {
2719 pt.DimensionModel = GAIA_XY;
2720 pt.X = x;
2721 pt.Y = y;
2722 }
2723 end_node = gaiaGetNetNodeByPoint (accessor, &pt, 0.0);
2724 if (end_node < 0)
2725 end_node = gaiaAddIsoNetNode (accessor, &pt);
2726 if (end_node < 0)
2727 {
2728 const char *msg = lwn_GetErrorMsg (network->lwn_iface);
2729 gaianet_set_last_error_msg (accessor, msg);
2730 goto error;
2731 }
2732
2733 lwn_line = gaianet_convert_linestring_to_lwnline (ln, network->srid,
2734 network->has_z);
2735 ret =
2736 lwn_AddLink ((LWN_NETWORK *) (network->lwn_network), start_node,
2737 end_node, lwn_line);
2738 lwn_free_line (lwn_line);
2739 if (ret <= 0)
2740 {
2741 const char *msg = lwn_GetErrorMsg (network->lwn_iface);
2742 gaianet_set_last_error_msg (accessor, msg);
2743 goto error;
2744 }
2745
2746 ln = ln->Next;
2747 }
2748
2749 return 1;
2750
2751 error:
2752 return 0;
2753 }
2754
2755 GAIANET_DECLARE int
gaiaTopoNet_FromGeoTable(GaiaNetworkAccessorPtr accessor,const char * db_prefix,const char * table,const char * column)2756 gaiaTopoNet_FromGeoTable (GaiaNetworkAccessorPtr accessor,
2757 const char *db_prefix, const char *table,
2758 const char *column)
2759 {
2760 /* attempting to import a whole GeoTable into a Topoology-Network */
2761 struct gaia_network *net = (struct gaia_network *) accessor;
2762 sqlite3_stmt *stmt = NULL;
2763 int ret;
2764 char *sql;
2765 char *xprefix;
2766 char *xtable;
2767 char *xcolumn;
2768 int gpkg_amphibious = 0;
2769 int gpkg_mode = 0;
2770
2771 if (net == NULL)
2772 return 0;
2773 if (net->cache != NULL)
2774 {
2775 struct splite_internal_cache *cache =
2776 (struct splite_internal_cache *) (net->cache);
2777 gpkg_amphibious = cache->gpkg_amphibious_mode;
2778 gpkg_mode = cache->gpkg_mode;
2779 }
2780
2781 /* building the SQL statement */
2782 xprefix = gaiaDoubleQuotedSql (db_prefix);
2783 xtable = gaiaDoubleQuotedSql (table);
2784 xcolumn = gaiaDoubleQuotedSql (column);
2785 sql =
2786 sqlite3_mprintf ("SELECT \"%s\" FROM \"%s\".\"%s\"", xcolumn,
2787 xprefix, xtable);
2788 free (xprefix);
2789 free (xtable);
2790 free (xcolumn);
2791 ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
2792 sqlite3_free (sql);
2793 if (ret != SQLITE_OK)
2794 {
2795 char *msg = sqlite3_mprintf ("TopoNet_FromGeoTable error: \"%s\"",
2796 sqlite3_errmsg (net->db_handle));
2797 gaianet_set_last_error_msg (accessor, msg);
2798 sqlite3_free (msg);
2799 goto error;
2800 }
2801
2802 /* setting up the prepared statement */
2803 sqlite3_reset (stmt);
2804 sqlite3_clear_bindings (stmt);
2805
2806 while (1)
2807 {
2808 /* scrolling the result set rows */
2809 ret = sqlite3_step (stmt);
2810 if (ret == SQLITE_DONE)
2811 break; /* end of result set */
2812 if (ret == SQLITE_ROW)
2813 {
2814 if (sqlite3_column_type (stmt, 0) == SQLITE_NULL)
2815 continue;
2816 if (sqlite3_column_type (stmt, 0) == SQLITE_BLOB)
2817 {
2818 const unsigned char *blob = sqlite3_column_blob (stmt, 0);
2819 int blob_sz = sqlite3_column_bytes (stmt, 0);
2820 gaiaGeomCollPtr geom =
2821 gaiaFromSpatiaLiteBlobWkbEx (blob, blob_sz, gpkg_mode,
2822 gpkg_amphibious);
2823 if (geom != NULL)
2824 {
2825 if (!auxnet_insert_into_network (accessor, geom))
2826 {
2827 gaiaFreeGeomColl (geom);
2828 goto error;
2829 }
2830 gaiaFreeGeomColl (geom);
2831 }
2832 else
2833 {
2834 char *msg =
2835 sqlite3_mprintf
2836 ("TopoNet_FromGeoTable error: Invalid Geometry");
2837 gaianet_set_last_error_msg (accessor, msg);
2838 sqlite3_free (msg);
2839 goto error;
2840 }
2841 }
2842 else
2843 {
2844 char *msg =
2845 sqlite3_mprintf
2846 ("TopoNet_FromGeoTable error: not a BLOB value");
2847 gaianet_set_last_error_msg (accessor, msg);
2848 sqlite3_free (msg);
2849 goto error;
2850 }
2851 }
2852 else
2853 {
2854 char *msg =
2855 sqlite3_mprintf ("TopoNet_FromGeoTable error: \"%s\"",
2856 sqlite3_errmsg (net->db_handle));
2857 gaianet_set_last_error_msg (accessor, msg);
2858 sqlite3_free (msg);
2859 goto error;
2860 }
2861 }
2862
2863 sqlite3_finalize (stmt);
2864 return 1;
2865
2866 error:
2867 if (stmt != NULL)
2868 sqlite3_finalize (stmt);
2869 return 0;
2870 }
2871
2872 GAIANET_DECLARE gaiaGeomCollPtr
gaiaGetLinkSeed(GaiaNetworkAccessorPtr accessor,sqlite3_int64 link)2873 gaiaGetLinkSeed (GaiaNetworkAccessorPtr accessor, sqlite3_int64 link)
2874 {
2875 /* attempting to get a Point (seed) identifying a Network Link */
2876 struct gaia_network *net = (struct gaia_network *) accessor;
2877 sqlite3_stmt *stmt = NULL;
2878 int ret;
2879 char *sql;
2880 char *table;
2881 char *xtable;
2882 gaiaGeomCollPtr point = NULL;
2883 if (net == NULL)
2884 return NULL;
2885
2886 /* building the SQL statement */
2887 table = sqlite3_mprintf ("%s_link", net->network_name);
2888 xtable = gaiaDoubleQuotedSql (table);
2889 sqlite3_free (table);
2890 sql =
2891 sqlite3_mprintf ("SELECT geometry FROM MAIN.\"%s\" WHERE link_id = ?",
2892 xtable);
2893 free (xtable);
2894 ret = sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt, NULL);
2895 sqlite3_free (sql);
2896 if (ret != SQLITE_OK)
2897 {
2898 char *msg = sqlite3_mprintf ("GetLinkSeed error: \"%s\"",
2899 sqlite3_errmsg (net->db_handle));
2900 gaianet_set_last_error_msg (accessor, msg);
2901 sqlite3_free (msg);
2902 goto error;
2903 }
2904
2905 /* setting up the prepared statement */
2906 sqlite3_reset (stmt);
2907 sqlite3_clear_bindings (stmt);
2908 sqlite3_bind_int64 (stmt, 1, link);
2909
2910 while (1)
2911 {
2912 /* scrolling the result set rows */
2913 ret = sqlite3_step (stmt);
2914 if (ret == SQLITE_DONE)
2915 break; /* end of result set */
2916 if (ret == SQLITE_ROW)
2917 {
2918 if (sqlite3_column_type (stmt, 0) == SQLITE_BLOB)
2919 {
2920 const unsigned char *blob = sqlite3_column_blob (stmt, 0);
2921 int blob_sz = sqlite3_column_bytes (stmt, 0);
2922 gaiaGeomCollPtr geom =
2923 gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
2924 if (geom != NULL)
2925 {
2926 int iv;
2927 double x;
2928 double y;
2929 double z = 0.0;
2930 double m = 0.0;
2931 gaiaLinestringPtr ln = geom->FirstLinestring;
2932 if (ln == NULL)
2933 {
2934 char *msg =
2935 sqlite3_mprintf
2936 ("TopoNet_GetLinkSeed error: Invalid Geometry");
2937 gaianet_set_last_error_msg (accessor, msg);
2938 sqlite3_free (msg);
2939 gaiaFreeGeomColl (geom);
2940 goto error;
2941 }
2942 iv = ln->Points / 2;
2943 if (ln->DimensionModel == GAIA_XY_Z)
2944 {
2945 gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
2946 }
2947 else if (ln->DimensionModel == GAIA_XY_M)
2948 {
2949 gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
2950 }
2951 else if (ln->DimensionModel == GAIA_XY_Z_M)
2952 {
2953 gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z,
2954 &m);
2955 }
2956 else
2957 {
2958 gaiaGetPoint (ln->Coords, iv, &x, &y);
2959 }
2960 gaiaFreeGeomColl (geom);
2961 if (net->has_z)
2962 {
2963 point = gaiaAllocGeomCollXYZ ();
2964 gaiaAddPointToGeomCollXYZ (point, x, y, z);
2965 }
2966 else
2967 {
2968 point = gaiaAllocGeomColl ();
2969 gaiaAddPointToGeomColl (point, x, y);
2970 }
2971 point->Srid = net->srid;
2972 }
2973 else
2974 {
2975 char *msg =
2976 sqlite3_mprintf
2977 ("TopoNet_GetLinkSeed error: Invalid Geometry");
2978 gaianet_set_last_error_msg (accessor, msg);
2979 sqlite3_free (msg);
2980 goto error;
2981 }
2982 }
2983 else
2984 {
2985 char *msg =
2986 sqlite3_mprintf
2987 ("TopoNet_GetLinkSeed error: not a BLOB value");
2988 gaianet_set_last_error_msg (accessor, msg);
2989 sqlite3_free (msg);
2990 goto error;
2991 }
2992 }
2993 else
2994 {
2995 char *msg =
2996 sqlite3_mprintf ("TopoNet_GetLinkSeed error: \"%s\"",
2997 sqlite3_errmsg (net->db_handle));
2998 gaianet_set_last_error_msg (accessor, msg);
2999 sqlite3_free (msg);
3000 goto error;
3001 }
3002 }
3003
3004 sqlite3_finalize (stmt);
3005 return point;
3006
3007 error:
3008 if (stmt != NULL)
3009 sqlite3_finalize (stmt);
3010 return NULL;
3011 }
3012
3013 static int
delete_all_seeds(struct gaia_network * net)3014 delete_all_seeds (struct gaia_network *net)
3015 {
3016 /* deleting all existing Seeds */
3017 char *table;
3018 char *xtable;
3019 char *sql;
3020 char *errMsg;
3021 int ret;
3022
3023 table = sqlite3_mprintf ("%s_seeds", net->network_name);
3024 xtable = gaiaDoubleQuotedSql (table);
3025 sqlite3_free (table);
3026 sql = sqlite3_mprintf ("DELETE FROM MAIN.\"%s\"", xtable);
3027 free (xtable);
3028 ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
3029 sqlite3_free (sql);
3030 if (ret != SQLITE_OK)
3031 {
3032 char *msg =
3033 sqlite3_mprintf ("TopoNet_UpdateSeeds() error: \"%s\"", errMsg);
3034 sqlite3_free (errMsg);
3035 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
3036 sqlite3_free (msg);
3037 return 0;
3038 }
3039 return 1;
3040 }
3041
3042 static int
update_outdated_link_seeds(struct gaia_network * net)3043 update_outdated_link_seeds (struct gaia_network *net)
3044 {
3045 /* updating all outdated Link Seeds */
3046 char *table;
3047 char *xseeds;
3048 char *xlinks;
3049 char *sql;
3050 int ret;
3051 sqlite3_stmt *stmt_out;
3052 sqlite3_stmt *stmt_in;
3053
3054 /* preparing the UPDATE statement */
3055 table = sqlite3_mprintf ("%s_seeds", net->network_name);
3056 xseeds = gaiaDoubleQuotedSql (table);
3057 sqlite3_free (table);
3058 sql = sqlite3_mprintf ("UPDATE MAIN.\"%s\" SET geometry = "
3059 "TopoNet_GetLinkSeed(%Q, link_id) WHERE link_id = ?",
3060 xseeds, net->network_name);
3061 free (xseeds);
3062 ret =
3063 sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_out, NULL);
3064 sqlite3_free (sql);
3065 if (ret != SQLITE_OK)
3066 {
3067 char *msg = sqlite3_mprintf ("TopoNet_UpdateSeeds() error: \"%s\"",
3068 sqlite3_errmsg (net->db_handle));
3069 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
3070 sqlite3_free (msg);
3071 goto error;
3072 }
3073
3074 /* preparing the SELECT statement */
3075 table = sqlite3_mprintf ("%s_seeds", net->network_name);
3076 xseeds = gaiaDoubleQuotedSql (table);
3077 sqlite3_free (table);
3078 table = sqlite3_mprintf ("%s_link", net->network_name);
3079 xlinks = gaiaDoubleQuotedSql (table);
3080 sqlite3_free (table);
3081 sql = sqlite3_mprintf ("SELECT s.link_id FROM MAIN.\"%s\" AS s "
3082 "JOIN MAIN.\"%s\" AS l ON (l.link_id = s.link_id) "
3083 "WHERE s.link_id IS NOT NULL AND l.timestamp > s.timestamp",
3084 xseeds, xlinks);
3085 free (xseeds);
3086 free (xlinks);
3087 ret =
3088 sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_in, NULL);
3089 sqlite3_free (sql);
3090 if (ret != SQLITE_OK)
3091 {
3092 char *msg = sqlite3_mprintf ("TopoNet_UpdateSeeds() error: \"%s\"",
3093 sqlite3_errmsg (net->db_handle));
3094 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
3095 sqlite3_free (msg);
3096 goto error;
3097 }
3098
3099 sqlite3_reset (stmt_in);
3100 sqlite3_clear_bindings (stmt_in);
3101 while (1)
3102 {
3103 /* scrolling the result set rows */
3104 ret = sqlite3_step (stmt_in);
3105 if (ret == SQLITE_DONE)
3106 break; /* end of result set */
3107 if (ret == SQLITE_ROW)
3108 {
3109 sqlite3_reset (stmt_out);
3110 sqlite3_clear_bindings (stmt_out);
3111 sqlite3_bind_int64 (stmt_out, 1,
3112 sqlite3_column_int64 (stmt_in, 0));
3113 /* updating the Seeds table */
3114 ret = sqlite3_step (stmt_out);
3115 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
3116 ;
3117 else
3118 {
3119 char *msg =
3120 sqlite3_mprintf
3121 ("TopoNet_UpdateSeeds() error: \"%s\"",
3122 sqlite3_errmsg (net->db_handle));
3123 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr)
3124 net, msg);
3125 sqlite3_free (msg);
3126 goto error;
3127 }
3128 }
3129 else
3130 {
3131 char *msg =
3132 sqlite3_mprintf ("TopoNet_UpdateSeeds() error: \"%s\"",
3133 sqlite3_errmsg (net->db_handle));
3134 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
3135 sqlite3_free (msg);
3136 goto error;
3137 }
3138 }
3139
3140 sqlite3_finalize (stmt_in);
3141 sqlite3_finalize (stmt_out);
3142 return 1;
3143
3144 error:
3145 if (stmt_in != NULL)
3146 sqlite3_finalize (stmt_in);
3147 if (stmt_out != NULL)
3148 sqlite3_finalize (stmt_out);
3149 return 0;
3150 }
3151
3152 GAIANET_DECLARE int
gaiaTopoNetUpdateSeeds(GaiaNetworkAccessorPtr accessor,int incremental_mode)3153 gaiaTopoNetUpdateSeeds (GaiaNetworkAccessorPtr accessor, int incremental_mode)
3154 {
3155 /* updating all TopoNet Seeds */
3156 char *table;
3157 char *xseeds;
3158 char *xlinks;
3159 char *sql;
3160 char *errMsg;
3161 int ret;
3162 struct gaia_network *net = (struct gaia_network *) accessor;
3163 if (net == NULL)
3164 return 0;
3165
3166 if (!incremental_mode)
3167 {
3168 /* deleting all existing Seeds */
3169 if (!delete_all_seeds (net))
3170 return 0;
3171 }
3172
3173 /* paranoid precaution: deleting all orphan Link Seeds */
3174 table = sqlite3_mprintf ("%s_seeds", net->network_name);
3175 xseeds = gaiaDoubleQuotedSql (table);
3176 sqlite3_free (table);
3177 table = sqlite3_mprintf ("%s_link", net->network_name);
3178 xlinks = gaiaDoubleQuotedSql (table);
3179 sqlite3_free (table);
3180 sql = sqlite3_mprintf ("DELETE FROM MAIN.\"%s\" WHERE link_id IN ("
3181 "SELECT s.link_id FROM MAIN.\"%s\" AS s "
3182 "LEFT JOIN MAIN.\"%s\" AS l ON (s.link_id = l.link_id) "
3183 "WHERE l.link_id IS NULL)", xseeds, xseeds, xlinks);
3184 free (xseeds);
3185 free (xlinks);
3186 ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
3187 sqlite3_free (sql);
3188 if (ret != SQLITE_OK)
3189 {
3190 char *msg =
3191 sqlite3_mprintf ("TopoNet_UpdateSeeds() error: \"%s\"", errMsg);
3192 sqlite3_free (errMsg);
3193 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
3194 sqlite3_free (msg);
3195 return 0;
3196 }
3197
3198 /* updating all outdated Link Seeds */
3199 if (!update_outdated_link_seeds (net))
3200 return 0;
3201
3202 /* inserting all missing Link Seeds */
3203 table = sqlite3_mprintf ("%s_seeds", net->network_name);
3204 xseeds = gaiaDoubleQuotedSql (table);
3205 sqlite3_free (table);
3206 table = sqlite3_mprintf ("%s_link", net->network_name);
3207 xlinks = gaiaDoubleQuotedSql (table);
3208 sqlite3_free (table);
3209 sql =
3210 sqlite3_mprintf
3211 ("INSERT INTO MAIN.\"%s\" (seed_id, link_id, geometry) "
3212 "SELECT NULL, l.link_id, TopoNet_GetLinkSeed(%Q, l.link_id) "
3213 "FROM MAIN.\"%s\" AS l "
3214 "LEFT JOIN MAIN.\"%s\" AS s ON (l.link_id = s.link_id) WHERE s.link_id IS NULL",
3215 xseeds, net->network_name, xlinks, xseeds);
3216 free (xseeds);
3217 free (xlinks);
3218 ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
3219 sqlite3_free (sql);
3220 if (ret != SQLITE_OK)
3221 {
3222 char *msg =
3223 sqlite3_mprintf ("TopoNet_UpdateSeeds() error: \"%s\"", errMsg);
3224 sqlite3_free (errMsg);
3225 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
3226 sqlite3_free (msg);
3227 return 0;
3228 }
3229
3230 return 1;
3231 }
3232
3233 static gaiaGeomCollPtr
do_interpolate_middlepoint(gaiaGeomCollPtr geom)3234 do_interpolate_middlepoint (gaiaGeomCollPtr geom)
3235 {
3236 /* building a three-point segment */
3237 gaiaGeomCollPtr newg;
3238 gaiaLinestringPtr old_ln;
3239 gaiaLinestringPtr new_ln;
3240 double x0;
3241 double y0;
3242 double z0;
3243 double x1;
3244 double y1;
3245 double z1;
3246 double mx;
3247 double my;
3248 double mz;
3249
3250 if (geom == NULL)
3251 return NULL;
3252 if (geom->FirstPoint != NULL || geom->FirstPolygon != NULL)
3253 return NULL;
3254 if (geom->FirstLinestring != geom->LastLinestring)
3255 return NULL;
3256 old_ln = geom->FirstLinestring;
3257 if (old_ln == NULL)
3258 return NULL;
3259 if (old_ln->Points != 2)
3260 return NULL;
3261
3262 if (geom->DimensionModel == GAIA_XY_Z)
3263 {
3264 gaiaGetPointXYZ (old_ln->Coords, 0, &x0, &y0, &z0);
3265 gaiaGetPointXYZ (old_ln->Coords, 1, &x1, &y1, &z1);
3266 newg = gaiaAllocGeomCollXYZ ();
3267 }
3268 else
3269 {
3270 gaiaGetPoint (old_ln->Coords, 0, &x0, &y0);
3271 gaiaGetPoint (old_ln->Coords, 1, &x1, &y1);
3272 newg = gaiaAllocGeomColl ();
3273 }
3274 newg->Srid = geom->Srid;
3275
3276 if (x0 > x1)
3277 mx = x1 + ((x0 - x1) / 2.0);
3278 else
3279 mx = x0 + ((x1 - x0) / 2.0);
3280 if (y0 > y1)
3281 my = y1 + ((y0 - y1) / 2.0);
3282 else
3283 my = y0 + ((y1 - y0) / 2.0);
3284 if (geom->DimensionModel == GAIA_XY_Z)
3285 {
3286 if (z0 > z1)
3287 mz = z1 + ((z0 - z1) / 2.0);
3288 else
3289 mz = z0 + ((z1 - z0) / 2.0);
3290 }
3291
3292 new_ln = gaiaAddLinestringToGeomColl (newg, 3);
3293 if (newg->DimensionModel == GAIA_XY_Z)
3294 {
3295 gaiaSetPointXYZ (new_ln->Coords, 0, x0, y0, z0);
3296 gaiaSetPointXYZ (new_ln->Coords, 1, mx, my, mz);
3297 gaiaSetPointXYZ (new_ln->Coords, 2, x1, y1, z1);
3298 }
3299 else
3300 {
3301 gaiaSetPoint (new_ln->Coords, 0, x0, y0);
3302 gaiaSetPoint (new_ln->Coords, 1, mx, my);
3303 gaiaSetPoint (new_ln->Coords, 2, x1, y1);
3304 }
3305
3306 return newg;
3307 }
3308
3309 GAIANET_DECLARE int
gaiaTopoNet_DisambiguateSegmentLinks(GaiaNetworkAccessorPtr accessor)3310 gaiaTopoNet_DisambiguateSegmentLinks (GaiaNetworkAccessorPtr accessor)
3311 {
3312 /*
3313 / Ensures that all Links on a Topology-Network will have not less
3314 / than three vertices; for all Links found beign simple two-points
3315 / segments a third intermediate point will be interpolated.
3316 */
3317 struct gaia_network *net = (struct gaia_network *) accessor;
3318 int ret;
3319 char *sql;
3320 char *link;
3321 char *xlink;
3322 sqlite3_stmt *stmt_in = NULL;
3323 sqlite3_stmt *stmt_out = NULL;
3324 int count = 0;
3325 if (net == NULL)
3326 return -1;
3327
3328 /* preparing the SQL query identifying all two-points Links */
3329 link = sqlite3_mprintf ("%s_link", net->network_name);
3330 xlink = gaiaDoubleQuotedSql (link);
3331 sqlite3_free (link);
3332 sql =
3333 sqlite3_mprintf
3334 ("SELECT link_id, geometry FROM \"%s\" WHERE ST_NumPoints(geometry) = 2 "
3335 "ORDER BY link_id", xlink);
3336 free (xlink);
3337 ret =
3338 sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_in, NULL);
3339 sqlite3_free (sql);
3340 if (ret != SQLITE_OK)
3341 {
3342 char *msg =
3343 sqlite3_mprintf ("TopoNet_DisambiguateSegmentLinks error: \"%s\"",
3344 sqlite3_errmsg (net->db_handle));
3345 gaianet_set_last_error_msg (accessor, msg);
3346 sqlite3_free (msg);
3347 goto error;
3348 }
3349
3350 /* preparing the UPDATE SQL query */
3351 sql =
3352 sqlite3_mprintf ("SELECT ST_ChangeLinkGeom(%Q, ?, ?)",
3353 net->network_name);
3354 ret =
3355 sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_out, NULL);
3356 sqlite3_free (sql);
3357 if (ret != SQLITE_OK)
3358 {
3359 char *msg =
3360 sqlite3_mprintf ("TopoNet_DisambiguateSegmentLinks error: \"%s\"",
3361 sqlite3_errmsg (net->db_handle));
3362 gaianet_set_last_error_msg (accessor, msg);
3363 sqlite3_free (msg);
3364 goto error;
3365 }
3366
3367 while (1)
3368 {
3369 /* scrolling the result set rows */
3370 ret = sqlite3_step (stmt_in);
3371 if (ret == SQLITE_DONE)
3372 break; /* end of result set */
3373 if (ret == SQLITE_ROW)
3374 {
3375 sqlite3_int64 link_id = sqlite3_column_int64 (stmt_in, 0);
3376 if (sqlite3_column_type (stmt_in, 1) == SQLITE_BLOB)
3377 {
3378 const unsigned char *blob =
3379 sqlite3_column_blob (stmt_in, 1);
3380 int blob_sz = sqlite3_column_bytes (stmt_in, 1);
3381 gaiaGeomCollPtr geom =
3382 gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
3383 if (geom != NULL)
3384 {
3385 gaiaGeomCollPtr newg =
3386 do_interpolate_middlepoint (geom);
3387 gaiaFreeGeomColl (geom);
3388 if (newg != NULL)
3389 {
3390 unsigned char *outblob = NULL;
3391 int outblob_size = 0;
3392 sqlite3_reset (stmt_out);
3393 sqlite3_clear_bindings (stmt_out);
3394 sqlite3_bind_int64 (stmt_out, 1, link_id);
3395 gaiaToSpatiaLiteBlobWkb (newg, &outblob,
3396 &outblob_size);
3397 gaiaFreeGeomColl (newg);
3398 if (blob == NULL)
3399 continue;
3400 else
3401 sqlite3_bind_blob (stmt_out, 2, outblob,
3402 outblob_size, free);
3403 /* updating the Links table */
3404 ret = sqlite3_step (stmt_out);
3405 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
3406 count++;
3407 else
3408 {
3409 char *msg =
3410 sqlite3_mprintf
3411 ("TopoNet_DisambiguateSegmentLinks() error: \"%s\"",
3412 sqlite3_errmsg (net->db_handle));
3413 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
3414 sqlite3_free (msg);
3415 goto error;
3416 }
3417 }
3418 }
3419 }
3420 }
3421 else
3422 {
3423 char *msg =
3424 sqlite3_mprintf
3425 ("TopoNet_DisambiguateSegmentLinks error: \"%s\"",
3426 sqlite3_errmsg (net->db_handle));
3427 gaianet_set_last_error_msg (accessor, msg);
3428 sqlite3_free (msg);
3429 goto error;
3430 }
3431 }
3432
3433 sqlite3_finalize (stmt_in);
3434 sqlite3_finalize (stmt_out);
3435 return count;
3436
3437 error:
3438 if (stmt_out != NULL)
3439 sqlite3_finalize (stmt_in);
3440 if (stmt_out != NULL)
3441 sqlite3_finalize (stmt_out);
3442 return -1;
3443 }
3444
3445 static void
do_eval_toponet_point(struct gaia_network * net,gaiaGeomCollPtr result,gaiaGeomCollPtr reference,sqlite3_stmt * stmt_node)3446 do_eval_toponet_point (struct gaia_network *net, gaiaGeomCollPtr result,
3447 gaiaGeomCollPtr reference, sqlite3_stmt * stmt_node)
3448 {
3449 /* retrieving Points from Topology */
3450 int ret;
3451 unsigned char *p_blob;
3452 int n_bytes;
3453
3454 /* initializing the Topo-Node query */
3455 gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
3456 sqlite3_reset (stmt_node);
3457 sqlite3_clear_bindings (stmt_node);
3458 sqlite3_bind_blob (stmt_node, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
3459 sqlite3_bind_blob (stmt_node, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
3460 free (p_blob);
3461
3462 while (1)
3463 {
3464 /* scrolling the result set rows */
3465 ret = sqlite3_step (stmt_node);
3466 if (ret == SQLITE_DONE)
3467 break; /* end of result set */
3468 if (ret == SQLITE_ROW)
3469 {
3470 const unsigned char *blob = sqlite3_column_blob (stmt_node, 0);
3471 int blob_sz = sqlite3_column_bytes (stmt_node, 0);
3472 gaiaGeomCollPtr geom =
3473 gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
3474 if (geom != NULL)
3475 {
3476 gaiaPointPtr pt = geom->FirstPoint;
3477 while (pt != NULL)
3478 {
3479 /* copying all Points into the result Geometry */
3480 if (net->has_z)
3481 gaiaAddPointToGeomCollXYZ (result, pt->X, pt->Y,
3482 pt->Z);
3483 else
3484 gaiaAddPointToGeomColl (result, pt->X, pt->Y);
3485 pt = pt->Next;
3486 }
3487 gaiaFreeGeomColl (geom);
3488 }
3489 }
3490 else
3491 {
3492 char *msg = sqlite3_mprintf ("TopoNet_ToGeoTable error: \"%s\"",
3493 sqlite3_errmsg (net->db_handle));
3494 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
3495 sqlite3_free (msg);
3496 return;
3497 }
3498 }
3499 }
3500
3501 static void
do_collect_topo_links(struct gaia_network * net,gaiaGeomCollPtr sparse,sqlite3_stmt * stmt_link,sqlite3_int64 link_id)3502 do_collect_topo_links (struct gaia_network *net, gaiaGeomCollPtr sparse,
3503 sqlite3_stmt * stmt_link, sqlite3_int64 link_id)
3504 {
3505 /* collecting Link Geometries one by one */
3506 int ret;
3507
3508 /* initializing the Topo-Link query */
3509 sqlite3_reset (stmt_link);
3510 sqlite3_clear_bindings (stmt_link);
3511 sqlite3_bind_int64 (stmt_link, 1, link_id);
3512
3513 while (1)
3514 {
3515 /* scrolling the result set rows */
3516 ret = sqlite3_step (stmt_link);
3517 if (ret == SQLITE_DONE)
3518 break; /* end of result set */
3519 if (ret == SQLITE_ROW)
3520 {
3521 const unsigned char *blob = sqlite3_column_blob (stmt_link, 0);
3522 int blob_sz = sqlite3_column_bytes (stmt_link, 0);
3523 gaiaGeomCollPtr geom =
3524 gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
3525 if (geom != NULL)
3526 {
3527 gaiaLinestringPtr ln = geom->FirstLinestring;
3528 while (ln != NULL)
3529 {
3530 if (net->has_z)
3531 auxtopo_copy_linestring3d (ln, sparse);
3532 else
3533 auxtopo_copy_linestring (ln, sparse);
3534 ln = ln->Next;
3535 }
3536 gaiaFreeGeomColl (geom);
3537 }
3538 }
3539 else
3540 {
3541 char *msg = sqlite3_mprintf ("TopoNet_ToGeoTable error: \"%s\"",
3542 sqlite3_errmsg (net->db_handle));
3543 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
3544 sqlite3_free (msg);
3545 return;
3546 }
3547 }
3548 }
3549
3550 static void
do_eval_toponet_line(struct gaia_network * net,gaiaGeomCollPtr result,gaiaGeomCollPtr reference,sqlite3_stmt * stmt_seed_link,sqlite3_stmt * stmt_link)3551 do_eval_toponet_line (struct gaia_network *net, gaiaGeomCollPtr result,
3552 gaiaGeomCollPtr reference, sqlite3_stmt * stmt_seed_link,
3553 sqlite3_stmt * stmt_link)
3554 {
3555 /* retrieving Linestrings from Topology */
3556 int ret;
3557 unsigned char *p_blob;
3558 int n_bytes;
3559 gaiaGeomCollPtr sparse;
3560 gaiaGeomCollPtr rearranged;
3561 gaiaLinestringPtr ln;
3562
3563 if (net->has_z)
3564 sparse = gaiaAllocGeomCollXYZ ();
3565 else
3566 sparse = gaiaAllocGeomColl ();
3567 sparse->Srid = net->srid;
3568
3569 /* initializing the Topo-Seed-Link query */
3570 gaiaToSpatiaLiteBlobWkb (reference, &p_blob, &n_bytes);
3571 sqlite3_reset (stmt_seed_link);
3572 sqlite3_clear_bindings (stmt_seed_link);
3573 sqlite3_bind_blob (stmt_seed_link, 1, p_blob, n_bytes, SQLITE_TRANSIENT);
3574 sqlite3_bind_blob (stmt_seed_link, 2, p_blob, n_bytes, SQLITE_TRANSIENT);
3575 free (p_blob);
3576
3577 while (1)
3578 {
3579 /* scrolling the result set rows */
3580 ret = sqlite3_step (stmt_seed_link);
3581 if (ret == SQLITE_DONE)
3582 break; /* end of result set */
3583 if (ret == SQLITE_ROW)
3584 {
3585 sqlite3_int64 link_id =
3586 sqlite3_column_int64 (stmt_seed_link, 0);
3587 do_collect_topo_links (net, sparse, stmt_link, link_id);
3588 }
3589 else
3590 {
3591 char *msg = sqlite3_mprintf ("TopoNet_ToGeoTable error: \"%s\"",
3592 sqlite3_errmsg (net->db_handle));
3593 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
3594 sqlite3_free (msg);
3595 gaiaFreeGeomColl (sparse);
3596 return;
3597 }
3598 }
3599
3600 /* attempting to rearrange sparse lines */
3601 rearranged = gaiaLineMerge_r (net->cache, sparse);
3602 gaiaFreeGeomColl (sparse);
3603 if (rearranged == NULL)
3604 return;
3605 ln = rearranged->FirstLinestring;
3606 while (ln != NULL)
3607 {
3608 if (net->has_z)
3609 auxtopo_copy_linestring3d (ln, result);
3610 else
3611 auxtopo_copy_linestring (ln, result);
3612 ln = ln->Next;
3613 }
3614 gaiaFreeGeomColl (rearranged);
3615 }
3616
3617 static gaiaGeomCollPtr
do_eval_toponet_geom(struct gaia_network * net,gaiaGeomCollPtr geom,sqlite3_stmt * stmt_seed_link,sqlite3_stmt * stmt_node,sqlite3_stmt * stmt_link,int out_type)3618 do_eval_toponet_geom (struct gaia_network *net, gaiaGeomCollPtr geom,
3619 sqlite3_stmt * stmt_seed_link,
3620 sqlite3_stmt * stmt_node, sqlite3_stmt * stmt_link,
3621 int out_type)
3622 {
3623 /* retrieving Topology-Network geometries via matching Seeds */
3624 gaiaGeomCollPtr result;
3625
3626 if (net->has_z)
3627 result = gaiaAllocGeomCollXYZ ();
3628 else
3629 result = gaiaAllocGeomColl ();
3630 result->Srid = net->srid;
3631 result->DeclaredType = out_type;
3632
3633 if (out_type == GAIA_POINT || out_type == GAIA_MULTIPOINT
3634 || out_type == GAIA_GEOMETRYCOLLECTION || out_type == GAIA_UNKNOWN)
3635 {
3636 /* processing all Points */
3637 gaiaPointPtr pt = geom->FirstPoint;
3638 while (pt != NULL)
3639 {
3640 gaiaPointPtr next = pt->Next;
3641 gaiaGeomCollPtr reference = (gaiaGeomCollPtr)
3642 auxtopo_make_geom_from_point (net->srid, net->has_z, pt);
3643 do_eval_toponet_point (net, result, reference, stmt_node);
3644 auxtopo_destroy_geom_from (reference);
3645 pt->Next = next;
3646 pt = pt->Next;
3647 }
3648 }
3649
3650 if (out_type == GAIA_MULTILINESTRING || out_type == GAIA_GEOMETRYCOLLECTION
3651 || out_type == GAIA_UNKNOWN)
3652 {
3653 /* processing all Linestrings */
3654 gaiaLinestringPtr ln = geom->FirstLinestring;
3655 while (ln != NULL)
3656 {
3657 gaiaLinestringPtr next = ln->Next;
3658 gaiaGeomCollPtr reference = (gaiaGeomCollPtr)
3659 auxtopo_make_geom_from_line (net->srid, ln);
3660 do_eval_toponet_line (net, result, reference, stmt_seed_link,
3661 stmt_link);
3662 auxtopo_destroy_geom_from (reference);
3663 ln->Next = next;
3664 ln = ln->Next;
3665 }
3666 }
3667
3668 if (out_type == GAIA_MULTIPOLYGON || out_type == GAIA_GEOMETRYCOLLECTION
3669 || out_type == GAIA_UNKNOWN)
3670 {
3671 /* processing all Polygons */
3672 if (geom->FirstPolygon != NULL)
3673 goto error;
3674 }
3675
3676 if (result->FirstPoint == NULL && result->FirstLinestring == NULL
3677 && result->FirstPolygon == NULL)
3678 goto error;
3679 return result;
3680
3681 error:
3682 gaiaFreeGeomColl (result);
3683 return NULL;
3684 }
3685
3686 static int
do_eval_toponet_seeds(struct gaia_network * net,sqlite3_stmt * stmt_ref,int ref_geom_col,sqlite3_stmt * stmt_ins,sqlite3_stmt * stmt_seed_link,sqlite3_stmt * stmt_node,sqlite3_stmt * stmt_link,int out_type)3687 do_eval_toponet_seeds (struct gaia_network *net, sqlite3_stmt * stmt_ref,
3688 int ref_geom_col, sqlite3_stmt * stmt_ins,
3689 sqlite3_stmt * stmt_seed_link, sqlite3_stmt * stmt_node,
3690 sqlite3_stmt * stmt_link, int out_type)
3691 {
3692 /* querying the ref-table */
3693 int ret;
3694
3695 sqlite3_reset (stmt_ref);
3696 sqlite3_clear_bindings (stmt_ref);
3697 while (1)
3698 {
3699 /* scrolling the result set rows */
3700 ret = sqlite3_step (stmt_ref);
3701 if (ret == SQLITE_DONE)
3702 break; /* end of result set */
3703 if (ret == SQLITE_ROW)
3704 {
3705 int icol;
3706 int ncol = sqlite3_column_count (stmt_ref);
3707 sqlite3_reset (stmt_ins);
3708 sqlite3_clear_bindings (stmt_ins);
3709 for (icol = 0; icol < ncol; icol++)
3710 {
3711 int col_type = sqlite3_column_type (stmt_ref, icol);
3712 if (icol == ref_geom_col)
3713 {
3714 /* the geometry column */
3715 const unsigned char *blob =
3716 sqlite3_column_blob (stmt_ref, icol);
3717 int blob_sz = sqlite3_column_bytes (stmt_ref, icol);
3718 gaiaGeomCollPtr geom =
3719 gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
3720 if (geom != NULL)
3721 {
3722 gaiaGeomCollPtr result;
3723 unsigned char *p_blob;
3724 int n_bytes;
3725 int gpkg_mode = 0;
3726 int tiny_point = 0;
3727 if (net->cache != NULL)
3728 {
3729 struct splite_internal_cache *cache =
3730 (struct splite_internal_cache
3731 *) (net->cache);
3732 gpkg_mode = cache->gpkg_mode;
3733 tiny_point = cache->tinyPointEnabled;
3734 }
3735 result =
3736 do_eval_toponet_geom (net, geom,
3737 stmt_seed_link,
3738 stmt_node,
3739 stmt_link,
3740 out_type);
3741 gaiaFreeGeomColl (geom);
3742 if (result != NULL)
3743 {
3744 gaiaToSpatiaLiteBlobWkbEx2 (result,
3745 &p_blob,
3746 &n_bytes,
3747 gpkg_mode,
3748 tiny_point);
3749 gaiaFreeGeomColl (result);
3750 sqlite3_bind_blob (stmt_ins, icol + 1,
3751 p_blob, n_bytes,
3752 free);
3753 }
3754 else
3755 sqlite3_bind_null (stmt_ins, icol + 1);
3756 }
3757 else
3758 sqlite3_bind_null (stmt_ins, icol + 1);
3759 continue;
3760 }
3761 switch (col_type)
3762 {
3763 case SQLITE_INTEGER:
3764 sqlite3_bind_int64 (stmt_ins, icol + 1,
3765 sqlite3_column_int64 (stmt_ref,
3766 icol));
3767 break;
3768 case SQLITE_FLOAT:
3769 sqlite3_bind_double (stmt_ins, icol + 1,
3770 sqlite3_column_double
3771 (stmt_ref, icol));
3772 break;
3773 case SQLITE_TEXT:
3774 sqlite3_bind_text (stmt_ins, icol + 1,
3775 (const char *)
3776 sqlite3_column_text (stmt_ref,
3777 icol),
3778 sqlite3_column_bytes (stmt_ref,
3779 icol),
3780 SQLITE_STATIC);
3781 break;
3782 case SQLITE_BLOB:
3783 sqlite3_bind_blob (stmt_ins, icol + 1,
3784 sqlite3_column_blob (stmt_ref,
3785 icol),
3786 sqlite3_column_bytes (stmt_ref,
3787 icol),
3788 SQLITE_STATIC);
3789 break;
3790 default:
3791 sqlite3_bind_null (stmt_ins, icol + 1);
3792 break;
3793 };
3794 }
3795 ret = sqlite3_step (stmt_ins);
3796 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
3797 ;
3798 else
3799 {
3800 char *msg =
3801 sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"",
3802 sqlite3_errmsg (net->db_handle));
3803 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr)
3804 net, msg);
3805 sqlite3_free (msg);
3806 return 0;
3807 }
3808 }
3809 else
3810 {
3811 char *msg =
3812 sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"",
3813 sqlite3_errmsg (net->db_handle));
3814 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
3815 sqlite3_free (msg);
3816 return 0;
3817 }
3818 }
3819 return 1;
3820 }
3821
3822 GAIANET_DECLARE int
gaiaTopoNet_ToGeoTableGeneralize(GaiaNetworkAccessorPtr accessor,const char * db_prefix,const char * ref_table,const char * ref_column,const char * out_table,double tolerance,int with_spatial_index)3823 gaiaTopoNet_ToGeoTableGeneralize (GaiaNetworkAccessorPtr accessor,
3824 const char *db_prefix, const char *ref_table,
3825 const char *ref_column, const char *out_table,
3826 double tolerance, int with_spatial_index)
3827 {
3828 /*
3829 / attempting to create and populate a new GeoTable out from a Topology-Network
3830 / (simplified/generalized version)
3831 */
3832 struct gaia_network *net = (struct gaia_network *) accessor;
3833 sqlite3_stmt *stmt_ref = NULL;
3834 sqlite3_stmt *stmt_ins = NULL;
3835 sqlite3_stmt *stmt_seed_link = NULL;
3836 sqlite3_stmt *stmt_node = NULL;
3837 sqlite3_stmt *stmt_link = NULL;
3838 int ret;
3839 char *create;
3840 char *select;
3841 char *insert;
3842 char *sql;
3843 char *errMsg;
3844 char *xprefix;
3845 char *xtable;
3846 int ref_type;
3847 const char *type;
3848 int out_type;
3849 int ref_geom_col;
3850 if (net == NULL)
3851 return 0;
3852
3853 /* incrementally updating all Topology Seeds */
3854 if (!gaiaTopoNetUpdateSeeds (accessor, 1))
3855 return 0;
3856
3857 /* composing the CREATE TABLE output-table statement */
3858 if (!auxtopo_create_togeotable_sql
3859 (net->db_handle, db_prefix, ref_table, ref_column, out_table, &create,
3860 &select, &insert, &ref_geom_col))
3861 goto error;
3862
3863 /* creating the output-table */
3864 ret = sqlite3_exec (net->db_handle, create, NULL, NULL, &errMsg);
3865 sqlite3_free (create);
3866 create = NULL;
3867 if (ret != SQLITE_OK)
3868 {
3869 char *msg =
3870 sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"", errMsg);
3871 sqlite3_free (errMsg);
3872 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
3873 sqlite3_free (msg);
3874 goto error;
3875 }
3876
3877 /* checking the Geometry Type */
3878 if (!auxtopo_retrieve_geometry_type
3879 (net->db_handle, db_prefix, ref_table, ref_column, &ref_type))
3880 goto error;
3881 switch (ref_type)
3882 {
3883 case GAIA_POINT:
3884 case GAIA_POINTZ:
3885 case GAIA_POINTM:
3886 case GAIA_POINTZM:
3887 type = "POINT";
3888 out_type = GAIA_POINT;
3889 break;
3890 case GAIA_MULTIPOINT:
3891 case GAIA_MULTIPOINTZ:
3892 case GAIA_MULTIPOINTM:
3893 case GAIA_MULTIPOINTZM:
3894 type = "MULTIPOINT";
3895 out_type = GAIA_MULTIPOINT;
3896 break;
3897 case GAIA_LINESTRING:
3898 case GAIA_LINESTRINGZ:
3899 case GAIA_LINESTRINGM:
3900 case GAIA_LINESTRINGZM:
3901 case GAIA_MULTILINESTRING:
3902 case GAIA_MULTILINESTRINGZ:
3903 case GAIA_MULTILINESTRINGM:
3904 case GAIA_MULTILINESTRINGZM:
3905 type = "MULTILINESTRING";
3906 out_type = GAIA_MULTILINESTRING;
3907 break;
3908 case GAIA_GEOMETRYCOLLECTION:
3909 case GAIA_GEOMETRYCOLLECTIONZ:
3910 case GAIA_GEOMETRYCOLLECTIONM:
3911 case GAIA_GEOMETRYCOLLECTIONZM:
3912 type = "GEOMETRYCOLLECTION";
3913 out_type = GAIA_GEOMETRYCOLLECTION;
3914 break;
3915 default:
3916 type = "GEOMETRY";
3917 out_type = GAIA_UNKNOWN;
3918 break;
3919 };
3920
3921 /* creating the output Geometry Column */
3922 sql =
3923 sqlite3_mprintf
3924 ("SELECT AddGeometryColumn(Lower(%Q), Lower(%Q), %d, '%s', '%s')",
3925 out_table, ref_column, net->srid, type,
3926 (net->has_z == 0) ? "XY" : "XYZ");
3927 ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
3928 sqlite3_free (sql);
3929 if (ret != SQLITE_OK)
3930 {
3931 char *msg =
3932 sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"", errMsg);
3933 sqlite3_free (errMsg);
3934 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
3935 sqlite3_free (msg);
3936 goto error;
3937 }
3938
3939 if (with_spatial_index)
3940 {
3941 /* adding a Spatial Index supporting the Geometry Column */
3942 sql =
3943 sqlite3_mprintf
3944 ("SELECT CreateSpatialIndex(Lower(%Q), Lower(%Q))",
3945 out_table, ref_column);
3946 ret = sqlite3_exec (net->db_handle, sql, NULL, NULL, &errMsg);
3947 sqlite3_free (sql);
3948 if (ret != SQLITE_OK)
3949 {
3950 char *msg =
3951 sqlite3_mprintf ("TopoGeo_ToGeoTable() error: \"%s\"",
3952 errMsg);
3953 sqlite3_free (errMsg);
3954 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
3955 sqlite3_free (msg);
3956 goto error;
3957 }
3958 }
3959
3960 /* preparing the "SELECT * FROM ref-table" query */
3961 ret =
3962 sqlite3_prepare_v2 (net->db_handle, select, strlen (select), &stmt_ref,
3963 NULL);
3964 sqlite3_free (select);
3965 select = NULL;
3966 if (ret != SQLITE_OK)
3967 {
3968 char *msg = sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"",
3969 sqlite3_errmsg (net->db_handle));
3970 sqlite3_free (errMsg);
3971 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
3972 sqlite3_free (msg);
3973 goto error;
3974 }
3975
3976 /* preparing the "INSERT INTO out-table" query */
3977 ret =
3978 sqlite3_prepare_v2 (net->db_handle, insert, strlen (insert), &stmt_ins,
3979 NULL);
3980 sqlite3_free (insert);
3981 insert = NULL;
3982 if (ret != SQLITE_OK)
3983 {
3984 char *msg = sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"",
3985 sqlite3_errmsg (net->db_handle));
3986 sqlite3_free (errMsg);
3987 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
3988 sqlite3_free (msg);
3989 goto error;
3990 }
3991
3992 /* preparing the Topo-Seed-Links query */
3993 xprefix = sqlite3_mprintf ("%s_seeds", net->network_name);
3994 xtable = gaiaDoubleQuotedSql (xprefix);
3995 sql = sqlite3_mprintf ("SELECT link_id FROM MAIN.\"%s\" "
3996 "WHERE ST_Intersects(geometry, ?) = 1 AND ROWID IN ("
3997 "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ?)",
3998 xtable, xprefix);
3999 free (xtable);
4000 sqlite3_free (xprefix);
4001 ret =
4002 sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_seed_link,
4003 NULL);
4004 sqlite3_free (sql);
4005 if (ret != SQLITE_OK)
4006 {
4007 char *msg = sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"",
4008 sqlite3_errmsg (net->db_handle));
4009 sqlite3_free (errMsg);
4010 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
4011 sqlite3_free (msg);
4012 goto error;
4013 }
4014
4015 /* preparing the Topo-Nodes query */
4016 xprefix = sqlite3_mprintf ("%s_node", net->network_name);
4017 xtable = gaiaDoubleQuotedSql (xprefix);
4018 sql = sqlite3_mprintf ("SELECT geometry FROM MAIN.\"%s\" "
4019 "WHERE ST_Intersects(geometry, ?) = 1 AND ROWID IN ("
4020 "SELECT ROWID FROM SpatialIndex WHERE f_table_name = %Q AND search_frame = ?)",
4021 xtable, xprefix);
4022 free (xtable);
4023 sqlite3_free (xprefix);
4024 ret =
4025 sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_node,
4026 NULL);
4027 sqlite3_free (sql);
4028 if (ret != SQLITE_OK)
4029 {
4030 char *msg = sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"",
4031 sqlite3_errmsg (net->db_handle));
4032 sqlite3_free (errMsg);
4033 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
4034 sqlite3_free (msg);
4035 goto error;
4036 }
4037
4038 /* preparing the Topo-Links query */
4039 xprefix = sqlite3_mprintf ("%s_link", net->network_name);
4040 xtable = gaiaDoubleQuotedSql (xprefix);
4041 if (tolerance > 0.0)
4042 sql =
4043 sqlite3_mprintf
4044 ("SELECT ST_SimplifyPreserveTopology(geometry, %1.6f) FROM MAIN.\"%s\" WHERE link_id = ?",
4045 tolerance, xtable, xprefix);
4046 else
4047 sql =
4048 sqlite3_mprintf
4049 ("SELECT geometry FROM MAIN.\"%s\" WHERE link_id = ?", xtable,
4050 xprefix);
4051 free (xtable);
4052 sqlite3_free (xprefix);
4053 ret =
4054 sqlite3_prepare_v2 (net->db_handle, sql, strlen (sql), &stmt_link,
4055 NULL);
4056 sqlite3_free (sql);
4057 if (ret != SQLITE_OK)
4058 {
4059 char *msg = sqlite3_mprintf ("TopoNet_ToGeoTable() error: \"%s\"",
4060 sqlite3_errmsg (net->db_handle));
4061 sqlite3_free (errMsg);
4062 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) net, msg);
4063 sqlite3_free (msg);
4064 goto error;
4065 }
4066
4067 /* evaluating feature/topology matching via coincident topo-seeds */
4068 if (!do_eval_toponet_seeds
4069 (net, stmt_ref, ref_geom_col, stmt_ins, stmt_seed_link, stmt_node,
4070 stmt_link, out_type))
4071 goto error;
4072
4073 sqlite3_finalize (stmt_ref);
4074 sqlite3_finalize (stmt_ins);
4075 sqlite3_finalize (stmt_seed_link);
4076 sqlite3_finalize (stmt_node);
4077 sqlite3_finalize (stmt_link);
4078 return 1;
4079
4080 error:
4081 if (create != NULL)
4082 sqlite3_free (create);
4083 if (select != NULL)
4084 sqlite3_free (select);
4085 if (insert != NULL)
4086 sqlite3_free (insert);
4087 if (stmt_ref != NULL)
4088 sqlite3_finalize (stmt_ref);
4089 if (stmt_ins != NULL)
4090 sqlite3_finalize (stmt_ins);
4091 if (stmt_seed_link != NULL)
4092 sqlite3_finalize (stmt_seed_link);
4093 if (stmt_node != NULL)
4094 sqlite3_finalize (stmt_node);
4095 if (stmt_link != NULL)
4096 sqlite3_finalize (stmt_link);
4097 return 0;
4098 }
4099
4100 GAIANET_DECLARE int
gaiaTopoNet_ToGeoTable(GaiaNetworkAccessorPtr accessor,const char * db_prefix,const char * ref_table,const char * ref_column,const char * out_table,int with_spatial_index)4101 gaiaTopoNet_ToGeoTable (GaiaNetworkAccessorPtr accessor,
4102 const char *db_prefix, const char *ref_table,
4103 const char *ref_column, const char *out_table,
4104 int with_spatial_index)
4105 {
4106 /* attempting to create and populate a new GeoTable out from a Topology-Network */
4107 return gaiaTopoNet_ToGeoTableGeneralize (accessor, db_prefix, ref_table,
4108 ref_column, out_table, -1.0,
4109 with_spatial_index);
4110 }
4111
4112 static int
find_linelink_matches(struct gaia_network * network,sqlite3_stmt * stmt_ref,sqlite3_stmt * stmt_ins,sqlite3_int64 link_id,const unsigned char * blob,int blob_sz)4113 find_linelink_matches (struct gaia_network *network,
4114 sqlite3_stmt * stmt_ref, sqlite3_stmt * stmt_ins,
4115 sqlite3_int64 link_id, const unsigned char *blob,
4116 int blob_sz)
4117 {
4118 /* retrieving LineLink relationships */
4119 int ret;
4120 int count = 0;
4121 char direction[2];
4122 strcpy (direction, "?");
4123
4124 sqlite3_reset (stmt_ref);
4125 sqlite3_clear_bindings (stmt_ref);
4126 sqlite3_bind_int64 (stmt_ref, 1, link_id);
4127
4128 while (1)
4129 {
4130 /* scrolling the result set rows - Spatial Relationships */
4131 ret = sqlite3_step (stmt_ref);
4132 if (ret == SQLITE_DONE)
4133 break; /* end of result set */
4134 if (ret == SQLITE_ROW)
4135 {
4136 sqlite3_int64 rowid = sqlite3_column_int64 (stmt_ref, 0);
4137
4138 if (sqlite3_column_type (stmt_ref, 1) == SQLITE_BLOB)
4139 {
4140 /* testing directions */
4141 gaiaGeomCollPtr geom_link = NULL;
4142 gaiaGeomCollPtr geom_line = NULL;
4143 const unsigned char *blob2 =
4144 sqlite3_column_blob (stmt_ref, 1);
4145 int blob2_sz = sqlite3_column_bytes (stmt_ref, 1);
4146 geom_link = gaiaFromSpatiaLiteBlobWkb (blob, blob_sz);
4147 geom_line = gaiaFromSpatiaLiteBlobWkb (blob2, blob2_sz);
4148 if (geom_link != NULL && geom_line != NULL)
4149 gaia_do_check_direction (geom_link, geom_line,
4150 direction);
4151 if (geom_link != NULL)
4152 gaiaFreeGeomColl (geom_link);
4153 if (geom_line != NULL)
4154 gaiaFreeGeomColl (geom_line);
4155 }
4156
4157 sqlite3_reset (stmt_ins);
4158 sqlite3_clear_bindings (stmt_ins);
4159 sqlite3_bind_int64 (stmt_ins, 1, link_id);
4160 sqlite3_bind_int64 (stmt_ins, 2, rowid);
4161 sqlite3_bind_text (stmt_ins, 3, direction, 1, SQLITE_STATIC);
4162 /* inserting a row into the output table */
4163 ret = sqlite3_step (stmt_ins);
4164 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4165 count++;
4166 else
4167 {
4168 char *msg =
4169 sqlite3_mprintf ("LineLinksList error: \"%s\"",
4170 sqlite3_errmsg (network->db_handle));
4171 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr)
4172 network, msg);
4173 sqlite3_free (msg);
4174 return 0;
4175 }
4176 }
4177 else
4178 {
4179 char *msg = sqlite3_mprintf ("LineLinksList error: \"%s\"",
4180 sqlite3_errmsg
4181 (network->db_handle));
4182 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) network,
4183 msg);
4184 sqlite3_free (msg);
4185 return 0;
4186 }
4187 }
4188
4189 if (count == 0)
4190 {
4191 /* unrelated Link */
4192 sqlite3_reset (stmt_ins);
4193 sqlite3_clear_bindings (stmt_ins);
4194 sqlite3_bind_int64 (stmt_ins, 1, link_id);
4195 sqlite3_bind_null (stmt_ins, 2);
4196 sqlite3_bind_null (stmt_ins, 3);
4197 /* inserting a row into the output table */
4198 ret = sqlite3_step (stmt_ins);
4199 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4200 ;
4201 else
4202 {
4203 char *msg = sqlite3_mprintf ("LineLinksList error: \"%s\"",
4204 sqlite3_errmsg
4205 (network->db_handle));
4206 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) network,
4207 msg);
4208 sqlite3_free (msg);
4209 return 0;
4210 }
4211 }
4212 return 1;
4213 }
4214
4215 static int
insert_linelink_reverse(struct gaia_network * network,sqlite3_stmt * stmt_ins,sqlite3_int64 polygon_id)4216 insert_linelink_reverse (struct gaia_network *network, sqlite3_stmt * stmt_ins,
4217 sqlite3_int64 polygon_id)
4218 {
4219 /* found a mismatching RefLinestring - inserting into the output table */
4220 int ret;
4221
4222 sqlite3_reset (stmt_ins);
4223 sqlite3_clear_bindings (stmt_ins);
4224 sqlite3_bind_null (stmt_ins, 1);
4225 sqlite3_bind_int64 (stmt_ins, 2, polygon_id);
4226 sqlite3_bind_null (stmt_ins, 3);
4227 /* inserting a row into the output table */
4228 ret = sqlite3_step (stmt_ins);
4229 if (ret == SQLITE_DONE || ret == SQLITE_ROW)
4230 ;
4231 else
4232 {
4233 char *msg = sqlite3_mprintf ("LineLinksList error: \"%s\"",
4234 sqlite3_errmsg (network->db_handle));
4235 gaianet_set_last_error_msg ((GaiaNetworkAccessorPtr) network, msg);
4236 sqlite3_free (msg);
4237 return 0;
4238 }
4239 return 1;
4240 }
4241
4242 GAIANET_DECLARE int
gaiaTopoNet_LineLinksList(GaiaNetworkAccessorPtr accessor,const char * db_prefix,const char * ref_table,const char * ref_column,const char * out_table)4243 gaiaTopoNet_LineLinksList (GaiaNetworkAccessorPtr accessor,
4244 const char *db_prefix, const char *ref_table,
4245 const char *ref_column, const char *out_table)
4246 {
4247 /* creating and populating a new Table reporting about Links/Linestring correspondencies */
4248 struct gaia_network *network = (struct gaia_network *) accessor;
4249 sqlite3_stmt *stmt_links = NULL;
4250 sqlite3_stmt *stmt_ref = NULL;
4251 sqlite3_stmt *stmt_rev = NULL;
4252 sqlite3_stmt *stmt_ins = NULL;
4253 int ret;
4254 char *sql;
4255 char *table;
4256 char *idx_name;
4257 char *xtable;
4258 char *xprefix;
4259 char *xcolumn;
4260 char *xidx_name;
4261 char *rtree_name;
4262 char *seeds;
4263 char *xseeds;
4264 int ref_has_spatial_index = 0;
4265 if (network == NULL)
4266 return 0;
4267
4268 /* attempting to build the output table */
4269 xtable = gaiaDoubleQuotedSql (out_table);
4270 sql = sqlite3_mprintf ("CREATE TABLE main.\"%s\" (\n"
4271 "\tid INTEGER PRIMARY KEY AUTOINCREMENT,\n"
4272 "\tlink_id INTEGER,\n"
4273 "\tref_rowid INTEGER,\n"
4274 "\tdirection TEXT)", xtable);
4275 free (xtable);
4276 ret = sqlite3_exec (network->db_handle, sql, NULL, NULL, NULL);
4277 sqlite3_free (sql);
4278 if (ret != SQLITE_OK)
4279 {
4280 char *msg = sqlite3_mprintf ("LineLinksList error: \"%s\"",
4281 sqlite3_errmsg (network->db_handle));
4282 gaianet_set_last_error_msg (accessor, msg);
4283 sqlite3_free (msg);
4284 goto error;
4285 }
4286 idx_name = sqlite3_mprintf ("idx_%s_link_id", out_table);
4287 xidx_name = gaiaDoubleQuotedSql (idx_name);
4288 sqlite3_free (idx_name);
4289 xtable = gaiaDoubleQuotedSql (out_table);
4290 sql =
4291 sqlite3_mprintf
4292 ("CREATE INDEX main.\"%s\" ON \"%s\" (link_id, ref_rowid)", xidx_name,
4293 xtable);
4294 free (xidx_name);
4295 free (xtable);
4296 ret = sqlite3_exec (network->db_handle, sql, NULL, NULL, NULL);
4297 sqlite3_free (sql);
4298 if (ret != SQLITE_OK)
4299 {
4300 char *msg = sqlite3_mprintf ("LineLinksList error: \"%s\"",
4301 sqlite3_errmsg (network->db_handle));
4302 gaianet_set_last_error_msg (accessor, msg);
4303 sqlite3_free (msg);
4304 goto error;
4305 }
4306
4307 /* building the Links SQL statement */
4308 table = sqlite3_mprintf ("%s_link", network->network_name);
4309 xtable = gaiaDoubleQuotedSql (table);
4310 sqlite3_free (table);
4311 sql = sqlite3_mprintf ("SELECT link_id, geometry FROM main.\"%s\"", xtable);
4312 free (xtable);
4313 ret =
4314 sqlite3_prepare_v2 (network->db_handle, sql, strlen (sql), &stmt_links,
4315 NULL);
4316 sqlite3_free (sql);
4317 if (ret != SQLITE_OK)
4318 {
4319 char *msg = sqlite3_mprintf ("LineLinksList error: \"%s\"",
4320 sqlite3_errmsg (network->db_handle));
4321 gaianet_set_last_error_msg (accessor, msg);
4322 sqlite3_free (msg);
4323 goto error;
4324 }
4325
4326 /* building the RefTable SQL statement */
4327 seeds = sqlite3_mprintf ("%s_seeds", network->network_name);
4328 rtree_name = sqlite3_mprintf ("DB=%s.%s", db_prefix, ref_table);
4329 ref_has_spatial_index =
4330 gaia_check_spatial_index (network->db_handle, db_prefix, ref_table,
4331 ref_column);
4332 xprefix = gaiaDoubleQuotedSql (db_prefix);
4333 xtable = gaiaDoubleQuotedSql (ref_table);
4334 xcolumn = gaiaDoubleQuotedSql (ref_column);
4335 xseeds = gaiaDoubleQuotedSql (seeds);
4336 if (ref_has_spatial_index)
4337 sql =
4338 sqlite3_mprintf
4339 ("SELECT r.rowid, r.\"%s\" FROM MAIN.\"%s\" AS s, \"%s\".\"%s\" AS r "
4340 "WHERE ST_Intersects(r.\"%s\", s.geometry) == 1 AND s.link_id = ? "
4341 "AND r.rowid IN (SELECT rowid FROM SpatialIndex WHERE f_table_name = %Q "
4342 "AND f_geometry_column = %Q AND search_frame = s.geometry)",
4343 xcolumn, xseeds, xprefix, xtable, xcolumn, rtree_name, xcolumn);
4344 else
4345 sql =
4346 sqlite3_mprintf
4347 ("SELECT r.rowid, r.\"%s\" FROM MAIN.\"%s\" AS s, \"%s\".\"%s\" AS r "
4348 "WHERE ST_Intersects(r.\"%s\", s.geometry) == 1 AND s.link_id = ?",
4349 xcolumn, xseeds, xprefix, xtable, xcolumn);
4350 free (xprefix);
4351 free (xtable);
4352 free (xcolumn);
4353 free (xseeds);
4354 sqlite3_free (rtree_name);
4355 sqlite3_free (seeds);
4356 ret =
4357 sqlite3_prepare_v2 (network->db_handle, sql, strlen (sql), &stmt_ref,
4358 NULL);
4359 sqlite3_free (sql);
4360 if (ret != SQLITE_OK)
4361 {
4362 char *msg = sqlite3_mprintf ("LineLinksList error: \"%s\"",
4363 sqlite3_errmsg (network->db_handle));
4364 gaianet_set_last_error_msg (accessor, msg);
4365 sqlite3_free (msg);
4366 goto error;
4367 }
4368
4369 /* building the Reverse RefTable SQL statement */
4370 seeds = sqlite3_mprintf ("%s_seeds", network->network_name);
4371 rtree_name = sqlite3_mprintf ("DB=%s.%s", db_prefix, ref_table);
4372 xprefix = gaiaDoubleQuotedSql (db_prefix);
4373 xtable = gaiaDoubleQuotedSql (ref_table);
4374 xcolumn = gaiaDoubleQuotedSql (ref_column);
4375 xseeds = gaiaDoubleQuotedSql (seeds);
4376 sql = sqlite3_mprintf ("SELECT r.rowid FROM \"%s\".\"%s\" AS r "
4377 "LEFT JOIN MAIN.\"%s\" AS s ON (ST_Intersects(r.\"%s\", s.geometry) = 1 "
4378 "AND s.link_id IS NOT NULL AND s.rowid IN (SELECT rowid FROM SpatialIndex "
4379 "WHERE f_table_name = %Q AND search_frame = r.\"%s\")) "
4380 "WHERE s.link_id IS NULL", xprefix, xtable, xseeds,
4381 xcolumn, rtree_name, xcolumn);
4382 free (xprefix);
4383 free (xtable);
4384 free (xcolumn);
4385 free (xseeds);
4386 sqlite3_free (rtree_name);
4387 sqlite3_free (seeds);
4388 ret =
4389 sqlite3_prepare_v2 (network->db_handle, sql, strlen (sql), &stmt_rev,
4390 NULL);
4391 sqlite3_free (sql);
4392 if (ret != SQLITE_OK)
4393 {
4394 char *msg = sqlite3_mprintf ("PolyFacesList error: \"%s\"",
4395 sqlite3_errmsg (network->db_handle));
4396 gaianet_set_last_error_msg (accessor, msg);
4397 sqlite3_free (msg);
4398 goto error;
4399 }
4400
4401 /* building the Insert SQL statement */
4402 xtable = gaiaDoubleQuotedSql (out_table);
4403 sql = sqlite3_mprintf ("INSERT INTO main.\"%s\" (id, link_id, ref_rowid, "
4404 "direction) VALUES (NULL, ?, ?, ?)", xtable);
4405 free (xtable);
4406 ret =
4407 sqlite3_prepare_v2 (network->db_handle, sql, strlen (sql), &stmt_ins,
4408 NULL);
4409 sqlite3_free (sql);
4410 if (ret != SQLITE_OK)
4411 {
4412 char *msg = sqlite3_mprintf ("LineLinksList error: \"%s\"",
4413 sqlite3_errmsg (network->db_handle));
4414 gaianet_set_last_error_msg (accessor, msg);
4415 sqlite3_free (msg);
4416 goto error;
4417 }
4418
4419 while (1)
4420 {
4421 /* scrolling the result set rows - Links */
4422 ret = sqlite3_step (stmt_links);
4423 if (ret == SQLITE_DONE)
4424 break; /* end of result set */
4425 if (ret == SQLITE_ROW)
4426 {
4427 sqlite3_int64 link_id = sqlite3_column_int64 (stmt_links, 0);
4428 if (sqlite3_column_type (stmt_links, 1) == SQLITE_BLOB)
4429 {
4430 if (!find_linelink_matches
4431 (network, stmt_ref, stmt_ins, link_id,
4432 sqlite3_column_blob (stmt_links, 1),
4433 sqlite3_column_bytes (stmt_links, 1)))
4434 goto error;
4435 }
4436 else
4437 {
4438 char *msg =
4439 sqlite3_mprintf
4440 ("LineLinksList error: Link not a BLOB value");
4441 gaianet_set_last_error_msg (accessor, msg);
4442 sqlite3_free (msg);
4443 goto error;
4444 }
4445 }
4446 else
4447 {
4448 char *msg = sqlite3_mprintf ("LineLinksList error: \"%s\"",
4449 sqlite3_errmsg
4450 (network->db_handle));
4451 gaianet_set_last_error_msg (accessor, msg);
4452 sqlite3_free (msg);
4453 goto error;
4454 }
4455 }
4456
4457 while (1)
4458 {
4459 /* scrolling the Reverse result set rows - Linestrings */
4460 ret = sqlite3_step (stmt_rev);
4461 if (ret == SQLITE_DONE)
4462 break; /* end of result set */
4463 if (ret == SQLITE_ROW)
4464 {
4465 sqlite3_int64 line_id = sqlite3_column_int64 (stmt_rev, 0);
4466 if (!insert_linelink_reverse (network, stmt_ins, line_id))
4467 goto error;
4468 }
4469 else
4470 {
4471 char *msg = sqlite3_mprintf ("LineLinksList error: \"%s\"",
4472 sqlite3_errmsg
4473 (network->db_handle));
4474 gaianet_set_last_error_msg (accessor, msg);
4475 sqlite3_free (msg);
4476 goto error;
4477 }
4478 }
4479
4480 sqlite3_finalize (stmt_links);
4481 sqlite3_finalize (stmt_ref);
4482 sqlite3_finalize (stmt_rev);
4483 sqlite3_finalize (stmt_ins);
4484 return 1;
4485
4486 error:
4487 if (stmt_links != NULL)
4488 sqlite3_finalize (stmt_links);
4489 if (stmt_ref != NULL)
4490 sqlite3_finalize (stmt_ref);
4491 if (stmt_rev != NULL)
4492 sqlite3_finalize (stmt_rev);
4493 if (stmt_ins != NULL)
4494 sqlite3_finalize (stmt_ins);
4495 return 0;
4496 }
4497
4498 #endif /* end RTTOPO conditionals */
4499