1 /*
2
3 virtualgeojson.c -- SQLite3 extension [VIRTUAL TABLE GeoJson]
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) 2016-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 <sys/types.h>
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <float.h>
51
52 #if defined(_WIN32) && !defined(__MINGW32__)
53 #include "config-msvc.h"
54 #else
55 #include "config.h"
56 #endif
57
58 #include <spatialite/sqlite.h>
59 #include <spatialite/debug.h>
60
61 #include <spatialite/gaiaaux.h>
62 #include <spatialite.h>
63 #include <spatialite/spatialite_ext.h>
64 #include <spatialite/geojson.h>
65
66 #ifdef _WIN32
67 #define strcasecmp _stricmp
68 #endif /* not WIN32 */
69
70 static struct sqlite3_module my_geojson_module;
71
72 typedef struct VirtualGeoJsonStruct
73 {
74 /* extends the sqlite3_vtab struct */
75 const sqlite3_module *pModule; /* ptr to sqlite module: USED INTERNALLY BY SQLITE */
76 int nRef; /* # references: USED INTERNALLY BY SQLITE */
77 char *zErrMsg; /* error message: USE INTERNALLY BY SQLITE */
78 sqlite3 *db; /* the sqlite db holding the virtual table */
79 int Srid; /* the GeoJSON SRID */
80 char *TableName; /* the VirtualTable name */
81 int Valid; /* validity flag */
82 geojson_parser_ptr Parser; /* the GeoJSON Parser */
83 int DeclaredType; /* Geometry DeclaredType */
84 int DimensionModel; /* Geometry Dimension Model */
85 double MinX; /* the GeoJSON Full Extent */
86 double MinY;
87 double MaxX;
88 double MaxY;
89 } VirtualGeoJson;
90 typedef VirtualGeoJson *VirtualGeoJsonPtr;
91
92 typedef struct VirtualGeoJsonConstraintStruct
93 {
94 /* a constraint to be verified for xFilter */
95 int iColumn; /* Column on left-hand side of constraint */
96 int op; /* Constraint operator */
97 char valueType; /* value Type (GEOJSON_TEXT, GEOJSON_INTEGER, GEOJSON_DOUBLE etc) */
98 sqlite3_int64 intValue; /* Int64 comparison value */
99 double dblValue; /* Double comparison value */
100 char *txtValue; /* Text comparison value */
101 struct VirtualGeoJsonConstraintStruct *next;
102 } VirtualGeoJsonConstraint;
103 typedef VirtualGeoJsonConstraint *VirtualGeoJsonConstraintPtr;
104
105 typedef struct VirtualGeoJsonCursorStruct
106 {
107 /* extends the sqlite3_vtab_cursor struct */
108 VirtualGeoJsonPtr pVtab; /* Virtual table of this cursor */
109 int current_fid; /* the current row FID */
110 geojson_feature_ptr Feature; /* pointer to the current Feature */
111 int eof; /* the EOF marker */
112 VirtualGeoJsonConstraintPtr firstConstraint;
113 VirtualGeoJsonConstraintPtr lastConstraint;
114 } VirtualGeoJsonCursor;
115 typedef VirtualGeoJsonCursor *VirtualGeoJsonCursorPtr;
116
117
118 static int
geojson_is_float(const char * buf)119 geojson_is_float (const char *buf)
120 {
121 /* checking for a possible floating point number */
122 int ok = 0;
123 int err = 0;
124 unsigned int i;
125 for (i = 0; i < strlen (buf); i++)
126 {
127 if (i == 0 && (*(buf + i) == '-' || *(buf + i) == '+'))
128 continue;
129 if (*(buf + i) == '.')
130 {
131 ok++;
132 continue;
133 }
134 if (*(buf + i) == 'e' || *(buf + i) == 'E')
135 {
136 ok++;
137 continue;
138 }
139 if (*(buf + i) >= '0' && *(buf + i) <= '9')
140 ;
141 else
142 err++;
143 }
144 if (!err && ok == 1)
145 return 1;
146 return 0;
147 }
148
149 static geojson_property_ptr
geojson_create_property()150 geojson_create_property ()
151 {
152 /* creating an empty GeoJSON property */
153 geojson_property_ptr prop = malloc (sizeof (geojson_property));
154 prop->name = NULL;
155 prop->type = GEOJSON_UNKNOWN;
156 prop->txt_value = NULL;
157 prop->next = NULL;
158 return prop;
159 }
160
161 static void
geojson_destroy_property(geojson_property_ptr prop)162 geojson_destroy_property (geojson_property_ptr prop)
163 {
164 /* destroying a GeoJSON property */
165 if (prop->name != NULL)
166 free (prop->name);
167 if (prop->txt_value != NULL)
168 free (prop->txt_value);
169 free (prop);
170 }
171
172 static void
geojson_init_property(geojson_property_ptr prop)173 geojson_init_property (geojson_property_ptr prop)
174 {
175 /* initializing an empty GeoJSON property */
176 prop->name = NULL;
177 prop->type = GEOJSON_UNKNOWN;
178 prop->txt_value = NULL;
179 prop->next = NULL;
180 }
181
182 static void
geojson_reset_property(geojson_property_ptr prop)183 geojson_reset_property (geojson_property_ptr prop)
184 {
185 /* resetting a GeoJSON property */
186 if (prop->name != NULL)
187 free (prop->name);
188 if (prop->txt_value != NULL)
189 free (prop->txt_value);
190 geojson_init_property (prop);
191 }
192
193 static geojson_column_ptr
geojson_create_column(const char * name,int type)194 geojson_create_column (const char *name, int type)
195 {
196 /* creating a GeoJSON column object */
197 int len;
198 geojson_column_ptr col = malloc (sizeof (geojson_column));
199 len = strlen (name);
200 col->name = malloc (len + 1);
201 strcpy (col->name, name);
202 col->n_text = 0;
203 col->n_int = 0;
204 col->n_double = 0;
205 col->n_bool = 0;
206 col->n_null = 0;
207 col->next = NULL;
208 switch (type)
209 {
210 case GEOJSON_TEXT:
211 col->n_text = 1;
212 break;
213 case GEOJSON_INTEGER:
214 col->n_int = 1;
215 break;
216 case GEOJSON_DOUBLE:
217 col->n_double = 1;
218 break;
219 case GEOJSON_TRUE:
220 case GEOJSON_FALSE:
221 col->n_bool = 1;
222 break;
223 case GEOJSON_NULL:
224 col->n_null = 1;
225 break;
226 };
227 return col;
228 }
229
230 static geojson_stack_ptr
geojson_create_stack()231 geojson_create_stack ()
232 {
233 /* creating an empty GeoJSON stack object */
234 int i;
235 geojson_stack_ptr ptr = malloc (sizeof (geojson_stack));
236 ptr->level = -1;
237 memset (ptr->key, '\0', GEOJSON_MAX);
238 ptr->key_idx = 0;
239 memset (ptr->value, '\0', GEOJSON_MAX);
240 ptr->value_idx = 0;
241 memset (ptr->numvalue, '\0', GEOJSON_MAX);
242 ptr->numvalue_idx = 0;
243 for (i = 0; i < GEOJSON_STACK; i++)
244 {
245 geojson_stack_entry_ptr p = ptr->entries + i;
246 p->obj = NULL;
247 p->first = NULL;
248 p->last = NULL;
249 }
250 return ptr;
251 }
252
253 static void
geojson_destroy_stack(geojson_stack_ptr ptr)254 geojson_destroy_stack (geojson_stack_ptr ptr)
255 {
256 /* memory cleanup - destroying a GeoJSON stack object */
257 int i;
258 if (ptr == NULL)
259 return;
260 for (i = 0; i < GEOJSON_STACK; i++)
261 {
262 geojson_stack_entry_ptr p = ptr->entries + i;
263 geojson_keyval_ptr pkv = p->first;
264 while (pkv != NULL)
265 {
266 geojson_keyval_ptr pn = pkv->next;
267 if (pkv->key != NULL)
268 free (pkv->key);
269 if (pkv->value != NULL)
270 free (pkv->value);
271 free (pkv);
272 pkv = pn;
273 }
274 }
275 free (ptr);
276 }
277
278 static int
geojson_parse_key(geojson_stack_ptr stack,char c,char ** error_message)279 geojson_parse_key (geojson_stack_ptr stack, char c, char **error_message)
280 {
281 /* parsing a GeoJSON Object's Key string */
282 if (stack->key_idx >= GEOJSON_MAX - 1)
283 {
284 *error_message =
285 sqlite3_mprintf ("GeoJSON Object's Key string: len > %d chars\n",
286 GEOJSON_MAX);
287 return 0;
288 }
289 *(stack->key + stack->key_idx) = c;
290 stack->key_idx += 1;
291 return 1;
292 }
293
294 static int
geojson_parse_value(geojson_stack_ptr stack,char c,char ** error_message)295 geojson_parse_value (geojson_stack_ptr stack, char c, char **error_message)
296 {
297 /* parsing a GeoJSON Object's Value string */
298 if (stack->key_idx >= GEOJSON_MAX - 1)
299 {
300 *error_message =
301 sqlite3_mprintf
302 ("GeoJSON Object's Value string: len > %d chars\n", GEOJSON_MAX);
303 return 0;
304 }
305 *(stack->value + stack->value_idx) = c;
306 stack->value_idx += 1;
307 return 1;
308 }
309
310 static int
geojson_parse_numvalue(geojson_stack_ptr stack,char c,char ** error_message)311 geojson_parse_numvalue (geojson_stack_ptr stack, char c, char **error_message)
312 {
313 /* parsing a GeoJSON Object's numeric or special Value */
314 if (stack->numvalue_idx >= GEOJSON_MAX - 1)
315 {
316 *error_message =
317 sqlite3_mprintf
318 ("GeoJSON Object's Numeric Value: len > %d chars\n", GEOJSON_MAX);
319 return 0;
320 }
321 *(stack->numvalue + stack->numvalue_idx) = c;
322 stack->numvalue_idx += 1;
323 return 1;
324 }
325
326 static void
geojson_add_keyval(geojson_stack_ptr stack,int level)327 geojson_add_keyval (geojson_stack_ptr stack, int level)
328 {
329 /* adding a Key-Value item to a GeoJSON Object */
330 geojson_stack_entry_ptr entry;
331 geojson_keyval_ptr pkv;
332 int len;
333
334 if (*(stack->key) == '\0')
335 goto reset;
336 entry = stack->entries + level;
337 /* setting the Key name */
338 pkv = malloc (sizeof (geojson_keyval));
339 len = strlen (stack->key);
340 if (len > 0)
341 {
342 pkv->key = malloc (len + 1);
343 strcpy (pkv->key, stack->key);
344 }
345 else
346 pkv->key = NULL;
347 len = strlen (stack->value);
348 if (len > 0)
349 {
350 /* setting a string value */
351 pkv->value = malloc (len + 1);
352 strcpy (pkv->value, stack->value);
353 pkv->numvalue = 0;
354 }
355 else
356 pkv->value = NULL;
357 if (pkv->value == NULL)
358 {
359 len = strlen (stack->numvalue);
360 if (len > 0)
361 {
362 /* setting a numeric or special value */
363 pkv->value = malloc (len + 1);
364 strcpy (pkv->value, stack->numvalue);
365 pkv->numvalue = 1;
366 }
367 }
368 pkv->next = NULL;
369 /* updating the Key-Value linked list */
370 if (entry->first == NULL)
371 entry->first = pkv;
372 if (entry->last != NULL)
373 entry->last->next = pkv;
374 entry->last = pkv;
375
376 /* resetting the Key-Value input buffers */
377 reset:
378 memset (stack->key, '\0', GEOJSON_MAX);
379 stack->key_idx = 0;
380 memset (stack->value, '\0', GEOJSON_MAX);
381 stack->value_idx = 0;
382 memset (stack->numvalue, '\0', GEOJSON_MAX);
383 stack->numvalue_idx = 0;
384 }
385
386 static geojson_block_ptr
geojson_add_block(geojson_parser_ptr parser)387 geojson_add_block (geojson_parser_ptr parser)
388 {
389 /* adding a new block of objects to the GeoJSON parser */
390 int i;
391 geojson_block_ptr block;
392 if (parser == NULL)
393 return NULL;
394 block = malloc (sizeof (geojson_block));
395 /* initializing an empty block */
396 for (i = 0; i < GEOJSON_BLOCK; i++)
397 {
398 geojson_entry_ptr entry = block->entries + i;
399 entry->parent_key = NULL;
400 entry->type = GEOJSON_UNKNOWN;
401 entry->properties = 0;
402 entry->geometry = 0;
403 entry->offset_start = -1;
404 entry->offset_end = -1;
405 }
406 block->next_free_entry = 0;
407 block->next = NULL;
408 /* appending to the linked list */
409 if (parser->first == NULL)
410 parser->first = block;
411 if (parser->last != NULL)
412 parser->last->next = block;
413 parser->last = block;
414 return block;
415 }
416
417 static void
geojson_add_column(geojson_parser_ptr parser,const char * name,int type)418 geojson_add_column (geojson_parser_ptr parser, const char *name, int type)
419 {
420 /* updating the Columns list */
421 geojson_column_ptr col;
422
423 col = parser->first_col;
424 while (col != NULL)
425 {
426 if (strcasecmp (col->name, name) == 0)
427 {
428 /* already defined: updating stats */
429 switch (type)
430 {
431 case GEOJSON_TEXT:
432 col->n_text += 1;
433 break;
434 case GEOJSON_INTEGER:
435 col->n_int += 1;
436 break;
437 case GEOJSON_DOUBLE:
438 col->n_double += 1;
439 break;
440 case GEOJSON_TRUE:
441 case GEOJSON_FALSE:
442 col->n_bool += 1;
443 break;
444 case GEOJSON_NULL:
445 col->n_null += 1;
446 break;
447 };
448 return;
449 }
450 col = col->next;
451 }
452
453 /* inserting a new column into the list */
454 col = geojson_create_column (name, type);
455 if (parser->first_col == NULL)
456 parser->first_col = col;
457 if (parser->last_col != NULL)
458 parser->last_col->next = col;
459 parser->last_col = col;
460 }
461
462 static int
geojson_push(geojson_stack_ptr stack,geojson_entry_ptr entry,int level,char ** error_message)463 geojson_push (geojson_stack_ptr stack, geojson_entry_ptr entry, int level,
464 char **error_message)
465 {
466 /* GeoJSON stack pseudo-push */
467 geojson_stack_entry_ptr p_entry;
468 if (stack == NULL || entry == NULL)
469 {
470 *error_message = sqlite3_mprintf ("GeoJSON push: NULL pointer\n");
471 return 0;
472 }
473 if (level < 0 || level >= GEOJSON_STACK)
474 {
475 *error_message =
476 sqlite3_mprintf ("GeoJSON push: forbidden nesting level %d\n",
477 level);
478 return 0;
479 }
480 if (level != (stack->level + 1))
481 {
482 *error_message =
483 sqlite3_mprintf
484 ("GeoJSON push: unexpected nesting level %d (%d)\n", level,
485 stack->level);
486 return 0;
487 }
488 stack->level += 1;
489 p_entry = stack->entries + level;
490 if (p_entry->obj != NULL)
491 {
492 *error_message =
493 sqlite3_mprintf ("GeoJSON push: unexpected unfreed level %d\n",
494 level);
495 return 0;
496 }
497 /* initializing the stack entry */
498 p_entry->obj = entry;
499 memset (stack->key, '\0', GEOJSON_MAX);
500 stack->key_idx = 0;
501 memset (stack->value, '\0', GEOJSON_MAX);
502 stack->value_idx = 0;
503 memset (stack->numvalue, '\0', GEOJSON_MAX);
504 stack->numvalue_idx = 0;
505 return 1;
506 }
507
508 static int
geojson_pop(geojson_stack_ptr stack,int level,long offset,char ** error_message)509 geojson_pop (geojson_stack_ptr stack, int level, long offset,
510 char **error_message)
511 {
512 /* GeoJSON stack pseudo-pop */
513 geojson_stack_entry_ptr p_entry;
514 geojson_keyval_ptr pkv;
515 if (level < 0 || level >= GEOJSON_STACK)
516 {
517 *error_message =
518 sqlite3_mprintf ("GeoJSON pop: forbidden nesting level %d\n",
519 level);
520 return 0;
521 }
522 if (level != stack->level)
523 {
524 *error_message =
525 sqlite3_mprintf
526 ("GeoJSON pop: unexpected nesting level %d (%d)\n", level,
527 stack->level);
528 return 0;
529 }
530 p_entry = stack->entries + level;
531 if (p_entry->obj == NULL)
532 {
533 *error_message =
534 sqlite3_mprintf
535 ("GeoJSON pop: unexpected uninitialized level %d\n", level);
536 return 0;
537 }
538 p_entry->obj->offset_end = offset;
539 if (strcasecmp (p_entry->obj->parent_key, "properties") == 0)
540 p_entry->obj->type = GEOJSON_PROPERTIES;
541 pkv = p_entry->first;
542 if (pkv != NULL)
543 {
544 if (pkv->key != NULL)
545 {
546 if (strcasecmp (pkv->key, "type") == 0)
547 {
548 if (pkv->value != NULL)
549 {
550 if (strcasecmp (pkv->value, "FeatureCollection") ==
551 0)
552 p_entry->obj->type = GEOJSON_FCOLLECTION;
553 if (strcasecmp (pkv->value, "Feature") == 0)
554 p_entry->obj->type = GEOJSON_FEATURE;
555 if (strcasecmp
556 (p_entry->obj->parent_key, "geometry") == 0)
557 {
558 if (strcasecmp (pkv->value, "Point") == 0)
559 p_entry->obj->type = GEOJSON_POINT;
560 if (strcasecmp (pkv->value, "LineString") ==
561 0)
562 p_entry->obj->type = GEOJSON_LINESTRING;
563 if (strcasecmp (pkv->value, "Polygon") == 0)
564 p_entry->obj->type = GEOJSON_POLYGON;
565 if (strcasecmp (pkv->value, "MultiPoint") ==
566 0)
567 p_entry->obj->type = GEOJSON_MULTIPOINT;
568 if (strcasecmp (pkv->value, "MultiLineString")
569 == 0)
570 p_entry->obj->type =
571 GEOJSON_MULTILINESTRING;
572 if (strcasecmp (pkv->value, "MultiPolygon") ==
573 0)
574 p_entry->obj->type = GEOJSON_MULTIPOLYGON;
575 if (strcasecmp
576 (pkv->value, "GeometryCollection") == 0)
577 p_entry->obj->type =
578 GEOJSON_GEOMCOLLECTION;
579 }
580 }
581 }
582 }
583 }
584 if (p_entry->obj->type == GEOJSON_FEATURE)
585 {
586 pkv = p_entry->first;
587 while (pkv != NULL)
588 {
589 if (strcasecmp (pkv->key, "geometry") == 0
590 && pkv->value == NULL)
591 p_entry->obj->geometry += 1;
592 if (strcasecmp (pkv->key, "properties") == 0
593 && pkv->value == NULL)
594 p_entry->obj->properties += 1;
595 pkv = pkv->next;
596 }
597 }
598
599 /* resetting the Key-Value list */
600 pkv = p_entry->first;
601 while (pkv != NULL)
602 {
603 geojson_keyval_ptr pn = pkv->next;
604 if (pkv->key != NULL)
605 free (pkv->key);
606 if (pkv->value != NULL)
607 free (pkv->value);
608 free (pkv);
609 pkv = pn;
610 }
611 p_entry->first = NULL;
612 p_entry->last = NULL;
613
614 /* resetting the stack entry */
615 p_entry->obj = NULL;
616 memset (stack->key, '\0', GEOJSON_MAX);
617 stack->key_idx = 0;
618 memset (stack->value, '\0', GEOJSON_MAX);
619 stack->value_idx = 0;
620 memset (stack->numvalue, '\0', GEOJSON_MAX);
621 stack->numvalue_idx = 0;
622 stack->level -= 1;
623 return 1;
624 }
625
626 static geojson_entry_ptr
geojson_add_object(geojson_block_ptr block,long offset,const char * parent_key)627 geojson_add_object (geojson_block_ptr block, long offset,
628 const char *parent_key)
629 {
630 /* adding a new GeoJSON object */
631 geojson_entry_ptr entry;
632 if (block->next_free_entry < 0 || block->next_free_entry >= GEOJSON_BLOCK)
633 return NULL;
634 entry = block->entries + block->next_free_entry;
635 block->next_free_entry += 1;
636 entry->type = GEOJSON_UNKNOWN;
637 if (entry->parent_key != NULL)
638 free (entry->parent_key);
639 entry->parent_key = NULL;
640 if (parent_key != NULL)
641 {
642 int len = strlen (parent_key);
643 entry->parent_key = malloc (len + 1);
644 strcpy (entry->parent_key, parent_key);
645 }
646 entry->offset_start = offset;
647 entry->offset_end = -1;
648 return entry;
649 }
650
651
652 static int
geojson_start_object(geojson_parser_ptr parser,geojson_stack_ptr stack,int level,long offset,const char * parent_key,char ** error_message)653 geojson_start_object (geojson_parser_ptr parser, geojson_stack_ptr stack,
654 int level, long offset, const char *parent_key,
655 char **error_message)
656 {
657 /* registering a GeoJSON object */
658 int expand = 0;
659 geojson_block_ptr block;
660 geojson_entry_ptr entry;
661
662 if (parser->last == NULL)
663 expand = 1;
664 else if (parser->last->next_free_entry >= GEOJSON_BLOCK)
665 expand = 1;
666 if (expand)
667 {
668 /* adding a new GeoJSON Block to the parser's list */
669 block = geojson_add_block (parser);
670 }
671 else
672 {
673 /* continuing to insert into the last Block */
674 block = parser->last;
675 }
676 if (block == NULL)
677 {
678 *error_message =
679 sqlite3_mprintf ("GeoJSON start_object: NULL pointer\n");
680 return 0;
681 }
682 entry = geojson_add_object (block, offset, parent_key);
683 if (!geojson_push (stack, entry, level, error_message))
684 return 0;
685 return 1;
686 }
687
688 static int
geojson_end_object(geojson_stack_ptr stack,int level,long offset,char ** error_message)689 geojson_end_object (geojson_stack_ptr stack, int level, long offset,
690 char **error_message)
691 {
692 /* completing the definition of a GeoJSON object */
693 if (!geojson_pop (stack, level, offset, error_message))
694 return 0;
695 return 1;
696 }
697
698 SPATIALITE_DECLARE geojson_parser_ptr
geojson_create_parser(FILE * in)699 geojson_create_parser (FILE * in)
700 {
701 /* creating an empty GeoJSON parser object */
702 geojson_parser_ptr ptr = malloc (sizeof (geojson_parser));
703 ptr->in = in;
704 ptr->first = NULL;
705 ptr->last = NULL;
706 ptr->count = 0;
707 ptr->features = NULL;
708 ptr->first_col = NULL;
709 ptr->last_col = NULL;
710 ptr->n_points = 0;
711 ptr->n_linestrings = 0;
712 ptr->n_polygons = 0;
713 ptr->n_mpoints = 0;
714 ptr->n_mlinestrings = 0;
715 ptr->n_mpolygons = 0;
716 ptr->n_geomcolls = 0;
717 ptr->n_geom_2d = 0;
718 ptr->n_geom_3d = 0;
719 ptr->n_geom_4d = 0;
720 *(ptr->cast_type) = '\0';
721 *(ptr->cast_dims) = '\0';
722 return ptr;
723 }
724
725 SPATIALITE_DECLARE void
geojson_destroy_parser(geojson_parser_ptr ptr)726 geojson_destroy_parser (geojson_parser_ptr ptr)
727 {
728 /* memory cleanup - destroying a GeoJSON parser object */
729 geojson_block_ptr pb;
730 geojson_block_ptr pbn;
731 geojson_column_ptr pc;
732 geojson_column_ptr pcn;
733 int i;
734 if (ptr == NULL)
735 return;
736 pb = ptr->first;
737 while (pb != NULL)
738 {
739 pbn = pb->next;
740 free (pb);
741 pb = pbn;
742 }
743 pc = ptr->first_col;
744 while (pc != NULL)
745 {
746 pcn = pc->next;
747 if (pc->name != NULL)
748 free (pc->name);
749 free (pc);
750 pc = pcn;
751 }
752 if (ptr->features != NULL)
753 {
754 for (i = 0; i < ptr->count; i++)
755 {
756 geojson_property_ptr pp;
757 geojson_feature_ptr pf = ptr->features + i;
758 if (pf->geometry != NULL)
759 free (pf->geometry);
760 pp = pf->first;
761 while (pp != NULL)
762 {
763 geojson_property_ptr ppn = pp->next;
764 if (pp->name != NULL)
765 free (pp->name);
766 if (pp->txt_value != NULL)
767 free (pp->txt_value);
768 free (pp);
769 pp = ppn;
770 }
771 }
772 free (ptr->features);
773 }
774 /* close the GeoJSON file handle */
775 if (ptr->in != NULL)
776 fclose (ptr->in);
777 free (ptr);
778 }
779
780 SPATIALITE_DECLARE int
geojson_parser_init(geojson_parser_ptr parser,char ** error_message)781 geojson_parser_init (geojson_parser_ptr parser, char **error_message)
782 {
783 /* initializing the GeoJSON parser object */
784 int c;
785 long offset;
786 int level = -1;
787 int is_string = 0;
788 int prev_char = '\0';
789 int is_first = 0;
790 int is_second = 0;
791 int is_first_ready = 0;
792 int is_second_ready = 0;
793 int is_numeric = 0;
794 geojson_stack_ptr stack = geojson_create_stack ();
795 *error_message = NULL;
796
797 while ((c = getc (parser->in)) != EOF)
798 {
799 /* consuming the GeoJSON input file */
800 if (is_string)
801 {
802 /* consuming a quoted text string */
803 if (c == '"' && prev_char != '/')
804 {
805 is_string = 0; /* end string marker */
806 if (is_first)
807 {
808 /* found the GeoJSON object Key terminator */
809 is_first = 0;
810 }
811 if (is_second)
812 {
813 /* found the GeoJSON object Value terminator */
814 is_second = 0;
815 }
816 }
817 else
818 {
819 if (is_first)
820 {
821 /* found the GeoJSON object Key */
822 if (!geojson_parse_key (stack, c, error_message))
823 goto err;
824 }
825 if (is_second)
826 {
827 /* found the GeoJSON object Value */
828 if (!geojson_parse_value (stack, c, error_message))
829 goto err;
830 }
831 }
832 prev_char = c;
833 continue;
834 }
835 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
836 {
837 /* ignoring white spaces */
838 prev_char = c;
839 continue;
840 }
841 if (c == '[' || c == ']')
842 {
843 prev_char = c;
844 is_second_ready = 0;
845 is_second = 0;
846 is_numeric = 0;
847 continue;
848 }
849 if (c == '{')
850 {
851 /* found a JSON Start Object marker */
852 char parent_key[GEOJSON_MAX];
853 strcpy (parent_key, stack->key);
854 if (level >= 0)
855 geojson_add_keyval (stack, level);
856 level++;
857 offset = ftell (parser->in);
858 if (!geojson_start_object
859 (parser, stack, level, offset, parent_key, error_message))
860 goto err;
861 prev_char = c;
862 is_first_ready = 1;
863 is_first = 0;
864 is_second_ready = 0;
865 is_second = 0;
866 is_numeric = 0;
867 continue;
868 }
869 if (c == '}')
870 {
871 /* found a JSON End Object marker */
872 geojson_add_keyval (stack, level);
873 offset = ftell (parser->in);
874 if (!geojson_end_object (stack, level, offset, error_message))
875 goto err;
876 level--;
877 prev_char = c;
878 is_first_ready = 0;
879 is_first = 0;
880 is_second_ready = 0;
881 is_second = 0;
882 is_numeric = 0;
883 continue;
884 }
885 if (c == ':')
886 {
887 prev_char = c;
888 is_first_ready = 0;
889 is_second_ready = 1;
890 continue;
891 }
892 if (c == ',')
893 {
894 geojson_add_keyval (stack, level);
895 prev_char = c;
896 is_first_ready = 1;
897 is_first = 0;
898 is_second_ready = 0;
899 is_second = 0;
900 is_numeric = 0;
901 continue;
902 }
903 if (c == '"')
904 {
905 /* a quoted text string starts here */
906 is_string = 1;
907 prev_char = c;
908 if (is_first_ready)
909 {
910 is_first_ready = 0;
911 is_first = 1;
912 }
913 if (is_second_ready)
914 {
915 is_second_ready = 0;
916 is_second = 1;
917 }
918 continue;
919 }
920 if (is_second_ready)
921 {
922 /* should be the beginning of some numeric value */
923 is_second_ready = 0;
924 is_numeric = 1;
925 }
926 if (is_numeric)
927 {
928 /* consuming a numeric or special value */
929 if (!geojson_parse_numvalue (stack, c, error_message))
930 goto err;
931 prev_char = c;
932 continue;
933 }
934 prev_char = c;
935 }
936 geojson_destroy_stack (stack);
937 return 1;
938
939 err:
940 geojson_destroy_stack (stack);
941 return 0;
942 }
943
944 static int
geojson_get_property(const char * buf,geojson_stack_ptr stack,geojson_property_ptr prop,int * off,char ** error_message)945 geojson_get_property (const char *buf, geojson_stack_ptr stack,
946 geojson_property_ptr prop, int *off, char **error_message)
947 {
948 /* parsing the Feature's Properties string */
949 char c;
950 int len;
951 int is_string = 0;
952 int prev_char = '\0';
953 int is_first = 0;
954 int is_second = 0;
955 int is_first_ready = 1;
956 int is_second_ready = 0;
957 int is_numeric = 0;
958 const char *end_p = buf + strlen (buf);
959 const char *p = buf + *off;
960 if (p < buf || p >= end_p)
961 return -1; /* the string has been completely parsed */
962
963 /* resetting all stack buffers */
964 memset (stack->key, '\0', GEOJSON_MAX);
965 stack->key_idx = 0;
966 memset (stack->value, '\0', GEOJSON_MAX);
967 stack->value_idx = 0;
968 memset (stack->numvalue, '\0', GEOJSON_MAX);
969 stack->numvalue_idx = 0;
970
971 while (1)
972 {
973 /* consuming the GeoJSON Properties string */
974 if (p >= end_p)
975 break;
976 c = *p++;
977 if (is_string)
978 {
979 /* consuming a quoted text string */
980 if (c == '"' && prev_char != '/')
981 {
982 is_string = 0; /* end string marker */
983 if (is_first)
984 {
985 /* found the GeoJSON object Key terminator */
986 is_first = 0;
987 }
988 if (is_second)
989 {
990 /* found the GeoJSON object Value terminator */
991 is_second = 0;
992 }
993 }
994 else
995 {
996 if (is_first)
997 {
998 /* found the GeoJSON object Key */
999 if (!geojson_parse_key (stack, c, error_message))
1000 goto err;
1001 if (prop->name != NULL)
1002 free (prop->name);
1003 len = strlen (stack->key);
1004 if (len == 0)
1005 prop->name = NULL;
1006 else
1007 {
1008 prop->name = malloc (len + 1);
1009 strcpy (prop->name, stack->key);
1010 }
1011 }
1012 if (is_second)
1013 {
1014 /* found the GeoJSON object Value */
1015 if (!geojson_parse_value (stack, c, error_message))
1016 goto err;
1017 if (prop->txt_value != NULL)
1018 free (prop->txt_value);
1019 prop->txt_value = NULL;
1020 len = strlen (stack->value);
1021 if (len > 0)
1022 {
1023 prop->txt_value = malloc (len + 1);
1024 strcpy (prop->txt_value, stack->value);
1025 }
1026 prop->type = GEOJSON_TEXT;
1027 }
1028 }
1029 prev_char = c;
1030 continue;
1031 }
1032 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
1033 {
1034 /* ignoring white spaces */
1035 prev_char = c;
1036 continue;
1037 }
1038 if (c == ':')
1039 {
1040 prev_char = c;
1041 is_first = 0;
1042 is_first_ready = 0;
1043 is_second_ready = 1;
1044 continue;
1045 }
1046 if (c == ',')
1047 break;
1048 if (c == '"')
1049 {
1050 /* a quoted text string starts here */
1051 is_string = 1;
1052 prev_char = c;
1053 if (is_first_ready)
1054 {
1055 is_first_ready = 0;
1056 is_first = 1;
1057 }
1058 if (is_second_ready)
1059 {
1060 is_second_ready = 0;
1061 is_second = 1;
1062 }
1063 continue;
1064 }
1065 if (is_second_ready)
1066 {
1067 /* should be the beginning of some numeric value */
1068 is_second_ready = 0;
1069 is_numeric = 1;
1070 }
1071 if (is_numeric)
1072 {
1073 /* consuming a numeric or special value */
1074 if (!geojson_parse_numvalue (stack, c, error_message))
1075 goto err;
1076 prev_char = c;
1077 continue;
1078 }
1079 prev_char = c;
1080 }
1081 if (is_numeric)
1082 {
1083 if (strcmp (stack->numvalue, "null") == 0)
1084 prop->type = GEOJSON_NULL;
1085 else if (strcmp (stack->numvalue, "true") == 0)
1086 prop->type = GEOJSON_TRUE;
1087 else if (strcmp (stack->numvalue, "false") == 0)
1088 prop->type = GEOJSON_FALSE;
1089 else
1090 {
1091 len = strlen (stack->numvalue);
1092 if (len > 0)
1093 {
1094 if (geojson_is_float (stack->numvalue))
1095 {
1096 prop->dbl_value = atof (stack->numvalue);
1097 prop->type = GEOJSON_DOUBLE;
1098 }
1099 else
1100 {
1101 prop->int_value = atoll (stack->numvalue);
1102 prop->type = GEOJSON_INTEGER;
1103 }
1104 }
1105 }
1106 }
1107
1108 *off = p - buf;
1109 return 1;
1110
1111 err:
1112 return 0;
1113 }
1114
1115 static int
geojson_parse_columns(geojson_parser_ptr parser,const char * buf,char ** error_message)1116 geojson_parse_columns (geojson_parser_ptr parser, const char *buf,
1117 char **error_message)
1118 {
1119 /* attempting to parse Feature's Properties for detecting Column types */
1120 int off = 0;
1121 geojson_stack_ptr stack = geojson_create_stack ();
1122 geojson_property prop;
1123 geojson_init_property (&prop);
1124
1125 while (1)
1126 {
1127 int ret;
1128 geojson_reset_property (&prop);
1129 ret = geojson_get_property (buf, stack, &prop, &off, error_message);
1130 if (ret <= 0)
1131 geojson_reset_property (&prop);
1132 if (ret < 0)
1133 break;
1134 if (ret == 0)
1135 goto err;
1136 if (prop.name != NULL)
1137 {
1138 switch (prop.type)
1139 {
1140 case GEOJSON_TEXT:
1141 case GEOJSON_INTEGER:
1142 case GEOJSON_DOUBLE:
1143 case GEOJSON_TRUE:
1144 case GEOJSON_FALSE:
1145 case GEOJSON_NULL:
1146 geojson_add_column (parser, prop.name, prop.type);
1147 break;
1148 default:
1149 goto err;
1150 };
1151 }
1152 else
1153 goto err;
1154 geojson_reset_property (&prop);
1155 }
1156 geojson_destroy_stack (stack);
1157 return 1;
1158
1159 err:
1160 geojson_destroy_stack (stack);
1161 return 0;
1162 }
1163
1164 static int
geojson_parse_properties(geojson_feature_ptr ft,const char * buf,char ** error_message)1165 geojson_parse_properties (geojson_feature_ptr ft, const char *buf,
1166 char **error_message)
1167 {
1168 /* attempting to parse Feature's Properties for loading Values */
1169 int off = 0;
1170 geojson_stack_ptr stack = geojson_create_stack ();
1171 geojson_property_ptr prop;
1172
1173 while (1)
1174 {
1175 int ret;
1176 prop = geojson_create_property ();
1177 ret = geojson_get_property (buf, stack, prop, &off, error_message);
1178 if (ret <= 0)
1179 geojson_destroy_property (prop);
1180 if (ret < 0)
1181 break;
1182 if (ret == 0)
1183 goto err;
1184 if (prop->name != NULL)
1185 {
1186 switch (prop->type)
1187 {
1188 case GEOJSON_TEXT:
1189 case GEOJSON_INTEGER:
1190 case GEOJSON_DOUBLE:
1191 case GEOJSON_TRUE:
1192 case GEOJSON_FALSE:
1193 case GEOJSON_NULL:
1194 /* adding a Property into the linked list */
1195 if (ft->first == NULL)
1196 ft->first = prop;
1197 if (ft->last != NULL)
1198 ft->last->next = prop;
1199 ft->last = prop;
1200 break;
1201 default:
1202 geojson_destroy_property (prop);
1203 goto err;
1204 };
1205 }
1206 else
1207 {
1208 geojson_destroy_property (prop);
1209 goto err;
1210 }
1211 }
1212 geojson_destroy_stack (stack);
1213 return 1;
1214
1215 err:
1216 geojson_destroy_stack (stack);
1217 return 0;
1218 }
1219
1220 SPATIALITE_DECLARE int
geojson_check_features(geojson_parser_ptr parser,char ** error_message)1221 geojson_check_features (geojson_parser_ptr parser, char **error_message)
1222 {
1223 /* checking Features for validity */
1224 int i;
1225 int len;
1226 char *buf;
1227 gaiaGeomCollPtr geo = NULL;
1228 *error_message = NULL;
1229
1230 if (parser == NULL)
1231 {
1232 *error_message = sqlite3_mprintf ("GeoJSON parser: NULL object\n");
1233 return 0;
1234 }
1235 parser->n_points = 0;
1236 parser->n_linestrings = 0;
1237 parser->n_polygons = 0;
1238 parser->n_mpoints = 0;
1239 parser->n_mlinestrings = 0;
1240 parser->n_mpolygons = 0;
1241 parser->n_geomcolls = 0;
1242 parser->n_geom_2d = 0;
1243 parser->n_geom_3d = 0;
1244 parser->n_geom_4d = 0;
1245 *(parser->cast_type) = '\0';
1246 *(parser->cast_dims) = '\0';
1247 for (i = 0; i < parser->count; i++)
1248 {
1249 /* reading and parsing Properties for each Feature */
1250 int ret;
1251 geojson_feature_ptr ft = parser->features + i;
1252 if (ft->prop_offset_start < 0 || ft->prop_offset_end < 0)
1253 {
1254 *error_message =
1255 sqlite3_mprintf
1256 ("GeoJSON parser: invalid Properties (fid=%d)\n", ft->fid);
1257 return 0;
1258 }
1259 if (ft->prop_offset_end <= ft->prop_offset_start)
1260 {
1261 *error_message =
1262 sqlite3_mprintf
1263 ("GeoJSON parser: invalid Properties (fid=%d)\n", ft->fid);
1264 return 0;
1265 }
1266 ret = fseek (parser->in, ft->prop_offset_start, SEEK_SET);
1267 if (ret != 0)
1268 {
1269 *error_message =
1270 sqlite3_mprintf
1271 ("GeoJSON parser: Properties invalid seek (fid=%d)\n",
1272 ft->fid);
1273 return 0;
1274 }
1275 len = ft->prop_offset_end - ft->prop_offset_start - 1;
1276 buf = malloc (len + 1);
1277 if (buf == NULL)
1278 {
1279 *error_message =
1280 sqlite3_mprintf
1281 ("GeoJSON parser: Properties insufficient memory (fid=%d)\n",
1282 ft->fid);
1283 return 0;
1284 }
1285 ret = fread (buf, 1, len, parser->in);
1286 if (ret != len)
1287 {
1288 *error_message =
1289 sqlite3_mprintf
1290 ("GeoJSON parser: Properties read error (fid=%d)\n",
1291 ft->fid);
1292 free (buf);
1293 return 0;
1294 }
1295 *(buf + len) = '\0';
1296 geojson_parse_columns (parser, buf, error_message);
1297 free (buf);
1298 }
1299 for (i = 0; i < parser->count; i++)
1300 {
1301 /* reading and parsing Geometry for each Feature */
1302 int ret;
1303 geojson_feature_ptr ft = parser->features + i;
1304 if (ft->geom_offset_start < 0 || ft->geom_offset_end < 0)
1305 {
1306 *error_message =
1307 sqlite3_mprintf
1308 ("GeoJSON parser: invalid Geometry (fid=%d)\n", ft->fid);
1309 return 0;
1310 }
1311 if (ft->geom_offset_end <= ft->geom_offset_start)
1312 {
1313 *error_message =
1314 sqlite3_mprintf
1315 ("GeoJSON parser: invalid Geometry (fid=%d)\n", ft->fid);
1316 return 0;
1317 }
1318 ret = fseek (parser->in, ft->geom_offset_start, SEEK_SET);
1319 if (ret != 0)
1320 {
1321 *error_message =
1322 sqlite3_mprintf
1323 ("GeoJSON parser: Geometry invalid seek (fid=%d)\n",
1324 ft->fid);
1325 return 0;
1326 }
1327 len = ft->geom_offset_end - ft->geom_offset_start;
1328 if (len == 0)
1329 {
1330 /* NULL Geometry */
1331 parser->n_geom_null += 1;
1332 continue;
1333 }
1334 buf = malloc (len + 2);
1335 if (buf == NULL)
1336 {
1337 *error_message =
1338 sqlite3_mprintf
1339 ("GeoJSON parser: Geometry insufficient memory (fid=%d)\n",
1340 ft->fid);
1341 return 0;
1342 }
1343 *buf = '{';
1344 ret = fread (buf + 1, 1, len, parser->in);
1345 if (ret != len)
1346 {
1347 *error_message =
1348 sqlite3_mprintf
1349 ("GeoJSON parser: Geometry read error (fid=%d)\n", ft->fid);
1350 free (buf);
1351 return 0;
1352 }
1353 *(buf + len + 1) = '\0';
1354 geo = gaiaParseGeoJSON ((const unsigned char *) buf);
1355 if (geo != NULL)
1356 {
1357 /* sniffing GeometryType and Dimensions */
1358 switch (geo->DimensionModel)
1359 {
1360 case GAIA_XY:
1361 parser->n_geom_2d += 1;
1362 break;
1363 case GAIA_XY_Z:
1364 parser->n_geom_3d += 1;
1365 break;
1366 case GAIA_XY_Z_M:
1367 parser->n_geom_4d += 1;
1368 break;
1369 default:
1370 *error_message =
1371 sqlite3_mprintf
1372 ("GeoJSON parser: Geometry has invalid dimensions (fid=%d)\n",
1373 ft->fid);
1374 free (buf);
1375 gaiaFreeGeomColl (geo);
1376 return 0;
1377 };
1378 switch (geo->DeclaredType)
1379 {
1380 case GAIA_POINT:
1381 parser->n_points += 1;
1382 break;
1383 case GAIA_LINESTRING:
1384 parser->n_linestrings += 1;
1385 break;
1386 case GAIA_POLYGON:
1387 parser->n_polygons += 1;
1388 break;
1389 case GAIA_MULTIPOINT:
1390 parser->n_mpoints += 1;
1391 break;
1392 case GAIA_MULTILINESTRING:
1393 parser->n_mlinestrings += 1;
1394 break;
1395 case GAIA_MULTIPOLYGON:
1396 parser->n_mpolygons += 1;
1397 break;
1398 case GAIA_GEOMETRYCOLLECTION:
1399 parser->n_geomcolls += 1;
1400 break;
1401 default:
1402 *error_message =
1403 sqlite3_mprintf
1404 ("GeoJSON parser: Geometry has an invalid Type (fid=%d)\n",
1405 ft->fid);
1406 free (buf);
1407 gaiaFreeGeomColl (geo);
1408 return 0;
1409 };
1410 gaiaFreeGeomColl (geo);
1411 }
1412 else
1413 parser->n_geom_null += 1;
1414 free (buf);
1415 }
1416 return 1;
1417 }
1418
1419 SPATIALITE_DECLARE int
geojson_create_features_index(geojson_parser_ptr parser,char ** error_message)1420 geojson_create_features_index (geojson_parser_ptr parser, char **error_message)
1421 {
1422 /* creating the index of all GeoJSON Features */
1423 geojson_block_ptr pb;
1424 geojson_block_ptr pbn;
1425 geojson_feature_ptr pf = NULL;
1426 geojson_entry_ptr entry;
1427 int count;
1428 int i;
1429 *error_message = NULL;
1430
1431 if (parser == NULL)
1432 {
1433 *error_message = sqlite3_mprintf ("GeoJSON parser: NULL object\n");
1434 return 0;
1435 }
1436
1437 parser->count = 0;
1438 pb = parser->first;
1439 while (pb != NULL)
1440 {
1441 /* counting how many Features are there */
1442 for (i = 0; i < pb->next_free_entry; i++)
1443 {
1444 entry = pb->entries + i;
1445 if (entry->type != GEOJSON_FEATURE)
1446 continue;
1447 parser->count += 1;
1448 }
1449 pb = pb->next;
1450 }
1451 if (parser->features != NULL)
1452 free (parser->features);
1453 /* allocating the index of all Features */
1454 if (parser->count <= 0)
1455 {
1456 *error_message =
1457 sqlite3_mprintf
1458 ("GeoJSON parser: not a single Feature was found ... invalid format ?\n");
1459 return 0;
1460 }
1461 parser->features = malloc (sizeof (geojson_feature) * parser->count);
1462 if (parser->features == NULL)
1463 {
1464 *error_message =
1465 sqlite3_mprintf ("GeoJSON parser: insufficient memory\n");
1466 return 0;
1467 }
1468 for (i = 0; i < parser->count; i++)
1469 {
1470 /* initializing empty Features */
1471 pf = parser->features + i;
1472 pf->fid = i + 1;
1473 pf->geom_offset_start = -1;
1474 pf->geom_offset_end = -1;
1475 pf->prop_offset_start = -1;
1476 pf->prop_offset_end = -1;
1477 pf->geometry = NULL;
1478 pf->first = NULL;
1479 pf->last = NULL;
1480 }
1481
1482 count = 0;
1483 pb = parser->first;
1484 while (pb != NULL)
1485 {
1486 /* properly initializing Features */
1487 for (i = 0; i < pb->next_free_entry; i++)
1488 {
1489 entry = pb->entries + i;
1490 if (entry->type != GEOJSON_FEATURE)
1491 {
1492 if (pf != NULL)
1493 {
1494 if (entry->type == GEOJSON_POINT ||
1495 entry->type == GEOJSON_LINESTRING ||
1496 entry->type == GEOJSON_POLYGON ||
1497 entry->type == GEOJSON_MULTIPOINT ||
1498 entry->type == GEOJSON_MULTILINESTRING ||
1499 entry->type == GEOJSON_MULTIPOLYGON ||
1500 entry->type == GEOJSON_GEOMCOLLECTION)
1501 {
1502 pf->geom_offset_start = entry->offset_start;
1503 pf->geom_offset_end = entry->offset_end;
1504 }
1505 if (entry->type == GEOJSON_PROPERTIES)
1506 {
1507 pf->prop_offset_start = entry->offset_start;
1508 pf->prop_offset_end = entry->offset_end;
1509 }
1510 }
1511 continue;
1512 }
1513 pf = parser->features + count;
1514 count += 1;
1515 }
1516 pb = pb->next;
1517 }
1518
1519 /* destroying the Pass I dictionary */
1520 pb = parser->first;
1521 while (pb != NULL)
1522 {
1523 for (i = 0; i < pb->next_free_entry; i++)
1524 {
1525 geojson_entry_ptr e = pb->entries + i;
1526 if (e->parent_key != NULL)
1527 free (e->parent_key);
1528 }
1529 pbn = pb->next;
1530 free (pb);
1531 pb = pbn;
1532 }
1533 parser->first = NULL;
1534 parser->last = NULL;
1535 return 1;
1536 }
1537
1538 static char *
geojson_normalize_case(const char * name,int colname_case)1539 geojson_normalize_case (const char *name, int colname_case)
1540 {
1541 /* transforming a name in full lower- or upper-case */
1542 int len = strlen (name);
1543 char *clean = malloc (len + 1);
1544 char *p = clean;
1545 strcpy (clean, name);
1546 while (*p != '\0')
1547 {
1548 if (colname_case == GAIA_DBF_COLNAME_LOWERCASE)
1549 {
1550 if (*p >= 'A' && *p <= 'Z')
1551 *p = *p - 'A' + 'a';
1552 }
1553 if (colname_case == GAIA_DBF_COLNAME_UPPERCASE)
1554 {
1555 if (*p >= 'a' && *p <= 'z')
1556 *p = *p - 'a' + 'A';
1557 }
1558 p++;
1559 }
1560 return clean;
1561 }
1562
1563 static char *
geojson_unique_pk(geojson_parser_ptr parser,const char * pk_base_name)1564 geojson_unique_pk (geojson_parser_ptr parser, const char *pk_base_name)
1565 {
1566 /* will return a surely unique PK name */
1567 int ok = 0;
1568 int idx = 0;
1569 char *pk = sqlite3_mprintf ("%s", pk_base_name);
1570 while (ok == 0)
1571 {
1572 geojson_column_ptr col = parser->first_col;
1573 ok = 1;
1574 while (col != NULL)
1575 {
1576 if (strcasecmp (pk, col->name) == 0)
1577 {
1578 sqlite3_free (pk);
1579 pk = sqlite3_mprintf ("%s_%d", pk_base_name, idx++);
1580 ok = 0;
1581 break;
1582 }
1583 col = col->next;
1584 }
1585 }
1586 return pk;
1587 }
1588
1589 static char *
geojson_unique_geom(geojson_parser_ptr parser,const char * geom_base_name)1590 geojson_unique_geom (geojson_parser_ptr parser, const char *geom_base_name)
1591 {
1592 /* will return a surely unique PK name */
1593 int ok = 0;
1594 int idx = 0;
1595 char *geom = sqlite3_mprintf ("%s", geom_base_name);
1596 while (ok == 0)
1597 {
1598 geojson_column_ptr col = parser->first_col;
1599 ok = 1;
1600 while (col != NULL)
1601 {
1602 if (strcasecmp (geom, col->name) == 0)
1603 {
1604 sqlite3_free (geom);
1605 geom = sqlite3_mprintf ("%s_%d", geom_base_name, idx++);
1606 ok = 0;
1607 break;
1608 }
1609 col = col->next;
1610 }
1611 }
1612 return geom;
1613 }
1614
1615 static char *
geojson_sql_create_virtual_table(geojson_parser_ptr parser,const char * table,int colname_case)1616 geojson_sql_create_virtual_table (geojson_parser_ptr parser, const char *table,
1617 int colname_case)
1618 {
1619 /* will return the SQL CREATE TABLE statement */
1620 char *sql;
1621 char *prev;
1622 char *xname;
1623 char *pk_name;
1624 char *geom_name;
1625 char *xpk_name;
1626 char *xgeom_name;
1627 const char *type;
1628 geojson_column_ptr col;
1629 if (table == NULL)
1630 return NULL;
1631
1632 xname = gaiaDoubleQuotedSql (table);
1633 pk_name = geojson_unique_pk (parser, "fid");
1634 xpk_name = geojson_normalize_case (pk_name, colname_case);
1635 sqlite3_free (pk_name);
1636 geom_name = geojson_unique_geom (parser, "geometry");
1637 xgeom_name = geojson_normalize_case (geom_name, colname_case);
1638 sqlite3_free (geom_name);
1639 sql =
1640 sqlite3_mprintf
1641 ("CREATE TABLE \"%s\" (\n\t%s INTEGER PRIMARY KEY AUTOINCREMENT,\n\t%s BLOB",
1642 xname, xpk_name, xgeom_name);
1643 free (xname);
1644 free (xpk_name);
1645 free (xgeom_name);
1646 col = parser->first_col;
1647 while (col != NULL)
1648 {
1649 /* adding columns */
1650 char *xcol = geojson_normalize_case (col->name, colname_case);
1651 xname = gaiaDoubleQuotedSql (xcol);
1652 free (xcol);
1653 type = "TEXT";
1654 if (col->n_null > 0)
1655 {
1656 /* NULL values */
1657 if (col->n_text > 0 && col->n_int == 0 && col->n_double == 0
1658 && col->n_bool == 0)
1659 type = "TEXT";
1660 if (col->n_text == 0 && col->n_int > 0 && col->n_double == 0
1661 && col->n_bool == 0)
1662 type = "INTEGER";
1663 if (col->n_text == 0 && (col->n_int > 0 && col->n_bool > 0)
1664 && col->n_double == 0)
1665 type = "INTEGER";
1666 if (col->n_text == 0 && col->n_int == 0 && col->n_double > 0
1667 && col->n_bool == 0)
1668 type = "DOUBLE";
1669 if (col->n_text == 0 && col->n_int == 0 && col->n_double == 0
1670 && col->n_bool > 0)
1671 type = "BOOLEAN";
1672 }
1673 else
1674 {
1675 /* NOT NULL */
1676 if (col->n_text > 0 && col->n_int == 0 && col->n_double == 0
1677 && col->n_bool == 0)
1678 type = "TEXT NOT NULL";
1679 if (col->n_text == 0 && col->n_int > 0 && col->n_double == 0
1680 && col->n_bool == 0)
1681 type = "INTEGER NOT NULL";
1682 if (col->n_text == 0 && (col->n_int > 0 && col->n_bool > 0)
1683 && col->n_double == 0)
1684 type = "INTEGER NOT NULL";
1685 if (col->n_text == 0 && col->n_int == 0 && col->n_double > 0
1686 && col->n_bool == 0)
1687 type = "DOUBLE NOT NULL";
1688 if (col->n_text == 0 && col->n_int == 0 && col->n_double == 0
1689 && col->n_bool > 0)
1690 type = "BOOLEAN NOT NULL";
1691 }
1692 prev = sql;
1693 sql = sqlite3_mprintf ("%s,\n\t\"%s\" %s", prev, xname, type);
1694 free (xname);
1695 sqlite3_free (prev);
1696 col = col->next;
1697 }
1698 prev = sql;
1699 sql = sqlite3_mprintf ("%s)\n", prev);
1700 sqlite3_free (prev);
1701 return sql;
1702 }
1703
1704 SPATIALITE_DECLARE char *
geojson_sql_create_table(geojson_parser_ptr parser,const char * table,int colname_case)1705 geojson_sql_create_table (geojson_parser_ptr parser, const char *table,
1706 int colname_case)
1707 {
1708 /* will return the SQL CREATE TABLE statement */
1709 char *sql;
1710 char *prev;
1711 char *xname;
1712 char *pk_name;
1713 char *xpk_name;
1714 const char *type;
1715 geojson_column_ptr col;
1716 if (table == NULL)
1717 return NULL;
1718
1719 xname = gaiaDoubleQuotedSql (table);
1720 pk_name = geojson_unique_pk (parser, "pk_uid");
1721 xpk_name = geojson_normalize_case (pk_name, colname_case);
1722 sqlite3_free (pk_name);
1723 sql =
1724 sqlite3_mprintf
1725 ("CREATE TABLE \"%s\" (\n\t%s INTEGER PRIMARY KEY AUTOINCREMENT", xname,
1726 xpk_name);
1727 free (xname);
1728 free (xpk_name);
1729 col = parser->first_col;
1730 while (col != NULL)
1731 {
1732 /* adding columns */
1733 char *xcol = geojson_normalize_case (col->name, colname_case);
1734 xname = gaiaDoubleQuotedSql (xcol);
1735 free (xcol);
1736 type = "TEXT";
1737 if (col->n_null > 0)
1738 {
1739 /* NULL values */
1740 if (col->n_text > 0 && col->n_int == 0 && col->n_double == 0
1741 && col->n_bool == 0)
1742 type = "TEXT";
1743 if (col->n_text == 0 && col->n_int > 0 && col->n_double == 0
1744 && col->n_bool == 0)
1745 type = "INTEGER";
1746 if (col->n_text == 0 && (col->n_int > 0 && col->n_bool > 0)
1747 && col->n_double == 0)
1748 type = "INTEGER";
1749 if (col->n_text == 0 && col->n_int == 0 && col->n_double > 0
1750 && col->n_bool == 0)
1751 type = "DOUBLE";
1752 if (col->n_text == 0 && col->n_int == 0 && col->n_double == 0
1753 && col->n_bool > 0)
1754 type = "BOOLEAN";
1755 }
1756 else
1757 {
1758 /* NOT NULL */
1759 if (col->n_text > 0 && col->n_int == 0 && col->n_double == 0
1760 && col->n_bool == 0)
1761 type = "TEXT NOT NULL";
1762 if (col->n_text == 0 && col->n_int > 0 && col->n_double == 0
1763 && col->n_bool == 0)
1764 type = "INTEGER NOT NULL";
1765 if (col->n_text == 0 && (col->n_int > 0 && col->n_bool > 0)
1766 && col->n_double == 0)
1767 type = "INTEGER NOT NULL";
1768 if (col->n_text == 0 && col->n_int == 0 && col->n_double > 0
1769 && col->n_bool == 0)
1770 type = "DOUBLE NOT NULL";
1771 if (col->n_text == 0 && col->n_int == 0 && col->n_double == 0
1772 && col->n_bool > 0)
1773 type = "BOOLEAN NOT NULL";
1774 }
1775 prev = sql;
1776 sql = sqlite3_mprintf ("%s,\n\t\"%s\" %s", prev, xname, type);
1777 free (xname);
1778 sqlite3_free (prev);
1779 col = col->next;
1780 }
1781 prev = sql;
1782 sql = sqlite3_mprintf ("%s)\n", prev);
1783 sqlite3_free (prev);
1784 return sql;
1785 }
1786
1787 SPATIALITE_DECLARE char *
geojson_sql_add_geometry(geojson_parser_ptr parser,const char * table,const char * geom_col,int colname_case,int srid)1788 geojson_sql_add_geometry (geojson_parser_ptr parser, const char *table,
1789 const char *geom_col, int colname_case, int srid)
1790 {
1791 /* will return the SQL AddGeometryColumn() statement */
1792 char *sql;
1793 char *geom_name;
1794 char *xgeom_col;
1795 char *type = "GEOMETRY";
1796 char *dims = "XY";
1797 if (table == NULL || geom_col == NULL)
1798 return NULL;
1799 if (parser->n_points == 0 && parser->n_linestrings == 0
1800 && parser->n_polygons == 0 && parser->n_mpoints == 0
1801 && parser->n_mlinestrings == 0 && parser->n_mpolygons == 0
1802 && parser->n_geomcolls == 0)
1803 return NULL;
1804 if (parser->n_geom_2d == 0 && parser->n_geom_3d == 0
1805 && parser->n_geom_4d == 0)
1806 return NULL;
1807
1808 if (parser->n_points > 0 && parser->n_linestrings == 0
1809 && parser->n_polygons == 0 && parser->n_mpoints == 0
1810 && parser->n_mlinestrings == 0 && parser->n_mpolygons == 0
1811 && parser->n_geomcolls == 0)
1812 {
1813 type = "POINT";
1814 strcpy (parser->cast_type, "CastToPoint");
1815 }
1816 if (parser->n_mpoints > 0 && parser->n_linestrings == 0
1817 && parser->n_polygons == 0 && parser->n_mlinestrings == 0
1818 && parser->n_mpolygons == 0 && parser->n_geomcolls == 0)
1819 {
1820 type = "MULTIPOINT";
1821 strcpy (parser->cast_type, "CastToMultiPoint");
1822 }
1823 if (parser->n_points == 0 && parser->n_linestrings > 0
1824 && parser->n_polygons == 0 && parser->n_mpoints == 0
1825 && parser->n_mlinestrings == 0 && parser->n_mpolygons == 0
1826 && parser->n_geomcolls == 0)
1827 {
1828 type = "LINESTRING";
1829 strcpy (parser->cast_type, "CastToLinestring");
1830 }
1831 if (parser->n_mlinestrings > 0 && parser->n_points == 0
1832 && parser->n_polygons == 0 && parser->n_mpoints == 0
1833 && parser->n_mpolygons == 0 && parser->n_geomcolls == 0)
1834 {
1835 type = "MULTILINESTRING";
1836 strcpy (parser->cast_type, "CastToMultiLinestring");
1837 }
1838 if (parser->n_points == 0 && parser->n_linestrings > 0
1839 && parser->n_polygons > 0 && parser->n_mpoints == 0
1840 && parser->n_mlinestrings == 0 && parser->n_mpolygons == 0
1841 && parser->n_geomcolls == 0)
1842 {
1843 type = "POLYGON";
1844 strcpy (parser->cast_type, "CastToPolygon");
1845 }
1846 if (parser->n_mpolygons > 0 && parser->n_points == 0
1847 && parser->n_linestrings == 0 && parser->n_mpoints == 0
1848 && parser->n_mlinestrings == 0 && parser->n_geomcolls == 0)
1849 {
1850 type = "MULTIPOLYGON";
1851 strcpy (parser->cast_type, "CastToMultiPolygon");
1852 }
1853 if ((parser->n_points + parser->n_mpoints) > 0
1854 && (parser->n_linestrings + parser->n_mlinestrings) > 0)
1855 {
1856 type = "GEOMETRYCOLLECTION";
1857 strcpy (parser->cast_type, "CastToGeometryCollection");
1858 }
1859 if ((parser->n_points + parser->n_mpoints) > 0
1860 && (parser->n_polygons + parser->n_mpolygons) > 0)
1861 {
1862 type = "GEOMETRYCOLLECTION";
1863 strcpy (parser->cast_type, "CastToGeometryCollection");
1864 }
1865 if ((parser->n_linestrings + parser->n_mlinestrings) > 0
1866 && (parser->n_polygons + parser->n_mpolygons) > 0)
1867 {
1868 type = "GEOMETRYCOLLECTION";
1869 strcpy (parser->cast_type, "CastToGeometryCollection");
1870 }
1871
1872 if (parser->n_geom_2d > 0 && parser->n_geom_3d == 0
1873 && parser->n_geom_4d == 0)
1874 {
1875 dims = "XY";
1876 strcpy (parser->cast_dims, "CastToXY");
1877 }
1878 if (parser->n_geom_3d > 0 && parser->n_geom_4d == 0)
1879 {
1880 dims = "XYZ";
1881 strcpy (parser->cast_dims, "CastToXYZ");
1882 }
1883 if (parser->n_geom_4d > 0)
1884 {
1885 dims = "XYZM";
1886 strcpy (parser->cast_dims, "CastToXYZM");
1887 }
1888 geom_name = geojson_unique_geom (parser, geom_col);
1889 xgeom_col = geojson_normalize_case (geom_name, colname_case);
1890 sqlite3_free (geom_name);
1891 sql =
1892 sqlite3_mprintf ("SELECT AddGeometryColumn(%Q, %Q, %d, %Q, %Q)", table,
1893 xgeom_col, srid, type, dims);
1894 free (xgeom_col);
1895 return sql;
1896 }
1897
1898 SPATIALITE_DECLARE char *
geojson_sql_create_rtree(const char * table,const char * geom_col,int colname_case)1899 geojson_sql_create_rtree (const char *table, const char *geom_col,
1900 int colname_case)
1901 {
1902 /* will return the SQL CreateSpatialIndex() statement */
1903 char *sql;
1904 char *xgeom_col;
1905 if (table == NULL || geom_col == NULL)
1906 return NULL;
1907 xgeom_col = geojson_normalize_case (geom_col, colname_case);
1908 sql =
1909 sqlite3_mprintf ("SELECT CreateSpatialIndex(%Q, %Q)", table, xgeom_col);
1910 free (xgeom_col);
1911 return sql;
1912 }
1913
1914 SPATIALITE_DECLARE char *
geojson_sql_insert_into(geojson_parser_ptr parser,const char * table)1915 geojson_sql_insert_into (geojson_parser_ptr parser, const char *table)
1916 {
1917 /* will return the SQL INSERT INTO statement */
1918 char *sql;
1919 char *prev;
1920 char *xname;
1921 geojson_column_ptr col;
1922 if (table == NULL)
1923 return NULL;
1924
1925 xname = gaiaDoubleQuotedSql (table);
1926 sql = sqlite3_mprintf ("INSERT INTO \"%s\" VALUES (NULL", xname);
1927 free (xname);
1928
1929 col = parser->first_col;
1930 while (col != NULL)
1931 {
1932 prev = sql;
1933 sql = sqlite3_mprintf ("%s, ?", prev);
1934 sqlite3_free (prev);
1935 col = col->next;
1936 }
1937 prev = sql;
1938 /* Geometry is always the last Column */
1939 sql =
1940 sqlite3_mprintf ("%s, %s(%s(?)))", prev, parser->cast_dims,
1941 parser->cast_type);
1942 sqlite3_free (prev);
1943 return sql;
1944 }
1945
1946 SPATIALITE_DECLARE int
geojson_init_feature(geojson_parser_ptr parser,geojson_feature_ptr ft,char ** error_message)1947 geojson_init_feature (geojson_parser_ptr parser, geojson_feature_ptr ft,
1948 char **error_message)
1949 {
1950 /* attempting to fully initialize a GeoJSON Feature object */
1951 int ret;
1952 int len;
1953 char *buf;
1954 geojson_property_ptr prop;
1955 *error_message = NULL;
1956
1957 if (ft->prop_offset_start < 0 || ft->prop_offset_end < 0)
1958 {
1959 *error_message =
1960 sqlite3_mprintf ("GeoJSON parser: invalid Properties (fid=%d)\n",
1961 ft->fid);
1962 return 0;
1963 }
1964 if (ft->prop_offset_end <= ft->prop_offset_start)
1965 {
1966 *error_message =
1967 sqlite3_mprintf ("GeoJSON parser: invalid Properties (fid=%d)\n",
1968 ft->fid);
1969 return 0;
1970 }
1971 ret = fseek (parser->in, ft->prop_offset_start, SEEK_SET);
1972 if (ret != 0)
1973 {
1974 *error_message =
1975 sqlite3_mprintf
1976 ("GeoJSON parser: Properties invalid seek (fid=%d)\n", ft->fid);
1977 return 0;
1978 }
1979 len = ft->prop_offset_end - ft->prop_offset_start - 1;
1980 buf = malloc (len + 1);
1981 if (buf == NULL)
1982 {
1983 *error_message =
1984 sqlite3_mprintf
1985 ("GeoJSON parser: Properties insufficient memory (fid=%d)\n",
1986 ft->fid);
1987 return 0;
1988 }
1989 ret = fread (buf, 1, len, parser->in);
1990 if (ret != len)
1991 {
1992 *error_message =
1993 sqlite3_mprintf
1994 ("GeoJSON parser: Properties read error (fid=%d)\n", ft->fid);
1995 free (buf);
1996 return 0;
1997 }
1998 *(buf + len) = '\0';
1999 geojson_parse_properties (ft, buf, error_message);
2000 free (buf);
2001
2002 /* checking for duplicate Droperty names */
2003 prop = ft->first;
2004 while (prop != NULL)
2005 {
2006 geojson_property_ptr prop2 = prop->next;
2007 while (prop2 != NULL)
2008 {
2009 if (strcasecmp (prop->name, prop2->name) == 0)
2010 {
2011 *error_message =
2012 sqlite3_mprintf
2013 ("GeoJSON parser: duplicate property name \"%s\" (fid=%d)\n",
2014 prop->name, ft->fid);
2015 return 0;
2016 }
2017 prop2 = prop2->next;
2018 }
2019 prop = prop->next;
2020 }
2021
2022 /* reading the GeoJSON Geometry */
2023 if (ft->geom_offset_start < 0 || ft->geom_offset_end < 0)
2024 {
2025 *error_message =
2026 sqlite3_mprintf ("GeoJSON parser: invalid Geometry (fid=%d)\n",
2027 ft->fid);
2028 return 0;
2029 }
2030 if (ft->geom_offset_end <= ft->geom_offset_start)
2031 {
2032 *error_message =
2033 sqlite3_mprintf ("GeoJSON parser: invalid Geometry (fid=%d)\n",
2034 ft->fid);
2035 return 0;
2036 }
2037 ret = fseek (parser->in, ft->geom_offset_start, SEEK_SET);
2038 if (ret != 0)
2039 {
2040 *error_message =
2041 sqlite3_mprintf
2042 ("GeoJSON parser: Geometry invalid seek (fid=%d)\n", ft->fid);
2043 return 0;
2044 }
2045 len = ft->geom_offset_end - ft->geom_offset_start;
2046 if (len == 0)
2047 {
2048 /* NULL Geometry */
2049 if (ft->geometry != NULL)
2050 free (ft->geometry);
2051 ft->geometry = NULL;
2052 return 1;
2053 }
2054 buf = malloc (len + 2);
2055 if (buf == NULL)
2056 {
2057 *error_message =
2058 sqlite3_mprintf
2059 ("GeoJSON parser: Geometry insufficient memory (fid=%d)\n",
2060 ft->fid);
2061 return 0;
2062 }
2063 *buf = '{';
2064 ret = fread (buf + 1, 1, len, parser->in);
2065 if (ret != len)
2066 {
2067 *error_message =
2068 sqlite3_mprintf ("GeoJSON parser: Geometry read error (fid=%d)\n",
2069 ft->fid);
2070 free (buf);
2071 return 0;
2072 }
2073 *(buf + len + 1) = '\0';
2074 if (ft->geometry != NULL)
2075 free (ft->geometry);
2076 ft->geometry = buf;
2077 return 1;
2078 }
2079
2080 SPATIALITE_DECLARE void
geojson_reset_feature(geojson_feature_ptr ft)2081 geojson_reset_feature (geojson_feature_ptr ft)
2082 {
2083 /* memory cleanup - freeing a Feature */
2084 geojson_property_ptr pp;
2085 if (ft == NULL)
2086 return;
2087
2088 if (ft->geometry != NULL)
2089 free (ft->geometry);
2090 pp = ft->first;
2091 while (pp != NULL)
2092 {
2093 geojson_property_ptr ppn = pp->next;
2094 if (pp->name != NULL)
2095 free (pp->name);
2096 if (pp->txt_value != NULL)
2097 free (pp->txt_value);
2098 free (pp);
2099 pp = ppn;
2100 }
2101 ft->geometry = NULL;
2102 ft->first = NULL;
2103 ft->last = NULL;
2104 }
2105
2106 SPATIALITE_DECLARE geojson_property_ptr
geojson_get_property_by_name(geojson_feature_ptr ft,const char * name)2107 geojson_get_property_by_name (geojson_feature_ptr ft, const char *name)
2108 {
2109 /* will return the pointer to a Property indentified by its name */
2110 geojson_property_ptr pp;
2111 if (ft == NULL || name == NULL)
2112 return NULL;
2113
2114 pp = ft->first;
2115 while (pp != NULL)
2116 {
2117 if (strcasecmp (pp->name, name) == 0)
2118 return pp;
2119 pp = pp->next;
2120 }
2121 return NULL;
2122 }
2123
2124 static int
vgeojson_has_metadata(sqlite3 * db,int * geotype)2125 vgeojson_has_metadata (sqlite3 * db, int *geotype)
2126 {
2127 /* testing the layout of virts_geometry_columns table */
2128 char **results;
2129 int ret;
2130 int rows;
2131 int columns;
2132 int i;
2133 int ok_virt_name = 0;
2134 int ok_virt_geometry = 0;
2135 int ok_srid = 0;
2136 int ok_geometry_type = 0;
2137 int ok_type = 0;
2138 int ok_coord_dimension = 0;
2139
2140 ret =
2141 sqlite3_get_table (db, "PRAGMA table_info(virts_geometry_columns)",
2142 &results, &rows, &columns, NULL);
2143 if (ret != SQLITE_OK)
2144 return 0;
2145 for (i = 1; i <= rows; i++)
2146 {
2147 if (strcasecmp ("virt_name", results[(i * columns) + 1]) == 0)
2148 ok_virt_name = 1;
2149 if (strcasecmp ("virt_geometry", results[(i * columns) + 1]) == 0)
2150 ok_virt_geometry = 1;
2151 if (strcasecmp ("srid", results[(i * columns) + 1]) == 0)
2152 ok_srid = 1;
2153 if (strcasecmp ("geometry_type", results[(i * columns) + 1]) == 0)
2154 ok_geometry_type = 1;
2155 if (strcasecmp ("type", results[(i * columns) + 1]) == 0)
2156 ok_type = 1;
2157 if (strcasecmp ("coord_dimension", results[(i * columns) + 1]) == 0)
2158 ok_coord_dimension = 1;
2159 }
2160 sqlite3_free_table (results);
2161
2162 if (ok_virt_name && ok_virt_geometry && ok_srid && ok_geometry_type
2163 && ok_coord_dimension)
2164 {
2165 *geotype = 1;
2166 return 1;
2167 }
2168 if (ok_virt_name && ok_virt_geometry && ok_srid && ok_type)
2169 {
2170 *geotype = 0;
2171 return 1;
2172 }
2173 return 0;
2174 }
2175
2176 static geojson_property_ptr
vgeojson_get_property_by_name(VirtualGeoJsonCursorPtr cursor,const char * name)2177 vgeojson_get_property_by_name (VirtualGeoJsonCursorPtr cursor, const char *name)
2178 {
2179 /* attempting to retrieve a Property from the current Feature (by property name) */
2180 geojson_feature_ptr ft = cursor->Feature;
2181 geojson_property_ptr prop;
2182 if (ft == NULL)
2183 return NULL;
2184 prop = ft->first;
2185 while (prop != NULL)
2186 {
2187 if (prop->name != NULL)
2188 {
2189 if (strcasecmp (prop->name, name) == 0)
2190 return prop;
2191 }
2192 prop = prop->next;
2193 }
2194 return NULL;
2195 }
2196
2197 static geojson_property_ptr
vgeojson_get_property_by_col(VirtualGeoJsonCursorPtr cursor,int column)2198 vgeojson_get_property_by_col (VirtualGeoJsonCursorPtr cursor, int column)
2199 {
2200 /* attempting to retrieve a Property from the current Feature (by column index) */
2201 int icol = 0;
2202 geojson_column_ptr col;
2203 geojson_parser_ptr parser = cursor->pVtab->Parser;
2204 if (parser == NULL)
2205 return NULL;
2206 col = parser->first_col;
2207 while (col != NULL)
2208 {
2209 if (icol == column)
2210 return vgeojson_get_property_by_name (cursor, col->name);
2211 icol++;
2212 col = col->next;
2213 }
2214 return NULL;
2215 }
2216
2217 static void
vgeojson_get_extent(VirtualGeoJsonPtr p_vt)2218 vgeojson_get_extent (VirtualGeoJsonPtr p_vt)
2219 {
2220 /* determining the Full Extent */
2221 int fid;
2222 geojson_feature_ptr ft;
2223 char *error_message;
2224 gaiaGeomCollPtr geom;
2225 if (!(p_vt->Valid))
2226 return;
2227
2228 for (fid = 0; fid < p_vt->Parser->count; fid++)
2229 {
2230 ft = p_vt->Parser->features + fid;
2231 if (!geojson_init_feature (p_vt->Parser, ft, &error_message))
2232 {
2233 /* an error occurred */
2234 spatialite_e ("%s\n", error_message);
2235 sqlite3_free (error_message);
2236 p_vt->Valid = 0;
2237 return;
2238 }
2239 geom = gaiaParseGeoJSON ((const unsigned char *) (ft->geometry));
2240 if (geom != NULL)
2241 {
2242 if (geom->MinX < p_vt->MinX)
2243 p_vt->MinX = geom->MinX;
2244 if (geom->MaxX > p_vt->MaxX)
2245 p_vt->MaxX = geom->MaxX;
2246 if (geom->MinY < p_vt->MinY)
2247 p_vt->MinY = geom->MinY;
2248 if (geom->MaxY > p_vt->MaxY)
2249 p_vt->MaxY = geom->MaxY;
2250 gaiaFreeGeomColl (geom);
2251 }
2252 geojson_reset_feature (ft);
2253 }
2254 }
2255
2256 static int
vgeojson_create(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVTab,char ** pzErr)2257 vgeojson_create (sqlite3 * db, void *pAux, int argc, const char *const *argv,
2258 sqlite3_vtab ** ppVTab, char **pzErr)
2259 {
2260 /* creates the virtual table connected to some GeoJSON file */
2261 char *sql;
2262 VirtualGeoJsonPtr p_vt;
2263 char path[2048];
2264 char ColnameCase[128];
2265 const char *pColnameCase;
2266 int len;
2267 const char *pPath = NULL;
2268 int srid = 4326;
2269 int colname_case = GAIA_DBF_COLNAME_LOWERCASE;
2270 char *xname;
2271 int geotype;
2272 int ret;
2273 sqlite3_stmt *stmt = NULL;
2274 FILE *in;
2275 char *error_message = NULL;
2276 geojson_parser_ptr parser;
2277 if (pAux)
2278 pAux = pAux; /* unused arg warning suppression */
2279 /* checking for GeoJSON PATH */
2280 if (argc == 4 || argc == 5 || argc == 6)
2281 {
2282 pPath = argv[3];
2283 len = strlen (pPath);
2284 if ((*(pPath + 0) == '\'' || *(pPath + 0) == '"')
2285 && (*(pPath + len - 1) == '\'' || *(pPath + len - 1) == '"'))
2286 {
2287 /* the path is enclosed between quotes - we need to dequote it */
2288 strcpy (path, pPath + 1);
2289 len = strlen (path);
2290 *(path + len - 1) = '\0';
2291 }
2292 else
2293 strcpy (path, pPath);
2294 if (argc >= 5)
2295 {
2296 srid = atoi (argv[4]);
2297 if (srid < 0)
2298 srid = -1;
2299 }
2300 if (argc >= 6)
2301 {
2302 pColnameCase = argv[5];
2303 len = strlen (pColnameCase);
2304 if ((*(pColnameCase + 0) == '\'' || *(pColnameCase + 0) == '"')
2305 && (*(pColnameCase + len - 1) == '\''
2306 || *(pColnameCase + len - 1) == '"'))
2307 {
2308 /* the colcase-name is enclosed between quotes - we need to dequote it */
2309 strcpy (ColnameCase, pColnameCase + 1);
2310 len = strlen (ColnameCase);
2311 *(ColnameCase + len - 1) = '\0';
2312 }
2313 else
2314 strcpy (ColnameCase, pColnameCase);
2315 if (strcasecmp (ColnameCase, "uppercase") == 0
2316 || strcasecmp (ColnameCase, "upper") == 0)
2317 colname_case = GAIA_DBF_COLNAME_UPPERCASE;
2318 else if (strcasecmp (ColnameCase, "samecase") == 0
2319 || strcasecmp (ColnameCase, "same") == 0)
2320 colname_case = GAIA_DBF_COLNAME_CASE_IGNORE;
2321 else
2322 colname_case = GAIA_DBF_COLNAME_LOWERCASE;
2323 }
2324 }
2325 else
2326 {
2327 *pzErr =
2328 sqlite3_mprintf
2329 ("[VirtualGeoJSON module] CREATE VIRTUAL: illegal arg list {geojson_path [ , srid [ , colname_case ]] }");
2330 return SQLITE_ERROR;
2331 }
2332 p_vt = (VirtualGeoJsonPtr) sqlite3_malloc (sizeof (VirtualGeoJson));
2333 if (!p_vt)
2334 return SQLITE_NOMEM;
2335 p_vt->pModule = &my_geojson_module;
2336 p_vt->nRef = 0;
2337 p_vt->zErrMsg = NULL;
2338 p_vt->db = db;
2339 p_vt->Srid = srid;
2340 p_vt->Valid = 0;
2341 p_vt->DeclaredType = GAIA_GEOMETRYCOLLECTION;
2342 p_vt->DimensionModel = GAIA_XY;
2343 len = strlen (argv[2]);
2344 p_vt->TableName = malloc (len + 1);
2345 strcpy (p_vt->TableName, argv[2]);
2346 p_vt->MinX = DBL_MAX;
2347 p_vt->MinY = DBL_MAX;
2348 p_vt->MaxX = -DBL_MAX;
2349 p_vt->MaxY = -DBL_MAX;
2350
2351 /* attempting to open the GeoJSON file for reading */
2352 #ifdef _WIN32
2353 in = gaia_win_fopen (path, "rb");
2354 #else
2355 in = fopen (path, "rb");
2356 #endif
2357 if (in == NULL)
2358 {
2359 error_message =
2360 sqlite3_mprintf
2361 ("GeoJSON parser: unable to open %s for reading\n", path);
2362 goto err;
2363 }
2364 /* creating the GeoJSON parser */
2365 parser = geojson_create_parser (in);
2366 if (!geojson_parser_init (parser, &error_message))
2367 goto err;
2368 if (!geojson_create_features_index (parser, &error_message))
2369 goto err;
2370 if (!geojson_check_features (parser, &error_message))
2371 goto err;
2372 p_vt->Valid = 1;
2373 p_vt->Parser = parser;
2374 goto ok;
2375 err:
2376 if (error_message != NULL)
2377 {
2378 spatialite_e ("%s\n", error_message);
2379 sqlite3_free (error_message);
2380 }
2381 ok:
2382 vgeojson_get_extent (p_vt);
2383 if (!(p_vt->Valid))
2384 {
2385 /* something is going the wrong way; creating a stupid default table */
2386 xname = gaiaDoubleQuotedSql ((const char *) argv[2]);
2387 sql =
2388 sqlite3_mprintf
2389 ("CREATE TABLE \"%s\" (FID INTEGER, Geometry BLOB)", xname);
2390 free (xname);
2391 if (sqlite3_declare_vtab (db, sql) != SQLITE_OK)
2392 {
2393 sqlite3_free (sql);
2394 *pzErr =
2395 sqlite3_mprintf
2396 ("[VirtualGeoJSON module] cannot build a table from the GeoJSON file\n");
2397 return SQLITE_ERROR;
2398 }
2399 sqlite3_free (sql);
2400 *ppVTab = (sqlite3_vtab *) p_vt;
2401 return SQLITE_OK;
2402 }
2403 if (parser->n_points > 0 && parser->n_linestrings == 0
2404 && parser->n_polygons == 0 && parser->n_mpoints == 0
2405 && parser->n_mlinestrings == 0 && parser->n_mpolygons == 0
2406 && parser->n_geomcolls == 0)
2407 p_vt->DeclaredType = GAIA_POINT;
2408 if (parser->n_mpoints > 0 && parser->n_linestrings == 0
2409 && parser->n_polygons == 0 && parser->n_mlinestrings == 0
2410 && parser->n_mpolygons == 0 && parser->n_geomcolls == 0)
2411 p_vt->DeclaredType = GAIA_MULTIPOINT;
2412 if (parser->n_points == 0 && parser->n_linestrings > 0
2413 && parser->n_polygons == 0 && parser->n_mpoints == 0
2414 && parser->n_mlinestrings == 0 && parser->n_mpolygons == 0
2415 && parser->n_geomcolls == 0)
2416 p_vt->DeclaredType = GAIA_LINESTRING;
2417 if (parser->n_mlinestrings > 0 && parser->n_points == 0
2418 && parser->n_polygons == 0 && parser->n_mpoints == 0
2419 && parser->n_mpolygons == 0 && parser->n_geomcolls == 0)
2420 p_vt->DeclaredType = GAIA_MULTILINESTRING;
2421 if (parser->n_points == 0 && parser->n_linestrings > 0
2422 && parser->n_polygons > 0 && parser->n_mpoints == 0
2423 && parser->n_mlinestrings == 0 && parser->n_mpolygons == 0
2424 && parser->n_geomcolls == 0)
2425 p_vt->DeclaredType = GAIA_POLYGON;
2426 if (parser->n_mpolygons > 0 && parser->n_points == 0
2427 && parser->n_linestrings == 0 && parser->n_mpoints == 0
2428 && parser->n_mlinestrings == 0 && parser->n_geomcolls == 0)
2429 p_vt->DeclaredType = GAIA_MULTIPOLYGON;
2430 if ((parser->n_points + parser->n_mpoints) > 0
2431 && (parser->n_linestrings + parser->n_mlinestrings) > 0)
2432 p_vt->DeclaredType = GAIA_GEOMETRYCOLLECTION;
2433 if ((parser->n_points + parser->n_mpoints) > 0
2434 && (parser->n_polygons + parser->n_mpolygons) > 0)
2435 p_vt->DeclaredType = GAIA_GEOMETRYCOLLECTION;
2436 if ((parser->n_linestrings + parser->n_mlinestrings) > 0
2437 && (parser->n_polygons + parser->n_mpolygons) > 0)
2438 p_vt->DeclaredType = GAIA_GEOMETRYCOLLECTION;
2439 if (parser->n_geom_2d > 0 && parser->n_geom_3d == 0
2440 && parser->n_geom_4d == 0)
2441 p_vt->DimensionModel = GAIA_XY;
2442 if (parser->n_geom_3d > 0 && parser->n_geom_4d == 0)
2443 p_vt->DimensionModel = GAIA_XY_Z;
2444 if (parser->n_geom_4d > 0)
2445 p_vt->DimensionModel = GAIA_XY_Z_M;
2446 /* preparing the COLUMNs for this VIRTUAL TABLE */
2447 sql =
2448 geojson_sql_create_virtual_table (parser, (const char *) argv[2],
2449 colname_case);
2450 ret = sqlite3_declare_vtab (db, sql);
2451 sqlite3_free (sql);
2452 if (ret != SQLITE_OK)
2453 {
2454 *pzErr =
2455 sqlite3_mprintf
2456 ("[VirtualGeoJSON module] CREATE VIRTUAL: invalid SQL statement \"%s\"",
2457 sql);
2458 return SQLITE_ERROR;
2459 }
2460 *ppVTab = (sqlite3_vtab *) p_vt;
2461
2462 if (vgeojson_has_metadata (db, &geotype))
2463 {
2464 /* registering the Virtual Geometry */
2465 if (geotype)
2466 {
2467 int xtype = 0;
2468 int xdims = 0;
2469 switch (p_vt->DeclaredType)
2470 {
2471 case GAIA_POINT:
2472 switch (p_vt->DimensionModel)
2473 {
2474 case GAIA_XY_Z_M:
2475 xtype = 3001;
2476 xdims = 4;
2477 break;
2478 case GAIA_XY_M:
2479 xtype = 2001;
2480 xdims = 3;
2481 break;
2482 case GAIA_XY_Z:
2483 xtype = 1001;
2484 xdims = 3;
2485 break;
2486 default:
2487 xtype = 1;
2488 xdims = 2;
2489 break;
2490 };
2491 break;
2492 case GAIA_LINESTRING:
2493 switch (p_vt->DimensionModel)
2494 {
2495 case GAIA_XY_Z_M:
2496 xtype = 3002;
2497 xdims = 4;
2498 break;
2499 case GAIA_XY_M:
2500 xtype = 2002;
2501 xdims = 3;
2502 break;
2503 case GAIA_XY_Z:
2504 xtype = 1002;
2505 xdims = 3;
2506 break;
2507 default:
2508 xtype = 2;
2509 xdims = 2;
2510 break;
2511 };
2512 break;
2513 case GAIA_POLYGON:
2514 switch (p_vt->DimensionModel)
2515 {
2516 case GAIA_XY_Z_M:
2517 xtype = 3003;
2518 xdims = 4;
2519 break;
2520 case GAIA_XY_M:
2521 xtype = 2003;
2522 xdims = 3;
2523 break;
2524 case GAIA_XY_Z:
2525 xtype = 1003;
2526 xdims = 3;
2527 break;
2528 default:
2529 xtype = 3;
2530 xdims = 2;
2531 break;
2532 };
2533 break;
2534 case GAIA_MULTIPOINT:
2535 switch (p_vt->DimensionModel)
2536 {
2537 case GAIA_XY_Z_M:
2538 xtype = 3004;
2539 xdims = 4;
2540 break;
2541 case GAIA_XY_M:
2542 xtype = 2004;
2543 xdims = 3;
2544 break;
2545 case GAIA_XY_Z:
2546 xtype = 1004;
2547 xdims = 3;
2548 break;
2549 default:
2550 xtype = 4;
2551 xdims = 2;
2552 break;
2553 };
2554 break;
2555 case GAIA_MULTILINESTRING:
2556 switch (p_vt->DimensionModel)
2557 {
2558 case GAIA_XY_Z_M:
2559 xtype = 3005;
2560 xdims = 4;
2561 break;
2562 case GAIA_XY_M:
2563 xtype = 2005;
2564 xdims = 3;
2565 break;
2566 case GAIA_XY_Z:
2567 xtype = 1005;
2568 xdims = 3;
2569 break;
2570 default:
2571 xtype = 5;
2572 xdims = 2;
2573 break;
2574 };
2575 break;
2576 case GAIA_MULTIPOLYGON:
2577 switch (p_vt->DimensionModel)
2578 {
2579 case GAIA_XY_Z_M:
2580 xtype = 3006;
2581 xdims = 4;
2582 break;
2583 case GAIA_XY_M:
2584 xtype = 2006;
2585 xdims = 3;
2586 break;
2587 case GAIA_XY_Z:
2588 xtype = 1006;
2589 xdims = 3;
2590 break;
2591 default:
2592 xtype = 6;
2593 xdims = 2;
2594 break;
2595 };
2596 break;
2597 case GAIA_GEOMETRYCOLLECTION:
2598 switch (p_vt->DimensionModel)
2599 {
2600 case GAIA_XY_Z_M:
2601 xtype = 3007;
2602 xdims = 4;
2603 break;
2604 case GAIA_XY_M:
2605 xtype = 2007;
2606 xdims = 3;
2607 break;
2608 case GAIA_XY_Z:
2609 xtype = 1007;
2610 xdims = 3;
2611 break;
2612 default:
2613 xtype = 7;
2614 xdims = 2;
2615 break;
2616 };
2617 break;
2618 };
2619 sql =
2620 sqlite3_mprintf
2621 ("INSERT OR IGNORE INTO virts_geometry_columns "
2622 "(virt_name, virt_geometry, geometry_type, coord_dimension, srid) "
2623 "VALUES (Lower(%Q), 'geometry', %d, %d, %d)", argv[2],
2624 xtype, xdims, p_vt->Srid);
2625 }
2626 else
2627 {
2628 const char *xgtype = "GEOMETRY";
2629 switch (p_vt->DeclaredType)
2630 {
2631 case GAIA_POINT:
2632 xgtype = "POINT";
2633 break;
2634 case GAIA_LINESTRING:
2635 xgtype = "LINESTRING";
2636 break;
2637 case GAIA_POLYGON:
2638 xgtype = "POLYGON";
2639 break;
2640 case GAIA_MULTIPOINT:
2641 xgtype = "MULTIPOINT";
2642 break;
2643 case GAIA_MULTILINESTRING:
2644 xgtype = "MULTILINESTRING";
2645 break;
2646 case GAIA_MULTIPOLYGON:
2647 xgtype = "MULTIPOLYGON";
2648 break;
2649 case GAIA_GEOMETRYCOLLECTION:
2650 xgtype = "GEOMETRYCOLLECTION";
2651 break;
2652 };
2653 sql =
2654 sqlite3_mprintf
2655 ("INSERT OR IGNORE INTO virts_geometry_columns "
2656 "(virt_name, virt_geometry, type, srid) "
2657 "VALUES (Lower(%Q), 'geometry', %Q, %d)", argv[2], xgtype,
2658 p_vt->Srid);
2659 }
2660 sqlite3_exec (db, sql, NULL, NULL, NULL);
2661 sqlite3_free (sql);
2662 }
2663 if (checkSpatialMetaData (db) == 3)
2664 {
2665 /* current metadata style >= v.4.0.0 */
2666
2667 /* inserting a row into VIRTS_GEOMETRY_COLUMNS_AUTH */
2668 sql = sqlite3_mprintf ("INSERT OR IGNORE INTO "
2669 "virts_geometry_columns_auth (virt_name, virt_geometry, hidden) "
2670 "VALUES (Lower(%Q), 'geometry', 0)", argv[2]);
2671 sqlite3_exec (db, sql, NULL, NULL, NULL);
2672 sqlite3_free (sql);
2673
2674 /* inserting a row into GEOMETRY_COLUMNS_STATISTICS */
2675 sql = sqlite3_mprintf ("INSERT OR IGNORE INTO "
2676 "virts_geometry_columns_statistics (virt_name, virt_geometry) "
2677 "VALUES (Lower(%Q), 'geometry')", argv[2]);
2678 sqlite3_exec (db, sql, NULL, NULL, NULL);
2679 sqlite3_free (sql);
2680 }
2681
2682 /* inserting into the connection cache: Virtual Extent */
2683 sql = "SELECT \"*Add-VirtualTable+Extent\"(?, ?, ?, ?, ?, ?)";
2684 ret = sqlite3_prepare_v2 (db, sql, strlen (sql), &stmt, NULL);
2685 if (ret == SQLITE_OK)
2686 {
2687 sqlite3_reset (stmt);
2688 sqlite3_clear_bindings (stmt);
2689 sqlite3_bind_text (stmt, 1, argv[2], strlen (argv[2]), SQLITE_STATIC);
2690 sqlite3_bind_double (stmt, 2, p_vt->MinX);
2691 sqlite3_bind_double (stmt, 3, p_vt->MinY);
2692 sqlite3_bind_double (stmt, 4, p_vt->MaxX);
2693 sqlite3_bind_double (stmt, 5, p_vt->MaxY);
2694 sqlite3_bind_int (stmt, 6, p_vt->Srid);
2695 ret = sqlite3_step (stmt);
2696 }
2697 sqlite3_finalize (stmt);
2698 return SQLITE_OK;
2699 }
2700
2701 static int
vgeojson_connect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVTab,char ** pzErr)2702 vgeojson_connect (sqlite3 * db, void *pAux, int argc, const char *const *argv,
2703 sqlite3_vtab ** ppVTab, char **pzErr)
2704 {
2705 /* connects the virtual table to some GeoJSON file - simply aliases vgeojson_create() */
2706 return vgeojson_create (db, pAux, argc, argv, ppVTab, pzErr);
2707 }
2708
2709 static int
vgeojson_best_index(sqlite3_vtab * pVTab,sqlite3_index_info * pIndex)2710 vgeojson_best_index (sqlite3_vtab * pVTab, sqlite3_index_info * pIndex)
2711 {
2712 /* best index selection */
2713 int i;
2714 int iArg = 0;
2715 char str[2048];
2716 char buf[64];
2717
2718 if (pVTab)
2719 pVTab = pVTab; /* unused arg warning suppression */
2720
2721 *str = '\0';
2722 for (i = 0; i < pIndex->nConstraint; i++)
2723 {
2724 if (pIndex->aConstraint[i].usable)
2725 {
2726 iArg++;
2727 pIndex->aConstraintUsage[i].argvIndex = iArg;
2728 pIndex->aConstraintUsage[i].omit = 1;
2729 sprintf (buf, "%d:%d,", pIndex->aConstraint[i].iColumn,
2730 pIndex->aConstraint[i].op);
2731 strcat (str, buf);
2732 }
2733 }
2734 if (*str != '\0')
2735 {
2736 pIndex->idxStr = sqlite3_mprintf ("%s", str);
2737 pIndex->needToFreeIdxStr = 1;
2738 }
2739
2740 return SQLITE_OK;
2741 }
2742
2743 static int
vgeojson_disconnect(sqlite3_vtab * pVTab)2744 vgeojson_disconnect (sqlite3_vtab * pVTab)
2745 {
2746 /* disconnects the virtual table */
2747 int ret;
2748 sqlite3_stmt *stmt;
2749 const char *sql;
2750 VirtualGeoJsonPtr p_vt = (VirtualGeoJsonPtr) pVTab;
2751
2752 /* removing from the connection cache: Virtual Extent */
2753 sql = "SELECT \"*Remove-VirtualTable+Extent\"(?)";
2754 ret = sqlite3_prepare_v2 (p_vt->db, sql, strlen (sql), &stmt, NULL);
2755 if (ret == SQLITE_OK)
2756 {
2757 sqlite3_reset (stmt);
2758 sqlite3_clear_bindings (stmt);
2759 sqlite3_bind_text (stmt, 1, p_vt->TableName, strlen (p_vt->TableName),
2760 SQLITE_STATIC);
2761 ret = sqlite3_step (stmt);
2762 }
2763 sqlite3_finalize (stmt);
2764
2765 if (p_vt->TableName != NULL)
2766 free (p_vt->TableName);
2767 sqlite3_free (p_vt);
2768
2769 return SQLITE_OK;
2770 }
2771
2772 static int
vgeojson_destroy(sqlite3_vtab * pVTab)2773 vgeojson_destroy (sqlite3_vtab * pVTab)
2774 {
2775 /* destroys the virtual table - simply aliases vgeojson_disconnect() */
2776 return vgeojson_disconnect (pVTab);
2777 }
2778
2779 static void
vgeojson_read_row(VirtualGeoJsonCursorPtr cursor)2780 vgeojson_read_row (VirtualGeoJsonCursorPtr cursor)
2781 {
2782 /* trying to read a "row" from the GeoJSON file */
2783 int fid;
2784 geojson_feature_ptr ft;
2785 char *error_message;
2786 if (!(cursor->pVtab->Valid))
2787 {
2788 cursor->eof = 1;
2789 return;
2790 }
2791 if (cursor->Feature != NULL)
2792 geojson_reset_feature (cursor->Feature);
2793 fid = cursor->current_fid;
2794 if (fid < 0 || fid >= cursor->pVtab->Parser->count)
2795 {
2796 /* normal GeoJSON EOF */
2797 cursor->eof = 1;
2798 return;
2799 }
2800 ft = cursor->pVtab->Parser->features + fid;
2801 if (!geojson_init_feature (cursor->pVtab->Parser, ft, &error_message))
2802 {
2803 /* an error occurred */
2804 spatialite_e ("%s\n", error_message);
2805 sqlite3_free (error_message);
2806 cursor->eof = 1;
2807 return;
2808 }
2809 cursor->Feature = ft;
2810 }
2811
2812 static int
vgeojson_open(sqlite3_vtab * pVTab,sqlite3_vtab_cursor ** ppCursor)2813 vgeojson_open (sqlite3_vtab * pVTab, sqlite3_vtab_cursor ** ppCursor)
2814 {
2815 /* opening a new cursor */
2816 VirtualGeoJsonCursorPtr cursor =
2817 (VirtualGeoJsonCursorPtr)
2818 sqlite3_malloc (sizeof (VirtualGeoJsonCursor));
2819 if (cursor == NULL)
2820 return SQLITE_ERROR;
2821 cursor->firstConstraint = NULL;
2822 cursor->lastConstraint = NULL;
2823 cursor->pVtab = (VirtualGeoJsonPtr) pVTab;
2824 cursor->current_fid = 0;
2825 cursor->Feature = NULL;
2826 cursor->eof = 0;
2827 *ppCursor = (sqlite3_vtab_cursor *) cursor;
2828 vgeojson_read_row (cursor);
2829 return SQLITE_OK;
2830 }
2831
2832 static void
vgeojson_free_constraints(VirtualGeoJsonCursorPtr cursor)2833 vgeojson_free_constraints (VirtualGeoJsonCursorPtr cursor)
2834 {
2835 /* memory cleanup - cursor constraints */
2836 VirtualGeoJsonConstraintPtr pC;
2837 VirtualGeoJsonConstraintPtr pCn;
2838 pC = cursor->firstConstraint;
2839 while (pC)
2840 {
2841 pCn = pC->next;
2842 if (pC->txtValue)
2843 sqlite3_free (pC->txtValue);
2844 sqlite3_free (pC);
2845 pC = pCn;
2846 }
2847 cursor->firstConstraint = NULL;
2848 cursor->lastConstraint = NULL;
2849 }
2850
2851 static int
vgeojson_close(sqlite3_vtab_cursor * pCursor)2852 vgeojson_close (sqlite3_vtab_cursor * pCursor)
2853 {
2854 /* closing the cursor */
2855 VirtualGeoJsonCursorPtr cursor = (VirtualGeoJsonCursorPtr) pCursor;
2856 if (cursor->Feature != NULL)
2857 geojson_reset_feature (cursor->Feature);
2858 vgeojson_free_constraints (cursor);
2859 sqlite3_free (pCursor);
2860 return SQLITE_OK;
2861 }
2862
2863 static int
vgeojson_parse_constraint(const char * str,int index,int * iColumn,int * op)2864 vgeojson_parse_constraint (const char *str, int index, int *iColumn, int *op)
2865 {
2866 /* parsing a constraint string */
2867 char buf[64];
2868 const char *in = str;
2869 char *out = buf;
2870 int i = 0;
2871 int found = 0;
2872
2873 *out = '\0';
2874 while (*in != '\0')
2875 {
2876 if (*in == ',')
2877 {
2878 if (index == i)
2879 {
2880 *out = '\0';
2881 found = 1;
2882 break;
2883 }
2884 i++;
2885 in++;
2886 continue;
2887 }
2888 if (index == i)
2889 *out++ = *in;
2890 in++;
2891 }
2892 if (!found)
2893 return 0;
2894 in = buf;
2895 for (i = 0; i < (int) strlen (buf); i++)
2896 {
2897 if (buf[i] == ':')
2898 {
2899 buf[i] = '\0';
2900 *iColumn = atoi (buf);
2901 *op = atoi (buf + i + 1);
2902 return 1;
2903 }
2904 in++;
2905 }
2906 return 0;
2907 }
2908
2909 static int
vgeojson_eval_constraints(VirtualGeoJsonCursorPtr cursor)2910 vgeojson_eval_constraints (VirtualGeoJsonCursorPtr cursor)
2911 {
2912 /* evaluating Filter constraints */
2913 int nCol;
2914 geojson_column_ptr col;
2915 geojson_property_ptr prop;
2916 VirtualGeoJsonConstraintPtr pC = cursor->firstConstraint;
2917 if (pC == NULL)
2918 return 1;
2919 while (pC)
2920 {
2921 int ok = 0;
2922 if (pC->iColumn == 0)
2923 {
2924 /* the PRIMARY KEY column */
2925 if (pC->op == SQLITE_INDEX_CONSTRAINT_ISNULL)
2926 {
2927 ok = 0;
2928 goto done;
2929 }
2930 if (pC->op == SQLITE_INDEX_CONSTRAINT_ISNOTNULL)
2931 {
2932 ok = 1;
2933 goto done;
2934 }
2935 if (pC->valueType == 'I')
2936 {
2937 switch (pC->op)
2938 {
2939 case SQLITE_INDEX_CONSTRAINT_EQ:
2940 if (cursor->current_fid == pC->intValue)
2941 ok = 1;
2942 break;
2943 case SQLITE_INDEX_CONSTRAINT_GT:
2944 if (cursor->current_fid > pC->intValue)
2945 ok = 1;
2946 break;
2947 case SQLITE_INDEX_CONSTRAINT_LE:
2948 if (cursor->current_fid <= pC->intValue)
2949 ok = 1;
2950 break;
2951 case SQLITE_INDEX_CONSTRAINT_LT:
2952 if (cursor->current_fid < pC->intValue)
2953 ok = 1;
2954 break;
2955 case SQLITE_INDEX_CONSTRAINT_GE:
2956 if (cursor->current_fid >= pC->intValue)
2957 ok = 1;
2958 break;
2959 case SQLITE_INDEX_CONSTRAINT_NE:
2960 if (cursor->current_fid != pC->intValue)
2961 ok = 1;
2962 break;
2963 };
2964 }
2965 goto done;
2966 }
2967 if (pC->iColumn == 1)
2968 {
2969 /* the Geometry column */
2970 if (cursor->Feature != NULL)
2971 {
2972 switch (pC->op)
2973 {
2974 case SQLITE_INDEX_CONSTRAINT_ISNULL:
2975 if (cursor->Feature->geometry == NULL)
2976 ok = 1;
2977 break;
2978 case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
2979 if (cursor->Feature->geometry != NULL)
2980 ok = 1;
2981 break;
2982 };
2983
2984 }
2985 else
2986 {
2987 if (pC->op == SQLITE_INDEX_CONSTRAINT_ISNULL)
2988 ok = 1;
2989 }
2990 goto done;
2991 }
2992 /* any other ordinary column */
2993 nCol = 2;
2994 col = cursor->pVtab->Parser->first_col;
2995 while (col)
2996 {
2997 if (nCol != pC->iColumn)
2998 {
2999 nCol++;
3000 col = col->next;
3001 continue;
3002 }
3003 if (col->name == NULL)
3004 {
3005 ok = 1;
3006 goto done;
3007 }
3008 prop = vgeojson_get_property_by_name (cursor, col->name);
3009 if (prop == NULL)
3010 {
3011 nCol++;
3012 col = col->next;
3013 continue;
3014 }
3015 switch (pC->op)
3016 {
3017 case SQLITE_INDEX_CONSTRAINT_ISNULL:
3018 if (prop->type == GEOJSON_NULL)
3019 ok = 1;
3020 break;
3021 case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
3022 if (prop->type != GEOJSON_NULL)
3023 ok = 1;
3024 break;
3025 };
3026 if (ok)
3027 break;
3028 switch (prop->type)
3029 {
3030 case GEOJSON_INTEGER:
3031 if (pC->valueType == 'I')
3032 {
3033 switch (pC->op)
3034 {
3035 case SQLITE_INDEX_CONSTRAINT_EQ:
3036 if (prop->int_value == pC->intValue)
3037 ok = 1;
3038 break;
3039 case SQLITE_INDEX_CONSTRAINT_GT:
3040 if (prop->int_value > pC->intValue)
3041 ok = 1;
3042 break;
3043 case SQLITE_INDEX_CONSTRAINT_LE:
3044 if (prop->int_value <= pC->intValue)
3045 ok = 1;
3046 break;
3047 case SQLITE_INDEX_CONSTRAINT_LT:
3048 if (prop->int_value < pC->intValue)
3049 ok = 1;
3050 break;
3051 case SQLITE_INDEX_CONSTRAINT_GE:
3052 if (prop->int_value >= pC->intValue)
3053 ok = 1;
3054 break;
3055 case SQLITE_INDEX_CONSTRAINT_NE:
3056 if (prop->int_value != pC->intValue)
3057 ok = 1;
3058 break;
3059 };
3060 }
3061 break;
3062 case GEOJSON_DOUBLE:
3063 if (pC->valueType == 'I')
3064 {
3065 switch (pC->op)
3066 {
3067 case SQLITE_INDEX_CONSTRAINT_EQ:
3068 if (prop->dbl_value == pC->intValue)
3069 ok = 1;
3070 break;
3071 case SQLITE_INDEX_CONSTRAINT_GT:
3072 if (prop->dbl_value > pC->intValue)
3073 ok = 1;
3074 break;
3075 case SQLITE_INDEX_CONSTRAINT_LE:
3076 if (prop->dbl_value <= pC->intValue)
3077 ok = 1;
3078 break;
3079 case SQLITE_INDEX_CONSTRAINT_LT:
3080 if (prop->dbl_value < pC->intValue)
3081 ok = 1;
3082 break;
3083 case SQLITE_INDEX_CONSTRAINT_GE:
3084 if (prop->dbl_value >= pC->intValue)
3085 ok = 1;
3086 break;
3087 case SQLITE_INDEX_CONSTRAINT_NE:
3088 if (prop->dbl_value != pC->intValue)
3089 ok = 1;
3090 break;
3091 };
3092 }
3093 if (pC->valueType == 'D')
3094 {
3095 switch (pC->op)
3096 {
3097 case SQLITE_INDEX_CONSTRAINT_EQ:
3098 if (prop->dbl_value == pC->dblValue)
3099 ok = 1;
3100 break;
3101 case SQLITE_INDEX_CONSTRAINT_GT:
3102 if (prop->dbl_value > pC->dblValue)
3103 ok = 1;
3104 break;
3105 case SQLITE_INDEX_CONSTRAINT_LE:
3106 if (prop->dbl_value <= pC->dblValue)
3107 ok = 1;
3108 break;
3109 case SQLITE_INDEX_CONSTRAINT_LT:
3110 if (prop->dbl_value < pC->dblValue)
3111 ok = 1;
3112 break;
3113 case SQLITE_INDEX_CONSTRAINT_GE:
3114 if (prop->dbl_value >= pC->dblValue)
3115 ok = 1;
3116 break;
3117 case SQLITE_INDEX_CONSTRAINT_NE:
3118 if (prop->dbl_value != pC->dblValue)
3119 ok = 1;
3120 break;
3121 }
3122 }
3123 break;
3124 case GEOJSON_TEXT:
3125 if (pC->valueType == 'T' && pC->txtValue)
3126 {
3127 int ret;
3128 ret = strcmp (prop->txt_value, pC->txtValue);
3129 switch (pC->op)
3130 {
3131 case SQLITE_INDEX_CONSTRAINT_EQ:
3132 if (ret == 0)
3133 ok = 1;
3134 break;
3135 case SQLITE_INDEX_CONSTRAINT_GT:
3136 if (ret > 0)
3137 ok = 1;
3138 break;
3139 case SQLITE_INDEX_CONSTRAINT_LE:
3140 if (ret <= 0)
3141 ok = 1;
3142 break;
3143 case SQLITE_INDEX_CONSTRAINT_LT:
3144 if (ret < 0)
3145 ok = 1;
3146 break;
3147 case SQLITE_INDEX_CONSTRAINT_GE:
3148 if (ret >= 0)
3149 ok = 1;
3150 break;
3151 case SQLITE_INDEX_CONSTRAINT_NE:
3152 if (ret != 0)
3153 ok = 1;
3154 break;
3155 #ifdef HAVE_DECL_SQLITE_INDEX_CONSTRAINT_LIKE
3156 case SQLITE_INDEX_CONSTRAINT_LIKE:
3157 ret =
3158 sqlite3_strlike (pC->txtValue,
3159 prop->txt_value, 0);
3160 if (ret == 0)
3161 ok = 1;
3162 break;
3163 #endif
3164 };
3165 }
3166 break;
3167 };
3168 break;
3169 }
3170 done:
3171 if (!ok)
3172 return 0;
3173 pC = pC->next;
3174 }
3175 return 1;
3176 }
3177
3178 static int
vgeojson_filter(sqlite3_vtab_cursor * pCursor,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)3179 vgeojson_filter (sqlite3_vtab_cursor * pCursor, int idxNum, const char *idxStr,
3180 int argc, sqlite3_value ** argv)
3181 {
3182 /* setting up a cursor filter */
3183 int i;
3184 int iColumn;
3185 int op;
3186 int len;
3187 VirtualGeoJsonConstraintPtr pC;
3188 VirtualGeoJsonCursorPtr cursor = (VirtualGeoJsonCursorPtr) pCursor;
3189 if (idxNum)
3190 idxNum = idxNum; /* unused arg warning suppression */
3191
3192 /* resetting any previously set filter constraint */
3193 vgeojson_free_constraints (cursor);
3194
3195 for (i = 0; i < argc; i++)
3196 {
3197 if (!vgeojson_parse_constraint (idxStr, i, &iColumn, &op))
3198 continue;
3199 pC = sqlite3_malloc (sizeof (VirtualGeoJsonConstraint));
3200 if (!pC)
3201 continue;
3202 pC->iColumn = iColumn;
3203 pC->op = op;
3204 pC->valueType = '\0';
3205 pC->txtValue = NULL;
3206 pC->next = NULL;
3207
3208 if (sqlite3_value_type (argv[i]) == SQLITE_INTEGER)
3209 {
3210 pC->valueType = 'I';
3211 pC->intValue = sqlite3_value_int64 (argv[i]);
3212 }
3213 if (sqlite3_value_type (argv[i]) == SQLITE_FLOAT)
3214 {
3215 pC->valueType = 'D';
3216 pC->dblValue = sqlite3_value_double (argv[i]);
3217 }
3218 if (sqlite3_value_type (argv[i]) == SQLITE_TEXT)
3219 {
3220 pC->valueType = 'T';
3221 len = sqlite3_value_bytes (argv[i]) + 1;
3222 pC->txtValue = (char *) sqlite3_malloc (len);
3223 if (pC->txtValue)
3224 strcpy (pC->txtValue,
3225 (char *) sqlite3_value_text (argv[i]));
3226 }
3227 if (cursor->firstConstraint == NULL)
3228 cursor->firstConstraint = pC;
3229 if (cursor->lastConstraint != NULL)
3230 cursor->lastConstraint->next = pC;
3231 cursor->lastConstraint = pC;
3232 }
3233
3234 cursor->current_fid = 0;
3235 cursor->eof = 0;
3236 while (1)
3237 {
3238 vgeojson_read_row (cursor);
3239 if (cursor->eof)
3240 break;
3241 if (vgeojson_eval_constraints (cursor))
3242 break;
3243 cursor->current_fid += 1;
3244 }
3245 return SQLITE_OK;
3246 }
3247
3248 static int
vgeojson_next(sqlite3_vtab_cursor * pCursor)3249 vgeojson_next (sqlite3_vtab_cursor * pCursor)
3250 {
3251 /* fetching a next row from cursor */
3252 VirtualGeoJsonCursorPtr cursor = (VirtualGeoJsonCursorPtr) pCursor;
3253 cursor->current_fid += 1;
3254 while (1)
3255 {
3256 vgeojson_read_row (cursor);
3257 if (cursor->eof)
3258 break;
3259 if (vgeojson_eval_constraints (cursor))
3260 break;
3261 cursor->current_fid += 1;
3262 }
3263 return SQLITE_OK;
3264 }
3265
3266 static int
vgeojson_eof(sqlite3_vtab_cursor * pCursor)3267 vgeojson_eof (sqlite3_vtab_cursor * pCursor)
3268 {
3269 /* cursor EOF */
3270 VirtualGeoJsonCursorPtr cursor = (VirtualGeoJsonCursorPtr) pCursor;
3271 return cursor->eof;
3272 }
3273
3274 static gaiaGeomCollPtr
vgeojson_get_geometry(VirtualGeoJsonCursorPtr cursor)3275 vgeojson_get_geometry (VirtualGeoJsonCursorPtr cursor)
3276 {
3277 /* attempting to return a normalized GeoJSON geometry */
3278 gaiaGeomCollPtr geom;
3279 if (cursor == NULL)
3280 return NULL;
3281 if (cursor->Feature == NULL)
3282 return NULL;
3283 if (cursor->Feature->geometry == NULL)
3284 return NULL;
3285
3286 geom =
3287 gaiaParseGeoJSON ((const unsigned char *) (cursor->Feature->geometry));
3288 if (geom == NULL)
3289 return NULL;
3290 geom->Srid = cursor->pVtab->Srid;
3291 geom->DeclaredType = cursor->pVtab->DeclaredType;
3292 if (cursor->pVtab->DimensionModel != geom->DimensionModel)
3293 {
3294 /* normalizing Dimensions */
3295 gaiaGeomCollPtr g2;
3296 switch (cursor->pVtab->DimensionModel)
3297 {
3298 case GAIA_XY_Z_M:
3299 g2 = gaiaCastGeomCollToXYZM (geom);
3300 break;
3301 case GAIA_XY_Z:
3302 g2 = gaiaCastGeomCollToXYZ (geom);
3303 break;
3304 case GAIA_XY_M:
3305 g2 = gaiaCastGeomCollToXYM (geom);
3306 break;
3307 case GAIA_XY:
3308 default:
3309 g2 = gaiaCastGeomCollToXY (geom);
3310 break;
3311 };
3312 gaiaFreeGeomColl (geom);
3313 geom = g2;
3314 }
3315 return geom;
3316 }
3317
3318 static int
vgeojson_column(sqlite3_vtab_cursor * pCursor,sqlite3_context * pContext,int column)3319 vgeojson_column (sqlite3_vtab_cursor * pCursor, sqlite3_context * pContext,
3320 int column)
3321 {
3322 /* fetching value for the Nth column */
3323 gaiaGeomCollPtr geom;
3324 geojson_property_ptr prop;
3325 VirtualGeoJsonCursorPtr cursor = (VirtualGeoJsonCursorPtr) pCursor;
3326 if (column == 0)
3327 {
3328 /* the PRIMARY KEY column */
3329 sqlite3_result_int (pContext, cursor->current_fid);
3330 return SQLITE_OK;
3331 }
3332 if (column == 1)
3333 {
3334 /* the GEOMETRY column */
3335 geom = vgeojson_get_geometry (cursor);
3336 if (geom)
3337 {
3338 unsigned char *blob;
3339 int blobSize;
3340 gaiaToSpatiaLiteBlobWkb (geom, &blob, &blobSize);
3341 sqlite3_result_blob (pContext, blob, blobSize, free);
3342 gaiaFreeGeomColl (geom);
3343 }
3344 else
3345 sqlite3_result_null (pContext);
3346 return SQLITE_OK;
3347 }
3348 prop = vgeojson_get_property_by_col (cursor, column - 2);
3349 if (prop == NULL)
3350 {
3351 sqlite3_result_null (pContext);
3352 return SQLITE_OK;
3353 }
3354 switch (prop->type)
3355 {
3356 case GEOJSON_TRUE:
3357 sqlite3_result_int (pContext, 1);
3358 break;
3359 case GEOJSON_FALSE:
3360 sqlite3_result_int (pContext, 0);
3361 break;
3362 case GEOJSON_INTEGER:
3363 sqlite3_result_int64 (pContext, prop->int_value);
3364 break;
3365 case GEOJSON_DOUBLE:
3366 sqlite3_result_double (pContext, prop->dbl_value);
3367 break;
3368 case GEOJSON_TEXT:
3369 sqlite3_result_text (pContext, prop->txt_value,
3370 strlen (prop->txt_value), SQLITE_STATIC);
3371 break;
3372 case GEOJSON_NULL:
3373 default:
3374 sqlite3_result_null (pContext);
3375 break;
3376 };
3377 return SQLITE_OK;
3378 }
3379
3380 static int
vgeojson_rowid(sqlite3_vtab_cursor * pCursor,sqlite_int64 * pRowid)3381 vgeojson_rowid (sqlite3_vtab_cursor * pCursor, sqlite_int64 * pRowid)
3382 {
3383 /* fetching the ROWID */
3384 VirtualGeoJsonCursorPtr cursor = (VirtualGeoJsonCursorPtr) pCursor;
3385 *pRowid = cursor->current_fid;
3386 return SQLITE_OK;
3387 }
3388
3389 static int
vgeojson_update(sqlite3_vtab * pVTab,int argc,sqlite3_value ** argv,sqlite_int64 * pRowid)3390 vgeojson_update (sqlite3_vtab * pVTab, int argc, sqlite3_value ** argv,
3391 sqlite_int64 * pRowid)
3392 {
3393 /* generic update [INSERT / UPDATE / DELETE */
3394 if (pVTab || argc || argv || pRowid)
3395 pVTab = pVTab; /* unused arg warning suppression */
3396 return SQLITE_READONLY;
3397 }
3398
3399 static int
vgeojson_begin(sqlite3_vtab * pVTab)3400 vgeojson_begin (sqlite3_vtab * pVTab)
3401 {
3402 /* BEGIN TRANSACTION */
3403 if (pVTab)
3404 pVTab = pVTab; /* unused arg warning suppression */
3405 return SQLITE_OK;
3406 }
3407
3408 static int
vgeojson_sync(sqlite3_vtab * pVTab)3409 vgeojson_sync (sqlite3_vtab * pVTab)
3410 {
3411 /* BEGIN TRANSACTION */
3412 if (pVTab)
3413 pVTab = pVTab; /* unused arg warning suppression */
3414 return SQLITE_OK;
3415 }
3416
3417 static int
vgeojson_commit(sqlite3_vtab * pVTab)3418 vgeojson_commit (sqlite3_vtab * pVTab)
3419 {
3420 /* BEGIN TRANSACTION */
3421 if (pVTab)
3422 pVTab = pVTab; /* unused arg warning suppression */
3423 return SQLITE_OK;
3424 }
3425
3426 static int
vgeojson_rollback(sqlite3_vtab * pVTab)3427 vgeojson_rollback (sqlite3_vtab * pVTab)
3428 {
3429 /* BEGIN TRANSACTION */
3430 if (pVTab)
3431 pVTab = pVTab; /* unused arg warning suppression */
3432 return SQLITE_OK;
3433 }
3434
3435 static int
vgeojson_rename(sqlite3_vtab * pVTab,const char * zNew)3436 vgeojson_rename (sqlite3_vtab * pVTab, const char *zNew)
3437 {
3438 /* BEGIN TRANSACTION */
3439 if (pVTab)
3440 pVTab = pVTab; /* unused arg warning suppression */
3441 if (zNew)
3442 zNew = zNew; /* unused arg warning suppression */
3443 return SQLITE_ERROR;
3444 }
3445
3446 static int
spliteVirtualGeoJsonInit(sqlite3 * db)3447 spliteVirtualGeoJsonInit (sqlite3 * db)
3448 {
3449 int rc = SQLITE_OK;
3450 my_geojson_module.iVersion = 1;
3451 my_geojson_module.xCreate = &vgeojson_create;
3452 my_geojson_module.xConnect = &vgeojson_connect;
3453 my_geojson_module.xBestIndex = &vgeojson_best_index;
3454 my_geojson_module.xDisconnect = &vgeojson_disconnect;
3455 my_geojson_module.xDestroy = &vgeojson_destroy;
3456 my_geojson_module.xOpen = &vgeojson_open;
3457 my_geojson_module.xClose = &vgeojson_close;
3458 my_geojson_module.xFilter = &vgeojson_filter;
3459 my_geojson_module.xNext = &vgeojson_next;
3460 my_geojson_module.xEof = &vgeojson_eof;
3461 my_geojson_module.xColumn = &vgeojson_column;
3462 my_geojson_module.xRowid = &vgeojson_rowid;
3463 my_geojson_module.xUpdate = &vgeojson_update;
3464 my_geojson_module.xBegin = &vgeojson_begin;
3465 my_geojson_module.xSync = &vgeojson_sync;
3466 my_geojson_module.xCommit = &vgeojson_commit;
3467 my_geojson_module.xRollback = &vgeojson_rollback;
3468 my_geojson_module.xFindFunction = NULL;
3469 my_geojson_module.xRename = &vgeojson_rename;
3470 sqlite3_create_module_v2 (db, "VirtualGeoJSON", &my_geojson_module, NULL,
3471 0);
3472 return rc;
3473 }
3474
3475 SPATIALITE_PRIVATE int
virtualgeojson_extension_init(void * xdb)3476 virtualgeojson_extension_init (void *xdb)
3477 {
3478 sqlite3 *db = (sqlite3 *) xdb;
3479 return spliteVirtualGeoJsonInit (db);
3480 }
3481