1 /*
2 alloc_cache.c -- Gaia spatial support for SQLite
3
4 version 5.0, 2020 August 1
5
6 Author: Sandro Furieri a.furieri@lqt.it
7
8 ------------------------------------------------------------------------------
9
10 Version: MPL 1.1/GPL 2.0/LGPL 2.1
11
12 The contents of this file are subject to the Mozilla Public License Version
13 1.1 (the "License"); you may not use this file except in compliance with
14 the License. You may obtain a copy of the License at
15 http://www.mozilla.org/MPL/
16
17 Software distributed under the License is distributed on an "AS IS" basis,
18 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
19 for the specific language governing rights and limitations under the
20 License.
21
22 The Original Code is the SpatiaLite library
23
24 The Initial Developer of the Original Code is Alessandro Furieri
25
26 Portions created by the Initial Developer are Copyright (C) 2013-2021
27 the Initial Developer. All Rights Reserved.
28
29 Contributor(s):
30
31 Alternatively, the contents of this file may be used under the terms of
32 either the GNU General Public License Version 2 or later (the "GPL"), or
33 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34 in which case the provisions of the GPL or the LGPL are applicable instead
35 of those above. If you wish to allow use of your version of this file only
36 under the terms of either the GPL or the LGPL, and not to allow others to
37 use your version of this file under the terms of the MPL, indicate your
38 decision by deleting the provisions above and replace them with the notice
39 and other provisions required by the GPL or the LGPL. If you do not delete
40 the provisions above, a recipient may use your version of this file under
41 the terms of any one of the MPL, the GPL or the LGPL.
42
43 */
44
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
48
49 #if defined(_WIN32)
50 #include <windows.h>
51 #include <libloaderapi.h>
52 #endif
53
54 #if defined(_WIN32) && !defined(__MINGW32__)
55 #include <windows.h>
56 #else
57 #include <pthread.h>
58 #endif
59
60 #if defined(_WIN32) && !defined(__MINGW32__)
61 #include "config-msvc.h"
62 #else
63 #include "config.h"
64 #endif
65
66 #ifdef ENABLE_LIBXML2 /* only if LIBXML2 is supported */
67 #include <libxml/parser.h>
68 #endif /* end LIBXML2 conditional */
69
70 #include <spatialite/sqlite.h>
71 #include <spatialite/debug.h>
72
73 #include <spatialite.h>
74 #include <spatialite_private.h>
75 #include <spatialite/gg_advanced.h>
76 #include <spatialite/gaiamatrix.h>
77
78 #ifndef OMIT_GEOS /* including GEOS */
79 #ifdef GEOS_REENTRANT
80 #ifdef GEOS_ONLY_REENTRANT
81 #define GEOS_USE_ONLY_R_API /* only fully thread-safe GEOS API */
82 #endif
83 #endif
84 #include <geos_c.h>
85 #endif
86
87 #ifndef OMIT_PROJ /* including PROJ.4 */
88 #ifdef PROJ_NEW /* supporting new PROJ.6 */
89 #include <proj.h>
90 #else /* supporting old PROJ.4 */
91 #include <proj_api.h>
92 #endif
93 #endif
94
95 #ifdef ENABLE_RTTOPO /* including RTTOPO */
96 #include <librttopo.h>
97 #endif
98
99 #ifndef GEOS_REENTRANT /* only when using the obsolete partially thread-safe mode */
100 #include "cache_aux_1.h"
101 #endif /* end GEOS_REENTRANT */
102
103 #ifdef _WIN32
104 #define strcasecmp _stricmp
105 #endif /* not WIN32 */
106
107 /* GLOBAL variables */
108 extern char *gaia_geos_error_msg;
109 extern char *gaia_geos_warning_msg;
110
111 /* GLOBAL semaphores */
112 int gaia_already_initialized = 0;
113 #if defined(_WIN32) && !defined(__MINGW32__)
114 static CRITICAL_SECTION gaia_cache_semaphore;
115 #else
116 static pthread_mutex_t gaia_cache_semaphore = PTHREAD_MUTEX_INITIALIZER;
117 #endif
118
119 #define GAIA_CONN_RESERVED (char *)1
120
121 #ifdef PROJ_NEW /* supporting new PROJ.6 */
122 static void
gaia_proj_log_funct(void * data,int level,const char * err_msg)123 gaia_proj_log_funct (void *data, int level, const char *err_msg)
124 {
125 /* intercepting PROJ.6 error messages */
126 gaiaSetProjErrorMsg_r (data, err_msg);
127 if (level == 0)
128 return; /* just silencing stupid compiler warnings aboit unused args */
129 }
130 #endif
131
132 static void
conn_geos_error(const char * msg,void * userdata)133 conn_geos_error (const char *msg, void *userdata)
134 {
135 /* reporting some GEOS error - thread safe */
136 int len;
137 struct splite_internal_cache *cache =
138 (struct splite_internal_cache *) userdata;
139 if (cache == NULL)
140 goto invalid_cache;
141 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
142 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
143 goto invalid_cache;
144
145 if (cache->gaia_geos_error_msg != NULL)
146 free (cache->gaia_geos_error_msg);
147 cache->gaia_geos_error_msg = NULL;
148 if (msg)
149 {
150 if (cache->silent_mode == 0)
151 spatialite_e ("GEOS error: %s\n", msg);
152 len = strlen (msg);
153 cache->gaia_geos_error_msg = malloc (len + 1);
154 strcpy (cache->gaia_geos_error_msg, msg);
155 }
156 return;
157
158 invalid_cache:
159 if (msg)
160 spatialite_e ("GEOS error: %s\n", msg);
161 }
162
163 static void
conn_geos_warning(const char * msg,void * userdata)164 conn_geos_warning (const char *msg, void *userdata)
165 {
166 /* reporting some GEOS warning - thread safe */
167 int len;
168 struct splite_internal_cache *cache =
169 (struct splite_internal_cache *) userdata;
170 if (cache == NULL)
171 goto invalid_cache;
172 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
173 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
174 goto invalid_cache;
175
176 if (cache->gaia_geos_warning_msg != NULL)
177 free (cache->gaia_geos_warning_msg);
178 cache->gaia_geos_warning_msg = NULL;
179 if (msg)
180 {
181 if (cache->silent_mode == 0)
182 spatialite_e ("GEOS warning: %s\n", msg);
183 len = strlen (msg);
184 cache->gaia_geos_warning_msg = malloc (len + 1);
185 strcpy (cache->gaia_geos_warning_msg, msg);
186 }
187 return;
188
189 invalid_cache:
190 if (msg)
191 spatialite_e ("GEOS warning: %s\n", msg);
192 }
193
194 static void
conn_rttopo_error(const char * fmt,va_list ap,void * userdata)195 conn_rttopo_error (const char *fmt, va_list ap, void *userdata)
196 {
197 /* reporting some RTTOPO error - thread safe */
198 char *msg = NULL;
199 int len;
200 struct splite_internal_cache *cache =
201 (struct splite_internal_cache *) userdata;
202 if (cache == NULL)
203 goto invalid_cache;
204 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
205 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
206 goto invalid_cache;
207
208 if (cache->gaia_rttopo_error_msg != NULL)
209 free (cache->gaia_rttopo_error_msg);
210 cache->gaia_rttopo_error_msg = NULL;
211
212 msg = sqlite3_vmprintf (fmt, ap);
213 if (msg)
214 {
215 if (strlen (msg) > 0)
216 {
217 if (cache->silent_mode == 0)
218 spatialite_e ("RTTOPO error: %s\n\n", msg);
219 len = strlen (msg);
220 cache->gaia_rttopo_error_msg = malloc (len + 1);
221 strcpy (cache->gaia_rttopo_error_msg, msg);
222 }
223 sqlite3_free (msg);
224 }
225 return;
226
227 invalid_cache:
228 if (msg)
229 {
230 spatialite_e ("RTTOPO error: %s\n", msg);
231 sqlite3_free (msg);
232 }
233 }
234
235 static void
conn_rttopo_warning(const char * fmt,va_list ap,void * userdata)236 conn_rttopo_warning (const char *fmt, va_list ap, void *userdata)
237 {
238 /* reporting some RTTOPO warning - thread safe */
239 char *msg = NULL;
240 int len;
241 struct splite_internal_cache *cache =
242 (struct splite_internal_cache *) userdata;
243 if (cache == NULL)
244 goto invalid_cache;
245 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
246 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
247 goto invalid_cache;
248
249 if (cache->gaia_rttopo_warning_msg != NULL)
250 free (cache->gaia_rttopo_warning_msg);
251 cache->gaia_rttopo_warning_msg = NULL;
252
253 msg = sqlite3_vmprintf (fmt, ap);
254 if (msg)
255 {
256 if (strlen (msg) > 0)
257 {
258 /* disabled so to stop endless warnings caused by topo-tolerance */
259 if (cache->silent_mode == 0)
260 spatialite_e ("RTTOPO warning: %s\n", msg);
261 len = strlen (msg);
262 cache->gaia_rttopo_warning_msg = malloc (len + 1);
263 strcpy (cache->gaia_rttopo_warning_msg, msg);
264 }
265 sqlite3_free (msg);
266 }
267 return;
268
269 invalid_cache:
270 if (msg)
271 {
272 spatialite_e ("RTTOPO warning: %s\n\n", msg);
273 sqlite3_free (msg);
274 }
275 }
276
277 #ifndef GEOS_REENTRANT /* only when using the obsolete partially thread-safe mode */
278 static void
setGeosErrorMsg(int pool_index,const char * msg)279 setGeosErrorMsg (int pool_index, const char *msg)
280 {
281 /* setting the latest GEOS error message */
282 struct splite_connection *p = &(splite_connection_pool[pool_index]);
283 struct splite_internal_cache *cache =
284 (struct splite_internal_cache *) (p->conn_ptr);
285 conn_geos_error (msg, cache);
286 }
287
288 static void
setGeosWarningMsg(int pool_index,const char * msg)289 setGeosWarningMsg (int pool_index, const char *msg)
290 {
291 /* setting the latest GEOS error message */
292 struct splite_connection *p = &(splite_connection_pool[pool_index]);
293 struct splite_internal_cache *cache =
294 (struct splite_internal_cache *) (p->conn_ptr);
295 conn_geos_warning (msg, cache);
296 }
297
298 static void
geos_error_r(int pool_index,const char * fmt,va_list ap)299 geos_error_r (int pool_index, const char *fmt, va_list ap)
300 {
301 /* reporting some GEOS error - thread safe */
302 char *msg;
303 msg = sqlite3_vmprintf (fmt, ap);
304 if (msg)
305 {
306 spatialite_e ("GEOS error: %s\n", msg);
307 setGeosErrorMsg (pool_index, msg);
308 sqlite3_free (msg);
309 }
310 else
311 setGeosErrorMsg (pool_index, NULL);
312 }
313
314 static void
geos_warning_r(int pool_index,const char * fmt,va_list ap)315 geos_warning_r (int pool_index, const char *fmt, va_list ap)
316 {
317 /* reporting some GEOS warning - thread safe */
318 char *msg;
319 msg = sqlite3_vmprintf (fmt, ap);
320 if (msg)
321 {
322 spatialite_e ("GEOS warning: %s\n", msg);
323 setGeosWarningMsg (pool_index, msg);
324 sqlite3_free (msg);
325 }
326 else
327 setGeosWarningMsg (pool_index, NULL);
328 }
329
330 #include "cache_aux_2.h"
331
332 static int
find_free_connection()333 find_free_connection ()
334 {
335 int i;
336 for (i = 0; i < SPATIALITE_MAX_CONNECTIONS; i++)
337 {
338 struct splite_connection *p = &(splite_connection_pool[i]);
339 if (p->conn_ptr == NULL)
340 {
341 p->conn_ptr = GAIA_CONN_RESERVED;
342 return i;
343 }
344 }
345 spatialite_e ("ERROR: Too many connections: max %d\n",
346 SPATIALITE_MAX_CONNECTIONS);
347 return -1;
348 }
349
350 static void
confirm(int i,void * cache)351 confirm (int i, void *cache)
352 {
353 /* marking the slot as definitely reserved */
354 struct splite_connection *p = &(splite_connection_pool[i]);
355 p->conn_ptr = cache;
356 }
357
358 static void
invalidate(int i)359 invalidate (int i)
360 {
361 /* definitely releasing the slot */
362 struct splite_connection *p = &(splite_connection_pool[i]);
363 p->conn_ptr = NULL;
364 }
365 #endif /* END obsolete partially thread-safe mode */
366
367 static void
init_splite_internal_cache(struct splite_internal_cache * cache)368 init_splite_internal_cache (struct splite_internal_cache *cache)
369 {
370 /* common initialization of the internal cache */
371 gaiaOutBufferPtr out;
372 int i;
373 const char *tinyPoint;
374 struct splite_geos_cache_item *p;
375 struct splite_xmlSchema_cache_item *p_xmlSchema;
376 if (cache == NULL)
377 return;
378
379 cache->magic1 = SPATIALITE_CACHE_MAGIC1;
380 cache->magic2 = SPATIALITE_CACHE_MAGIC2;
381 cache->gpkg_mode = 0;
382 cache->gpkg_amphibious_mode = 0;
383 cache->decimal_precision = -1;
384 cache->GEOS_handle = NULL;
385 cache->PROJ_handle = NULL;
386 cache->proj6_cached = 0;
387 cache->proj6_cached_pj = NULL;
388 cache->proj6_cached_string_1 = NULL;
389 cache->proj6_cached_string_2 = NULL;
390 cache->proj6_cached_area = NULL;
391 cache->is_pause_enabled = 0;
392 cache->RTTOPO_handle = NULL;
393 cache->cutterMessage = NULL;
394 cache->storedProcError = NULL;
395 cache->createRoutingError = NULL;
396 cache->SqlProcLogfile = NULL;
397 cache->SqlProcLogfileAppend = 0;
398 cache->SqlProcLog = NULL;
399 cache->SqlProcContinue = 1;
400 cache->SqlProcRetValue = gaia_alloc_variant ();
401 cache->pool_index = -1;
402 cache->gaia_proj_error_msg = NULL;
403 cache->gaia_geos_error_msg = NULL;
404 cache->gaia_geos_warning_msg = NULL;
405 cache->gaia_geosaux_error_msg = NULL;
406 cache->gaia_rttopo_error_msg = NULL;
407 cache->gaia_rttopo_warning_msg = NULL;
408 cache->silent_mode = 0;
409 cache->tinyPointEnabled = 0;
410 tinyPoint = getenv ("SPATIALITE_TINYPOINT");
411 if (tinyPoint == NULL)
412 ;
413 else if (atoi (tinyPoint) != 0)
414 cache->tinyPointEnabled = 1;
415 cache->lastPostgreSqlError = NULL;
416 #ifndef OMIT_GEOS /* including GEOS */
417 cache->buffer_end_cap_style = GEOSBUF_CAP_ROUND;
418 cache->buffer_join_style = GEOSBUF_JOIN_ROUND;
419 cache->buffer_mitre_limit = 5.0;
420 cache->buffer_quadrant_segments = 30;
421 #endif /* end including GEOS */
422 /* initializing an empty linked list of Topologies */
423 cache->firstTopology = NULL;
424 cache->lastTopology = NULL;
425 cache->next_topo_savepoint = 0;
426 cache->first_topo_svpt = NULL;
427 cache->last_topo_svpt = NULL;
428 cache->firstNetwork = NULL;
429 cache->lastNetwork = NULL;
430 cache->next_network_savepoint = 0;
431 cache->first_net_svpt = NULL;
432 cache->last_net_svpt = NULL;
433 /* initializing Sequences */
434 cache->first_seq = NULL;
435 cache->last_seq = NULL;
436 cache->ok_last_used_sequence = 0;
437 cache->last_used_sequence_val = 0;
438 /* initializing Virtual BBOXes */
439 cache->first_vtable_extent = NULL;
440 cache->last_vtable_extent = NULL;
441 /* initializing the XML error buffers */
442 out = malloc (sizeof (gaiaOutBuffer));
443 gaiaOutBufferInitialize (out);
444 cache->xmlParsingErrors = out;
445 out = malloc (sizeof (gaiaOutBuffer));
446 gaiaOutBufferInitialize (out);
447 cache->xmlSchemaValidationErrors = out;
448 out = malloc (sizeof (gaiaOutBuffer));
449 gaiaOutBufferInitialize (out);
450 cache->xmlXPathErrors = out;
451 /* initializing the GEOS cache */
452 p = &(cache->cacheItem1);
453 memset (p->gaiaBlob, '\0', 64);
454 p->gaiaBlobSize = 0;
455 p->crc32 = 0;
456 p->geosGeom = NULL;
457 p->preparedGeosGeom = NULL;
458 p = &(cache->cacheItem2);
459 memset (p->gaiaBlob, '\0', 64);
460 p->gaiaBlobSize = 0;
461 p->crc32 = 0;
462 p->geosGeom = NULL;
463 p->preparedGeosGeom = NULL;
464 for (i = 0; i < MAX_XMLSCHEMA_CACHE; i++)
465 {
466 /* initializing the XmlSchema cache */
467 p_xmlSchema = &(cache->xmlSchemaCache[i]);
468 p_xmlSchema->timestamp = 0;
469 p_xmlSchema->schemaURI = NULL;
470 p_xmlSchema->schemaDoc = NULL;
471 p_xmlSchema->parserCtxt = NULL;
472 p_xmlSchema->schema = NULL;
473 }
474 }
475
476 #ifdef GEOS_REENTRANT /* reentrant (thread-safe) initialization */
477 static void *
spatialite_alloc_reentrant()478 spatialite_alloc_reentrant ()
479 {
480 /*
481 * allocating and initializing an empty internal cache
482 * fully reentrant (thread-safe) version requiring GEOS >= 3.5.0
483 */
484 struct splite_internal_cache *cache = NULL;
485 #ifdef PROJ_NEW /* supporting new PROJ.6 */
486 int proj_set_ext_var = 0;
487 char *proj_db = NULL;
488 const char *proj_db_path = NULL;
489 #ifdef _WIN32
490 char *win_prefix = NULL;
491 #endif
492 #endif
493
494 /* attempting to implicitly initialize the library */
495 spatialite_initialize ();
496
497 cache = malloc (sizeof (struct splite_internal_cache));
498 if (cache == NULL)
499 goto done;
500 init_splite_internal_cache (cache);
501
502 /* initializing GEOS and PROJ.4 handles */
503
504 #ifndef OMIT_GEOS /* initializing GEOS */
505 cache->GEOS_handle = GEOS_init_r ();
506 GEOSContext_setNoticeMessageHandler_r (cache->GEOS_handle,
507 conn_geos_warning, cache);
508 GEOSContext_setErrorMessageHandler_r (cache->GEOS_handle, conn_geos_error,
509 cache);
510 #endif /* end GEOS */
511
512 #ifndef OMIT_PROJ /* initializing the PROJ.4 context */
513 #ifdef PROJ_NEW /* supporting new PROJ.6 */
514 cache->PROJ_handle = proj_context_create ();
515 proj_log_func (cache->PROJ_handle, cache, gaia_proj_log_funct); /* installing an error handler routine */
516 if (getenv ("PROJ_LIB") != NULL)
517 proj_db = sqlite3_mprintf ("%s/proj.db", getenv ("PROJ_LIB"));
518 if (proj_db != NULL)
519 {
520 proj_context_set_database_path (cache->PROJ_handle, proj_db,
521 NULL, NULL);
522 sqlite3_free (proj_db);
523 goto skip_win;
524 }
525 #ifdef _WIN32 /* only for Windows - checking the default locations for PROJ.6 DB */
526 proj_set_ext_var = 1;
527 proj_db_path = proj_context_get_database_path (cache->PROJ_handle);
528 if (proj_db_path == NULL)
529 {
530 char *win_path;
531 char *exe_path;
532 int max_len = 8192;
533 int i;
534 exe_path = malloc (max_len);
535 GetModuleFileNameA (NULL, exe_path, max_len);
536 if (exe_path != NULL)
537 {
538 /* searching within the EXE's launch dir */
539 for (i = strlen (exe_path) - 1; i >= 0; i--)
540 {
541 /* truncating the EXE name */
542 if (exe_path[i] == '\\')
543 {
544 exe_path[i] = '\0';
545 break;
546 }
547 }
548 win_prefix = sqlite3_mprintf ("%s", exe_path);
549 win_path = sqlite3_mprintf ("%s\\proj.db", exe_path);
550 free (exe_path);
551 proj_context_set_database_path (cache->PROJ_handle, win_path,
552 NULL, NULL);
553 proj_db_path =
554 proj_context_get_database_path (cache->PROJ_handle);
555 sqlite3_free (win_path);
556 }
557 if (proj_db_path == NULL)
558 {
559 /* searching on PUBLIC dir */
560 if (win_prefix != NULL)
561 sqlite3_free (win_prefix);
562 win_prefix =
563 sqlite3_mprintf ("%s\\spatialite\\proj", getenv ("PUBLIC"));
564 win_path =
565 sqlite3_mprintf ("%s\\spatialite\\proj\\proj.db",
566 getenv ("PUBLIC"));
567 proj_context_set_database_path (cache->PROJ_handle, win_path,
568 NULL, NULL);
569 proj_db_path =
570 proj_context_get_database_path (cache->PROJ_handle);
571 sqlite3_free (win_path);
572 }
573 if (proj_db_path == NULL)
574 {
575 /* searching on USER dir */
576 if (win_prefix != NULL)
577 sqlite3_free (win_prefix);
578 win_prefix =
579 sqlite3_mprintf ("%s\\spatialite\\proj",
580 getenv ("USERPROFILE"));
581 win_path =
582 sqlite3_mprintf ("%s\\spatialite\\proj\\proj.db",
583 getenv ("USERPROFILE"));
584 proj_context_set_database_path (cache->PROJ_handle, win_path,
585 NULL, NULL);
586 sqlite3_free (win_path);
587 }
588 }
589 #endif
590 skip_win:
591 proj_db_path = proj_context_get_database_path (cache->PROJ_handle);
592 #ifdef _WIN32 /* only for Windows - setting PROJ_LIB */
593 if (proj_set_ext_var && win_prefix && proj_db_path)
594 {
595 char *proj_lib = sqlite3_mprintf ("PROJ_LIB=%s", win_prefix);
596 _putenv (proj_lib);
597 sqlite3_free (proj_lib);
598 }
599 if (win_prefix != NULL)
600 sqlite3_free (win_prefix);
601 #else
602 /* suppressing stupid compiler warnings about unused args */
603 if (proj_db_path == NULL && proj_set_ext_var < 0)
604 proj_set_ext_var = 1;
605 #endif
606
607 #else /* supporting old PROJ.4 */
608 cache->PROJ_handle = pj_ctx_alloc ();
609 #endif
610 #endif /* end PROJ.4 */
611
612 #ifdef ENABLE_RTTOPO /* initializing the RTTOPO context */
613 cache->RTTOPO_handle = rtgeom_init (NULL, NULL, NULL);
614 rtgeom_set_error_logger (cache->RTTOPO_handle, conn_rttopo_error, cache);
615 rtgeom_set_notice_logger (cache->RTTOPO_handle, conn_rttopo_warning, cache);
616 #endif /* end RTTOPO */
617
618 done:
619 return cache;
620 }
621 #endif /* end GEOS_REENTRANT */
622
623 SPATIALITE_DECLARE void *
spatialite_alloc_connection()624 spatialite_alloc_connection ()
625 {
626 /* allocating and initializing an empty internal cache */
627
628 #ifdef GEOS_REENTRANT /* reentrant (thread-safe) initialization */
629 return spatialite_alloc_reentrant ();
630 #else /* end GEOS_REENTRANT */
631 struct splite_internal_cache *cache = NULL;
632 int pool_index;
633
634 /* attempting to implicitly initialize the library */
635 spatialite_initialize ();
636
637 /* locking the semaphore */
638 splite_cache_semaphore_lock ();
639
640 pool_index = find_free_connection ();
641
642 if (pool_index < 0)
643 goto done;
644
645 cache = malloc (sizeof (struct splite_internal_cache));
646 if (cache == NULL)
647 {
648 invalidate (pool_index);
649 goto done;
650 }
651 init_splite_internal_cache (cache);
652 cache->pool_index = pool_index;
653 confirm (pool_index, cache);
654
655 #include "cache_aux_3.h"
656
657 /* initializing GEOS and PROJ.4 handles */
658
659 #ifndef OMIT_GEOS /* initializing GEOS */
660 cache->GEOS_handle = initGEOS_r (cache->geos_warning, cache->geos_error);
661 #endif /* end GEOS */
662
663 #ifndef OMIT_PROJ /* initializing the PROJ.4 context */
664 cache->PROJ_handle = pj_ctx_alloc ();
665 #endif /* end PROJ.4 */
666
667 done:
668 /* unlocking the semaphore */
669 splite_cache_semaphore_unlock ();
670 return cache;
671 #endif
672 }
673
674 SPATIALITE_DECLARE void
spatialite_finalize_topologies(const void * ptr)675 spatialite_finalize_topologies (const void *ptr)
676 {
677 #ifdef ENABLE_RTTOPO /* only if RTTOPO is enabled */
678 /* freeing all Topology Accessor Objects */
679 struct splite_savepoint *p_svpt;
680 struct splite_savepoint *p_svpt_n;
681 struct splite_internal_cache *cache = (struct splite_internal_cache *) ptr;
682 if (cache == NULL)
683 return;
684 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
685 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
686 return;
687 free_internal_cache_topologies (cache->firstTopology);
688 cache->firstTopology = NULL;
689 cache->lastTopology = NULL;
690 p_svpt = cache->first_topo_svpt;
691 while (p_svpt != NULL)
692 {
693 p_svpt_n = p_svpt->next;
694 if (p_svpt->savepoint_name != NULL)
695 sqlite3_free (p_svpt->savepoint_name);
696 free (p_svpt);
697 p_svpt = p_svpt_n;
698 }
699 cache->first_topo_svpt = NULL;
700 cache->last_topo_svpt = NULL;
701 free_internal_cache_networks (cache->firstNetwork);
702 cache->firstNetwork = NULL;
703 cache->lastTopology = NULL;
704 p_svpt = cache->first_net_svpt;
705 while (p_svpt != NULL)
706 {
707 p_svpt_n = p_svpt->next;
708 if (p_svpt->savepoint_name != NULL)
709 sqlite3_free (p_svpt->savepoint_name);
710 free (p_svpt);
711 p_svpt = p_svpt_n;
712 }
713 cache->first_net_svpt = NULL;
714 cache->last_net_svpt = NULL;
715 #else
716 if (ptr == NULL)
717 return; /* silencing stupid compiler warnings */
718 #endif /* end RTTOPO conditionals */
719 }
720
721 static void
free_sequences(struct splite_internal_cache * cache)722 free_sequences (struct splite_internal_cache *cache)
723 {
724 /* freeing all Sequences */
725 gaiaSequencePtr pS;
726 gaiaSequencePtr pSn;
727
728 pS = cache->first_seq;
729 while (pS != NULL)
730 {
731 pSn = pS->next;
732 if (pS->seq_name != NULL)
733 free (pS->seq_name);
734 free (pS);
735 pS = pSn;
736 }
737 }
738
739 static void
free_vtable_extents(struct splite_internal_cache * cache)740 free_vtable_extents (struct splite_internal_cache *cache)
741 {
742 /* freeing all Virtual BBOXes */
743 struct splite_vtable_extent *pS;
744 struct splite_vtable_extent *pSn;
745
746 pS = cache->first_vtable_extent;
747 while (pS != NULL)
748 {
749 pSn = pS->next;
750 if (pS->table != NULL)
751 free (pS->table);
752 free (pS);
753 pS = pSn;
754 }
755 }
756
757 SPATIALITE_PRIVATE void
add_vtable_extent(const char * table,double minx,double miny,double maxx,double maxy,int srid,const void * p_cache)758 add_vtable_extent (const char *table, double minx,
759 double miny, double maxx,
760 double maxy, int srid, const void *p_cache)
761 {
762 /* adding a Virtual Full Extent */
763 struct splite_internal_cache *cache =
764 (struct splite_internal_cache *) p_cache;
765 struct splite_vtable_extent *vtable =
766 malloc (sizeof (struct splite_vtable_extent));
767 int len = strlen (table);
768 vtable->table = malloc (len + 1);
769 strcpy (vtable->table, table);
770 vtable->minx = minx;
771 vtable->miny = miny;
772 vtable->maxx = maxx;
773 vtable->maxy = maxy;
774 vtable->srid = srid;
775 vtable->prev = cache->last_vtable_extent;
776 vtable->next = NULL;
777 if (cache->first_vtable_extent == NULL)
778 cache->first_vtable_extent = vtable;
779 if (cache->last_vtable_extent != NULL)
780 cache->last_vtable_extent->next = vtable;
781 cache->last_vtable_extent = vtable;
782 }
783
784 SPATIALITE_PRIVATE void
remove_vtable_extent(const char * table,const void * p_cache)785 remove_vtable_extent (const char *table, const void *p_cache)
786 {
787 /* adding a Virtual Full Extent */
788 struct splite_internal_cache *cache =
789 (struct splite_internal_cache *) p_cache;
790 struct splite_vtable_extent *vtable_n;
791 struct splite_vtable_extent *vtable = cache->first_vtable_extent;
792 while (vtable != NULL)
793 {
794 vtable_n = vtable->next;
795 if (strcasecmp (vtable->table, table) == 0)
796 {
797 if (vtable->table != NULL)
798 free (vtable->table);
799 if (vtable->next != NULL)
800 vtable->next->prev = vtable->prev;
801 if (vtable->prev != NULL)
802 vtable->prev->next = vtable->next;
803 if (cache->first_vtable_extent == vtable)
804 cache->first_vtable_extent = vtable->next;
805 if (cache->last_vtable_extent == vtable)
806 cache->last_vtable_extent = vtable->prev;
807 free (vtable);
808 }
809 vtable = vtable_n;
810 }
811 }
812
813 SPATIALITE_PRIVATE int
get_vtable_extent(const char * table,double * minx,double * miny,double * maxx,double * maxy,int * srid,const void * p_cache)814 get_vtable_extent (const char *table, double *minx, double *miny, double *maxx,
815 double *maxy, int *srid, const void *p_cache)
816 {
817 /* retrieving a Virtual Full Extent */
818 struct splite_internal_cache *cache =
819 (struct splite_internal_cache *) p_cache;
820 struct splite_vtable_extent *vtable = cache->first_vtable_extent;
821 while (vtable != NULL)
822 {
823 if (strcasecmp (vtable->table, table) == 0)
824 {
825 *minx = vtable->minx;
826 *miny = vtable->miny;
827 *maxx = vtable->maxx;
828 *maxy = vtable->maxy;
829 *srid = vtable->srid;
830 return 1;
831 }
832 vtable = vtable->next;
833 }
834 return 0;
835 }
836
837 SPATIALITE_PRIVATE void
free_internal_cache(struct splite_internal_cache * cache)838 free_internal_cache (struct splite_internal_cache *cache)
839 {
840 /* freeing an internal cache */
841 struct splite_geos_cache_item *p;
842 #ifndef OMIT_GEOS
843 GEOSContextHandle_t handle = NULL;
844 #endif
845
846 #ifdef ENABLE_LIBXML2
847 int i;
848 struct splite_xmlSchema_cache_item *p_xmlSchema;
849 #endif
850
851 if (cache == NULL)
852 return;
853 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
854 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
855 return;
856
857 if (cache->SqlProcRetValue != NULL)
858 gaia_free_variant (cache->SqlProcRetValue);
859 cache->SqlProcRetValue = NULL;
860
861 #ifndef OMIT_GEOS
862 handle = cache->GEOS_handle;
863 if (handle != NULL)
864 #ifdef GEOS_REENTRANT /* reentrant (thread-safe) initialization */
865 GEOS_finish_r (handle);
866 #else /* end GEOS_REENTRANT */
867 finishGEOS_r (handle);
868 #endif
869 cache->GEOS_handle = NULL;
870 gaiaResetGeosMsg_r (cache);
871 #endif
872
873 #ifndef OMIT_PROJ
874 #ifdef PROJ_NEW /* supporting new PROJ.6 */
875 if (cache->proj6_cached_string_1 != NULL)
876 free (cache->proj6_cached_string_1);
877 if (cache->proj6_cached_string_2 != NULL)
878 free (cache->proj6_cached_string_2);
879 if (cache->proj6_cached_area != NULL)
880 free (cache->proj6_cached_area);
881 if (cache->proj6_cached_pj != NULL)
882 proj_destroy (cache->proj6_cached_pj);
883 if (cache->PROJ_handle != NULL)
884 proj_context_destroy (cache->PROJ_handle);
885 cache->PROJ_handle = NULL;
886 cache->proj6_cached = 0;
887 cache->proj6_cached_pj = NULL;
888 cache->proj6_cached_string_1 = NULL;
889 cache->proj6_cached_string_2 = NULL;
890 cache->proj6_cached_area = NULL;
891 #else /* supporting old PROJ.4 */
892 if (cache->PROJ_handle != NULL)
893 pj_ctx_free (cache->PROJ_handle);
894 cache->PROJ_handle = NULL;
895 #endif
896 #endif
897
898 /* freeing PROJ error buffer */
899 if (cache->gaia_proj_error_msg)
900 sqlite3_free (cache->gaia_proj_error_msg);
901
902 /* freeing GEOS error buffers */
903 if (cache->gaia_geos_error_msg)
904 free (cache->gaia_geos_error_msg);
905 if (cache->gaia_geos_warning_msg)
906 free (cache->gaia_geos_warning_msg);
907 if (cache->gaia_geosaux_error_msg)
908 free (cache->gaia_geosaux_error_msg);
909
910 /* freeing RTTOPO error buffers */
911 if (cache->gaia_rttopo_error_msg)
912 free (cache->gaia_rttopo_error_msg);
913 if (cache->gaia_rttopo_warning_msg)
914 free (cache->gaia_rttopo_warning_msg);
915
916 /* freeing the XML error buffers */
917 gaiaOutBufferReset (cache->xmlParsingErrors);
918 gaiaOutBufferReset (cache->xmlSchemaValidationErrors);
919 gaiaOutBufferReset (cache->xmlXPathErrors);
920 free (cache->xmlParsingErrors);
921 free (cache->xmlSchemaValidationErrors);
922 free (cache->xmlXPathErrors);
923
924 /* freeing the GEOS cache */
925 p = &(cache->cacheItem1);
926 splite_free_geos_cache_item_r (cache, p);
927 p = &(cache->cacheItem2);
928 splite_free_geos_cache_item_r (cache, p);
929 #ifdef ENABLE_LIBXML2
930 for (i = 0; i < MAX_XMLSCHEMA_CACHE; i++)
931 {
932 /* freeing the XmlSchema cache */
933 p_xmlSchema = &(cache->xmlSchemaCache[i]);
934 splite_free_xml_schema_cache_item (p_xmlSchema);
935 }
936 #endif
937
938 if (cache->lastPostgreSqlError != NULL)
939 sqlite3_free (cache->lastPostgreSqlError);
940
941 if (cache->cutterMessage != NULL)
942 sqlite3_free (cache->cutterMessage);
943 cache->cutterMessage = NULL;
944 if (cache->createRoutingError != NULL)
945 free (cache->createRoutingError);
946 cache->createRoutingError = NULL;
947 if (cache->storedProcError != NULL)
948 free (cache->storedProcError);
949 cache->storedProcError = NULL;
950 if (cache->SqlProcLogfile != NULL)
951 free (cache->SqlProcLogfile);
952 cache->SqlProcLogfile = NULL;
953 if (cache->SqlProcLog != NULL)
954 fclose (cache->SqlProcLog);
955 cache->SqlProcLog = NULL;
956 free_sequences (cache);
957 free_vtable_extents (cache);
958
959 spatialite_finalize_topologies (cache);
960
961 #ifdef ENABLE_RTTOPO
962 if (cache->RTTOPO_handle != NULL)
963 rtgeom_finish (cache->RTTOPO_handle);
964 cache->RTTOPO_handle = NULL;
965 #endif
966
967 #ifndef GEOS_REENTRANT /* only partially thread-safe mode */
968 /* releasing the connection pool object */
969 invalidate (cache->pool_index);
970 #endif /* end GEOS_REENTRANT */
971
972 /* freeing the cache itself */
973 free (cache);
974 }
975
976 GAIAGEO_DECLARE void
gaiaResetGeosMsg_r(const void * p_cache)977 gaiaResetGeosMsg_r (const void *p_cache)
978 {
979 /* resets the GEOS error and warning messages */
980 struct splite_internal_cache *cache =
981 (struct splite_internal_cache *) p_cache;
982 if (cache == NULL)
983 return;
984 if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
985 || cache->magic2 == SPATIALITE_CACHE_MAGIC2)
986 ;
987 else
988 return;
989 if (cache->gaia_geos_error_msg != NULL)
990 free (cache->gaia_geos_error_msg);
991 if (cache->gaia_geos_warning_msg != NULL)
992 free (cache->gaia_geos_warning_msg);
993 if (cache->gaia_geosaux_error_msg != NULL)
994 free (cache->gaia_geosaux_error_msg);
995 cache->gaia_geos_error_msg = NULL;
996 cache->gaia_geos_warning_msg = NULL;
997 cache->gaia_geosaux_error_msg = NULL;
998 }
999
1000 GAIAGEO_DECLARE const char *
gaiaGetGeosErrorMsg_r(const void * p_cache)1001 gaiaGetGeosErrorMsg_r (const void *p_cache)
1002 {
1003 /* return the latest GEOS error message */
1004 struct splite_internal_cache *cache =
1005 (struct splite_internal_cache *) p_cache;
1006 if (cache == NULL)
1007 return NULL;
1008 if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1009 || cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1010 ;
1011 else
1012 return NULL;
1013 return cache->gaia_geos_error_msg;
1014 }
1015
1016 GAIAGEO_DECLARE const char *
gaiaGetGeosWarningMsg_r(const void * p_cache)1017 gaiaGetGeosWarningMsg_r (const void *p_cache)
1018 {
1019 /* return the latest GEOS error message */
1020 struct splite_internal_cache *cache =
1021 (struct splite_internal_cache *) p_cache;
1022 if (cache == NULL)
1023 return NULL;
1024 if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1025 || cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1026 ;
1027 else
1028 return NULL;
1029 return cache->gaia_geos_warning_msg;
1030 }
1031
1032 GAIAGEO_DECLARE const char *
gaiaGetGeosAuxErrorMsg_r(const void * p_cache)1033 gaiaGetGeosAuxErrorMsg_r (const void *p_cache)
1034 {
1035 /* return the latest GEOS (auxialiary) error message */
1036 struct splite_internal_cache *cache =
1037 (struct splite_internal_cache *) p_cache;
1038 if (cache == NULL)
1039 return NULL;
1040 if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1041 || cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1042 ;
1043 else
1044 return NULL;
1045 return cache->gaia_geosaux_error_msg;
1046 }
1047
1048 GAIAGEO_DECLARE void
gaiaSetGeosErrorMsg_r(const void * p_cache,const char * msg)1049 gaiaSetGeosErrorMsg_r (const void *p_cache, const char *msg)
1050 {
1051 /* setting the latest GEOS error message */
1052 int len;
1053 struct splite_internal_cache *cache =
1054 (struct splite_internal_cache *) p_cache;
1055 if (cache == NULL)
1056 return;
1057 if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1058 || cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1059 ;
1060 else
1061 return;
1062 if (cache->gaia_geos_error_msg != NULL)
1063 free (cache->gaia_geos_error_msg);
1064 cache->gaia_geos_error_msg = NULL;
1065 if (msg == NULL)
1066 return;
1067 len = strlen (msg);
1068 cache->gaia_geos_error_msg = malloc (len + 1);
1069 strcpy (cache->gaia_geos_error_msg, msg);
1070 }
1071
1072 GAIAGEO_DECLARE void
gaiaSetGeosWarningMsg_r(const void * p_cache,const char * msg)1073 gaiaSetGeosWarningMsg_r (const void *p_cache, const char *msg)
1074 {
1075 /* setting the latest GEOS error message */
1076 int len;
1077 struct splite_internal_cache *cache =
1078 (struct splite_internal_cache *) p_cache;
1079 if (cache == NULL)
1080 return;
1081 if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1082 || cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1083 ;
1084 else
1085 return;
1086 if (cache->gaia_geos_warning_msg != NULL)
1087 free (cache->gaia_geos_warning_msg);
1088 cache->gaia_geos_warning_msg = NULL;
1089 if (msg == NULL)
1090 return;
1091 len = strlen (msg);
1092 cache->gaia_geos_warning_msg = malloc (len + 1);
1093 strcpy (cache->gaia_geos_warning_msg, msg);
1094 }
1095
1096 GAIAGEO_DECLARE void
gaiaSetGeosAuxErrorMsg_r(const void * p_cache,const char * msg)1097 gaiaSetGeosAuxErrorMsg_r (const void *p_cache, const char *msg)
1098 {
1099 /* setting the latest GEOS (auxiliary) error message */
1100 int len;
1101 struct splite_internal_cache *cache =
1102 (struct splite_internal_cache *) p_cache;
1103 if (cache == NULL)
1104 return;
1105 if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1106 || cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1107 ;
1108 else
1109 return;
1110 if (cache->gaia_geosaux_error_msg != NULL)
1111 free (cache->gaia_geosaux_error_msg);
1112 cache->gaia_geosaux_error_msg = NULL;
1113 if (msg == NULL)
1114 return;
1115 len = strlen (msg);
1116 cache->gaia_geosaux_error_msg = malloc (len + 1);
1117 strcpy (cache->gaia_geosaux_error_msg, msg);
1118 }
1119
1120 static char *
parse_number_from_msg(const char * str)1121 parse_number_from_msg (const char *str)
1122 {
1123 /* attempting to parse a number from a string */
1124 int sign = 0;
1125 int point = 0;
1126 int digit = 0;
1127 int err = 0;
1128 int len;
1129 char *res;
1130 const char *p = str;
1131 while (1)
1132 {
1133 if (*p == '+' || *p == '-')
1134 {
1135 sign++;
1136 p++;
1137 continue;
1138 }
1139 if (*p == '.')
1140 {
1141 point++;
1142 p++;
1143 continue;
1144 }
1145 if (*p >= '0' && *p <= '9')
1146 {
1147 p++;
1148 digit++;
1149 continue;
1150 }
1151 break;
1152 }
1153 if (sign > 1)
1154 err = 1;
1155 if (sign == 1 && *str != '+' && *str != '-')
1156 err = 1;
1157 if (point > 1)
1158 err = 1;
1159 if (!digit)
1160 err = 1;
1161 if (err)
1162 return NULL;
1163 len = p - str;
1164 res = malloc (len + 1);
1165 memcpy (res, str, len);
1166 *(res + len) = '\0';
1167 return res;
1168 }
1169
1170 static int
check_geos_critical_point(const char * msg,double * x,double * y)1171 check_geos_critical_point (const char *msg, double *x, double *y)
1172 {
1173 /* attempts to extract an [X,Y] Point coords from within a string */
1174 char *px;
1175 char *py;
1176 const char *ref = " at or near point ";
1177 const char *ref2 = " conflict at ";
1178 const char *p = strstr (msg, ref);
1179 if (p != NULL)
1180 goto ok_ref;
1181 p = strstr (msg, ref2);
1182 if (p == NULL)
1183 return 0;
1184 p += strlen (ref2);
1185 goto ok_ref2;
1186 ok_ref:
1187 p += strlen (ref);
1188 ok_ref2:
1189 px = parse_number_from_msg (p);
1190 if (px == NULL)
1191 return 0;
1192 p += strlen (px) + 1;
1193 py = parse_number_from_msg (p);
1194 if (py == NULL)
1195 {
1196 free (px);
1197 return 0;
1198 }
1199 *x = atof (px);
1200 *y = atof (py);
1201 free (px);
1202 free (py);
1203 return 1;
1204 }
1205
1206 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaCriticalPointFromGEOSmsg(void)1207 gaiaCriticalPointFromGEOSmsg (void)
1208 {
1209 /*
1210 / Attempts to return a Point Geometry extracted from the latest GEOS
1211 / error / warning message
1212 */
1213 double x;
1214 double y;
1215 gaiaGeomCollPtr geom;
1216 const char *msg = gaia_geos_error_msg;
1217 if (msg == NULL)
1218 msg = gaia_geos_warning_msg;
1219 if (msg == NULL)
1220 return NULL;
1221 if (!check_geos_critical_point (msg, &x, &y))
1222 return NULL;
1223 geom = gaiaAllocGeomColl ();
1224 gaiaAddPointToGeomColl (geom, x, y);
1225 return geom;
1226 }
1227
1228 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaCriticalPointFromGEOSmsg_r(const void * p_cache)1229 gaiaCriticalPointFromGEOSmsg_r (const void *p_cache)
1230 {
1231 /*
1232 / Attempts to return a Point Geometry extracted from the latest GEOS
1233 / error / warning message
1234 */
1235 double x;
1236 double y;
1237 gaiaGeomCollPtr geom;
1238 const char *msg;
1239 struct splite_internal_cache *cache =
1240 (struct splite_internal_cache *) p_cache;
1241
1242 if (cache == NULL)
1243 return NULL;
1244 if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1245 || cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1246 ;
1247 else
1248 return NULL;
1249
1250 msg = cache->gaia_geos_error_msg;
1251 if (msg == NULL)
1252 msg = cache->gaia_geos_warning_msg;
1253 if (msg == NULL)
1254 return NULL;
1255 if (!check_geos_critical_point (msg, &x, &y))
1256 return NULL;
1257 geom = gaiaAllocGeomColl ();
1258 gaiaAddPointToGeomColl (geom, x, y);
1259 return geom;
1260 }
1261
1262 SPATIALITE_PRIVATE void
splite_cache_semaphore_lock(void)1263 splite_cache_semaphore_lock (void)
1264 {
1265 #if defined(_WIN32) && !defined(__MINGW32__)
1266 EnterCriticalSection (&gaia_cache_semaphore);
1267 #else
1268 pthread_mutex_lock (&gaia_cache_semaphore);
1269 #endif
1270 }
1271
1272 SPATIALITE_PRIVATE void
splite_cache_semaphore_unlock(void)1273 splite_cache_semaphore_unlock (void)
1274 {
1275 #if defined(_WIN32) && !defined(__MINGW32__)
1276 LeaveCriticalSection (&gaia_cache_semaphore);
1277 #else
1278 pthread_mutex_trylock (&gaia_cache_semaphore);
1279 pthread_mutex_unlock (&gaia_cache_semaphore);
1280 #endif
1281 }
1282
1283 SPATIALITE_DECLARE void
spatialite_initialize(void)1284 spatialite_initialize (void)
1285 {
1286 /* initializes the library */
1287 if (gaia_already_initialized)
1288 return;
1289
1290 #if defined(_WIN32) && !defined(__MINGW32__)
1291 InitializeCriticalSection (&gaia_cache_semaphore);
1292 #endif
1293
1294 #ifdef ENABLE_LIBXML2 /* only if LIBXML2 is supported */
1295 xmlInitParser ();
1296 #endif /* end LIBXML2 conditional */
1297
1298 gaia_already_initialized = 1;
1299 }
1300
1301 SPATIALITE_DECLARE void
spatialite_shutdown(void)1302 spatialite_shutdown (void)
1303 {
1304 /* finalizes the library */
1305 #ifndef GEOS_REENTRANT
1306 int i;
1307 #endif
1308 if (!gaia_already_initialized)
1309 return;
1310
1311 #if defined(_WIN32) && !defined(__MINGW32__)
1312 DeleteCriticalSection (&gaia_cache_semaphore);
1313 #endif
1314
1315 #ifdef ENABLE_LIBXML2 /* only if LIBXML2 is supported */
1316 xmlCleanupParser ();
1317 #endif /* end LIBXML2 conditional */
1318
1319 #ifndef GEOS_REENTRANT /* only when using the obsolete partially thread-safe mode */
1320 for (i = 0; i < SPATIALITE_MAX_CONNECTIONS; i++)
1321 {
1322 struct splite_connection *p = &(splite_connection_pool[i]);
1323 if (p->conn_ptr != NULL && p->conn_ptr != GAIA_CONN_RESERVED)
1324 free_internal_cache (p->conn_ptr);
1325 }
1326 #endif /* end GEOS_REENTRANT */
1327
1328 gaia_already_initialized = 0;
1329 }
1330
1331 SPATIALITE_DECLARE void
spatialite_set_silent_mode(const void * p_cache)1332 spatialite_set_silent_mode (const void *p_cache)
1333 {
1334 /* setting up the SILENT mode */
1335 struct splite_internal_cache *cache =
1336 (struct splite_internal_cache *) p_cache;
1337 if (cache == NULL)
1338 return;
1339 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1340 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1341 return;
1342 cache->silent_mode = 1;
1343 }
1344
1345 SPATIALITE_DECLARE void
spatialite_set_verbose_mode(const void * p_cache)1346 spatialite_set_verbose_mode (const void *p_cache)
1347 {
1348 /* setting up the VERBOSE mode */
1349 struct splite_internal_cache *cache =
1350 (struct splite_internal_cache *) p_cache;
1351 if (cache == NULL)
1352 return;
1353 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1354 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1355 return;
1356 cache->silent_mode = 0;
1357 }
1358
1359 SPATIALITE_DECLARE void
enable_tiny_point(const void * p_cache)1360 enable_tiny_point (const void *p_cache)
1361 {
1362 /* Enabling the BLOB-TinyPoint encoding */
1363 struct splite_internal_cache *cache =
1364 (struct splite_internal_cache *) p_cache;
1365 if (cache == NULL)
1366 return;
1367 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1368 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1369 return;
1370 cache->tinyPointEnabled = 1;
1371 }
1372
1373 SPATIALITE_DECLARE void
disable_tiny_point(const void * p_cache)1374 disable_tiny_point (const void *p_cache)
1375 {
1376 /* Disabling the BLOB-TinyPoint encoding */
1377 struct splite_internal_cache *cache =
1378 (struct splite_internal_cache *) p_cache;
1379 if (cache == NULL)
1380 return;
1381 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1382 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1383 return;
1384 cache->tinyPointEnabled = 0;
1385 }
1386
1387 SPATIALITE_DECLARE int
is_tiny_point_enabled(const void * p_cache)1388 is_tiny_point_enabled (const void *p_cache)
1389 {
1390 /* Checking if the BLOB-TinyPoint encoding is enabled or not */
1391 struct splite_internal_cache *cache =
1392 (struct splite_internal_cache *) p_cache;
1393 if (cache == NULL)
1394 return 0;
1395 if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
1396 || cache->magic2 != SPATIALITE_CACHE_MAGIC2)
1397 return 0;
1398 return cache->tinyPointEnabled;
1399 }
1400
1401 SPATIALITE_PRIVATE struct gaia_variant_value *
gaia_alloc_variant()1402 gaia_alloc_variant ()
1403 {
1404 /* allocating and initializing a NULL Variant Value */
1405 struct gaia_variant_value *var =
1406 malloc (sizeof (struct gaia_variant_value));
1407 if (var == NULL)
1408 return NULL;
1409 var->dataType = SQLITE_NULL;
1410 var->textValue = NULL;
1411 var->blobValue = NULL;
1412 var->size = 0;
1413 return var;
1414 }
1415
1416 SPATIALITE_PRIVATE void
gaia_free_variant(struct gaia_variant_value * variant)1417 gaia_free_variant (struct gaia_variant_value *variant)
1418 {
1419 /* destroying a Variant Value */
1420 if (variant == NULL)
1421 return;
1422 if (variant->textValue != NULL)
1423 free (variant->textValue);
1424 if (variant->blobValue != NULL)
1425 free (variant->blobValue);
1426 free (variant);
1427 }
1428
1429 SPATIALITE_PRIVATE void
gaia_set_variant_null(struct gaia_variant_value * variant)1430 gaia_set_variant_null (struct gaia_variant_value *variant)
1431 {
1432 /* setting a Variant Value - NULL */
1433 if (variant->textValue != NULL)
1434 free (variant->textValue);
1435 if (variant->blobValue != NULL)
1436 free (variant->blobValue);
1437 variant->dataType = SQLITE_NULL;
1438 variant->textValue = NULL;
1439 variant->blobValue = NULL;
1440 variant->size = 0;
1441 }
1442
1443 SPATIALITE_PRIVATE void
gaia_set_variant_int64(struct gaia_variant_value * variant,sqlite3_int64 value)1444 gaia_set_variant_int64 (struct gaia_variant_value *variant, sqlite3_int64 value)
1445 {
1446 /* setting a Variant Value - INT64 */
1447 if (variant->textValue != NULL)
1448 free (variant->textValue);
1449 if (variant->blobValue != NULL)
1450 free (variant->blobValue);
1451 variant->dataType = SQLITE_INTEGER;
1452 variant->intValue = value;
1453 variant->textValue = NULL;
1454 variant->blobValue = NULL;
1455 variant->size = 0;
1456 }
1457
1458 SPATIALITE_PRIVATE void
gaia_set_variant_double(struct gaia_variant_value * variant,double value)1459 gaia_set_variant_double (struct gaia_variant_value *variant, double value)
1460 {
1461 /* setting a Variant Value - DOUBLE */
1462 if (variant->textValue != NULL)
1463 free (variant->textValue);
1464 if (variant->blobValue != NULL)
1465 free (variant->blobValue);
1466 variant->dataType = SQLITE_FLOAT;
1467 variant->dblValue = value;
1468 variant->textValue = NULL;
1469 variant->blobValue = NULL;
1470 variant->size = 0;
1471 }
1472
1473 SPATIALITE_PRIVATE int
gaia_set_variant_text(struct gaia_variant_value * variant,const char * value,int size)1474 gaia_set_variant_text (struct gaia_variant_value *variant, const char *value,
1475 int size)
1476 {
1477 /* setting a Variant Value - TEXT */
1478 char *text;
1479 if (variant->textValue != NULL)
1480 free (variant->textValue);
1481 if (variant->blobValue != NULL)
1482 free (variant->blobValue);
1483 text = malloc (size + 1);
1484 if (text == NULL)
1485 {
1486 variant->dataType = SQLITE_NULL;
1487 variant->textValue = NULL;
1488 variant->blobValue = NULL;
1489 variant->size = 0;
1490 return 0;
1491 }
1492 variant->dataType = SQLITE_TEXT;
1493 strcpy (text, value);
1494 variant->textValue = text;
1495 variant->blobValue = NULL;
1496 variant->size = size;
1497 return 1;
1498 }
1499
1500 SPATIALITE_PRIVATE int
gaia_set_variant_blob(struct gaia_variant_value * variant,const unsigned char * value,int size)1501 gaia_set_variant_blob (struct gaia_variant_value *variant,
1502 const unsigned char *value, int size)
1503 {
1504 /* setting a Variant Value - BLOB */
1505 unsigned char *blob;
1506 if (variant->textValue != NULL)
1507 free (variant->textValue);
1508 if (variant->blobValue != NULL)
1509 free (variant->blobValue);
1510 blob = malloc (size + 1);
1511 if (blob == NULL)
1512 {
1513 variant->dataType = SQLITE_NULL;
1514 variant->textValue = NULL;
1515 variant->blobValue = NULL;
1516 variant->size = 0;
1517 return 0;
1518 }
1519 variant->dataType = SQLITE_BLOB;
1520 memcpy (blob, value, size);
1521 variant->textValue = NULL;
1522 variant->blobValue = blob;
1523 variant->size = size;
1524 return 1;
1525 }
1526
1527 #ifdef PROJ_NEW /* only when using new PROJ.6 */
1528 SPATIALITE_DECLARE const void *
gaiaGetCurrentProjContext(const void * p_cache)1529 gaiaGetCurrentProjContext (const void *p_cache)
1530 {
1531 /* return the current PROJ.6 context (if any) */
1532 struct splite_internal_cache *cache =
1533 (struct splite_internal_cache *) p_cache;
1534 if (cache != NULL)
1535 {
1536 if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1537 && cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1538 return cache->PROJ_handle;
1539 }
1540 return NULL;
1541 }
1542
1543 SPATIALITE_DECLARE int
gaiaSetCurrentCachedProj(const void * p_cache,void * pj,const char * proj_string_1,const char * proj_string_2,void * area)1544 gaiaSetCurrentCachedProj (const void
1545 *p_cache, void *pj,
1546 const char *proj_string_1,
1547 const char *proj_string_2, void *area)
1548 {
1549 /* updates the PROJ6 internal cache */
1550 int ok = 0;
1551 int len;
1552 gaiaProjAreaPtr bbox_in = (gaiaProjAreaPtr) area;
1553 struct splite_internal_cache *cache =
1554 (struct splite_internal_cache *) p_cache;
1555 if (cache != NULL)
1556 {
1557 if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1558 && cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1559 ok = 1;
1560 }
1561 if (!ok)
1562 return 0; /* invalid cache */
1563 if (proj_string_1 == NULL || pj == NULL)
1564 return 0;
1565
1566 /* resetting the PROJ6 internal cache */
1567 if (cache->proj6_cached_string_1 != NULL)
1568 free (cache->proj6_cached_string_1);
1569 if (cache->proj6_cached_string_2 != NULL)
1570 free (cache->proj6_cached_string_2);
1571 if (cache->proj6_cached_area != NULL)
1572 free (cache->proj6_cached_area);
1573 if (cache->proj6_cached_pj != NULL)
1574 proj_destroy (cache->proj6_cached_pj);
1575
1576 /* updating the PROJ6 internal cache */
1577 cache->proj6_cached = 1;
1578 cache->proj6_cached_pj = pj;
1579 len = strlen (proj_string_1);
1580 cache->proj6_cached_string_1 = malloc (len + 1);
1581 strcpy (cache->proj6_cached_string_1, proj_string_1);
1582 if (proj_string_2 == NULL)
1583 cache->proj6_cached_string_2 = NULL;
1584 else
1585 {
1586 len = strlen (proj_string_2);
1587 cache->proj6_cached_string_2 = malloc (len + 1);
1588 strcpy (cache->proj6_cached_string_2, proj_string_2);
1589 }
1590 if (bbox_in == NULL)
1591 cache->proj6_cached_area = NULL;
1592 else
1593 {
1594 gaiaProjAreaPtr bbox_out =
1595 (gaiaProjAreaPtr) (cache->proj6_cached_area);
1596 if (bbox_out != NULL)
1597 free (bbox_out);
1598 bbox_out = malloc (sizeof (gaiaProjArea));
1599 bbox_out->WestLongitude = bbox_in->WestLongitude;
1600 bbox_out->SouthLatitude = bbox_in->SouthLatitude;
1601 bbox_out->EastLongitude = bbox_in->EastLongitude;
1602 bbox_out->NorthLatitude = bbox_in->NorthLatitude;
1603 cache->proj6_cached_area = bbox_out;
1604 }
1605 return 1;
1606 }
1607
1608 SPATIALITE_DECLARE void *
gaiaGetCurrentCachedProj(const void * p_cache)1609 gaiaGetCurrentCachedProj (const void *p_cache)
1610 {
1611 /* returning the currently cached PROJ6 object */
1612 struct splite_internal_cache *cache =
1613 (struct splite_internal_cache *) p_cache;
1614 if (cache != NULL)
1615 {
1616 if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1617 && cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1618 {
1619 if (cache->proj6_cached)
1620 return cache->proj6_cached_pj;
1621 else
1622 return NULL;
1623 }
1624 }
1625 return NULL; /* invalid cache */
1626 }
1627
1628 SPATIALITE_DECLARE int
gaiaCurrentCachedProjMatches(const void * p_cache,const char * proj_string_1,const char * proj_string_2,void * area)1629 gaiaCurrentCachedProjMatches (const void *p_cache,
1630 const char
1631 *proj_string_1,
1632 const char *proj_string_2, void *area)
1633 {
1634 /* checking if the currently cached PROJ6 object matches */
1635 int ok = 0;
1636 gaiaProjAreaPtr bbox_1 = (gaiaProjAreaPtr) area;
1637 struct splite_internal_cache *cache =
1638 (struct splite_internal_cache *) p_cache;
1639 if (cache != NULL)
1640 {
1641 if (cache->magic1 == SPATIALITE_CACHE_MAGIC1
1642 && cache->magic2 == SPATIALITE_CACHE_MAGIC2)
1643 ok = 1;
1644 }
1645 if (!ok)
1646 return 0; /* invalid cache */
1647 if (proj_string_1 == NULL)
1648 return 0; /* invalid request */
1649 if (cache->proj6_cached == 0)
1650 return 0; /* there is no PROJ6 object currently cached */
1651
1652 /* checking all definitions */
1653 if (strcmp (proj_string_1, cache->proj6_cached_string_1) != 0)
1654 return 0; /* mismatching string #1 */
1655 if (proj_string_2 == NULL && cache->proj6_cached_string_2 == NULL)
1656 ;
1657 else if (proj_string_2 != NULL && cache->proj6_cached_string_2 != NULL)
1658 {
1659 if (strcmp (proj_string_2, cache->proj6_cached_string_2) != 0)
1660 return 0; /* mismatching string #2 */
1661 }
1662 else
1663 return 0; /* mismatching string #2 */
1664 if (bbox_1 == NULL && cache->proj6_cached_area == NULL)
1665 ;
1666 else if (bbox_1 != NULL && cache->proj6_cached_area != NULL)
1667 {
1668 gaiaProjAreaPtr bbox_2 = (gaiaProjAreaPtr) (cache->proj6_cached_area);
1669 if (bbox_1->WestLongitude != bbox_2->WestLongitude)
1670 return 0;
1671 if (bbox_1->SouthLatitude != bbox_2->SouthLatitude)
1672 return 0;
1673 if (bbox_1->EastLongitude != bbox_2->EastLongitude)
1674 return 0;
1675 if (bbox_1->NorthLatitude != bbox_2->NorthLatitude)
1676 return 0;
1677 }
1678 else
1679 return 0; /* mismatching area */
1680
1681 return 1; /* anything nicely matches */
1682 }
1683 #endif
1684