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