1 /*
2 
3  metatables.c -- creating the metadata tables and related triggers
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) 2008-2021
28 the Initial Developer. All Rights Reserved.
29 
30 Contributor(s):
31 Pepijn Van Eeckhoudt <pepijnvaneeckhoudt@luciad.com>
32 (implementing Android support)
33 
34 Mark Johnson <mj10777@googlemail.com>
35 (checking triggers supporting a supposed Writable Spatial View)
36 
37 Alternatively, the contents of this file may be used under the terms of
38 either the GNU General Public License Version 2 or later (the "GPL"), or
39 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
40 in which case the provisions of the GPL or the LGPL are applicable instead
41 of those above. If you wish to allow use of your version of this file only
42 under the terms of either the GPL or the LGPL, and not to allow others to
43 use your version of this file under the terms of the MPL, indicate your
44 decision by deleting the provisions above and replace them with the notice
45 and other provisions required by the GPL or the LGPL. If you do not delete
46 the provisions above, a recipient may use your version of this file under
47 the terms of any one of the MPL, the GPL or the LGPL.
48 
49 */
50 
51 #include <sys/types.h>
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <string.h>
55 #include <float.h>
56 
57 #if defined(_WIN32) && !defined(__MINGW32__)
58 #include "config-msvc.h"
59 #else
60 #include "config.h"
61 #endif
62 
63 #include <spatialite/sqlite.h>
64 #include <spatialite/debug.h>
65 
66 #include <spatialite.h>
67 #include <spatialite/spatialite_ext.h>
68 #include <spatialite_private.h>
69 #include <spatialite/gaiaaux.h>
70 #include <spatialite/gaiageo.h>
71 
72 #ifdef _WIN32
73 #define strcasecmp	_stricmp
74 #endif /* not WIN32 */
75 
76 struct rtree_envelope
77 {
78     int valid;
79     double minx;
80     double maxx;
81     double miny;
82     double maxy;
83 };
84 
85 struct spatial_index_str
86 {
87 /* a struct to implement a linked list of spatial-indexes */
88     char ValidRtree;
89     char ValidCache;
90     char *TableName;
91     char *ColumnName;
92     struct spatial_index_str *Next;
93 };
94 
95 static int
testSpatiaLiteHistory(sqlite3 * sqlite)96 testSpatiaLiteHistory (sqlite3 * sqlite)
97 {
98 /* internal utility function:
99 /
100 / checks if the SPATIALITE_HISTORY table already exists
101 /
102 */
103     int event_id = 0;
104     int table_name = 0;
105     int geometry_column = 0;
106     int event = 0;
107     int timestamp = 0;
108     int ver_sqlite = 0;
109     int ver_splite = 0;
110     char sql[1024];
111     int ret;
112     const char *name;
113     int i;
114     char **results;
115     int rows;
116     int columns;
117 /* checking the SPATIALITE_HISTORY table */
118     strcpy (sql, "PRAGMA table_info(spatialite_history)");
119     ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, NULL);
120     if (ret != SQLITE_OK)
121 	return 0;
122     if (rows < 1)
123 	;
124     else
125       {
126 	  for (i = 1; i <= rows; i++)
127 	    {
128 		name = results[(i * columns) + 1];
129 		if (strcasecmp (name, "event_id") == 0)
130 		    event_id = 1;
131 		if (strcasecmp (name, "table_name") == 0)
132 		    table_name = 1;
133 		if (strcasecmp (name, "geometry_column") == 0)
134 		    geometry_column = 1;
135 		if (strcasecmp (name, "event") == 0)
136 		    event = 1;
137 		if (strcasecmp (name, "timestamp") == 0)
138 		    timestamp = 1;
139 		if (strcasecmp (name, "ver_sqlite") == 0)
140 		    ver_sqlite = 1;
141 		if (strcasecmp (name, "ver_splite") == 0)
142 		    ver_splite = 1;
143 	    }
144       }
145     sqlite3_free_table (results);
146     if (event_id && table_name && geometry_column && event && timestamp
147 	&& ver_sqlite && ver_splite)
148 	return 1;
149     return 0;
150 }
151 
152 static int
checkSpatiaLiteHistory(sqlite3 * sqlite)153 checkSpatiaLiteHistory (sqlite3 * sqlite)
154 {
155 /* internal utility function:
156 /
157 / checks if the SPATIALITE_HISTORY table already exists
158 / if not, such table will then be created
159 /
160 */
161     char sql[1024];
162     char *errMsg = NULL;
163     int ret;
164 
165     if (testSpatiaLiteHistory (sqlite))
166 	return 1;
167 
168 /* creating the SPATIALITE_HISTORY table */
169     strcpy (sql, "CREATE TABLE IF NOT EXISTS ");
170     strcat (sql, "spatialite_history (\n");
171     strcat (sql, "event_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n");
172     strcat (sql, "table_name TEXT NOT NULL,\n");
173     strcat (sql, "geometry_column TEXT,\n");
174     strcat (sql, "event TEXT NOT NULL,\n");
175     strcat (sql, "timestamp TEXT NOT NULL,\n");
176     strcat (sql, "ver_sqlite TEXT NOT NULL,\n");
177     strcat (sql, "ver_splite TEXT NOT NULL)");
178     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
179     if (ret != SQLITE_OK)
180 	return 0;
181 
182     if (testSpatiaLiteHistory (sqlite))
183 	return 1;
184     return 0;
185 }
186 
187 SPATIALITE_PRIVATE void
updateSpatiaLiteHistory(void * p_sqlite,const char * table,const char * geom,const char * operation)188 updateSpatiaLiteHistory (void *p_sqlite, const char *table,
189 			 const char *geom, const char *operation)
190 {
191 /* inserting a row in SPATIALITE_HISTORY */
192     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
193     char sql[2048];
194     sqlite3_stmt *stmt = NULL;
195     int ret;
196 
197     if (checkSpatiaLiteHistory (sqlite) == 0)
198 	return;
199 
200     strcpy (sql, "INSERT INTO spatialite_history ");
201     strcat (sql, "(event_id, table_name, geometry_column, event, timestamp, ");
202     strcat (sql, "ver_sqlite, ver_splite) VALUES (NULL, ?, ?, ?, ");
203     strcat (sql, "strftime('%Y-%m-%dT%H:%M:%fZ', 'now'), ");
204     strcat (sql, "sqlite_version(), spatialite_version())");
205     ret = sqlite3_prepare_v2 (sqlite, sql, strlen (sql), &stmt, NULL);
206     if (ret != SQLITE_OK)
207       {
208 	  spatialite_e ("SQL error: %s: %s\n", sql, sqlite3_errmsg (sqlite));
209 	  goto stop;
210       }
211     sqlite3_reset (stmt);
212     sqlite3_clear_bindings (stmt);
213     sqlite3_bind_text (stmt, 1, table, strlen (table), SQLITE_STATIC);
214     if (!geom)
215 	sqlite3_bind_null (stmt, 2);
216     else
217 	sqlite3_bind_text (stmt, 2, geom, strlen (geom), SQLITE_STATIC);
218     sqlite3_bind_text (stmt, 3, operation, strlen (operation), SQLITE_STATIC);
219     ret = sqlite3_step (stmt);
220     if (ret == SQLITE_DONE || ret == SQLITE_ROW)
221 	goto stop;
222     spatialite_e ("SQL error: %s\n", sqlite3_errmsg (sqlite));
223 
224   stop:
225     if (stmt)
226 	sqlite3_finalize (stmt);
227 }
228 
229 static int
create_views_geometry_columns(sqlite3 * sqlite)230 create_views_geometry_columns (sqlite3 * sqlite)
231 {
232     char sql[4186];
233     char *errMsg = NULL;
234     int ret;
235 
236     if (sqlite3_db_readonly (sqlite, "MAIN") == 1)
237       {
238 	  /* ignoring a read-only database */
239 	  return 1;
240       }
241 
242 /* creating the VIEWS_GEOMETRY_COLUMNS table */
243     strcpy (sql, "CREATE TABLE IF NOT EXISTS ");
244     strcat (sql, "views_geometry_columns (\n");
245     strcat (sql, "view_name TEXT NOT NULL,\n");
246     strcat (sql, "view_geometry TEXT NOT NULL,\n");
247     strcat (sql, "view_rowid TEXT NOT NULL,\n");
248     strcat (sql, "f_table_name TEXT NOT NULL,\n");
249     strcat (sql, "f_geometry_column TEXT NOT NULL,\n");
250     strcat (sql, "read_only INTEGER NOT NULL,\n");
251     strcat (sql, "CONSTRAINT pk_geom_cols_views PRIMARY KEY ");
252     strcat (sql, "(view_name, view_geometry),\n");
253     strcat (sql, "CONSTRAINT fk_views_geom_cols FOREIGN KEY ");
254     strcat (sql, "(f_table_name, f_geometry_column) ");
255     strcat (sql, "REFERENCES geometry_columns ");
256     strcat (sql, "(f_table_name, f_geometry_column) ");
257     strcat (sql, "ON DELETE CASCADE,\n");
258     strcat (sql, "CONSTRAINT ck_vw_rdonly CHECK (read_only IN ");
259     strcat (sql, "(0,1)))");
260     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
261     if (ret != SQLITE_OK)
262       {
263 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
264 	  sqlite3_free (errMsg);
265 	  return 0;
266       }
267 /* creating an INDEX supporting the GEOMETRY_COLUMNS FK */
268     strcpy (sql, "CREATE INDEX IF NOT EXISTS ");
269     strcat (sql, "idx_viewsjoin ON views_geometry_columns\n");
270     strcat (sql, "(f_table_name, f_geometry_column)");
271     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
272     if (ret != SQLITE_OK)
273       {
274 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
275 	  sqlite3_free (errMsg);
276 	  return 0;
277       }
278 /* creating the VIEWS_GEOMETRY_COLUMNS triggers */
279     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgc_view_name_insert\n");
280     strcat (sql, "BEFORE INSERT ON 'views_geometry_columns'\n");
281     strcat (sql, "FOR EACH ROW BEGIN\n");
282     strcat (sql,
283 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: ");
284     strcat (sql, "view_name value must not contain a single quote')\n");
285     strcat (sql, "WHERE NEW.view_name LIKE ('%''%');\n");
286     strcat (sql,
287 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: ");
288     strcat (sql, "view_name value must not contain a double quote')\n");
289     strcat (sql, "WHERE NEW.view_name LIKE ('%\"%');\n");
290     strcat (sql,
291 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: \n");
292     strcat (sql, "view_name value must be lower case')\n");
293     strcat (sql, "WHERE NEW.view_name <> lower(NEW.view_name);\n");
294     strcat (sql, "END");
295     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
296     if (ret != SQLITE_OK)
297       {
298 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
299 	  sqlite3_free (errMsg);
300 	  return 0;
301       }
302     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgc_view_name_update\n");
303     strcat (sql, "BEFORE UPDATE OF 'view_name' ON 'views_geometry_columns'\n");
304     strcat (sql, "FOR EACH ROW BEGIN\n");
305     strcat (sql,
306 	    "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: ");
307     strcat (sql, "view_name value must not contain a single quote')\n");
308     strcat (sql, "WHERE NEW.view_name LIKE ('%''%');\n");
309     strcat (sql,
310 	    "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: ");
311     strcat (sql, "view_name value must not contain a double quote')\n");
312     strcat (sql, "WHERE NEW.view_name LIKE ('%\"%');\n");
313     strcat (sql,
314 	    "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: ");
315     strcat (sql, "view_name value must be lower case')\n");
316     strcat (sql, "WHERE NEW.view_name <> lower(NEW.view_name);\n");
317     strcat (sql, "END");
318     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
319     if (ret != SQLITE_OK)
320       {
321 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
322 	  sqlite3_free (errMsg);
323 	  return 0;
324       }
325     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgc_view_geometry_insert\n");
326     strcat (sql, "BEFORE INSERT ON 'views_geometry_columns'\n");
327     strcat (sql, "FOR EACH ROW BEGIN\n");
328     strcat (sql,
329 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: ");
330     strcat (sql, "view_geometry value must not contain a single quote')\n");
331     strcat (sql, "WHERE NEW.view_geometry LIKE ('%''%');\n");
332     strcat (sql,
333 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: \n");
334     strcat (sql, "view_geometry value must not contain a double quote')\n");
335     strcat (sql, "WHERE NEW.view_geometry LIKE ('%\"%');\n");
336     strcat (sql,
337 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: ");
338     strcat (sql, "view_geometry value must be lower case')\n");
339     strcat (sql, "WHERE NEW.view_geometry <> lower(NEW.view_geometry);\n");
340     strcat (sql, "END");
341     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
342     if (ret != SQLITE_OK)
343       {
344 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
345 	  sqlite3_free (errMsg);
346 	  return 0;
347       }
348     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgc_view_geometry_update\n");
349     strcat (sql,
350 	    "BEFORE UPDATE OF 'view_geometry' ON 'views_geometry_columns'\n");
351     strcat (sql, "FOR EACH ROW BEGIN\n");
352     strcat (sql,
353 	    "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: ");
354     strcat (sql, "view_geometry value must not contain a single quote')\n");
355     strcat (sql, "WHERE NEW.view_geometry LIKE ('%''%');\n");
356     strcat (sql,
357 	    "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: \n");
358     strcat (sql, "view_geometry value must not contain a double quote')\n");
359     strcat (sql, "WHERE NEW.view_geometry LIKE ('%\"%');\n");
360     strcat (sql,
361 	    "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: ");
362     strcat (sql, "view_geometry value must be lower case')\n");
363     strcat (sql, "WHERE NEW.view_geometry <> lower(NEW.view_geometry);\n");
364     strcat (sql, "END");
365     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
366     if (ret != SQLITE_OK)
367       {
368 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
369 	  sqlite3_free (errMsg);
370 	  return 0;
371       }
372     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgc_view_rowid_update\n");
373     strcat (sql, "BEFORE UPDATE OF 'view_rowid' ON 'views_geometry_columns'\n");
374     strcat (sql, "FOR EACH ROW BEGIN\n");
375     strcat (sql,
376 	    "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: ");
377     strcat (sql, "view_rowid value must not contain a single quote')\n");
378     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%''%');\n");
379     strcat (sql,
380 	    "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: ");
381     strcat (sql, "view_rowid value must not contain a double quote')\n");
382     strcat (sql, "WHERE NEW.view_rowid LIKE ('%\"%');\n");
383     strcat (sql,
384 	    "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: ");
385     strcat (sql, "view_rowid value must be lower case')\n");
386     strcat (sql, "WHERE NEW.view_rowid <> lower(NEW.view_rowid);\n");
387     strcat (sql, "END");
388     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
389     if (ret != SQLITE_OK)
390       {
391 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
392 	  sqlite3_free (errMsg);
393 	  return 0;
394       }
395     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgc_view_rowid_insert\n");
396     strcat (sql, "BEFORE INSERT ON 'views_geometry_columns'\n");
397     strcat (sql, "FOR EACH ROW BEGIN\n");
398     strcat (sql,
399 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: ");
400     strcat (sql, "view_rowid value must not contain a single quote')\n");
401     strcat (sql, "WHERE NEW.view_rowid LIKE ('%''%');\n");
402     strcat (sql,
403 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: \n");
404     strcat (sql, "view_rowid value must not contain a double quote')\n");
405     strcat (sql, "WHERE NEW.view_rowid LIKE ('%\"%');\n");
406     strcat (sql,
407 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: ");
408     strcat (sql, "view_rowid value must be lower case')\n");
409     strcat (sql, "WHERE NEW.view_rowid <> lower(NEW.view_rowid);\n");
410     strcat (sql, "END");
411     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
412     if (ret != SQLITE_OK)
413       {
414 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
415 	  sqlite3_free (errMsg);
416 	  return 0;
417       }
418     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgc_f_table_name_insert\n");
419     strcat (sql, "BEFORE INSERT ON 'views_geometry_columns'\n");
420     strcat (sql, "FOR EACH ROW BEGIN\n");
421     strcat (sql,
422 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: ");
423     strcat (sql, "f_table_name value must not contain a single quote')\n");
424     strcat (sql, "WHERE NEW.f_table_name LIKE ('%''%');\n");
425     strcat (sql,
426 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: ");
427     strcat (sql, "f_table_name value must not contain a double quote')\n");
428     strcat (sql, "WHERE NEW.f_table_name LIKE ('%\"%');\n");
429     strcat (sql,
430 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: \n");
431     strcat (sql, "f_table_name value must be lower case')\n");
432     strcat (sql, "WHERE NEW.f_table_name <> lower(NEW.f_table_name);\n");
433     strcat (sql, "END");
434     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
435     if (ret != SQLITE_OK)
436       {
437 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
438 	  sqlite3_free (errMsg);
439 	  return 0;
440       }
441     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgc_f_table_name_update\n");
442     strcat (sql,
443 	    "BEFORE UPDATE OF 'f_table_name' ON 'views_geometry_columns'\n");
444     strcat (sql, "FOR EACH ROW BEGIN\n");
445     strcat (sql,
446 	    "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: ");
447     strcat (sql, "f_table_name value must not contain a single quote')\n");
448     strcat (sql, "WHERE NEW.f_table_name LIKE ('%''%');\n");
449     strcat (sql,
450 	    "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: ");
451     strcat (sql, "f_table_name value must not contain a double quote')\n");
452     strcat (sql, "WHERE NEW.f_table_name LIKE ('%\"%');\n");
453     strcat (sql,
454 	    "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: ");
455     strcat (sql, "f_table_name value must be lower case')\n");
456     strcat (sql, "WHERE NEW.f_table_name <> lower(NEW.f_table_name);\n");
457     strcat (sql, "END");
458     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
459     if (ret != SQLITE_OK)
460       {
461 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
462 	  sqlite3_free (errMsg);
463 	  return 0;
464       }
465     strcpy (sql,
466 	    "CREATE TRIGGER IF NOT EXISTS vwgc_f_geometry_column_insert\n");
467     strcat (sql, "BEFORE INSERT ON 'views_geometry_columns'\n");
468     strcat (sql, "FOR EACH ROW BEGIN\n");
469     strcat (sql,
470 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: ");
471     strcat (sql, "f_geometry_column value must not contain a single quote')\n");
472     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%''%');\n");
473     strcat (sql,
474 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: \n");
475     strcat (sql, "f_geometry_column value must not contain a double quote')\n");
476     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%\"%');\n");
477     strcat (sql,
478 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: ");
479     strcat (sql, "f_geometry_column value must be lower case')\n");
480     strcat (sql,
481 	    "WHERE NEW.f_geometry_column <> lower(NEW.f_geometry_column);\n");
482     strcat (sql, "END");
483     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
484     if (ret != SQLITE_OK)
485       {
486 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
487 	  sqlite3_free (errMsg);
488 	  return 0;
489       }
490     strcpy (sql,
491 	    "CREATE TRIGGER IF NOT EXISTS vwgc_f_geometry_column_update\n");
492     strcat (sql,
493 	    "BEFORE UPDATE OF 'f_geometry_column' ON 'views_geometry_columns'\n");
494     strcat (sql, "FOR EACH ROW BEGIN\n");
495     strcat (sql,
496 	    "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: ");
497     strcat (sql, "f_geometry_column value must not contain a single quote')\n");
498     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%''%');\n");
499     strcat (sql,
500 	    "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: ");
501     strcat (sql, "f_geometry_column value must not contain a double quote')\n");
502     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%\"%');\n");
503     strcat (sql,
504 	    "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: ");
505     strcat (sql, "f_geometry_column value must be lower case')\n");
506     strcat (sql,
507 	    "WHERE NEW.f_geometry_column <> lower(NEW.f_geometry_column);\n");
508     strcat (sql, "END");
509     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
510     if (ret != SQLITE_OK)
511       {
512 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
513 	  sqlite3_free (errMsg);
514 	  return 0;
515       }
516     return 1;
517 }
518 
519 static int
create_virts_geometry_columns(sqlite3 * sqlite)520 create_virts_geometry_columns (sqlite3 * sqlite)
521 {
522     char sql[4186];
523     char *errMsg = NULL;
524     int ret;
525 
526     if (sqlite3_db_readonly (sqlite, "MAIN") == 1)
527       {
528 	  /* ignoring a read-only database */
529 	  return 1;
530       }
531 
532 /* creating the VIRTS_GEOMETRY_COLUMNS table */
533     strcpy (sql, "CREATE TABLE IF NOT EXISTS ");
534     strcat (sql, "virts_geometry_columns (\n");
535     strcat (sql, "virt_name TEXT NOT NULL,\n");
536     strcat (sql, "virt_geometry TEXT NOT NULL,\n");
537     strcat (sql, "geometry_type INTEGER NOT NULL,\n");
538     strcat (sql, "coord_dimension INTEGER NOT NULL,\n");
539     strcat (sql, "srid INTEGER NOT NULL,\n");
540     strcat (sql, "CONSTRAINT pk_geom_cols_virts PRIMARY KEY ");
541     strcat (sql, "(virt_name, virt_geometry),\n");
542     strcat (sql, "CONSTRAINT fk_vgc_srid FOREIGN KEY ");
543     strcat (sql, "(srid) REFERENCES spatial_ref_sys (srid))");
544     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
545     if (ret != SQLITE_OK)
546       {
547 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
548 	  sqlite3_free (errMsg);
549 	  return 0;
550       }
551 /* creating an INDEX supporting the SPATIAL_REF_SYS FK */
552     strcpy (sql, "CREATE INDEX IF NOT EXISTS ");
553     strcat (sql, "idx_virtssrid ON virts_geometry_columns\n");
554     strcat (sql, "(srid)");
555     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
556     if (ret != SQLITE_OK)
557       {
558 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
559 	  sqlite3_free (errMsg);
560 	  return 0;
561       }
562 /* creating the VIRTS_GEOMETRY_COLUMNS triggers */
563     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgc_virt_name_insert\n");
564     strcat (sql, "BEFORE INSERT ON 'virts_geometry_columns'\n");
565     strcat (sql, "FOR EACH ROW BEGIN\n");
566     strcat (sql,
567 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns violates constraint: ");
568     strcat (sql, "virt_name value must not contain a single quote')\n");
569     strcat (sql, "WHERE NEW.virt_name LIKE ('%''%');\n");
570     strcat (sql,
571 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns violates constraint: ");
572     strcat (sql, "virt_name value must not contain a double quote')\n");
573     strcat (sql, "WHERE NEW.virt_name LIKE ('%\"%');\n");
574     strcat (sql,
575 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns violates constraint: \n");
576     strcat (sql, "virt_name value must be lower case')\n");
577     strcat (sql, "WHERE NEW.virt_name <> lower(NEW.virt_name);\n");
578     strcat (sql, "END");
579     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
580     if (ret != SQLITE_OK)
581       {
582 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
583 	  sqlite3_free (errMsg);
584 	  return 0;
585       }
586     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgc_virt_name_update\n");
587     strcat (sql, "BEFORE UPDATE OF 'virt_name' ON 'virts_geometry_columns'\n");
588     strcat (sql, "FOR EACH ROW BEGIN\n");
589     strcat (sql,
590 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns violates constraint: ");
591     strcat (sql, "virt_name value must not contain a single quote')\n");
592     strcat (sql, "WHERE NEW.virt_name LIKE ('%''%');\n");
593     strcat (sql,
594 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns violates constraint: ");
595     strcat (sql, "virt_name value must not contain a double quote')\n");
596     strcat (sql, "WHERE NEW.virt_name LIKE ('%\"%');\n");
597     strcat (sql,
598 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns violates constraint: ");
599     strcat (sql, "virt_name value must be lower case')\n");
600     strcat (sql, "WHERE NEW.virt_name <> lower(NEW.virt_name);\n");
601     strcat (sql, "END");
602     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
603     if (ret != SQLITE_OK)
604       {
605 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
606 	  sqlite3_free (errMsg);
607 	  return 0;
608       }
609     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgc_virt_geometry_insert\n");
610     strcat (sql, "BEFORE INSERT ON 'virts_geometry_columns'\n");
611     strcat (sql, "FOR EACH ROW BEGIN\n");
612     strcat (sql,
613 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns violates constraint: ");
614     strcat (sql, "virt_geometry value must not contain a single quote')\n");
615     strcat (sql, "WHERE NEW.virt_geometry LIKE ('%''%');\n");
616     strcat (sql,
617 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns violates constraint: \n");
618     strcat (sql, "virt_geometry value must not contain a double quote')\n");
619     strcat (sql, "WHERE NEW.virt_geometry LIKE ('%\"%');\n");
620     strcat (sql,
621 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns violates constraint: ");
622     strcat (sql, "virt_geometry value must be lower case')\n");
623     strcat (sql, "WHERE NEW.virt_geometry <> lower(NEW.virt_geometry);\n");
624     strcat (sql, "END");
625     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
626     if (ret != SQLITE_OK)
627       {
628 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
629 	  sqlite3_free (errMsg);
630 	  return 0;
631       }
632     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgc_virt_geometry_update\n");
633     strcat (sql,
634 	    "BEFORE UPDATE OF 'virt_geometry' ON 'virts_geometry_columns'\n");
635     strcat (sql, "FOR EACH ROW BEGIN\n");
636     strcat (sql,
637 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns violates constraint: ");
638     strcat (sql, "virt_geometry value must not contain a single quote')\n");
639     strcat (sql, "WHERE NEW.virt_geometry LIKE ('%''%');\n");
640     strcat (sql,
641 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns violates constraint: \n");
642     strcat (sql, "virt_geometry value must not contain a double quote')\n");
643     strcat (sql, "WHERE NEW.virt_geometry LIKE ('%\"%');\n");
644     strcat (sql,
645 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns violates constraint: ");
646     strcat (sql, "virt_geometry value must be lower case')\n");
647     strcat (sql, "WHERE NEW.virt_geometry <> lower(NEW.virt_geometry);\n");
648     strcat (sql, "END");
649     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
650     if (ret != SQLITE_OK)
651       {
652 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
653 	  sqlite3_free (errMsg);
654 	  return 0;
655       }
656     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgc_geometry_type_insert\n");
657     strcat (sql, "BEFORE INSERT ON 'virts_geometry_columns'\n");
658     strcat (sql, "FOR EACH ROW BEGIN\n");
659     strcat (sql, "SELECT RAISE(ABORT,'geometry_type must be one of ");
660     strcat (sql, "0,1,2,3,4,5,6,7,");
661     strcat (sql, "1000,1001,1002,1003,1004,1005,1006,1007,");
662     strcat (sql, "2000,2001,2002,2003,2004,2005,2006,2007,");
663     strcat (sql, "3000,3001,3002,3003,3004,3005,3006,3007')\n");
664     strcat (sql, "WHERE NOT(NEW.geometry_type IN (0,1,2,3,4,5,6,7,");
665     strcat (sql, "1000,1001,1002,1003,1004,1005,1006,1007,");
666     strcat (sql, "2000,2001,2002,2003,2004,2005,2006,2007,");
667     strcat (sql, "3000,3001,3002,3003,3004,3005,3006,3007));\n");
668     strcat (sql, "END");
669     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
670     if (ret != SQLITE_OK)
671       {
672 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
673 	  sqlite3_free (errMsg);
674 	  return 0;
675       }
676     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgc_geometry_type_update\n");
677     strcat (sql,
678 	    "BEFORE UPDATE OF 'geometry_type' ON 'virts_geometry_columns'\n");
679     strcat (sql, "FOR EACH ROW BEGIN\n");
680     strcat (sql, "SELECT RAISE(ABORT,'geometry_type must be one of ");
681     strcat (sql, "0,1,2,3,4,5,6,7,");
682     strcat (sql, "1000,1001,1002,1003,1004,1005,1006,1007,");
683     strcat (sql, "2000,2001,2002,2003,2004,2005,2006,2007,");
684     strcat (sql, "3000,3001,3002,3003,3004,3005,3006,3007')\n");
685     strcat (sql, "WHERE NOT(NEW.geometry_type IN (0,1,2,3,4,5,6,7,");
686     strcat (sql, "1000,1001,1002,1003,1004,1005,1006,1007,");
687     strcat (sql, "2000,2001,2002,2003,2004,2005,2006,2007,");
688     strcat (sql, "3000,3001,3002,3003,3004,3005,3006,3007));\n");
689     strcat (sql, "END");
690     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
691     if (ret != SQLITE_OK)
692       {
693 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
694 	  sqlite3_free (errMsg);
695 	  return 0;
696       }
697     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgc_coord_dimension_insert\n");
698     strcat (sql, "BEFORE INSERT ON 'virts_geometry_columns'\n");
699     strcat (sql, "FOR EACH ROW BEGIN\n");
700     strcat (sql,
701 	    "SELECT RAISE(ABORT,'coord_dimension must be one of 2,3,4')\n");
702     strcat (sql, "WHERE NOT(NEW.coord_dimension IN (2,3,4));\n");
703     strcat (sql, "END");
704     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
705     if (ret != SQLITE_OK)
706       {
707 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
708 	  sqlite3_free (errMsg);
709 	  return 0;
710       }
711     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgc_coord_dimension_update\n");
712     strcat (sql,
713 	    "BEFORE UPDATE OF 'coord_dimension' ON 'virts_geometry_columns'\n");
714     strcat (sql, "FOR EACH ROW BEGIN\n");
715     strcat (sql,
716 	    "SELECT RAISE(ABORT,'coord_dimension must be one of 2,3,4')\n");
717     strcat (sql, "WHERE NOT(NEW.coord_dimension IN (2,3,4));\n");
718     strcat (sql, "END");
719     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
720     if (ret != SQLITE_OK)
721       {
722 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
723 	  sqlite3_free (errMsg);
724 	  return 0;
725       }
726     return 1;
727 }
728 
729 static int
create_geometry_columns_statistics(sqlite3 * sqlite)730 create_geometry_columns_statistics (sqlite3 * sqlite)
731 {
732     char sql[4186];
733     char *errMsg = NULL;
734     int ret;
735 
736     if (sqlite3_db_readonly (sqlite, "MAIN") == 1)
737       {
738 	  /* ignoring a read-only database */
739 	  return 1;
740       }
741 
742 /* creating the GEOMETRY_COLUMNS_STATISTICS table */
743     strcpy (sql, "CREATE TABLE IF NOT EXISTS ");
744     strcat (sql, "geometry_columns_statistics (\n");
745     strcat (sql, "f_table_name TEXT NOT NULL,\n");
746     strcat (sql, "f_geometry_column TEXT NOT NULL,\n");
747     strcat (sql, "last_verified TIMESTAMP,\n");
748     strcat (sql, "row_count INTEGER,\n");
749     strcat (sql, "extent_min_x DOUBLE,\n");
750     strcat (sql, "extent_min_y DOUBLE,\n");
751     strcat (sql, "extent_max_x DOUBLE,\n");
752     strcat (sql, "extent_max_y DOUBLE,\n");
753     strcat (sql, "CONSTRAINT pk_gc_statistics PRIMARY KEY ");
754     strcat (sql, "(f_table_name, f_geometry_column),\n");
755     strcat (sql, "CONSTRAINT fk_gc_statistics FOREIGN KEY ");
756     strcat (sql, "(f_table_name, f_geometry_column) REFERENCES ");
757     strcat (sql, "geometry_columns (f_table_name, f_geometry_column) ");
758     strcat (sql, "ON DELETE CASCADE)");
759     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
760     if (ret != SQLITE_OK)
761       {
762 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
763 	  sqlite3_free (errMsg);
764 	  return 0;
765       }
766 /* creating the GEOMETRY_COLUMNS_STATISTICS triggers */
767     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS gcs_f_table_name_insert\n");
768     strcat (sql, "BEFORE INSERT ON 'geometry_columns_statistics'\n");
769     strcat (sql, "FOR EACH ROW BEGIN\n");
770     strcat (sql,
771 	    "SELECT RAISE(ABORT,'insert on geometry_columns_statistics violates constraint: ");
772     strcat (sql, "f_table_name value must not contain a single quote')\n");
773     strcat (sql, "WHERE NEW.f_table_name LIKE ('%''%');\n");
774     strcat (sql,
775 	    "SELECT RAISE(ABORT,'insert on geometry_columns_statistics violates constraint: ");
776     strcat (sql, "f_table_name value must not contain a double quote')\n");
777     strcat (sql, "WHERE NEW.f_table_name LIKE ('%\"%');\n");
778     strcat (sql,
779 	    "SELECT RAISE(ABORT,'insert on geometry_columns_statistics violates constraint: \n");
780     strcat (sql, "f_table_name value must be lower case')\n");
781     strcat (sql, "WHERE NEW.f_table_name <> lower(NEW.f_table_name);\n");
782     strcat (sql, "END");
783     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
784     if (ret != SQLITE_OK)
785       {
786 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
787 	  sqlite3_free (errMsg);
788 	  return 0;
789       }
790     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS gcs_f_table_name_update\n");
791     strcat (sql,
792 	    "BEFORE UPDATE OF 'f_table_name' ON 'geometry_columns_statistics'\n");
793     strcat (sql, "FOR EACH ROW BEGIN\n");
794     strcat (sql,
795 	    "SELECT RAISE(ABORT,'update on geometry_columns_statistics violates constraint: ");
796     strcat (sql, "f_table_name value must not contain a single quote')\n");
797     strcat (sql, "WHERE NEW.f_table_name LIKE ('%''%');\n");
798     strcat (sql,
799 	    "SELECT RAISE(ABORT,'update on geometry_columns_statistics violates constraint: ");
800     strcat (sql, "f_table_name value must not contain a double quote')\n");
801     strcat (sql, "WHERE NEW.f_table_name LIKE ('%\"%');\n");
802     strcat (sql,
803 	    "SELECT RAISE(ABORT,'update on geometry_columns_statistics violates constraint: ");
804     strcat (sql, "f_table_name value must be lower case')\n");
805     strcat (sql, "WHERE NEW.f_table_name <> lower(NEW.f_table_name);\n");
806     strcat (sql, "END");
807     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
808     if (ret != SQLITE_OK)
809       {
810 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
811 	  sqlite3_free (errMsg);
812 	  return 0;
813       }
814     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS gcs_f_geometry_column_insert\n");
815     strcat (sql, "BEFORE INSERT ON 'geometry_columns_statistics'\n");
816     strcat (sql, "FOR EACH ROW BEGIN\n");
817     strcat (sql,
818 	    "SELECT RAISE(ABORT,'insert on geometry_columns_statistics violates constraint: ");
819     strcat (sql, "f_geometry_column value must not contain a single quote')\n");
820     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%''%');\n");
821     strcat (sql,
822 	    "SELECT RAISE(ABORT,'insert on geometry_columns_statistics violates constraint: \n");
823     strcat (sql, "f_geometry_column value must not contain a double quote')\n");
824     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%\"%');\n");
825     strcat (sql,
826 	    "SELECT RAISE(ABORT,'insert on geometry_columns_statistics violates constraint: ");
827     strcat (sql, "f_geometry_column value must be lower case')\n");
828     strcat (sql,
829 	    "WHERE NEW.f_geometry_column <> lower(NEW.f_geometry_column);\n");
830     strcat (sql, "END");
831     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
832     if (ret != SQLITE_OK)
833       {
834 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
835 	  sqlite3_free (errMsg);
836 	  return 0;
837       }
838     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS gcs_f_geometry_column_update\n");
839     strcat (sql,
840 	    "BEFORE UPDATE OF 'f_geometry_column' ON 'geometry_columns_statistics'\n");
841     strcat (sql, "FOR EACH ROW BEGIN\n");
842     strcat (sql,
843 	    "SELECT RAISE(ABORT,'update on geometry_columns_statistics violates constraint: ");
844     strcat (sql, "f_geometry_column value must not contain a single quote')\n");
845     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%''%');\n");
846     strcat (sql,
847 	    "SELECT RAISE(ABORT,'update on geometry_columns_statistics violates constraint: ");
848     strcat (sql, "f_geometry_column value must not contain a double quote')\n");
849     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%\"%');\n");
850     strcat (sql,
851 	    "SELECT RAISE(ABORT,'update on geometry_columns_statistics violates constraint: ");
852     strcat (sql, "f_geometry_column value must be lower case')\n");
853     strcat (sql,
854 	    "WHERE NEW.f_geometry_column <> lower(NEW.f_geometry_column);\n");
855     strcat (sql, "END");
856     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
857     if (ret != SQLITE_OK)
858       {
859 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
860 	  sqlite3_free (errMsg);
861 	  return 0;
862       }
863     return 1;
864 }
865 
866 static int
create_views_geometry_columns_statistics(sqlite3 * sqlite)867 create_views_geometry_columns_statistics (sqlite3 * sqlite)
868 {
869     char sql[4186];
870     char *errMsg = NULL;
871     int ret;
872 
873     if (sqlite3_db_readonly (sqlite, "MAIN") == 1)
874       {
875 	  /* ignoring a read-only database */
876 	  return 1;
877       }
878 
879 /* creating the VIEWS_GEOMETRY_COLUMNS_STATISTICS table */
880     strcpy (sql, "CREATE TABLE IF NOT EXISTS ");
881     strcat (sql, "views_geometry_columns_statistics (\n");
882     strcat (sql, "view_name TEXT NOT NULL,\n");
883     strcat (sql, "view_geometry TEXT NOT NULL,\n");
884     strcat (sql, "last_verified TIMESTAMP,\n");
885     strcat (sql, "row_count INTEGER,\n");
886     strcat (sql, "extent_min_x DOUBLE,\n");
887     strcat (sql, "extent_min_y DOUBLE,\n");
888     strcat (sql, "extent_max_x DOUBLE,\n");
889     strcat (sql, "extent_max_y DOUBLE,\n");
890     strcat (sql, "CONSTRAINT pk_vwgc_statistics PRIMARY KEY ");
891     strcat (sql, "(view_name, view_geometry),\n");
892     strcat (sql, "CONSTRAINT fk_vwgc_statistics FOREIGN KEY ");
893     strcat (sql, "(view_name, view_geometry) REFERENCES ");
894     strcat (sql, "views_geometry_columns (view_name, view_geometry) ");
895     strcat (sql, "ON DELETE CASCADE)");
896     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
897     if (ret != SQLITE_OK)
898       {
899 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
900 	  sqlite3_free (errMsg);
901 	  return 0;
902       }
903 /* creating the VIEWS_GEOMETRY_COLUMNS_STATISTICS triggers */
904     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgcs_view_name_insert\n");
905     strcat (sql, "BEFORE INSERT ON 'views_geometry_columns_statistics'\n");
906     strcat (sql, "FOR EACH ROW BEGIN\n");
907     strcat (sql,
908 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_statistics violates constraint: ");
909     strcat (sql, "view_name value must not contain a single quote')\n");
910     strcat (sql, "WHERE NEW.view_name LIKE ('%''%');\n");
911     strcat (sql,
912 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_statistics violates constraint: ");
913     strcat (sql, "view_name value must not contain a double quote')\n");
914     strcat (sql, "WHERE NEW.view_name LIKE ('%\"%');\n");
915     strcat (sql,
916 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_statistics violates constraint: \n");
917     strcat (sql, "view_name value must be lower case')\n");
918     strcat (sql, "WHERE NEW.view_name <> lower(NEW.view_name);\n");
919     strcat (sql, "END");
920     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
921     if (ret != SQLITE_OK)
922       {
923 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
924 	  sqlite3_free (errMsg);
925 	  return 0;
926       }
927     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgcs_view_name_update\n");
928     strcat (sql,
929 	    "BEFORE UPDATE OF 'view_name' ON 'views_geometry_columns_statistics'\n");
930     strcat (sql, "FOR EACH ROW BEGIN\n");
931     strcat (sql,
932 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_statistics violates constraint: ");
933     strcat (sql, "view_name value must not contain a single quote')\n");
934     strcat (sql, "WHERE NEW.view_name LIKE ('%''%');\n");
935     strcat (sql,
936 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_statistics violates constraint: ");
937     strcat (sql, "view_name value must not contain a double quote')\n");
938     strcat (sql, "WHERE NEW.view_name LIKE ('%\"%');\n");
939     strcat (sql,
940 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_statistics violates constraint: ");
941     strcat (sql, "view_name value must be lower case')\n");
942     strcat (sql, "WHERE NEW.view_name <> lower(NEW.view_name);\n");
943     strcat (sql, "END");
944     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
945     if (ret != SQLITE_OK)
946       {
947 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
948 	  sqlite3_free (errMsg);
949 	  return 0;
950       }
951     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgcs_view_geometry_insert\n");
952     strcat (sql, "BEFORE INSERT ON 'views_geometry_columns_statistics'\n");
953     strcat (sql, "FOR EACH ROW BEGIN\n");
954     strcat (sql,
955 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_statistics violates constraint: ");
956     strcat (sql, "view_geometry value must not contain a single quote')\n");
957     strcat (sql, "WHERE NEW.view_geometry LIKE ('%''%');\n");
958     strcat (sql,
959 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_statistics violates constraint: \n");
960     strcat (sql, "view_geometry value must not contain a double quote')\n");
961     strcat (sql, "WHERE NEW.view_geometry LIKE ('%\"%');\n");
962     strcat (sql,
963 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_statistics violates constraint: ");
964     strcat (sql, "view_geometry value must be lower case')\n");
965     strcat (sql, "WHERE NEW.view_geometry <> lower(NEW.view_geometry);\n");
966     strcat (sql, "END");
967     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
968     if (ret != SQLITE_OK)
969       {
970 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
971 	  sqlite3_free (errMsg);
972 	  return 0;
973       }
974     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgcs_view_geometry_update\n");
975     strcat (sql,
976 	    "BEFORE UPDATE OF 'view_geometry' ON 'views_geometry_columns_statistics'\n");
977     strcat (sql, "FOR EACH ROW BEGIN\n");
978     strcat (sql,
979 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_statistics violates constraint: ");
980     strcat (sql, "view_geometry value must not contain a single quote')\n");
981     strcat (sql, "WHERE NEW.view_geometry LIKE ('%''%');\n");
982     strcat (sql,
983 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_statistics violates constraint: \n");
984     strcat (sql, "view_geometry value must not contain a double quote')\n");
985     strcat (sql, "WHERE NEW.view_geometry LIKE ('%\"%');\n");
986     strcat (sql,
987 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_statistics violates constraint: ");
988     strcat (sql, "view_geometry value must be lower case')\n");
989     strcat (sql, "WHERE NEW.view_geometry <> lower(NEW.view_geometry);\n");
990     strcat (sql, "END");
991     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
992     if (ret != SQLITE_OK)
993       {
994 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
995 	  sqlite3_free (errMsg);
996 	  return 0;
997       }
998     return 1;
999 }
1000 
1001 static int
create_virts_geometry_columns_statistics(sqlite3 * sqlite)1002 create_virts_geometry_columns_statistics (sqlite3 * sqlite)
1003 {
1004     char sql[4186];
1005     char *errMsg = NULL;
1006     int ret;
1007 
1008     if (sqlite3_db_readonly (sqlite, "MAIN") == 1)
1009       {
1010 	  /* ignoring a read-only database */
1011 	  return 1;
1012       }
1013 
1014 /* creating the VIRTS_GEOMETRY_COLUMNS_STATISTICS table */
1015     strcpy (sql, "CREATE TABLE IF NOT EXISTS ");
1016     strcat (sql, "virts_geometry_columns_statistics (\n");
1017     strcat (sql, "virt_name TEXT NOT NULL,\n");
1018     strcat (sql, "virt_geometry TEXT NOT NULL,\n");
1019     strcat (sql, "last_verified TIMESTAMP,\n");
1020     strcat (sql, "row_count INTEGER,\n");
1021     strcat (sql, "extent_min_x DOUBLE,\n");
1022     strcat (sql, "extent_min_y DOUBLE,\n");
1023     strcat (sql, "extent_max_x DOUBLE,\n");
1024     strcat (sql, "extent_max_y DOUBLE,\n");
1025     strcat (sql, "CONSTRAINT pk_vrtgc_statistics PRIMARY KEY ");
1026     strcat (sql, "(virt_name, virt_geometry),\n");
1027     strcat (sql, "CONSTRAINT fk_vrtgc_statistics FOREIGN KEY ");
1028     strcat (sql, "(virt_name, virt_geometry) REFERENCES ");
1029     strcat (sql, "virts_geometry_columns (virt_name, virt_geometry) ");
1030     strcat (sql, "ON DELETE CASCADE)");
1031     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1032     if (ret != SQLITE_OK)
1033       {
1034 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1035 	  sqlite3_free (errMsg);
1036 	  return 0;
1037       }
1038 /* creating the VIRTS_GEOMETRY_COLUMNS_STATISTICS triggers */
1039     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgcs_virt_name_insert\n");
1040     strcat (sql, "BEFORE INSERT ON 'virts_geometry_columns_statistics'\n");
1041     strcat (sql, "FOR EACH ROW BEGIN\n");
1042     strcat (sql,
1043 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_statistics violates constraint: ");
1044     strcat (sql, "virt_name value must not contain a single quote')\n");
1045     strcat (sql, "WHERE NEW.virt_name LIKE ('%''%');\n");
1046     strcat (sql,
1047 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_statistics violates constraint: ");
1048     strcat (sql, "virt_name value must not contain a double quote')\n");
1049     strcat (sql, "WHERE NEW.virt_name LIKE ('%\"%');\n");
1050     strcat (sql,
1051 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_statistics violates constraint: \n");
1052     strcat (sql, "virt_name value must be lower case')\n");
1053     strcat (sql, "WHERE NEW.virt_name <> lower(NEW.virt_name);\n");
1054     strcat (sql, "END");
1055     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1056     if (ret != SQLITE_OK)
1057       {
1058 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1059 	  sqlite3_free (errMsg);
1060 	  return 0;
1061       }
1062     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgcs_virt_name_update\n");
1063     strcat (sql,
1064 	    "BEFORE UPDATE OF 'virt_name' ON 'virts_geometry_columns_statistics'\n");
1065     strcat (sql, "FOR EACH ROW BEGIN\n");
1066     strcat (sql,
1067 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_statistics violates constraint: ");
1068     strcat (sql, "virt_name value must not contain a single quote')\n");
1069     strcat (sql, "WHERE NEW.virt_name LIKE ('%''%');\n");
1070     strcat (sql,
1071 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_statistics violates constraint: ");
1072     strcat (sql, "virt_name value must not contain a double quote')\n");
1073     strcat (sql, "WHERE NEW.virt_name LIKE ('%\"%');\n");
1074     strcat (sql,
1075 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_statistics violates constraint: ");
1076     strcat (sql, "virt_name value must be lower case')\n");
1077     strcat (sql, "WHERE NEW.virt_name <> lower(NEW.virt_name);\n");
1078     strcat (sql, "END");
1079     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1080     if (ret != SQLITE_OK)
1081       {
1082 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1083 	  sqlite3_free (errMsg);
1084 	  return 0;
1085       }
1086     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgcs_virt_geometry_insert\n");
1087     strcat (sql, "BEFORE INSERT ON 'virts_geometry_columns_statistics'\n");
1088     strcat (sql, "FOR EACH ROW BEGIN\n");
1089     strcat (sql,
1090 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_statistics violates constraint: ");
1091     strcat (sql, "virt_geometry value must not contain a single quote')\n");
1092     strcat (sql, "WHERE NEW.virt_geometry LIKE ('%''%');\n");
1093     strcat (sql,
1094 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_statistics violates constraint: \n");
1095     strcat (sql, "virt_geometry value must not contain a double quote')\n");
1096     strcat (sql, "WHERE NEW.virt_geometry LIKE ('%\"%');\n");
1097     strcat (sql,
1098 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_statistics violates constraint: ");
1099     strcat (sql, "virt_geometry value must be lower case')\n");
1100     strcat (sql, "WHERE NEW.virt_geometry <> lower(NEW.virt_geometry);\n");
1101     strcat (sql, "END");
1102     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1103     if (ret != SQLITE_OK)
1104       {
1105 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1106 	  sqlite3_free (errMsg);
1107 	  return 0;
1108       }
1109     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgcs_virt_geometry_update\n");
1110     strcat (sql,
1111 	    "BEFORE UPDATE OF 'virt_geometry' ON 'virts_geometry_columns_statistics'\n");
1112     strcat (sql, "FOR EACH ROW BEGIN\n");
1113     strcat (sql,
1114 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_statistics violates constraint: ");
1115     strcat (sql, "virt_geometry value must not contain a single quote')\n");
1116     strcat (sql, "WHERE NEW.virt_geometry LIKE ('%''%');\n");
1117     strcat (sql,
1118 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_statistics violates constraint: \n");
1119     strcat (sql, "virt_geometry value must not contain a double quote')\n");
1120     strcat (sql, "WHERE NEW.virt_geometry LIKE ('%\"%');\n");
1121     strcat (sql,
1122 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_statistics violates constraint: ");
1123     strcat (sql, "virt_geometry value must be lower case')\n");
1124     strcat (sql, "WHERE NEW.virt_geometry <> lower(NEW.virt_geometry);\n");
1125     strcat (sql, "END");
1126     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1127     if (ret != SQLITE_OK)
1128       {
1129 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1130 	  sqlite3_free (errMsg);
1131 	  return 0;
1132       }
1133     return 1;
1134 }
1135 
1136 static int
create_geometry_columns_field_infos(sqlite3 * sqlite)1137 create_geometry_columns_field_infos (sqlite3 * sqlite)
1138 {
1139     char sql[4186];
1140     char *errMsg = NULL;
1141     int ret;
1142 
1143     if (sqlite3_db_readonly (sqlite, "MAIN") == 1)
1144       {
1145 	  /* ignoring a read-only database */
1146 	  return 1;
1147       }
1148 
1149 /* creating the GEOMETRY_COLUMNS_FIELD_INFOS table */
1150     strcpy (sql, "CREATE TABLE IF NOT EXISTS ");
1151     strcat (sql, "geometry_columns_field_infos (\n");
1152     strcat (sql, "f_table_name TEXT NOT NULL,\n");
1153     strcat (sql, "f_geometry_column TEXT NOT NULL,\n");
1154     strcat (sql, "ordinal INTEGER NOT NULL,\n");
1155     strcat (sql, "column_name TEXT NOT NULL,\n");
1156     strcat (sql, "null_values INTEGER NOT NULL,\n");
1157     strcat (sql, "integer_values INTEGER NOT NULL,\n");
1158     strcat (sql, "double_values INTEGER NOT NULL,\n");
1159     strcat (sql, "text_values INTEGER NOT NULL,\n");
1160     strcat (sql, "blob_values INTEGER NOT NULL,\n");
1161     strcat (sql, "max_size INTEGER,\n");
1162     strcat (sql, "integer_min INTEGER,\n");
1163     strcat (sql, "integer_max INTEGER,\n");
1164     strcat (sql, "double_min DOUBLE,\n");
1165     strcat (sql, "double_max DOUBLE,\n");
1166     strcat (sql, "CONSTRAINT pk_gcfld_infos PRIMARY KEY ");
1167     strcat (sql, "(f_table_name, f_geometry_column, ordinal, column_name),\n");
1168     strcat (sql, "CONSTRAINT fk_gcfld_infos FOREIGN KEY ");
1169     strcat (sql, "(f_table_name, f_geometry_column) REFERENCES ");
1170     strcat (sql, "geometry_columns (f_table_name, f_geometry_column) ");
1171     strcat (sql, "ON DELETE CASCADE)");
1172     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1173     if (ret != SQLITE_OK)
1174       {
1175 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1176 	  sqlite3_free (errMsg);
1177 	  return 0;
1178       }
1179 /* creating the GEOMETRY_COLUMNS_FIELD_INFOS triggers */
1180     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS gcfi_f_table_name_insert\n");
1181     strcat (sql, "BEFORE INSERT ON 'geometry_columns_field_infos'\n");
1182     strcat (sql, "FOR EACH ROW BEGIN\n");
1183     strcat (sql,
1184 	    "SELECT RAISE(ABORT,'insert on geometry_columns_field_infos violates constraint: ");
1185     strcat (sql, "f_table_name value must not contain a single quote')\n");
1186     strcat (sql, "WHERE NEW.f_table_name LIKE ('%''%');\n");
1187     strcat (sql,
1188 	    "SELECT RAISE(ABORT,'insert on geometry_columns_field_infos violates constraint: ");
1189     strcat (sql, "f_table_name value must not contain a double quote')\n");
1190     strcat (sql, "WHERE NEW.f_table_name LIKE ('%\"%');\n");
1191     strcat (sql,
1192 	    "SELECT RAISE(ABORT,'insert on geometry_columns_field_infos violates constraint: \n");
1193     strcat (sql, "f_table_name value must be lower case')\n");
1194     strcat (sql, "WHERE NEW.f_table_name <> lower(NEW.f_table_name);\n");
1195     strcat (sql, "END");
1196     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1197     if (ret != SQLITE_OK)
1198       {
1199 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1200 	  sqlite3_free (errMsg);
1201 	  return 0;
1202       }
1203     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS gcfi_f_table_name_update\n");
1204     strcat (sql,
1205 	    "BEFORE UPDATE OF 'f_table_name' ON 'geometry_columns_field_infos'\n");
1206     strcat (sql, "FOR EACH ROW BEGIN\n");
1207     strcat (sql,
1208 	    "SELECT RAISE(ABORT,'update on geometry_columns_field_infos violates constraint: ");
1209     strcat (sql, "f_table_name value must not contain a single quote')\n");
1210     strcat (sql, "WHERE NEW.f_table_name LIKE ('%''%');\n");
1211     strcat (sql,
1212 	    "SELECT RAISE(ABORT,'update on geometry_columns_field_infos violates constraint: ");
1213     strcat (sql, "f_table_name value must not contain a double quote')\n");
1214     strcat (sql, "WHERE NEW.f_table_name LIKE ('%\"%');\n");
1215     strcat (sql,
1216 	    "SELECT RAISE(ABORT,'update on geometry_columns_field_infos violates constraint: ");
1217     strcat (sql, "f_table_name value must be lower case')\n");
1218     strcat (sql, "WHERE NEW.f_table_name <> lower(NEW.f_table_name);\n");
1219     strcat (sql, "END");
1220     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1221     if (ret != SQLITE_OK)
1222       {
1223 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1224 	  sqlite3_free (errMsg);
1225 	  return 0;
1226       }
1227     strcpy (sql,
1228 	    "CREATE TRIGGER IF NOT EXISTS gcfi_f_geometry_column_insert\n");
1229     strcat (sql, "BEFORE INSERT ON 'geometry_columns_field_infos'\n");
1230     strcat (sql, "FOR EACH ROW BEGIN\n");
1231     strcat (sql,
1232 	    "SELECT RAISE(ABORT,'insert on geometry_columns_field_infos violates constraint: ");
1233     strcat (sql, "f_geometry_column value must not contain a single quote')\n");
1234     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%''%');\n");
1235     strcat (sql,
1236 	    "SELECT RAISE(ABORT,'insert on geometry_columns_field_infos violates constraint: \n");
1237     strcat (sql, "f_geometry_column value must not contain a double quote')\n");
1238     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%\"%');\n");
1239     strcat (sql,
1240 	    "SELECT RAISE(ABORT,'insert on geometry_columns_field_infos violates constraint: ");
1241     strcat (sql, "f_geometry_column value must be lower case')\n");
1242     strcat (sql,
1243 	    "WHERE NEW.f_geometry_column <> lower(NEW.f_geometry_column);\n");
1244     strcat (sql, "END");
1245     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1246     if (ret != SQLITE_OK)
1247       {
1248 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1249 	  sqlite3_free (errMsg);
1250 	  return 0;
1251       }
1252     strcpy (sql,
1253 	    "CREATE TRIGGER IF NOT EXISTS gcfi_f_geometry_column_update\n");
1254     strcat (sql,
1255 	    "BEFORE UPDATE OF 'f_geometry_column' ON 'geometry_columns_field_infos'\n");
1256     strcat (sql, "FOR EACH ROW BEGIN\n");
1257     strcat (sql,
1258 	    "SELECT RAISE(ABORT,'update on geometry_columns_field_infos violates constraint: ");
1259     strcat (sql, "f_geometry_column value must not contain a single quote')\n");
1260     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%''%');\n");
1261     strcat (sql,
1262 	    "SELECT RAISE(ABORT,'update on geometry_columns_field_infos violates constraint: ");
1263     strcat (sql, "f_geometry_column value must not contain a double quote')\n");
1264     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%\"%');\n");
1265     strcat (sql,
1266 	    "SELECT RAISE(ABORT,'update on geometry_columns_field_infos violates constraint: ");
1267     strcat (sql, "f_geometry_column value must be lower case')\n");
1268     strcat (sql,
1269 	    "WHERE NEW.f_geometry_column <> lower(NEW.f_geometry_column);\n");
1270     strcat (sql, "END");
1271     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1272     if (ret != SQLITE_OK)
1273       {
1274 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1275 	  sqlite3_free (errMsg);
1276 	  return 0;
1277       }
1278     return 1;
1279 }
1280 
1281 static int
create_views_geometry_columns_field_infos(sqlite3 * sqlite)1282 create_views_geometry_columns_field_infos (sqlite3 * sqlite)
1283 {
1284     char sql[4186];
1285     char *errMsg = NULL;
1286     int ret;
1287 
1288     if (sqlite3_db_readonly (sqlite, "MAIN") == 1)
1289       {
1290 	  /* ignoring a read-only database */
1291 	  return 1;
1292       }
1293 
1294 /* creating the VIEWS_COLUMNS_FIELD_INFOS table */
1295     strcpy (sql, "CREATE TABLE IF NOT EXISTS ");
1296     strcat (sql, "views_geometry_columns_field_infos (\n");
1297     strcat (sql, "view_name TEXT NOT NULL,\n");
1298     strcat (sql, "view_geometry TEXT NOT NULL,\n");
1299     strcat (sql, "ordinal INTEGER NOT NULL,\n");
1300     strcat (sql, "column_name TEXT NOT NULL,\n");
1301     strcat (sql, "null_values INTEGER NOT NULL,\n");
1302     strcat (sql, "integer_values INTEGER NOT NULL,\n");
1303     strcat (sql, "double_values INTEGER NOT NULL,\n");
1304     strcat (sql, "text_values INTEGER NOT NULL,\n");
1305     strcat (sql, "blob_values INTEGER NOT NULL,\n");
1306     strcat (sql, "max_size INTEGER,\n");
1307     strcat (sql, "integer_min INTEGER,\n");
1308     strcat (sql, "integer_max INTEGER,\n");
1309     strcat (sql, "double_min DOUBLE,\n");
1310     strcat (sql, "double_max DOUBLE,\n");
1311     strcat (sql, "CONSTRAINT pk_vwgcfld_infos PRIMARY KEY ");
1312     strcat (sql, "(view_name, view_geometry, ordinal, column_name),\n");
1313     strcat (sql, "CONSTRAINT fk_vwgcfld_infos FOREIGN KEY ");
1314     strcat (sql, "(view_name, view_geometry) REFERENCES ");
1315     strcat (sql, "views_geometry_columns (view_name, view_geometry) ");
1316     strcat (sql, "ON DELETE CASCADE)");
1317     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1318     if (ret != SQLITE_OK)
1319       {
1320 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1321 	  sqlite3_free (errMsg);
1322 	  return 0;
1323       }
1324 /* creating the VIEWS_COLUMNS_FIELD_INFOS triggers */
1325     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgcfi_view_name_insert\n");
1326     strcat (sql, "BEFORE INSERT ON 'views_geometry_columns_field_infos'\n");
1327     strcat (sql, "FOR EACH ROW BEGIN\n");
1328     strcat (sql,
1329 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_field_infos violates constraint: ");
1330     strcat (sql, "view_name value must not contain a single quote')\n");
1331     strcat (sql, "WHERE NEW.view_name LIKE ('%''%');\n");
1332     strcat (sql,
1333 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_field_infos violates constraint: ");
1334     strcat (sql, "view_name value must not contain a double quote')\n");
1335     strcat (sql, "WHERE NEW.view_name LIKE ('%\"%');\n");
1336     strcat (sql,
1337 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_field_infos violates constraint: \n");
1338     strcat (sql, "view_name value must be lower case')\n");
1339     strcat (sql, "WHERE NEW.view_name <> lower(NEW.view_name);\n");
1340     strcat (sql, "END");
1341     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1342     if (ret != SQLITE_OK)
1343       {
1344 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1345 	  sqlite3_free (errMsg);
1346 	  return 0;
1347       }
1348     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgcfi_view_name_update\n");
1349     strcat (sql,
1350 	    "BEFORE UPDATE OF 'view_name' ON 'views_geometry_columns_field_infos'\n");
1351     strcat (sql, "FOR EACH ROW BEGIN\n");
1352     strcat (sql,
1353 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_field_infos violates constraint: ");
1354     strcat (sql, "view_name value must not contain a single quote')\n");
1355     strcat (sql, "WHERE NEW.view_name LIKE ('%''%');\n");
1356     strcat (sql,
1357 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_field_infos violates constraint: ");
1358     strcat (sql, "view_name value must not contain a double quote')\n");
1359     strcat (sql, "WHERE NEW.view_name LIKE ('%\"%');\n");
1360     strcat (sql,
1361 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_field_infos violates constraint: ");
1362     strcat (sql, "view_name value must be lower case')\n");
1363     strcat (sql, "WHERE NEW.view_name <> lower(NEW.view_name);\n");
1364     strcat (sql, "END");
1365     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1366     if (ret != SQLITE_OK)
1367       {
1368 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1369 	  sqlite3_free (errMsg);
1370 	  return 0;
1371       }
1372     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgcfi_view_geometry_insert\n");
1373     strcat (sql, "BEFORE INSERT ON 'views_geometry_columns_field_infos'\n");
1374     strcat (sql, "FOR EACH ROW BEGIN\n");
1375     strcat (sql,
1376 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_field_infos violates constraint: ");
1377     strcat (sql, "view_geometry value must not contain a single quote')\n");
1378     strcat (sql, "WHERE NEW.view_geometry LIKE ('%''%');\n");
1379     strcat (sql,
1380 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_field_infos violates constraint: \n");
1381     strcat (sql, "view_geometry value must not contain a double quote')\n");
1382     strcat (sql, "WHERE NEW.view_geometry LIKE ('%\"%');\n");
1383     strcat (sql,
1384 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_field_infos violates constraint: ");
1385     strcat (sql, "view_geometry value must be lower case')\n");
1386     strcat (sql, "WHERE NEW.view_geometry <> lower(NEW.view_geometry);\n");
1387     strcat (sql, "END");
1388     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1389     if (ret != SQLITE_OK)
1390       {
1391 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1392 	  sqlite3_free (errMsg);
1393 	  return 0;
1394       }
1395     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgcfi_view_geometry_update\n");
1396     strcat (sql,
1397 	    "BEFORE UPDATE OF 'view_geometry' ON 'views_geometry_columns_field_infos'\n");
1398     strcat (sql, "FOR EACH ROW BEGIN\n");
1399     strcat (sql,
1400 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_field_infos violates constraint: ");
1401     strcat (sql, "view_geometry value must not contain a single quote')\n");
1402     strcat (sql, "WHERE NEW.view_geometry LIKE ('%''%');\n");
1403     strcat (sql,
1404 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_field_infos violates constraint: \n");
1405     strcat (sql, "view_geometry value must not contain a double quote')\n");
1406     strcat (sql, "WHERE NEW.view_geometry LIKE ('%\"%');\n");
1407     strcat (sql,
1408 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_field_infos violates constraint: ");
1409     strcat (sql, "view_geometry value must be lower case')\n");
1410     strcat (sql, "WHERE NEW.view_geometry <> lower(NEW.view_geometry);\n");
1411     strcat (sql, "END");
1412     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1413     if (ret != SQLITE_OK)
1414       {
1415 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1416 	  sqlite3_free (errMsg);
1417 	  return 0;
1418       }
1419     return 1;
1420 }
1421 
1422 static int
create_virts_geometry_columns_field_infos(sqlite3 * sqlite)1423 create_virts_geometry_columns_field_infos (sqlite3 * sqlite)
1424 {
1425     char sql[4186];
1426     char *errMsg = NULL;
1427     int ret;
1428 
1429     if (sqlite3_db_readonly (sqlite, "MAIN") == 1)
1430       {
1431 	  /* ignoring a read-only database */
1432 	  return 1;
1433       }
1434 
1435 /* creating the VIRTS_GEOMETRY_COLUMNS_FIELD_INFOS table */
1436     strcpy (sql, "CREATE TABLE IF NOT EXISTS ");
1437     strcat (sql, "virts_geometry_columns_field_infos (\n");
1438     strcat (sql, "virt_name TEXT NOT NULL,\n");
1439     strcat (sql, "virt_geometry TEXT NOT NULL,\n");
1440     strcat (sql, "ordinal INTEGER NOT NULL,\n");
1441     strcat (sql, "column_name TEXT NOT NULL,\n");
1442     strcat (sql, "null_values INTEGER NOT NULL,\n");
1443     strcat (sql, "integer_values INTEGER NOT NULL,\n");
1444     strcat (sql, "double_values INTEGER NOT NULL,\n");
1445     strcat (sql, "text_values INTEGER NOT NULL,\n");
1446     strcat (sql, "blob_values INTEGER NOT NULL,\n");
1447     strcat (sql, "max_size INTEGER,\n");
1448     strcat (sql, "integer_min INTEGER,\n");
1449     strcat (sql, "integer_max INTEGER,\n");
1450     strcat (sql, "double_min DOUBLE,\n");
1451     strcat (sql, "double_max DOUBLE,\n");
1452     strcat (sql, "CONSTRAINT pk_vrtgcfld_infos PRIMARY KEY ");
1453     strcat (sql, "(virt_name, virt_geometry, ordinal, column_name),\n");
1454     strcat (sql, "CONSTRAINT fk_vrtgcfld_infos FOREIGN KEY ");
1455     strcat (sql, "(virt_name, virt_geometry) REFERENCES ");
1456     strcat (sql, "virts_geometry_columns (virt_name, virt_geometry) ");
1457     strcat (sql, "ON DELETE CASCADE)");
1458     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1459     if (ret != SQLITE_OK)
1460       {
1461 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1462 	  sqlite3_free (errMsg);
1463 	  return 0;
1464       }
1465 /* creating the VIRTS_GEOMETRY_COLUMNS_FIELD_INFOS triggers */
1466     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgcfi_virt_name_insert\n");
1467     strcat (sql, "BEFORE INSERT ON 'virts_geometry_columns_field_infos'\n");
1468     strcat (sql, "FOR EACH ROW BEGIN\n");
1469     strcat (sql,
1470 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_field_infos violates constraint: ");
1471     strcat (sql, "virt_name value must not contain a single quote')\n");
1472     strcat (sql, "WHERE NEW.virt_name LIKE ('%''%');\n");
1473     strcat (sql,
1474 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_field_infos violates constraint: ");
1475     strcat (sql, "virt_name value must not contain a double quote')\n");
1476     strcat (sql, "WHERE NEW.virt_name LIKE ('%\"%');\n");
1477     strcat (sql,
1478 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_field_infos violates constraint: \n");
1479     strcat (sql, "virt_name value must be lower case')\n");
1480     strcat (sql, "WHERE NEW.virt_name <> lower(NEW.virt_name);\n");
1481     strcat (sql, "END");
1482     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1483     if (ret != SQLITE_OK)
1484       {
1485 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1486 	  sqlite3_free (errMsg);
1487 	  return 0;
1488       }
1489     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgcfi_virt_name_update\n");
1490     strcat (sql,
1491 	    "BEFORE UPDATE OF 'virt_name' ON 'virts_geometry_columns_field_infos'\n");
1492     strcat (sql, "FOR EACH ROW BEGIN\n");
1493     strcat (sql,
1494 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_field_infos violates constraint: ");
1495     strcat (sql, "virt_name value must not contain a single quote')\n");
1496     strcat (sql, "WHERE NEW.virt_name LIKE ('%''%');\n");
1497     strcat (sql,
1498 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_field_infos violates constraint: ");
1499     strcat (sql, "virt_name value must not contain a double quote')\n");
1500     strcat (sql, "WHERE NEW.virt_name LIKE ('%\"%');\n");
1501     strcat (sql,
1502 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_field_infos violates constraint: ");
1503     strcat (sql, "virt_name value must be lower case')\n");
1504     strcat (sql, "WHERE NEW.virt_name <> lower(NEW.virt_name);\n");
1505     strcat (sql, "END");
1506     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1507     if (ret != SQLITE_OK)
1508       {
1509 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1510 	  sqlite3_free (errMsg);
1511 	  return 0;
1512       }
1513     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgcfi_virt_geometry_insert\n");
1514     strcat (sql, "BEFORE INSERT ON 'virts_geometry_columns_field_infos'\n");
1515     strcat (sql, "FOR EACH ROW BEGIN\n");
1516     strcat (sql,
1517 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_field_infos violates constraint: ");
1518     strcat (sql, "virt_geometry value must not contain a single quote')\n");
1519     strcat (sql, "WHERE NEW.virt_geometry LIKE ('%''%');\n");
1520     strcat (sql,
1521 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_field_infos violates constraint: \n");
1522     strcat (sql, "virt_geometry value must not contain a double quote')\n");
1523     strcat (sql, "WHERE NEW.virt_geometry LIKE ('%\"%');\n");
1524     strcat (sql,
1525 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_field_infos violates constraint: ");
1526     strcat (sql, "virt_geometry value must be lower case')\n");
1527     strcat (sql, "WHERE NEW.virt_geometry <> lower(NEW.virt_geometry);\n");
1528     strcat (sql, "END");
1529     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1530     if (ret != SQLITE_OK)
1531       {
1532 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1533 	  sqlite3_free (errMsg);
1534 	  return 0;
1535       }
1536     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgcfi_virt_geometry_update\n");
1537     strcat (sql,
1538 	    "BEFORE UPDATE OF 'virt_geometry' ON 'virts_geometry_columns_field_infos'\n");
1539     strcat (sql, "FOR EACH ROW BEGIN\n");
1540     strcat (sql,
1541 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_field_infos violates constraint: ");
1542     strcat (sql, "virt_geometry value must not contain a single quote')\n");
1543     strcat (sql, "WHERE NEW.virt_geometry LIKE ('%''%');\n");
1544     strcat (sql,
1545 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_field_infos violates constraint: \n");
1546     strcat (sql, "virt_geometry value must not contain a double quote')\n");
1547     strcat (sql, "WHERE NEW.virt_geometry LIKE ('%\"%');\n");
1548     strcat (sql,
1549 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_field_infos violates constraint: ");
1550     strcat (sql, "virt_geometry value must be lower case')\n");
1551     strcat (sql, "WHERE NEW.virt_geometry <> lower(NEW.virt_geometry);\n");
1552     strcat (sql, "END");
1553     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1554     if (ret != SQLITE_OK)
1555       {
1556 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1557 	  sqlite3_free (errMsg);
1558 	  return 0;
1559       }
1560     return 1;
1561 }
1562 
1563 SPATIALITE_PRIVATE int
create_geometry_columns_time(sqlite3 * sqlite)1564 create_geometry_columns_time (sqlite3 * sqlite)
1565 {
1566     char sql[4186];
1567     char *errMsg = NULL;
1568     int ret;
1569 
1570     if (sqlite3_db_readonly (sqlite, "MAIN") == 1)
1571       {
1572 	  /* ignoring a read-only database */
1573 	  return 1;
1574       }
1575 
1576 /* creating the GEOMETRY_COLUMNS_TIME table */
1577     strcpy (sql, "CREATE TABLE IF NOT EXISTS ");
1578     strcat (sql, "geometry_columns_time (\n");
1579     strcat (sql, "f_table_name TEXT NOT NULL,\n");
1580     strcat (sql, "f_geometry_column TEXT NOT NULL,\n");
1581     strcat (sql,
1582 	    "last_insert TIMESTAMP NOT NULL DEFAULT '0000-01-01T00:00:00.000Z',\n");
1583     strcat (sql,
1584 	    "last_update TIMESTAMP NOT NULL DEFAULT '0000-01-01T00:00:00.000Z',\n");
1585     strcat (sql,
1586 	    "last_delete TIMESTAMP NOT NULL DEFAULT '0000-01-01T00:00:00.000Z',\n");
1587     strcat (sql, "CONSTRAINT pk_gc_time PRIMARY KEY ");
1588     strcat (sql, "(f_table_name, f_geometry_column),\n");
1589     strcat (sql, "CONSTRAINT fk_gc_time FOREIGN KEY ");
1590     strcat (sql, "(f_table_name, f_geometry_column) ");
1591     strcat (sql, "REFERENCES geometry_columns ");
1592     strcat (sql, "(f_table_name, f_geometry_column) ");
1593     strcat (sql, "ON DELETE CASCADE)");
1594     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1595     if (ret != SQLITE_OK)
1596       {
1597 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1598 	  sqlite3_free (errMsg);
1599 	  return 0;
1600       }
1601 /* creating the GEOMETRY_COLUMNS_TIME triggers */
1602     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS gctm_f_table_name_insert\n");
1603     strcat (sql, "BEFORE INSERT ON 'geometry_columns_time'\n");
1604     strcat (sql, "FOR EACH ROW BEGIN\n");
1605     strcat (sql,
1606 	    "SELECT RAISE(ABORT,'insert on geometry_columns_time violates constraint: ");
1607     strcat (sql, "f_table_name value must not contain a single quote')\n");
1608     strcat (sql, "WHERE NEW.f_table_name LIKE ('%''%');\n");
1609     strcat (sql,
1610 	    "SELECT RAISE(ABORT,'insert on geometry_columns_time violates constraint: ");
1611     strcat (sql, "f_table_name value must not contain a double quote')\n");
1612     strcat (sql, "WHERE NEW.f_table_name LIKE ('%\"%');\n");
1613     strcat (sql,
1614 	    "SELECT RAISE(ABORT,'insert on geometry_columns_time violates constraint: \n");
1615     strcat (sql, "f_table_name value must be lower case')\n");
1616     strcat (sql, "WHERE NEW.f_table_name <> lower(NEW.f_table_name);\n");
1617     strcat (sql, "END");
1618     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1619     if (ret != SQLITE_OK)
1620       {
1621 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1622 	  sqlite3_free (errMsg);
1623 	  return 0;
1624       }
1625     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS gctm_f_table_name_update\n");
1626     strcat (sql,
1627 	    "BEFORE UPDATE OF 'f_table_name' ON 'geometry_columns_time'\n");
1628     strcat (sql, "FOR EACH ROW BEGIN\n");
1629     strcat (sql,
1630 	    "SELECT RAISE(ABORT,'update on geometry_columns_time violates constraint: ");
1631     strcat (sql, "f_table_name value must not contain a single quote')\n");
1632     strcat (sql, "WHERE NEW.f_table_name LIKE ('%''%');\n");
1633     strcat (sql,
1634 	    "SELECT RAISE(ABORT,'update on geometry_columns_time violates constraint: ");
1635     strcat (sql, "f_table_name value must not contain a double quote')\n");
1636     strcat (sql, "WHERE NEW.f_table_name LIKE ('%\"%');\n");
1637     strcat (sql,
1638 	    "SELECT RAISE(ABORT,'update on geometry_columns_time violates constraint: ");
1639     strcat (sql, "f_table_name value must be lower case')\n");
1640     strcat (sql, "WHERE NEW.f_table_name <> lower(NEW.f_table_name);\n");
1641     strcat (sql, "END");
1642     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1643     if (ret != SQLITE_OK)
1644       {
1645 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1646 	  sqlite3_free (errMsg);
1647 	  return 0;
1648       }
1649     strcpy (sql,
1650 	    "CREATE TRIGGER IF NOT EXISTS gctm_f_geometry_column_insert\n");
1651     strcat (sql, "BEFORE INSERT ON 'geometry_columns_time'\n");
1652     strcat (sql, "FOR EACH ROW BEGIN\n");
1653     strcat (sql,
1654 	    "SELECT RAISE(ABORT,'insert on geometry_columns_time violates constraint: ");
1655     strcat (sql, "f_geometry_column value must not contain a single quote')\n");
1656     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%''%');\n");
1657     strcat (sql,
1658 	    "SELECT RAISE(ABORT,'insert on geometry_columns_time violates constraint: \n");
1659     strcat (sql, "f_geometry_column value must not contain a double quote')\n");
1660     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%\"%');\n");
1661     strcat (sql,
1662 	    "SELECT RAISE(ABORT,'insert on geometry_columns_time violates constraint: ");
1663     strcat (sql, "f_geometry_column value must be lower case')\n");
1664     strcat (sql,
1665 	    "WHERE NEW.f_geometry_column <> lower(NEW.f_geometry_column);\n");
1666     strcat (sql, "END");
1667     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1668     if (ret != SQLITE_OK)
1669       {
1670 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1671 	  sqlite3_free (errMsg);
1672 	  return 0;
1673       }
1674     strcpy (sql,
1675 	    "CREATE TRIGGER IF NOT EXISTS gctm_f_geometry_column_update\n");
1676     strcat (sql,
1677 	    "BEFORE UPDATE OF 'f_geometry_column' ON 'geometry_columns_time'\n");
1678     strcat (sql, "FOR EACH ROW BEGIN\n");
1679     strcat (sql,
1680 	    "SELECT RAISE(ABORT,'update on geometry_columns_time violates constraint: ");
1681     strcat (sql, "f_geometry_column value must not contain a single quote')\n");
1682     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%''%');\n");
1683     strcat (sql,
1684 	    "SELECT RAISE(ABORT,'update on geometry_columns_time violates constraint: ");
1685     strcat (sql, "f_geometry_column value must not contain a double quote')\n");
1686     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%\"%');\n");
1687     strcat (sql,
1688 	    "SELECT RAISE(ABORT,'update on geometry_columns_time violates constraint: ");
1689     strcat (sql, "f_geometry_column value must be lower case')\n");
1690     strcat (sql,
1691 	    "WHERE NEW.f_geometry_column <> lower(NEW.f_geometry_column);\n");
1692     strcat (sql, "END");
1693     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1694     if (ret != SQLITE_OK)
1695       {
1696 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1697 	  sqlite3_free (errMsg);
1698 	  return 0;
1699       }
1700     return 1;
1701 }
1702 
1703 static int
create_geometry_columns_auth(sqlite3 * sqlite)1704 create_geometry_columns_auth (sqlite3 * sqlite)
1705 {
1706     char sql[4186];
1707     char *errMsg = NULL;
1708     int ret;
1709 
1710     if (sqlite3_db_readonly (sqlite, "MAIN") == 1)
1711       {
1712 	  /* ignoring a read-only database */
1713 	  return 1;
1714       }
1715 
1716 /* creating the GEOMETRY_COLUMNS_AUTH table */
1717     strcpy (sql, "CREATE TABLE IF NOT EXISTS ");
1718     strcat (sql, "geometry_columns_auth (\n");
1719     strcat (sql, "f_table_name TEXT NOT NULL,\n");
1720     strcat (sql, "f_geometry_column TEXT NOT NULL,\n");
1721     strcat (sql, "read_only INTEGER NOT NULL,\n");
1722     strcat (sql, "hidden INTEGER NOT NULL,\n");
1723     strcat (sql, "CONSTRAINT pk_gc_auth PRIMARY KEY ");
1724     strcat (sql, "(f_table_name, f_geometry_column),\n");
1725     strcat (sql, "CONSTRAINT fk_gc_auth FOREIGN KEY ");
1726     strcat (sql, "(f_table_name, f_geometry_column) ");
1727     strcat (sql, "REFERENCES geometry_columns ");
1728     strcat (sql, "(f_table_name, f_geometry_column) ");
1729     strcat (sql, "ON DELETE CASCADE,\n");
1730     strcat (sql, "CONSTRAINT ck_gc_ronly CHECK (read_only IN ");
1731     strcat (sql, "(0,1)),\n");
1732     strcat (sql, "CONSTRAINT ck_gc_hidden CHECK (hidden IN ");
1733     strcat (sql, "(0,1)))");
1734     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1735     if (ret != SQLITE_OK)
1736       {
1737 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1738 	  sqlite3_free (errMsg);
1739 	  return 0;
1740       }
1741 /* creating the GEOMETRY_COLUMNS_AUTH triggers */
1742     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS gcau_f_table_name_insert\n");
1743     strcat (sql, "BEFORE INSERT ON 'geometry_columns_auth'\n");
1744     strcat (sql, "FOR EACH ROW BEGIN\n");
1745     strcat (sql,
1746 	    "SELECT RAISE(ABORT,'insert on geometry_columns_auth violates constraint: ");
1747     strcat (sql, "f_table_name value must not contain a single quote')\n");
1748     strcat (sql, "WHERE NEW.f_table_name LIKE ('%''%');\n");
1749     strcat (sql,
1750 	    "SELECT RAISE(ABORT,'insert on geometry_columns_auth violates constraint: ");
1751     strcat (sql, "f_table_name value must not contain a double quote')\n");
1752     strcat (sql, "WHERE NEW.f_table_name LIKE ('%\"%');\n");
1753     strcat (sql,
1754 	    "SELECT RAISE(ABORT,'insert on geometry_columns_auth violates constraint: \n");
1755     strcat (sql, "f_table_name value must be lower case')\n");
1756     strcat (sql, "WHERE NEW.f_table_name <> lower(NEW.f_table_name);\n");
1757     strcat (sql, "END");
1758     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1759     if (ret != SQLITE_OK)
1760       {
1761 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1762 	  sqlite3_free (errMsg);
1763 	  return 0;
1764       }
1765     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS gcau_f_table_name_update\n");
1766     strcat (sql,
1767 	    "BEFORE UPDATE OF 'f_table_name' ON 'geometry_columns_auth'\n");
1768     strcat (sql, "FOR EACH ROW BEGIN\n");
1769     strcat (sql,
1770 	    "SELECT RAISE(ABORT,'update on geometry_columns_auth violates constraint: ");
1771     strcat (sql, "f_table_name value must not contain a single quote')\n");
1772     strcat (sql, "WHERE NEW.f_table_name LIKE ('%''%');\n");
1773     strcat (sql,
1774 	    "SELECT RAISE(ABORT,'update on geometry_columns_auth violates constraint: ");
1775     strcat (sql, "f_table_name value must not contain a double quote')\n");
1776     strcat (sql, "WHERE NEW.f_table_name LIKE ('%\"%');\n");
1777     strcat (sql,
1778 	    "SELECT RAISE(ABORT,'update on geometry_columns_auth violates constraint: ");
1779     strcat (sql, "f_table_name value must be lower case')\n");
1780     strcat (sql, "WHERE NEW.f_table_name <> lower(NEW.f_table_name);\n");
1781     strcat (sql, "END");
1782     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1783     if (ret != SQLITE_OK)
1784       {
1785 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1786 	  sqlite3_free (errMsg);
1787 	  return 0;
1788       }
1789     strcpy (sql,
1790 	    "CREATE TRIGGER IF NOT EXISTS gcau_f_geometry_column_insert\n");
1791     strcat (sql, "BEFORE INSERT ON 'geometry_columns_auth'\n");
1792     strcat (sql, "FOR EACH ROW BEGIN\n");
1793     strcat (sql,
1794 	    "SELECT RAISE(ABORT,'insert on geometry_columns_auth violates constraint: ");
1795     strcat (sql, "f_geometry_column value must not contain a single quote')\n");
1796     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%''%');\n");
1797     strcat (sql,
1798 	    "SELECT RAISE(ABORT,'insert on geometry_columns_auth violates constraint: \n");
1799     strcat (sql, "f_geometry_column value must not contain a double quote')\n");
1800     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%\"%');\n");
1801     strcat (sql,
1802 	    "SELECT RAISE(ABORT,'insert on geometry_columns_auth violates constraint: ");
1803     strcat (sql, "f_geometry_column value must be lower case')\n");
1804     strcat (sql,
1805 	    "WHERE NEW.f_geometry_column <> lower(NEW.f_geometry_column);\n");
1806     strcat (sql, "END");
1807     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1808     if (ret != SQLITE_OK)
1809       {
1810 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1811 	  sqlite3_free (errMsg);
1812 	  return 0;
1813       }
1814     strcpy (sql,
1815 	    "CREATE TRIGGER IF NOT EXISTS gcau_f_geometry_column_update\n");
1816     strcat (sql,
1817 	    "BEFORE UPDATE OF 'f_geometry_column' ON 'geometry_columns_auth'\n");
1818     strcat (sql, "FOR EACH ROW BEGIN\n");
1819     strcat (sql,
1820 	    "SELECT RAISE(ABORT,'update on geometry_columns_auth violates constraint: ");
1821     strcat (sql, "f_geometry_column value must not contain a single quote')\n");
1822     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%''%');\n");
1823     strcat (sql,
1824 	    "SELECT RAISE(ABORT,'update on geometry_columns_auth violates constraint: ");
1825     strcat (sql, "f_geometry_column value must not contain a double quote')\n");
1826     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%\"%');\n");
1827     strcat (sql,
1828 	    "SELECT RAISE(ABORT,'update on geometry_columns_auth violates constraint: ");
1829     strcat (sql, "f_geometry_column value must be lower case')\n");
1830     strcat (sql,
1831 	    "WHERE NEW.f_geometry_column <> lower(NEW.f_geometry_column);\n");
1832     strcat (sql, "END");
1833     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1834     if (ret != SQLITE_OK)
1835       {
1836 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1837 	  sqlite3_free (errMsg);
1838 	  return 0;
1839       }
1840     return 1;
1841 }
1842 
1843 static int
create_views_geometry_columns_auth(sqlite3 * sqlite)1844 create_views_geometry_columns_auth (sqlite3 * sqlite)
1845 {
1846     char sql[4186];
1847     char *errMsg = NULL;
1848     int ret;
1849 
1850     if (sqlite3_db_readonly (sqlite, "MAIN") == 1)
1851       {
1852 	  /* ignoring a read-only database */
1853 	  return 1;
1854       }
1855 
1856 /* creating the VIEWS_GEOMETRY_COLUMNS_AUTH table */
1857     strcpy (sql, "CREATE TABLE IF NOT EXISTS ");
1858     strcat (sql, "views_geometry_columns_auth (\n");
1859     strcat (sql, "view_name TEXT NOT NULL,\n");
1860     strcat (sql, "view_geometry TEXT NOT NULL,\n");
1861     strcat (sql, "hidden INTEGER NOT NULL,\n");
1862     strcat (sql, "CONSTRAINT pk_vwgc_auth PRIMARY KEY ");
1863     strcat (sql, "(view_name, view_geometry),\n");
1864     strcat (sql, "CONSTRAINT fk_vwgc_auth FOREIGN KEY ");
1865     strcat (sql, "(view_name, view_geometry) ");
1866     strcat (sql, "REFERENCES views_geometry_columns ");
1867     strcat (sql, "(view_name, view_geometry) ");
1868     strcat (sql, "ON DELETE CASCADE,\n");
1869     strcat (sql, "CONSTRAINT ck_vwgc_hidden CHECK (hidden IN ");
1870     strcat (sql, "(0,1)))");
1871     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1872     if (ret != SQLITE_OK)
1873       {
1874 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1875 	  sqlite3_free (errMsg);
1876 	  return 0;
1877       }
1878 /* creating the VIEWS_GEOMETRY_COLUMNS_AUTH triggers */
1879     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgcau_view_name_insert\n");
1880     strcat (sql, "BEFORE INSERT ON 'views_geometry_columns_auth'\n");
1881     strcat (sql, "FOR EACH ROW BEGIN\n");
1882     strcat (sql,
1883 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_auth violates constraint: ");
1884     strcat (sql, "view_name value must not contain a single quote')\n");
1885     strcat (sql, "WHERE NEW.view_name LIKE ('%''%');\n");
1886     strcat (sql,
1887 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_auth violates constraint: ");
1888     strcat (sql, "view_name value must not contain a double quote')\n");
1889     strcat (sql, "WHERE NEW.view_name LIKE ('%\"%');\n");
1890     strcat (sql,
1891 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_auth violates constraint: \n");
1892     strcat (sql, "view_name value must be lower case')\n");
1893     strcat (sql, "WHERE NEW.view_name <> lower(NEW.view_name);\n");
1894     strcat (sql, "END");
1895     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1896     if (ret != SQLITE_OK)
1897       {
1898 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1899 	  sqlite3_free (errMsg);
1900 	  return 0;
1901       }
1902     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgcau_view_name_update\n");
1903     strcat (sql,
1904 	    "BEFORE UPDATE OF 'view_name' ON 'views_geometry_columns_auth'\n");
1905     strcat (sql, "FOR EACH ROW BEGIN\n");
1906     strcat (sql,
1907 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_auth violates constraint: ");
1908     strcat (sql, "view_name value must not contain a single quote')\n");
1909     strcat (sql, "WHERE NEW.view_name LIKE ('%''%');\n");
1910     strcat (sql,
1911 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_auth violates constraint: ");
1912     strcat (sql, "view_name value must not contain a double quote')\n");
1913     strcat (sql, "WHERE NEW.view_name LIKE ('%\"%');\n");
1914     strcat (sql,
1915 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_auth violates constraint: ");
1916     strcat (sql, "view_name value must be lower case')\n");
1917     strcat (sql, "WHERE NEW.view_name <> lower(NEW.view_name);\n");
1918     strcat (sql, "END");
1919     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1920     if (ret != SQLITE_OK)
1921       {
1922 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1923 	  sqlite3_free (errMsg);
1924 	  return 0;
1925       }
1926     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgcau_view_geometry_insert\n");
1927     strcat (sql, "BEFORE INSERT ON 'views_geometry_columns_auth'\n");
1928     strcat (sql, "FOR EACH ROW BEGIN\n");
1929     strcat (sql,
1930 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_auth violates constraint: ");
1931     strcat (sql, "view_geometry value must not contain a single quote')\n");
1932     strcat (sql, "WHERE NEW.view_geometry LIKE ('%''%');\n");
1933     strcat (sql,
1934 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_auth violates constraint: \n");
1935     strcat (sql, "view_geometry value must not contain a double quote')\n");
1936     strcat (sql, "WHERE NEW.view_geometry LIKE ('%\"%');\n");
1937     strcat (sql,
1938 	    "SELECT RAISE(ABORT,'insert on views_geometry_columns_auth violates constraint: ");
1939     strcat (sql, "view_geometry value must be lower case')\n");
1940     strcat (sql, "WHERE NEW.view_geometry <> lower(NEW.view_geometry);\n");
1941     strcat (sql, "END");
1942     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1943     if (ret != SQLITE_OK)
1944       {
1945 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1946 	  sqlite3_free (errMsg);
1947 	  return 0;
1948       }
1949     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vwgcau_view_geometry_update\n");
1950     strcat (sql,
1951 	    "BEFORE UPDATE OF 'view_geometry'  ON 'views_geometry_columns_auth'\n");
1952     strcat (sql, "FOR EACH ROW BEGIN\n");
1953     strcat (sql,
1954 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_auth violates constraint: ");
1955     strcat (sql, "view_geometry value must not contain a single quote')\n");
1956     strcat (sql, "WHERE NEW.view_geometry LIKE ('%''%');\n");
1957     strcat (sql,
1958 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_auth violates constraint: \n");
1959     strcat (sql, "view_geometry value must not contain a double quote')\n");
1960     strcat (sql, "WHERE NEW.view_geometry LIKE ('%\"%');\n");
1961     strcat (sql,
1962 	    "SELECT RAISE(ABORT,'update on views_geometry_columns_auth violates constraint: ");
1963     strcat (sql, "view_geometry value must be lower case')\n");
1964     strcat (sql, "WHERE NEW.view_geometry <> lower(NEW.view_geometry);\n");
1965     strcat (sql, "END");
1966     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
1967     if (ret != SQLITE_OK)
1968       {
1969 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
1970 	  sqlite3_free (errMsg);
1971 	  return 0;
1972       }
1973     return 1;
1974 }
1975 
1976 static int
create_virts_geometry_columns_auth(sqlite3 * sqlite)1977 create_virts_geometry_columns_auth (sqlite3 * sqlite)
1978 {
1979     char sql[4186];
1980     char *errMsg = NULL;
1981     int ret;
1982 
1983     if (sqlite3_db_readonly (sqlite, "MAIN") == 1)
1984       {
1985 	  /* ignoring a read-only database */
1986 	  return 1;
1987       }
1988 
1989 /* creating the VIRTS_GEOMETRY_COLUMNS_AUTH table */
1990     strcpy (sql, "CREATE TABLE IF NOT EXISTS ");
1991     strcat (sql, "virts_geometry_columns_auth (\n");
1992     strcat (sql, "virt_name TEXT NOT NULL,\n");
1993     strcat (sql, "virt_geometry TEXT NOT NULL,\n");
1994     strcat (sql, "hidden INTEGER NOT NULL,\n");
1995     strcat (sql, "CONSTRAINT pk_vrtgc_auth PRIMARY KEY ");
1996     strcat (sql, "(virt_name, virt_geometry),\n");
1997     strcat (sql, "CONSTRAINT fk_vrtgc_auth FOREIGN KEY ");
1998     strcat (sql, "(virt_name, virt_geometry) ");
1999     strcat (sql, "REFERENCES virts_geometry_columns ");
2000     strcat (sql, "(virt_name, virt_geometry) ");
2001     strcat (sql, "ON DELETE CASCADE,\n");
2002     strcat (sql, "CONSTRAINT ck_vrtgc_hidden CHECK (hidden IN ");
2003     strcat (sql, "(0,1)))");
2004     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2005     if (ret != SQLITE_OK)
2006       {
2007 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2008 	  sqlite3_free (errMsg);
2009 	  return 0;
2010       }
2011 /* creating the VIRTS_GEOMETRY_COLUMNS_AUTH triggers */
2012     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgcau_virt_name_insert\n");
2013     strcat (sql, "BEFORE INSERT ON 'virts_geometry_columns_auth'\n");
2014     strcat (sql, "FOR EACH ROW BEGIN\n");
2015     strcat (sql,
2016 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_auth violates constraint: ");
2017     strcat (sql, "virt_name value must not contain a single quote')\n");
2018     strcat (sql, "WHERE NEW.virt_name LIKE ('%''%');\n");
2019     strcat (sql,
2020 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_auth violates constraint: ");
2021     strcat (sql, "virt_name value must not contain a double quote')\n");
2022     strcat (sql, "WHERE NEW.virt_name LIKE ('%\"%');\n");
2023     strcat (sql,
2024 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_auth violates constraint: \n");
2025     strcat (sql, "virt_name value must be lower case')\n");
2026     strcat (sql, "WHERE NEW.virt_name <> lower(NEW.virt_name);\n");
2027     strcat (sql, "END");
2028     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2029     if (ret != SQLITE_OK)
2030       {
2031 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2032 	  sqlite3_free (errMsg);
2033 	  return 0;
2034       }
2035     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgcau_virt_name_update\n");
2036     strcat (sql,
2037 	    "BEFORE UPDATE OF 'virt_name' ON 'virts_geometry_columns_auth'\n");
2038     strcat (sql, "FOR EACH ROW BEGIN\n");
2039     strcat (sql,
2040 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_auth violates constraint: ");
2041     strcat (sql, "virt_name value must not contain a single quote')\n");
2042     strcat (sql, "WHERE NEW.virt_name LIKE ('%''%');\n");
2043     strcat (sql,
2044 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_auth violates constraint: ");
2045     strcat (sql, "virt_name value must not contain a double quote')\n");
2046     strcat (sql, "WHERE NEW.virt_name LIKE ('%\"%');\n");
2047     strcat (sql,
2048 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_auth violates constraint: ");
2049     strcat (sql, "virt_name value must be lower case')\n");
2050     strcat (sql, "WHERE NEW.virt_name <> lower(NEW.virt_name);\n");
2051     strcat (sql, "END");
2052     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2053     if (ret != SQLITE_OK)
2054       {
2055 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2056 	  sqlite3_free (errMsg);
2057 	  return 0;
2058       }
2059     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgcau_virt_geometry_insert\n");
2060     strcat (sql, "BEFORE INSERT ON 'virts_geometry_columns_auth'\n");
2061     strcat (sql, "FOR EACH ROW BEGIN\n");
2062     strcat (sql,
2063 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_auth violates constraint: ");
2064     strcat (sql, "virt_geometry value must not contain a single quote')\n");
2065     strcat (sql, "WHERE NEW.virt_geometry LIKE ('%''%');\n");
2066     strcat (sql,
2067 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_auth violates constraint: \n");
2068     strcat (sql, "virt_geometry value must not contain a double quote')\n");
2069     strcat (sql, "WHERE NEW.virt_geometry LIKE ('%\"%');\n");
2070     strcat (sql,
2071 	    "SELECT RAISE(ABORT,'insert on virts_geometry_columns_auth violates constraint: ");
2072     strcat (sql, "virt_geometry value must be lower case')\n");
2073     strcat (sql, "WHERE NEW.virt_geometry <> lower(NEW.virt_geometry);\n");
2074     strcat (sql, "END");
2075     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2076     if (ret != SQLITE_OK)
2077       {
2078 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2079 	  sqlite3_free (errMsg);
2080 	  return 0;
2081       }
2082     strcpy (sql, "CREATE TRIGGER IF NOT EXISTS vtgcau_virt_geometry_update\n");
2083     strcat (sql,
2084 	    "BEFORE UPDATE OF 'virt_geometry' ON 'virts_geometry_columns_auth'\n");
2085     strcat (sql, "FOR EACH ROW BEGIN\n");
2086     strcat (sql,
2087 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_auth violates constraint: ");
2088     strcat (sql, "virt_geometry value must not contain a single quote')\n");
2089     strcat (sql, "WHERE NEW.virt_geometry LIKE ('%''%');\n");
2090     strcat (sql,
2091 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_auth violates constraint: \n");
2092     strcat (sql, "virt_geometry value must not contain a double quote')\n");
2093     strcat (sql, "WHERE NEW.virt_geometry LIKE ('%\"%');\n");
2094     strcat (sql,
2095 	    "SELECT RAISE(ABORT,'update on virts_geometry_columns_auth violates constraint: ");
2096     strcat (sql, "virt_geometry value must be lower case')\n");
2097     strcat (sql, "WHERE NEW.virt_geometry <> lower(NEW.virt_geometry);\n");
2098     strcat (sql, "END");
2099     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2100     if (ret != SQLITE_OK)
2101       {
2102 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2103 	  sqlite3_free (errMsg);
2104 	  return 0;
2105       }
2106     return 1;
2107 }
2108 
2109 static int
create_geometry_columns_views(sqlite3 * sqlite)2110 create_geometry_columns_views (sqlite3 * sqlite)
2111 {
2112     char sql[4186];
2113     char *errMsg = NULL;
2114     int ret;
2115 
2116     if (sqlite3_db_readonly (sqlite, "MAIN") == 1)
2117       {
2118 	  /* ignoring a read-only database */
2119 	  return 1;
2120       }
2121 
2122 /* creating the VECTOR_LAYERS view */
2123     strcpy (sql, "CREATE VIEW  IF NOT EXISTS ");
2124     strcat (sql, "vector_layers AS\n");
2125     strcat (sql, "SELECT 'SpatialTable' AS layer_type, ");
2126     strcat (sql, "f_table_name AS table_name, ");
2127     strcat (sql, "f_geometry_column AS geometry_column, ");
2128     strcat (sql, "geometry_type AS geometry_type, ");
2129     strcat (sql, "coord_dimension AS coord_dimension, ");
2130     strcat (sql, "srid AS srid, ");
2131     strcat (sql, "spatial_index_enabled AS spatial_index_enabled\n");
2132     strcat (sql, "FROM geometry_columns\n");
2133     strcat (sql, "UNION\n");
2134     strcat (sql, "SELECT 'SpatialView' AS layer_type, ");
2135     strcat (sql, "a.view_name AS table_name, ");
2136     strcat (sql, "a.view_geometry AS geometry_column, ");
2137     strcat (sql, "b.geometry_type AS geometry_type, ");
2138     strcat (sql, "b.coord_dimension AS coord_dimension, ");
2139     strcat (sql, "b.srid AS srid, ");
2140     strcat (sql, "b.spatial_index_enabled AS spatial_index_enabled\n");
2141     strcat (sql, "FROM views_geometry_columns AS a\n");
2142     strcat (sql, "LEFT JOIN geometry_columns AS b ON (");
2143     strcat (sql, "Upper(a.f_table_name) = Upper(b.f_table_name) AND ");
2144     strcat (sql, "Upper(a.f_geometry_column) = Upper(b.f_geometry_column))\n");
2145     strcat (sql, "UNION\n");
2146     strcat (sql, "SELECT 'VirtualShape' AS layer_type, ");
2147     strcat (sql, "virt_name AS table_name, ");
2148     strcat (sql, "virt_geometry AS geometry_column, ");
2149     strcat (sql, "geometry_type AS geometry_type, ");
2150     strcat (sql, "coord_dimension AS coord_dimension, ");
2151     strcat (sql, "srid AS srid, ");
2152     strcat (sql, "0 AS spatial_index_enabled\n");
2153     strcat (sql, "FROM virts_geometry_columns");
2154     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2155     if (ret != SQLITE_OK)
2156       {
2157 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2158 	  sqlite3_free (errMsg);
2159 	  return 0;
2160       }
2161 /* creating the VECTOR_LAYERS_AUTH view */
2162     strcpy (sql, "CREATE VIEW  IF NOT EXISTS ");
2163     strcat (sql, "vector_layers_auth AS\n");
2164     strcat (sql, "SELECT 'SpatialTable' AS layer_type, ");
2165     strcat (sql, "f_table_name AS table_name, ");
2166     strcat (sql, "f_geometry_column AS geometry_column, ");
2167     strcat (sql, "read_only AS read_only, ");
2168     strcat (sql, "hidden AS hidden\n");
2169     strcat (sql, "FROM geometry_columns_auth\n");
2170     strcat (sql, "UNION\n");
2171     strcat (sql, "SELECT 'SpatialView' AS layer_type, ");
2172     strcat (sql, "a.view_name AS table_name, ");
2173     strcat (sql, "a.view_geometry AS geometry_column, ");
2174     strcat (sql, "b.read_only AS read_only, ");
2175     strcat (sql, "a.hidden AS hidden\n");
2176     strcat (sql, "FROM views_geometry_columns_auth AS a\n");
2177     strcat (sql, "JOIN views_geometry_columns AS b ON (");
2178     strcat (sql, "Upper(a.view_name) = Upper(b.view_name) AND ");
2179     strcat (sql, "Upper(a.view_geometry) = Upper(b.view_geometry))\n");
2180     strcat (sql, "UNION\n");
2181     strcat (sql, "SELECT 'VirtualShape' AS layer_type, ");
2182     strcat (sql, "virt_name AS table_name, ");
2183     strcat (sql, "virt_geometry AS geometry_column, ");
2184     strcat (sql, "1 AS read_only, ");
2185     strcat (sql, "hidden AS hidden\n");
2186     strcat (sql, "FROM virts_geometry_columns_auth");
2187     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2188     if (ret != SQLITE_OK)
2189       {
2190 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2191 	  sqlite3_free (errMsg);
2192 	  return 0;
2193       }
2194 /* creating the VECTOR_LAYERS_STATISTICS view */
2195     strcpy (sql, "CREATE VIEW IF NOT EXISTS ");
2196     strcat (sql, "vector_layers_statistics AS\n");
2197     strcat (sql, "SELECT 'SpatialTable' AS layer_type, ");
2198     strcat (sql, "f_table_name AS table_name, ");
2199     strcat (sql, "f_geometry_column AS geometry_column, ");
2200     strcat (sql, "last_verified AS last_verified, ");
2201     strcat (sql, "row_count AS row_count, ");
2202     strcat (sql, "extent_min_x AS extent_min_x, ");
2203     strcat (sql, "extent_min_y AS extent_min_y, ");
2204     strcat (sql, "extent_max_x AS extent_max_x, ");
2205     strcat (sql, "extent_max_y AS extent_max_y\n");
2206     strcat (sql, "FROM geometry_columns_statistics\n");
2207     strcat (sql, "UNION\n");
2208     strcat (sql, "SELECT 'SpatialView' AS layer_type, ");
2209     strcat (sql, "view_name AS table_name, ");
2210     strcat (sql, "view_geometry AS geometry_column, ");
2211     strcat (sql, "last_verified AS last_verified, ");
2212     strcat (sql, "row_count AS row_count, ");
2213     strcat (sql, "extent_min_x AS extent_min_x, ");
2214     strcat (sql, "extent_min_y AS extent_min_y, ");
2215     strcat (sql, "extent_max_x AS extent_max_x, ");
2216     strcat (sql, "extent_max_y AS extent_max_y\n");
2217     strcat (sql, "FROM views_geometry_columns_statistics\n");
2218     strcat (sql, "UNION\n");
2219     strcat (sql, "SELECT 'VirtualShape' AS layer_type, ");
2220     strcat (sql, "virt_name AS table_name, ");
2221     strcat (sql, "virt_geometry AS geometry_column, ");
2222     strcat (sql, "last_verified AS last_verified, ");
2223     strcat (sql, "row_count AS row_count, ");
2224     strcat (sql, "extent_min_x AS extent_min_x, ");
2225     strcat (sql, "extent_min_y AS extent_min_y, ");
2226     strcat (sql, "extent_max_x AS extent_max_x, ");
2227     strcat (sql, "extent_max_y AS extent_max_y\n");
2228     strcat (sql, "FROM virts_geometry_columns_statistics");
2229     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2230     if (ret != SQLITE_OK)
2231       {
2232 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2233 	  sqlite3_free (errMsg);
2234 	  return 0;
2235       }
2236 /* creating the VECTOR_LAYERS_FIELD_INFOS view */
2237     strcpy (sql, "CREATE VIEW IF NOT EXISTS ");
2238     strcat (sql, "vector_layers_field_infos AS\n");
2239     strcat (sql, "SELECT 'SpatialTable' AS layer_type, ");
2240     strcat (sql, "f_table_name AS table_name, ");
2241     strcat (sql, "f_geometry_column AS geometry_column, ");
2242     strcat (sql, "ordinal AS ordinal, ");
2243     strcat (sql, "column_name AS column_name, ");
2244     strcat (sql, "null_values AS null_values, ");
2245     strcat (sql, "integer_values AS integer_values, ");
2246     strcat (sql, "double_values AS double_values, ");
2247     strcat (sql, "text_values AS text_values, ");
2248     strcat (sql, "blob_values AS blob_values, ");
2249     strcat (sql, "max_size AS max_size, ");
2250     strcat (sql, "integer_min AS integer_min, ");
2251     strcat (sql, "integer_max AS integer_max, ");
2252     strcat (sql, "double_min AS double_min, ");
2253     strcat (sql, "double_max double_max\n");
2254     strcat (sql, "FROM geometry_columns_field_infos\n");
2255     strcat (sql, "UNION\n");
2256     strcat (sql, "SELECT 'SpatialView' AS layer_type, ");
2257     strcat (sql, "view_name AS table_name, ");
2258     strcat (sql, "view_geometry AS geometry_column, ");
2259     strcat (sql, "ordinal AS ordinal, ");
2260     strcat (sql, "column_name AS column_name, ");
2261     strcat (sql, "null_values AS null_values, ");
2262     strcat (sql, "integer_values AS integer_values, ");
2263     strcat (sql, "double_values AS double_values, ");
2264     strcat (sql, "text_values AS text_values, ");
2265     strcat (sql, "blob_values AS blob_values, ");
2266     strcat (sql, "max_size AS max_size, ");
2267     strcat (sql, "integer_min AS integer_min, ");
2268     strcat (sql, "integer_max AS integer_max, ");
2269     strcat (sql, "double_min AS double_min, ");
2270     strcat (sql, "double_max double_max\n");
2271     strcat (sql, "FROM views_geometry_columns_field_infos\n");
2272     strcat (sql, "UNION\n");
2273     strcat (sql, "SELECT 'VirtualShape' AS layer_type, ");
2274     strcat (sql, "virt_name AS table_name, ");
2275     strcat (sql, "virt_geometry AS geometry_column, ");
2276     strcat (sql, "ordinal AS ordinal, ");
2277     strcat (sql, "column_name AS column_name, ");
2278     strcat (sql, "null_values AS null_values, ");
2279     strcat (sql, "integer_values AS integer_values, ");
2280     strcat (sql, "double_values AS double_values, ");
2281     strcat (sql, "text_values AS text_values, ");
2282     strcat (sql, "blob_values AS blob_values, ");
2283     strcat (sql, "max_size AS max_size, ");
2284     strcat (sql, "integer_min AS integer_min, ");
2285     strcat (sql, "integer_max AS integer_max, ");
2286     strcat (sql, "double_min AS double_min, ");
2287     strcat (sql, "double_max double_max\n");
2288     strcat (sql, "FROM virts_geometry_columns_field_infos");
2289     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2290     if (ret != SQLITE_OK)
2291       {
2292 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2293 	  sqlite3_free (errMsg);
2294 	  return 0;
2295       }
2296     return 1;
2297 }
2298 
2299 SPATIALITE_PRIVATE int
create_data_licenses(sqlite3 * sqlite)2300 create_data_licenses (sqlite3 * sqlite)
2301 {
2302     char sql[4186];
2303     char *errMsg = NULL;
2304     int ret;
2305 
2306     if (sqlite3_db_readonly (sqlite, "MAIN") == 1)
2307       {
2308 	  /* ignoring a read-only database */
2309 	  return 1;
2310       }
2311 
2312 /* creating the DATA_LICENSES table */
2313     strcpy (sql, "CREATE TABLE IF NOT EXISTS data_licenses (\n");
2314     strcat (sql, "\tid INTEGER PRIMARY KEY AUTOINCREMENT,\n");
2315     strcat (sql, "\tname TEXT NOT NULL UNIQUE,\n");
2316     strcat (sql, "\turl TEXT)");
2317     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2318     if (ret != SQLITE_OK)
2319       {
2320 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2321 	  sqlite3_free (errMsg);
2322 	  return 0;
2323       }
2324 /* inserting the UNDEFINED license */
2325     strcpy (sql, "INSERT OR IGNORE INTO data_licenses (id, name, url) ");
2326     strcat (sql, "VALUES (0, 'Undefined', NULL)");
2327     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2328     if (ret != SQLITE_OK)
2329       {
2330 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2331 	  sqlite3_free (errMsg);
2332 	  return 0;
2333       }
2334 /* inserting the PROPRIETARY license */
2335     strcpy (sql, "INSERT OR IGNORE INTO data_licenses (id, name, url) ");
2336     strcat (sql, "VALUES (1, 'Proprietary - Non Free', NULL)");
2337     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2338     if (ret != SQLITE_OK)
2339       {
2340 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2341 	  sqlite3_free (errMsg);
2342 	  return 0;
2343       }
2344 /* inserting the PUBLIC DOMAIN license */
2345     strcpy (sql, "INSERT OR IGNORE INTO data_licenses (id, name, url) ");
2346     strcat (sql, "VALUES (2, 'PD - Public Domain', NULL)");
2347     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2348     if (ret != SQLITE_OK)
2349       {
2350 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2351 	  sqlite3_free (errMsg);
2352 	  return 0;
2353       }
2354 /* inserting the CC0 1.0 license */
2355     strcpy (sql, "INSERT OR IGNORE INTO data_licenses (id, name, url) ");
2356     strcat (sql,
2357 	    "VALUES (3, 'CC0 1.0', 'https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt')");
2358     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2359     if (ret != SQLITE_OK)
2360       {
2361 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2362 	  sqlite3_free (errMsg);
2363 	  return 0;
2364       }
2365 /* inserting the CC BY 3.0 license */
2366     strcpy (sql, "INSERT OR IGNORE INTO data_licenses (id, name, url) ");
2367     strcat (sql,
2368 	    "VALUES (4, 'CC BY 3.0', 'https://creativecommons.org/licenses/by/3.0/legalcode.txt')");
2369     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2370     if (ret != SQLITE_OK)
2371       {
2372 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2373 	  sqlite3_free (errMsg);
2374 	  return 0;
2375       }
2376 /* inserting the CC BY 4.0 license */
2377     strcpy (sql, "INSERT OR IGNORE INTO data_licenses (id, name, url) ");
2378     strcat (sql,
2379 	    "VALUES (5, 'CC BY 4.0', 'https://creativecommons.org/licenses/by/4.0/legalcode.txt')");
2380     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2381     if (ret != SQLITE_OK)
2382       {
2383 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2384 	  sqlite3_free (errMsg);
2385 	  return 0;
2386       }
2387 /* inserting the CC BY-SA 3.0 license */
2388     strcpy (sql, "INSERT OR IGNORE INTO data_licenses (id, name, url) ");
2389     strcat (sql,
2390 	    "VALUES (6, 'CC BY-SA 3.0', 'https://creativecommons.org/licenses/by-sa/3.0/legalcode.txt')");
2391     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2392     if (ret != SQLITE_OK)
2393       {
2394 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2395 	  sqlite3_free (errMsg);
2396 	  return 0;
2397       }
2398 /* inserting the CC BY-SA 4.0 license */
2399     strcpy (sql, "INSERT OR IGNORE INTO data_licenses (id, name, url) ");
2400     strcat (sql,
2401 	    "VALUES (7, 'CC BY-SA 4.0', 'https://creativecommons.org/licenses/by-sa/4.0/legalcode.txt')");
2402     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2403     if (ret != SQLITE_OK)
2404       {
2405 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2406 	  sqlite3_free (errMsg);
2407 	  return 0;
2408       }
2409 /* inserting the CC BY-SA-NC 3.0 license */
2410     strcpy (sql, "INSERT OR IGNORE INTO data_licenses (id, name, url) ");
2411     strcat (sql,
2412 	    "VALUES (8, 'CC BY-SA-NC 3.0', 'https://creativecommons.org/licenses/by-nc-sa/3.0/legalcode.txt')");
2413     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2414     if (ret != SQLITE_OK)
2415       {
2416 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2417 	  sqlite3_free (errMsg);
2418 	  return 0;
2419       }
2420 /* inserting the CC BY-SA-NC 4.0 license */
2421     strcpy (sql, "INSERT OR IGNORE INTO data_licenses (id, name, url) ");
2422     strcat (sql,
2423 	    "VALUES (9, 'CC BY-SA-NC 4.0', 'https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode.txt')");
2424     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2425     if (ret != SQLITE_OK)
2426       {
2427 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2428 	  sqlite3_free (errMsg);
2429 	  return 0;
2430       }
2431     return 1;
2432 }
2433 
2434 SPATIALITE_PRIVATE int
check_layer_statistics(void * p_sqlite)2435 check_layer_statistics (void *p_sqlite)
2436 {
2437 /*
2438 / checks the LAYER_STATISTICS table for validity;
2439 / if the table doesn't exist, attempts to create
2440 */
2441     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
2442     char sql[8192];
2443     char **results;
2444     int rows;
2445     int columns;
2446     int ret;
2447     int raster_layer = 0;
2448     int table_name = 0;
2449     int geometry_column = 0;
2450     int row_count = 0;
2451     int extent_min_x = 0;
2452     int extent_min_y = 0;
2453     int extent_max_x = 0;
2454     int extent_max_y = 0;
2455     int i;
2456     const char *name;
2457     int has_pk = 0;
2458 
2459 /* checking the LAYER_STATISTICS table */
2460     ret =
2461 	sqlite3_get_table (sqlite, "PRAGMA table_info(layer_statistics)",
2462 			   &results, &rows, &columns, NULL);
2463     if (ret != SQLITE_OK)
2464 	return 0;
2465     if (rows < 1)
2466 	;
2467     else
2468       {
2469 	  for (i = 1; i <= rows; i++)
2470 	    {
2471 		name = results[(i * columns) + 1];
2472 		if (strcasecmp (name, "raster_layer") == 0)
2473 		    raster_layer = 1;
2474 		if (strcasecmp (name, "table_name") == 0)
2475 		    table_name = 1;
2476 		if (strcasecmp (name, "geometry_column") == 0)
2477 		    geometry_column = 1;
2478 		if (strcasecmp (name, "row_count") == 0)
2479 		    row_count = 1;
2480 		if (strcasecmp (name, "extent_min_x") == 0)
2481 		    extent_min_x = 1;
2482 		if (strcasecmp (name, "extent_min_y") == 0)
2483 		    extent_min_y = 1;
2484 		if (strcasecmp (name, "extent_max_x") == 0)
2485 		    extent_max_x = 1;
2486 		if (strcasecmp (name, "extent_max_y") == 0)
2487 		    extent_max_y = 1;
2488 	    }
2489       }
2490     sqlite3_free_table (results);
2491 
2492 /* LAYER_STATISTICS already exists and has a valid layout */
2493     if (raster_layer && table_name && geometry_column && row_count
2494 	&& extent_min_x && extent_max_x && extent_min_y && extent_max_y)
2495 	return 1;
2496 /* LAYER_STATISTICS already exists, but has an invalid layout */
2497     if (raster_layer || table_name || geometry_column || row_count
2498 	|| extent_min_x || extent_max_x || extent_min_y || extent_max_y)
2499 	return 0;
2500 
2501 /* checking if GEOMETRY_COLUMNS has a Primary Key */
2502     ret =
2503 	sqlite3_get_table (sqlite, "PRAGMA table_info(geometry_columns)",
2504 			   &results, &rows, &columns, NULL);
2505     if (ret != SQLITE_OK)
2506 	return 0;
2507     if (rows < 1)
2508 	;
2509     else
2510       {
2511 	  for (i = 1; i <= rows; i++)
2512 	    {
2513 		name = results[(i * columns) + 5];
2514 		if (atoi (name) != 0)
2515 		    has_pk = 1;
2516 	    }
2517       }
2518     sqlite3_free_table (results);
2519 
2520 /* attempting to create LAYER_STATISTICS */
2521     if (has_pk)
2522       {
2523 	  /* GEOMETRY_COLUMNS has a Primary Key */
2524 	  strcpy (sql, "CREATE TABLE layer_statistics (\n");
2525 	  strcat (sql, "raster_layer INTEGER NOT NULL,\n");
2526 	  strcat (sql, "table_name TEXT NOT NULL,\n");
2527 	  strcat (sql, "geometry_column TEXT NOT NULL,\n");
2528 	  strcat (sql, "row_count INTEGER,\n");
2529 	  strcat (sql, "extent_min_x DOUBLE,\n");
2530 	  strcat (sql, "extent_min_y DOUBLE,\n");
2531 	  strcat (sql, "extent_max_x DOUBLE,\n");
2532 	  strcat (sql, "extent_max_y DOUBLE,\n");
2533 	  strcat (sql, "CONSTRAINT pk_layer_statistics PRIMARY KEY ");
2534 	  strcat (sql, "(raster_layer, table_name, geometry_column),\n");
2535 	  strcat (sql, "CONSTRAINT fk_layer_statistics FOREIGN KEY ");
2536 	  strcat (sql, "(table_name, geometry_column) REFERENCES ");
2537 	  strcat (sql, "geometry_columns (f_table_name, f_geometry_column) ");
2538 	  strcat (sql, "ON DELETE CASCADE)");
2539       }
2540     else
2541       {
2542 	  /* there is no Primary Key on GEOMETRY_COLUMNS */
2543 	  strcpy (sql, "CREATE TABLE layer_statistics (\n");
2544 	  strcat (sql, "raster_layer INTEGER NOT NULL,\n");
2545 	  strcat (sql, "table_name TEXT NOT NULL,\n");
2546 	  strcat (sql, "geometry_column TEXT NOT NULL,\n");
2547 	  strcat (sql, "row_count INTEGER,\n");
2548 	  strcat (sql, "extent_min_x DOUBLE,\n");
2549 	  strcat (sql, "extent_min_y DOUBLE,\n");
2550 	  strcat (sql, "extent_max_x DOUBLE,\n");
2551 	  strcat (sql, "extent_max_y DOUBLE,\n");
2552 	  strcat (sql, "CONSTRAINT pk_layer_statistics PRIMARY KEY ");
2553 	  strcat (sql, "(raster_layer, table_name, geometry_column))");
2554       }
2555     ret = sqlite3_exec (sqlite, sql, NULL, NULL, NULL);
2556     if (ret != SQLITE_OK)
2557 	return 0;
2558     return 1;
2559 }
2560 
2561 SPATIALITE_PRIVATE int
check_views_layer_statistics(void * p_sqlite)2562 check_views_layer_statistics (void *p_sqlite)
2563 {
2564 /*
2565 / checks the VIEWS_LAYER_STATISTICS table for validity;
2566 / if the table doesn't exist, attempts to create
2567 */
2568     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
2569     char sql[8192];
2570     char **results;
2571     int rows;
2572     int columns;
2573     int ret;
2574     int view_name = 0;
2575     int view_geometry = 0;
2576     int row_count = 0;
2577     int extent_min_x = 0;
2578     int extent_min_y = 0;
2579     int extent_max_x = 0;
2580     int extent_max_y = 0;
2581     int i;
2582     const char *name;
2583 
2584 /* checking the VIEWS_LAYER_STATISTICS table */
2585     ret =
2586 	sqlite3_get_table (sqlite, "PRAGMA table_info(views_layer_statistics)",
2587 			   &results, &rows, &columns, NULL);
2588     if (ret != SQLITE_OK)
2589 	return 0;
2590     if (rows < 1)
2591 	;
2592     else
2593       {
2594 	  for (i = 1; i <= rows; i++)
2595 	    {
2596 		name = results[(i * columns) + 1];
2597 		if (strcasecmp (name, "view_name") == 0)
2598 		    view_name = 1;
2599 		if (strcasecmp (name, "view_geometry") == 0)
2600 		    view_geometry = 1;
2601 		if (strcasecmp (name, "row_count") == 0)
2602 		    row_count = 1;
2603 		if (strcasecmp (name, "extent_min_x") == 0)
2604 		    extent_min_x = 1;
2605 		if (strcasecmp (name, "extent_min_y") == 0)
2606 		    extent_min_y = 1;
2607 		if (strcasecmp (name, "extent_max_x") == 0)
2608 		    extent_max_x = 1;
2609 		if (strcasecmp (name, "extent_max_y") == 0)
2610 		    extent_max_y = 1;
2611 	    }
2612       }
2613     sqlite3_free_table (results);
2614 
2615 /* VIEWS_LAYER_STATISTICS already exists and has a valid layout */
2616     if (view_name && view_geometry && row_count && extent_min_x && extent_max_x
2617 	&& extent_min_y && extent_max_y)
2618 	return 1;
2619 /* VIEWS_LAYER_STATISTICS already exists, but has an invalid layout */
2620     if (view_name || view_geometry || row_count || extent_min_x || extent_max_x
2621 	|| extent_min_y || extent_max_y)
2622 	return 0;
2623 
2624 /* attempting to create VIEWS_LAYER_STATISTICS */
2625     strcpy (sql, "CREATE TABLE views_layer_statistics (\n");
2626     strcat (sql, "view_name TEXT NOT NULL,\n");
2627     strcat (sql, "view_geometry TEXT NOT NULL,\n");
2628     strcat (sql, "row_count INTEGER,\n");
2629     strcat (sql, "extent_min_x DOUBLE,\n");
2630     strcat (sql, "extent_min_y DOUBLE,\n");
2631     strcat (sql, "extent_max_x DOUBLE,\n");
2632     strcat (sql, "extent_max_y DOUBLE,\n");
2633     strcat (sql, "CONSTRAINT pk_views_layer_statistics PRIMARY KEY ");
2634     strcat (sql, "(view_name, view_geometry),\n");
2635     strcat (sql, "CONSTRAINT fk_views_layer_statistics FOREIGN KEY ");
2636     strcat (sql, "(view_name, view_geometry) REFERENCES ");
2637     strcat (sql, "views_geometry_columns (view_name, view_geometry) ");
2638     strcat (sql, "ON DELETE CASCADE)");
2639     ret = sqlite3_exec (sqlite, sql, NULL, NULL, NULL);
2640     if (ret != SQLITE_OK)
2641 	return 0;
2642     return 1;
2643 }
2644 
2645 SPATIALITE_PRIVATE int
check_virts_layer_statistics(void * p_sqlite)2646 check_virts_layer_statistics (void *p_sqlite)
2647 {
2648 /*
2649 / checks the VIRTS_LAYER_STATISTICS table for validity;
2650 / if the table doesn't exist, attempts to create
2651 */
2652     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
2653     char sql[8192];
2654     char **results;
2655     int rows;
2656     int columns;
2657     int ret;
2658     int virt_name = 0;
2659     int virt_geometry = 0;
2660     int row_count = 0;
2661     int extent_min_x = 0;
2662     int extent_min_y = 0;
2663     int extent_max_x = 0;
2664     int extent_max_y = 0;
2665     int i;
2666     const char *name;
2667 
2668 /* checking the VIRTS_LAYER_STATISTICS table */
2669     ret =
2670 	sqlite3_get_table (sqlite, "PRAGMA table_info(virts_layer_statistics)",
2671 			   &results, &rows, &columns, NULL);
2672     if (ret != SQLITE_OK)
2673 	return 0;
2674     if (rows < 1)
2675 	;
2676     else
2677       {
2678 	  for (i = 1; i <= rows; i++)
2679 	    {
2680 		name = results[(i * columns) + 1];
2681 		if (strcasecmp (name, "virt_name") == 0)
2682 		    virt_name = 1;
2683 		if (strcasecmp (name, "virt_geometry") == 0)
2684 		    virt_geometry = 1;
2685 		if (strcasecmp (name, "row_count") == 0)
2686 		    row_count = 1;
2687 		if (strcasecmp (name, "extent_min_x") == 0)
2688 		    extent_min_x = 1;
2689 		if (strcasecmp (name, "extent_min_y") == 0)
2690 		    extent_min_y = 1;
2691 		if (strcasecmp (name, "extent_max_x") == 0)
2692 		    extent_max_x = 1;
2693 		if (strcasecmp (name, "extent_max_y") == 0)
2694 		    extent_max_y = 1;
2695 	    }
2696       }
2697     sqlite3_free_table (results);
2698 
2699 /* VIRTS_LAYER_STATISTICS already exists and has a valid layout */
2700     if (virt_name && virt_geometry && row_count && extent_min_x && extent_max_x
2701 	&& extent_min_y && extent_max_y)
2702 	return 1;
2703 /* VIRTS_LAYER_STATISTICS already exists, but has an invalid layout */
2704     if (virt_name || virt_geometry || row_count || extent_min_x || extent_max_x
2705 	|| extent_min_y || extent_max_y)
2706 	return 0;
2707 
2708 /* attempting to create VIRTS_LAYER_STATISTICS */
2709     strcpy (sql, "CREATE TABLE virts_layer_statistics (\n");
2710     strcat (sql, "virt_name TEXT NOT NULL,\n");
2711     strcat (sql, "virt_geometry TEXT NOT NULL,\n");
2712     strcat (sql, "row_count INTEGER,\n");
2713     strcat (sql, "extent_min_x DOUBLE,\n");
2714     strcat (sql, "extent_min_y DOUBLE,\n");
2715     strcat (sql, "extent_max_x DOUBLE,\n");
2716     strcat (sql, "extent_max_y DOUBLE,\n");
2717     strcat (sql, "CONSTRAINT pk_virts_layer_statistics PRIMARY KEY ");
2718     strcat (sql, "(virt_name, virt_geometry),\n");
2719     strcat (sql, "CONSTRAINT fk_virts_layer_statistics FOREIGN KEY ");
2720     strcat (sql, "(virt_name, virt_geometry) REFERENCES ");
2721     strcat (sql, "virts_geometry_columns (virt_name, virt_geometry) ");
2722     strcat (sql, "ON DELETE CASCADE)");
2723     ret = sqlite3_exec (sqlite, sql, NULL, NULL, NULL);
2724     if (ret != SQLITE_OK)
2725 	return 0;
2726     return 1;
2727 }
2728 
2729 static int
create_sql_statements_log(sqlite3 * sqlite)2730 create_sql_statements_log (sqlite3 * sqlite)
2731 {
2732     char sql[4186];
2733     char *errMsg = NULL;
2734     int ret;
2735 /* creating the SQL_STATEMENTS_LOG table */
2736     strcpy (sql, "CREATE TABLE  IF NOT EXISTS ");
2737     strcat (sql, "sql_statements_log (\n");
2738     strcat (sql, "id INTEGER PRIMARY KEY AUTOINCREMENT,\n");
2739     strcat (sql,
2740 	    "time_start TIMESTAMP NOT NULL DEFAULT '0000-01-01T00:00:00.000Z',\n");
2741     strcat (sql,
2742 	    "time_end TIMESTAMP NOT NULL DEFAULT '0000-01-01T00:00:00.000Z',\n");
2743     strcat (sql, "user_agent TEXT NOT NULL,\n");
2744     strcat (sql, "sql_statement TEXT NOT NULL,\n");
2745     strcat (sql, "success INTEGER NOT NULL DEFAULT 0,\n");
2746     strcat (sql, "error_cause TEXT NOT NULL DEFAULT 'ABORTED',\n");
2747     strcat (sql, "CONSTRAINT sqllog_success CHECK ");
2748     strcat (sql, "(success IN (0,1)))");
2749     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2750     if (ret != SQLITE_OK)
2751       {
2752 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2753 	  sqlite3_free (errMsg);
2754 	  return 0;
2755       }
2756     return 1;
2757 }
2758 
2759 SPATIALITE_PRIVATE int
createAdvancedMetaData(void * p_sqlite)2760 createAdvancedMetaData (void *p_sqlite)
2761 {
2762 /* creating the advanced MetaData tables */
2763     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
2764     if (!create_views_geometry_columns (sqlite))
2765 	return 0;
2766     if (!create_virts_geometry_columns (sqlite))
2767 	return 0;
2768     if (!create_geometry_columns_statistics (sqlite))
2769 	return 0;
2770     if (!create_views_geometry_columns_statistics (sqlite))
2771 	return 0;
2772     if (!create_virts_geometry_columns_statistics (sqlite))
2773 	return 0;
2774     if (!create_geometry_columns_field_infos (sqlite))
2775 	return 0;
2776     if (!create_views_geometry_columns_field_infos (sqlite))
2777 	return 0;
2778     if (!create_virts_geometry_columns_field_infos (sqlite))
2779 	return 0;
2780     if (!create_geometry_columns_time (sqlite))
2781 	return 0;
2782     if (!create_geometry_columns_auth (sqlite))
2783 	return 0;
2784     if (!create_views_geometry_columns_auth (sqlite))
2785 	return 0;
2786     if (!create_virts_geometry_columns_auth (sqlite))
2787 	return 0;
2788     if (!create_geometry_columns_views (sqlite))
2789 	return 0;
2790     if (!create_data_licenses (sqlite))
2791 	return 0;
2792     if (!create_sql_statements_log (sqlite))
2793 	return 0;
2794 
2795     return 1;
2796 }
2797 
2798 SPATIALITE_PRIVATE int
createGeometryColumns(void * p_sqlite)2799 createGeometryColumns (void *p_sqlite)
2800 {
2801     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
2802     char sql[4186];
2803     char *errMsg = NULL;
2804     int ret;
2805 /* creating the GEOMETRY_COLUMNS table */
2806     strcpy (sql, "CREATE TABLE geometry_columns (\n");
2807     strcat (sql, "f_table_name TEXT NOT NULL,\n");
2808     strcat (sql, "f_geometry_column TEXT NOT NULL,\n");
2809     strcat (sql, "geometry_type INTEGER NOT NULL,\n");
2810     strcat (sql, "coord_dimension INTEGER NOT NULL,\n");
2811     strcat (sql, "srid INTEGER NOT NULL,\n");
2812     strcat (sql, "spatial_index_enabled INTEGER NOT NULL,\n");
2813     strcat (sql, "CONSTRAINT pk_geom_cols PRIMARY KEY ");
2814     strcat (sql, "(f_table_name, f_geometry_column),\n");
2815     strcat (sql, "CONSTRAINT fk_gc_srs FOREIGN KEY ");
2816     strcat (sql, "(srid) REFERENCES spatial_ref_sys (srid),\n");
2817     strcat (sql, "CONSTRAINT ck_gc_rtree CHECK ");
2818     strcat (sql, "(spatial_index_enabled IN (0,1,2)))");
2819     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2820     if (ret != SQLITE_OK)
2821       {
2822 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2823 	  sqlite3_free (errMsg);
2824 	  return 0;
2825       }
2826     updateSpatiaLiteHistory (sqlite, "geometry_columns", NULL,
2827 			     "table successfully created");
2828 /* creating an INDEX corresponding to the SRID FK */
2829     strcpy (sql, "CREATE INDEX idx_srid_geocols ON geometry_columns\n");
2830     strcat (sql, "(srid) ");
2831     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2832     if (ret != SQLITE_OK)
2833       {
2834 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2835 	  sqlite3_free (errMsg);
2836 	  return 0;
2837       }
2838 /* creating the GEOMETRY_COLUMNS triggers */
2839     strcpy (sql, "CREATE TRIGGER geometry_columns_f_table_name_insert\n");
2840     strcat (sql, "BEFORE INSERT ON 'geometry_columns'\n");
2841     strcat (sql, "FOR EACH ROW BEGIN\n");
2842     strcat (sql,
2843 	    "SELECT RAISE(ABORT,'insert on geometry_columns violates constraint: ");
2844     strcat (sql, "f_table_name value must not contain a single quote')\n");
2845     strcat (sql, "WHERE NEW.f_table_name LIKE ('%''%');\n");
2846     strcat (sql,
2847 	    "SELECT RAISE(ABORT,'insert on geometry_columns violates constraint: ");
2848     strcat (sql, "f_table_name value must not contain a double quote')\n");
2849     strcat (sql, "WHERE NEW.f_table_name LIKE ('%\"%');\n");
2850     strcat (sql,
2851 	    "SELECT RAISE(ABORT,'insert on geometry_columns violates constraint: \n");
2852     strcat (sql, "f_table_name value must be lower case')\n");
2853     strcat (sql, "WHERE NEW.f_table_name <> lower(NEW.f_table_name);\n");
2854     strcat (sql, "END");
2855     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2856     if (ret != SQLITE_OK)
2857       {
2858 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2859 	  sqlite3_free (errMsg);
2860 	  return 0;
2861       }
2862     updateSpatiaLiteHistory (sqlite, "geometry_columns", NULL,
2863 			     "trigger 'geometry_columns_f_table_name_insert' successfully created");
2864     strcpy (sql, "CREATE TRIGGER geometry_columns_f_table_name_update\n");
2865     strcat (sql, "BEFORE UPDATE OF 'f_table_name' ON 'geometry_columns'\n");
2866     strcat (sql, "FOR EACH ROW BEGIN\n");
2867     strcat (sql,
2868 	    "SELECT RAISE(ABORT,'update on geometry_columns violates constraint: ");
2869     strcat (sql, "f_table_name value must not contain a single quote')\n");
2870     strcat (sql, "WHERE NEW.f_table_name LIKE ('%''%');\n");
2871     strcat (sql,
2872 	    "SELECT RAISE(ABORT,'update on geometry_columns violates constraint: ");
2873     strcat (sql, "f_table_name value must not contain a double quote')\n");
2874     strcat (sql, "WHERE NEW.f_table_name LIKE ('%\"%');\n");
2875     strcat (sql,
2876 	    "SELECT RAISE(ABORT,'update on geometry_columns violates constraint: ");
2877     strcat (sql, "f_table_name value must be lower case')\n");
2878     strcat (sql, "WHERE NEW.f_table_name <> lower(NEW.f_table_name);\n");
2879     strcat (sql, "END");
2880     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2881     if (ret != SQLITE_OK)
2882       {
2883 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2884 	  sqlite3_free (errMsg);
2885 	  return 0;
2886       }
2887     updateSpatiaLiteHistory (sqlite, "geometry_columns", NULL,
2888 			     "trigger 'geometry_columns_f_table_name_update' successfully created");
2889     strcpy (sql, "CREATE TRIGGER geometry_columns_f_geometry_column_insert\n");
2890     strcat (sql, "BEFORE INSERT ON 'geometry_columns'\n");
2891     strcat (sql, "FOR EACH ROW BEGIN\n");
2892     strcat (sql,
2893 	    "SELECT RAISE(ABORT,'insert on geometry_columns violates constraint: ");
2894     strcat (sql, "f_geometry_column value must not contain a single quote')\n");
2895     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%''%');\n");
2896     strcat (sql,
2897 	    "SELECT RAISE(ABORT,'insert on geometry_columns violates constraint: \n");
2898     strcat (sql, "f_geometry_column value must not contain a double quote')\n");
2899     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%\"%');\n");
2900     strcat (sql,
2901 	    "SELECT RAISE(ABORT,'insert on geometry_columns violates constraint: ");
2902     strcat (sql, "f_geometry_column value must be lower case')\n");
2903     strcat (sql,
2904 	    "WHERE NEW.f_geometry_column <> lower(NEW.f_geometry_column);\n");
2905     strcat (sql, "END");
2906     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2907     if (ret != SQLITE_OK)
2908       {
2909 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2910 	  sqlite3_free (errMsg);
2911 	  return 0;
2912       }
2913     updateSpatiaLiteHistory (sqlite, "geometry_columns", NULL,
2914 			     "trigger 'geometry_columns_f_geometry_column_insert' successfully created");
2915     strcpy (sql, "CREATE TRIGGER geometry_columns_f_geometry_column_update\n");
2916     strcat (sql,
2917 	    "BEFORE UPDATE OF 'f_geometry_column' ON 'geometry_columns'\n");
2918     strcat (sql, "FOR EACH ROW BEGIN\n");
2919     strcat (sql,
2920 	    "SELECT RAISE(ABORT,'update on geometry_columns violates constraint: ");
2921     strcat (sql, "f_geometry_column value must not contain a single quote')\n");
2922     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%''%');\n");
2923     strcat (sql,
2924 	    "SELECT RAISE(ABORT,'update on geometry_columns violates constraint: ");
2925     strcat (sql, "f_geometry_column value must not contain a double quote')\n");
2926     strcat (sql, "WHERE NEW.f_geometry_column LIKE ('%\"%');\n");
2927     strcat (sql,
2928 	    "SELECT RAISE(ABORT,'update on geometry_columns violates constraint: ");
2929     strcat (sql, "f_geometry_column value must be lower case')\n");
2930     strcat (sql,
2931 	    "WHERE NEW.f_geometry_column <> lower(NEW.f_geometry_column);\n");
2932     strcat (sql, "END");
2933     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2934     if (ret != SQLITE_OK)
2935       {
2936 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2937 	  sqlite3_free (errMsg);
2938 	  return 0;
2939       }
2940     updateSpatiaLiteHistory (sqlite, "geometry_columns", NULL,
2941 			     "trigger 'geometry_columns_f_geometry_column_update' successfully created");
2942     strcpy (sql, "CREATE TRIGGER geometry_columns_geometry_type_insert\n");
2943     strcat (sql, "BEFORE INSERT ON 'geometry_columns'\n");
2944     strcat (sql, "FOR EACH ROW BEGIN\n");
2945     strcat (sql, "SELECT RAISE(ABORT,'geometry_type must be one of ");
2946     strcat (sql, "0,1,2,3,4,5,6,7,");
2947     strcat (sql, "1000,1001,1002,1003,1004,1005,1006,1007,");
2948     strcat (sql, "2000,2001,2002,2003,2004,2005,2006,2007,");
2949     strcat (sql, "3000,3001,3002,3003,3004,3005,3006,3007')\n");
2950     strcat (sql, "WHERE NOT(NEW.geometry_type IN (0,1,2,3,4,5,6,7,");
2951     strcat (sql, "1000,1001,1002,1003,1004,1005,1006,1007,");
2952     strcat (sql, "2000,2001,2002,2003,2004,2005,2006,2007,");
2953     strcat (sql, "3000,3001,3002,3003,3004,3005,3006,3007));\n");
2954     strcat (sql, "END");
2955     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2956     if (ret != SQLITE_OK)
2957       {
2958 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2959 	  sqlite3_free (errMsg);
2960 	  return 0;
2961       }
2962     updateSpatiaLiteHistory (sqlite, "geometry_columns", NULL,
2963 			     "trigger 'geometry_columns_geometry_type_insert' successfully created");
2964     strcpy (sql, "CREATE TRIGGER geometry_columns_geometry_type_update\n");
2965     strcat (sql, "BEFORE UPDATE OF 'geometry_type' ON 'geometry_columns'\n");
2966     strcat (sql, "FOR EACH ROW BEGIN\n");
2967     strcat (sql, "SELECT RAISE(ABORT,'geometry_type must be one of ");
2968     strcat (sql, "0,1,2,3,4,5,6,7,");
2969     strcat (sql, "1000,1001,1002,1003,1004,1005,1006,1007,");
2970     strcat (sql, "2000,2001,2002,2003,2004,2005,2006,2007,");
2971     strcat (sql, "3000,3001,3002,3003,3004,3005,3006,3007')\n");
2972     strcat (sql, "WHERE NOT(NEW.geometry_type IN (0,1,2,3,4,5,6,7,");
2973     strcat (sql, "1000,1001,1002,1003,1004,1005,1006,1007,");
2974     strcat (sql, "2000,2001,2002,2003,2004,2005,2006,2007,");
2975     strcat (sql, "3000,3001,3002,3003,3004,3005,3006,3007));\n");
2976     strcat (sql, "END");
2977     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2978     if (ret != SQLITE_OK)
2979       {
2980 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2981 	  sqlite3_free (errMsg);
2982 	  return 0;
2983       }
2984     updateSpatiaLiteHistory (sqlite, "geometry_columns", NULL,
2985 			     "trigger 'geometry_columns_geometry_type_update' successfully created");
2986     strcpy (sql, "CREATE TRIGGER geometry_columns_coord_dimension_insert\n");
2987     strcat (sql, "BEFORE INSERT ON 'geometry_columns'\n");
2988     strcat (sql, "FOR EACH ROW BEGIN\n");
2989     strcat (sql,
2990 	    "SELECT RAISE(ABORT,'coord_dimension must be one of 2,3,4')\n");
2991     strcat (sql, "WHERE NOT(NEW.coord_dimension IN (2,3,4));\n");
2992     strcat (sql, "END");
2993     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
2994     if (ret != SQLITE_OK)
2995       {
2996 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
2997 	  sqlite3_free (errMsg);
2998 	  return 0;
2999       }
3000     updateSpatiaLiteHistory (sqlite, "geometry_columns", NULL,
3001 			     "trigger 'geometry_columns_coord_dimension_insert' successfully created");
3002     strcpy (sql, "CREATE TRIGGER geometry_columns_coord_dimension_update\n");
3003     strcat (sql, "BEFORE UPDATE OF 'coord_dimension' ON 'geometry_columns'\n");
3004     strcat (sql, "FOR EACH ROW BEGIN\n");
3005     strcat (sql,
3006 	    "SELECT RAISE(ABORT,'coord_dimension must be one of 2,3,4')\n");
3007     strcat (sql, "WHERE NOT(NEW.coord_dimension IN (2,3,4));\n");
3008     strcat (sql, "END");
3009     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3010     if (ret != SQLITE_OK)
3011       {
3012 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3013 	  sqlite3_free (errMsg);
3014 	  return 0;
3015       }
3016     updateSpatiaLiteHistory (sqlite, "geometry_columns", NULL,
3017 			     "trigger 'geometry_columns_coord_dimension_update' successfully created");
3018     return 1;
3019 }
3020 
3021 SPATIALITE_PRIVATE int
createTemporarySpatialRefSys(void * p_sqlite,const char * db_prefix)3022 createTemporarySpatialRefSys (void *p_sqlite, const char *db_prefix)
3023 {
3024     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
3025     char *sql_statement;
3026     sqlite3_stmt *stmt;
3027     int ret;
3028     char *prefix;
3029     int already_defined = 0;
3030     char *errMsg = NULL;
3031 
3032 /* checking if already defined */
3033     prefix = gaiaDoubleQuotedSql (db_prefix);
3034     sql_statement = sqlite3_mprintf ("SELECT name "
3035 				     "FROM \"%s\".sqlite_master WHERE type = 'table' "
3036 				     "AND Lower(name) = 'spatial_ref_sys'",
3037 				     prefix);
3038     free (prefix);
3039 /* compiling SQL prepared statement */
3040     ret =
3041 	sqlite3_prepare_v2 (sqlite, sql_statement, strlen (sql_statement),
3042 			    &stmt, NULL);
3043     sqlite3_free (sql_statement);
3044     if (ret != SQLITE_OK)
3045       {
3046 	  spatialite_e ("createTemporarySpatialRefSys: error %d \"%s\"\n",
3047 			sqlite3_errcode (sqlite), sqlite3_errmsg (sqlite));
3048 	  return 0;
3049       }
3050     sqlite3_reset (stmt);
3051     sqlite3_clear_bindings (stmt);
3052     while (1)
3053       {
3054 	  /* scrolling the result set rows */
3055 	  ret = sqlite3_step (stmt);
3056 	  if (ret == SQLITE_DONE)
3057 	      break;		/* end of result set */
3058 	  if (ret == SQLITE_ROW)
3059 	      already_defined = 1;
3060       }
3061     sqlite3_finalize (stmt);
3062 
3063     if (already_defined)
3064 	return 1;
3065 
3066 /* creating the SPATIAL_REF_SYS table */
3067     prefix = gaiaDoubleQuotedSql (db_prefix);
3068     sql_statement = sqlite3_mprintf ("CREATE TABLE \"%s\".spatial_ref_sys (\n"
3069 				     "srid INTEGER NOT NULL PRIMARY KEY,\n"
3070 				     "auth_name TEXT NOT NULL,\n"
3071 				     "auth_srid INTEGER NOT NULL,\n"
3072 				     "ref_sys_name TEXT NOT NULL DEFAULT 'Unknown',\n"
3073 				     "proj4text TEXT NOT NULL,\n"
3074 				     "srtext TEXT NOT NULL DEFAULT 'Undefined')",
3075 				     prefix);
3076     free (prefix);
3077     ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
3078     sqlite3_free (sql_statement);
3079     if (ret != SQLITE_OK)
3080 	goto error;
3081     prefix = gaiaDoubleQuotedSql (db_prefix);
3082     sql_statement =
3083 	sqlite3_mprintf ("CREATE UNIQUE INDEX \"%s\".idx_spatial_ref_sys \n"
3084 			 "ON spatial_ref_sys (auth_srid, auth_name)", prefix);
3085     free (prefix);
3086     ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
3087     sqlite3_free (sql_statement);
3088     if (ret != SQLITE_OK)
3089 	goto error;
3090 
3091     sql_statement = sqlite3_mprintf ("SAVEPOINT tmp_spatial_ref_sys");
3092     ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
3093     sqlite3_free (sql_statement);
3094     if (ret != SQLITE_OK)
3095 	goto error;
3096     prefix = gaiaDoubleQuotedSql (db_prefix);
3097     sql_statement = sqlite3_mprintf ("INSERT INTO \"%s\".spatial_ref_sys "
3098 				     "(srid, auth_name, auth_srid, ref_sys_name, proj4text, srtext) "
3099 				     "SELECT srid, auth_name, auth_srid, ref_sys_name, proj4text, srtext "
3100 				     "FROM main.spatial_ref_sys", prefix);
3101     free (prefix);
3102     ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
3103     sqlite3_free (sql_statement);
3104     if (ret != SQLITE_OK)
3105 	goto error;
3106     sql_statement = sqlite3_mprintf ("RELEASE SAVEPOINT tmp_spatial_ref_sys");
3107     ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
3108     sqlite3_free (sql_statement);
3109     if (ret != SQLITE_OK)
3110 	goto error;
3111 
3112     return 1;
3113 
3114   error:
3115     return 0;
3116 }
3117 
3118 static int
createTemporaryViewsGeometryColumns(sqlite3 * sqlite,const char * db_prefix)3119 createTemporaryViewsGeometryColumns (sqlite3 * sqlite, const char *db_prefix)
3120 {
3121 /* creating the VIEWS_GEOMETRY_COLUMNS table */
3122     char *sql;
3123     char *errMsg = NULL;
3124     int ret;
3125     char *prefix;
3126 
3127 /* creating the VIEWS_GEOMETRY_COLUMNS table */
3128     prefix = gaiaDoubleQuotedSql (db_prefix);
3129     sql =
3130 	sqlite3_mprintf
3131 	("CREATE TABLE IF NOT EXISTS \"%s\".views_geometry_columns (\n"
3132 	 "view_name TEXT NOT NULL,\n" "view_geometry TEXT NOT NULL,\n"
3133 	 "view_rowid TEXT NOT NULL,\n" "f_table_name TEXT NOT NULL,\n"
3134 	 "f_geometry_column TEXT NOT NULL,\n" "read_only INTEGER NOT NULL,\n"
3135 	 "CONSTRAINT pk_geom_cols_views PRIMARY KEY "
3136 	 "(view_name, view_geometry),\n"
3137 	 "CONSTRAINT fk_views_geom_cols FOREIGN KEY "
3138 	 "(f_table_name, f_geometry_column) " "REFERENCES geometry_columns "
3139 	 "(f_table_name, f_geometry_column) " "ON DELETE CASCADE,\n"
3140 	 "CONSTRAINT ck_vw_rdonly CHECK (read_only IN (0,1)))", prefix);
3141     free (prefix);
3142     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3143     sqlite3_free (sql);
3144     if (ret != SQLITE_OK)
3145       {
3146 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3147 	  sqlite3_free (errMsg);
3148 	  return 0;
3149       }
3150 /* creating an INDEX supporting the GEOMETRY_COLUMNS FK */
3151     prefix = gaiaDoubleQuotedSql (db_prefix);
3152     sql = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS \"%s\".idx_viewsjoin "
3153 			   "ON views_geometry_columns\n"
3154 			   "(f_table_name, f_geometry_column)", prefix);
3155     free (prefix);
3156     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3157     if (ret != SQLITE_OK)
3158       {
3159 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3160 	  sqlite3_free (errMsg);
3161 	  sqlite3_free (sql);
3162 	  return 0;
3163       }
3164     sqlite3_free (sql);
3165 /* creating the VIEWS_GEOMETRY_COLUMNS triggers */
3166     prefix = gaiaDoubleQuotedSql (db_prefix);
3167     sql =
3168 	sqlite3_mprintf
3169 	("CREATE TRIGGER IF NOT EXISTS \"%s\".vwgc_view_name_insert\n"
3170 	 "BEFORE INSERT ON 'views_geometry_columns'\n" "FOR EACH ROW BEGIN\n"
3171 	 "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: "
3172 	 "view_name value must not contain a single quote')\n"
3173 	 "WHERE NEW.view_name LIKE ('%%''%%');\n"
3174 	 "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: "
3175 	 "view_name value must not contain a double quote')\n"
3176 	 "WHERE NEW.view_name LIKE ('%%\"%%');\n"
3177 	 "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: \n"
3178 	 "view_name value must be lower case')\n"
3179 	 "WHERE NEW.view_name <> lower(NEW.view_name);\n" "END", prefix);
3180     free (prefix);
3181     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3182     if (ret != SQLITE_OK)
3183       {
3184 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3185 	  sqlite3_free (errMsg);
3186 	  sqlite3_free (sql);
3187 	  return 0;
3188       }
3189     sqlite3_free (sql);
3190     prefix = gaiaDoubleQuotedSql (db_prefix);
3191     sql =
3192 	sqlite3_mprintf
3193 	("CREATE TRIGGER IF NOT EXISTS \"%s\".vwgc_view_name_update\n"
3194 	 "BEFORE UPDATE OF 'view_name' ON 'views_geometry_columns'\n"
3195 	 "FOR EACH ROW BEGIN\n"
3196 	 "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: "
3197 	 "view_name value must not contain a single quote')\n"
3198 	 "WHERE NEW.view_name LIKE ('%%''%%');\n"
3199 	 "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: "
3200 	 "view_name value must not contain a double quote')\n"
3201 	 "WHERE NEW.view_name LIKE ('%%\"%%');\n"
3202 	 "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: "
3203 	 "view_name value must be lower case')\n"
3204 	 "WHERE NEW.view_name <> lower(NEW.view_name);\n" "END", prefix);
3205     free (prefix);
3206     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3207     if (ret != SQLITE_OK)
3208       {
3209 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3210 	  sqlite3_free (errMsg);
3211 	  sqlite3_free (sql);
3212 	  return 0;
3213       }
3214     sqlite3_free (sql);
3215     prefix = gaiaDoubleQuotedSql (db_prefix);
3216     sql =
3217 	sqlite3_mprintf
3218 	("CREATE TRIGGER IF NOT EXISTS \"%s\".vwgc_view_geometry_insert\n"
3219 	 "BEFORE INSERT ON 'views_geometry_columns'\n" "FOR EACH ROW BEGIN\n"
3220 	 "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: "
3221 	 "view_geometry value must not contain a single quote')\n"
3222 	 "WHERE NEW.view_geometry LIKE ('%%''%%');\n"
3223 	 "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: \n"
3224 	 "view_geometry value must not contain a double quote')\n"
3225 	 "WHERE NEW.view_geometry LIKE ('%%\"%%');\n"
3226 	 "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: "
3227 	 "view_geometry value must be lower case')\n"
3228 	 "WHERE NEW.view_geometry <> lower(NEW.view_geometry);\n" "END",
3229 	 prefix);
3230     free (prefix);
3231     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3232     if (ret != SQLITE_OK)
3233       {
3234 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3235 	  sqlite3_free (errMsg);
3236 	  sqlite3_free (sql);
3237 	  return 0;
3238       }
3239     sqlite3_free (sql);
3240     prefix = gaiaDoubleQuotedSql (db_prefix);
3241     sql =
3242 	sqlite3_mprintf
3243 	("CREATE TRIGGER IF NOT EXISTS \"%s\".vwgc_view_geometry_update\n"
3244 	 "BEFORE UPDATE OF 'view_geometry' ON 'views_geometry_columns'\n"
3245 	 "FOR EACH ROW BEGIN\n"
3246 	 "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: "
3247 	 "view_geometry value must not contain a single quote')\n"
3248 	 "WHERE NEW.view_geometry LIKE ('%%''%%');\n"
3249 	 "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: \n"
3250 	 "view_geometry value must not contain a double quote')\n"
3251 	 "WHERE NEW.view_geometry LIKE ('%%\"%%');\n"
3252 	 "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: "
3253 	 "view_geometry value must be lower case')\n"
3254 	 "WHERE NEW.view_geometry <> lower(NEW.view_geometry);\n" "END",
3255 	 prefix);
3256     free (prefix);
3257     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3258     if (ret != SQLITE_OK)
3259       {
3260 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3261 	  sqlite3_free (errMsg);
3262 	  sqlite3_free (sql);
3263 	  return 0;
3264       }
3265     sqlite3_free (sql);
3266     prefix = gaiaDoubleQuotedSql (db_prefix);
3267     sql =
3268 	sqlite3_mprintf
3269 	("CREATE TRIGGER IF NOT EXISTS \"%s\".vwgc_view_rowid_update\n"
3270 	 "BEFORE UPDATE OF 'view_rowid' ON 'views_geometry_columns'\n"
3271 	 "FOR EACH ROW BEGIN\n"
3272 	 "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: "
3273 	 "view_rowid value must not contain a single quote')\n"
3274 	 "WHERE NEW.f_geometry_column LIKE ('%%''%%');\n"
3275 	 "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: "
3276 	 "view_rowid value must not contain a double quote')\n"
3277 	 "WHERE NEW.view_rowid LIKE ('%%\"%%');\n"
3278 	 "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: "
3279 	 "view_rowid value must be lower case')\n"
3280 	 "WHERE NEW.view_rowid <> lower(NEW.view_rowid);\n" "END", prefix);
3281     free (prefix);
3282     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3283     if (ret != SQLITE_OK)
3284       {
3285 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3286 	  sqlite3_free (errMsg);
3287 	  sqlite3_free (sql);
3288 	  return 0;
3289       }
3290     sqlite3_free (sql);
3291     prefix = gaiaDoubleQuotedSql (db_prefix);
3292     sql =
3293 	sqlite3_mprintf
3294 	("CREATE TRIGGER IF NOT EXISTS \"%s\".vwgc_view_rowid_insert\n"
3295 	 "BEFORE INSERT ON 'views_geometry_columns'\n" "FOR EACH ROW BEGIN\n"
3296 	 "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: "
3297 	 "view_rowid value must not contain a single quote')\n"
3298 	 "WHERE NEW.view_rowid LIKE ('%%''%%');\n"
3299 	 "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: \n"
3300 	 "view_rowid value must not contain a double quote')\n"
3301 	 "WHERE NEW.view_rowid LIKE ('%%\"%%');\n"
3302 	 "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: "
3303 	 "view_rowid value must be lower case')\n"
3304 	 "WHERE NEW.view_rowid <> lower(NEW.view_rowid);\n" "END", prefix);
3305     free (prefix);
3306     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3307     if (ret != SQLITE_OK)
3308       {
3309 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3310 	  sqlite3_free (errMsg);
3311 	  sqlite3_free (sql);
3312 	  return 0;
3313       }
3314     sqlite3_free (sql);
3315     prefix = gaiaDoubleQuotedSql (db_prefix);
3316     sql =
3317 	sqlite3_mprintf
3318 	("CREATE TRIGGER IF NOT EXISTS \"%s\".vwgc_f_table_name_insert\n"
3319 	 "BEFORE INSERT ON 'views_geometry_columns'\n" "FOR EACH ROW BEGIN\n"
3320 	 "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: "
3321 	 "f_table_name value must not contain a single quote')\n"
3322 	 "WHERE NEW.f_table_name LIKE ('%%''%%');\n"
3323 	 "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: "
3324 	 "f_table_name value must not contain a double quote')\n"
3325 	 "WHERE NEW.f_table_name LIKE ('%%\"%%');\n"
3326 	 "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: \n"
3327 	 "f_table_name value must be lower case')\n"
3328 	 "WHERE NEW.f_table_name <> lower(NEW.f_table_name);\n" "END", prefix);
3329     free (prefix);
3330     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3331     if (ret != SQLITE_OK)
3332       {
3333 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3334 	  sqlite3_free (errMsg);
3335 	  sqlite3_free (sql);
3336 	  return 0;
3337       }
3338     sqlite3_free (sql);
3339     prefix = gaiaDoubleQuotedSql (db_prefix);
3340     sql =
3341 	sqlite3_mprintf
3342 	("CREATE TRIGGER IF NOT EXISTS \"%s\".vwgc_f_table_name_update\n"
3343 	 "BEFORE UPDATE OF 'f_table_name' ON 'views_geometry_columns'\n"
3344 	 "FOR EACH ROW BEGIN\n"
3345 	 "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: "
3346 	 "f_table_name value must not contain a single quote')\n"
3347 	 "WHERE NEW.f_table_name LIKE ('%%''%%');\n"
3348 	 "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: "
3349 	 "f_table_name value must not contain a double quote')\n"
3350 	 "WHERE NEW.f_table_name LIKE ('%%\"%%');\n"
3351 	 "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: "
3352 	 "f_table_name value must be lower case')\n"
3353 	 "WHERE NEW.f_table_name <> lower(NEW.f_table_name);\n" "END", prefix);
3354     free (prefix);
3355     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3356     if (ret != SQLITE_OK)
3357       {
3358 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3359 	  sqlite3_free (errMsg);
3360 	  sqlite3_free (sql);
3361 	  return 0;
3362       }
3363     sqlite3_free (sql);
3364     prefix = gaiaDoubleQuotedSql (db_prefix);
3365     sql =
3366 	sqlite3_mprintf
3367 	("CREATE TRIGGER IF NOT EXISTS \"%s\".vwgc_f_geometry_column_insert\n"
3368 	 "BEFORE INSERT ON 'views_geometry_columns'\n" "FOR EACH ROW BEGIN\n"
3369 	 "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: "
3370 	 "f_geometry_column value must not contain a single quote')\n"
3371 	 "WHERE NEW.f_geometry_column LIKE ('%%''%%');\n"
3372 	 "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: \n"
3373 	 "f_geometry_column value must not contain a double quote')\n"
3374 	 "WHERE NEW.f_geometry_column LIKE ('%%\"%%');\n"
3375 	 "SELECT RAISE(ABORT,'insert on views_geometry_columns violates constraint: "
3376 	 "f_geometry_column value must be lower case')\n"
3377 	 "WHERE NEW.f_geometry_column <> lower(NEW.f_geometry_column);\n" "END",
3378 	 prefix);
3379     free (prefix);
3380     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3381     if (ret != SQLITE_OK)
3382       {
3383 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3384 	  sqlite3_free (errMsg);
3385 	  sqlite3_free (sql);
3386 	  return 0;
3387       }
3388     sqlite3_free (sql);
3389     prefix = gaiaDoubleQuotedSql (db_prefix);
3390     sql =
3391 	sqlite3_mprintf
3392 	("CREATE TRIGGER IF NOT EXISTS \"%s\".vwgc_f_geometry_column_update\n"
3393 	 "BEFORE UPDATE OF 'f_geometry_column' ON 'views_geometry_columns'\n"
3394 	 "FOR EACH ROW BEGIN\n"
3395 	 "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: "
3396 	 "f_geometry_column value must not contain a single quote')\n"
3397 	 "WHERE NEW.f_geometry_column LIKE ('%%''%%');\n"
3398 	 "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: "
3399 	 "f_geometry_column value must not contain a double quote')\n"
3400 	 "WHERE NEW.f_geometry_column LIKE ('%%\"%%');\n"
3401 	 "SELECT RAISE(ABORT,'update on views_geometry_columns violates constraint: "
3402 	 "f_geometry_column value must be lower case')\n"
3403 	 "WHERE NEW.f_geometry_column <> lower(NEW.f_geometry_column);\n" "END",
3404 	 prefix);
3405     free (prefix);
3406     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3407     if (ret != SQLITE_OK)
3408       {
3409 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3410 	  sqlite3_free (errMsg);
3411 	  sqlite3_free (sql);
3412 	  return 0;
3413       }
3414     sqlite3_free (sql);
3415     return 1;
3416 }
3417 
3418 SPATIALITE_PRIVATE int
createTemporaryGeometryColumns(void * p_sqlite,const char * db_prefix)3419 createTemporaryGeometryColumns (void *p_sqlite, const char *db_prefix)
3420 {
3421     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
3422     char *sql;
3423     char *errMsg = NULL;
3424     int ret;
3425     char *prefix;
3426 /* creating the GEOMETRY_COLUMNS table */
3427     prefix = gaiaDoubleQuotedSql (db_prefix);
3428     sql =
3429 	sqlite3_mprintf
3430 	("CREATE TABLE IF NOT EXISTS \"%s\".geometry_columns (\n"
3431 	 "f_table_name TEXT NOT NULL,\n" "f_geometry_column TEXT NOT NULL,\n"
3432 	 "geometry_type INTEGER NOT NULL,\n"
3433 	 "coord_dimension INTEGER NOT NULL,\n" "srid INTEGER NOT NULL,\n"
3434 	 "spatial_index_enabled INTEGER NOT NULL,\n"
3435 	 "CONSTRAINT pk_geom_cols PRIMARY KEY "
3436 	 "(f_table_name, f_geometry_column),\n"
3437 	 "CONSTRAINT fk_gc_srs FOREIGN KEY "
3438 	 "(srid) REFERENCES spatial_ref_sys (srid),\n"
3439 	 "CONSTRAINT ck_gc_rtree CHECK " "(spatial_index_enabled IN (0,1)))",
3440 	 prefix);
3441     free (prefix);
3442     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3443     if (ret != SQLITE_OK)
3444       {
3445 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3446 	  sqlite3_free (errMsg);
3447 	  sqlite3_free (sql);
3448 	  return 0;
3449       }
3450     sqlite3_free (sql);
3451 /* creating an INDEX corresponding to the SRID FK */
3452     prefix = gaiaDoubleQuotedSql (db_prefix);
3453     sql = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS \"%s\".idx_srid_geocols "
3454 			   "ON geometry_columns (srid)", prefix);
3455     free (prefix);
3456     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3457     if (ret != SQLITE_OK)
3458       {
3459 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3460 	  sqlite3_free (sql);
3461 	  sqlite3_free (errMsg);
3462 	  return 0;
3463       }
3464     sqlite3_free (sql);
3465 /* creating the GEOMETRY_COLUMNS triggers */
3466     prefix = gaiaDoubleQuotedSql (db_prefix);
3467     sql =
3468 	sqlite3_mprintf
3469 	("CREATE TRIGGER IF NOT EXISTS \"%s\".geometry_columns_f_table_name_insert\n"
3470 	 "BEFORE INSERT ON 'geometry_columns'\n" "FOR EACH ROW BEGIN\n"
3471 	 "SELECT RAISE(ABORT,'insert on geometry_columns violates constraint: "
3472 	 "f_table_name value must not contain a single quote')\n"
3473 	 "WHERE NEW.f_table_name LIKE ('%%''%%');\n"
3474 	 "SELECT RAISE(ABORT,'insert on geometry_columns violates constraint: "
3475 	 "f_table_name value must not contain a double quote')\n"
3476 	 "WHERE NEW.f_table_name LIKE ('%%\"%%');\n"
3477 	 "SELECT RAISE(ABORT,'insert on geometry_columns violates constraint: \n"
3478 	 "f_table_name value must be lower case')\n"
3479 	 "WHERE NEW.f_table_name <> lower(NEW.f_table_name);\n" "END", prefix);
3480     free (prefix);
3481     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3482     if (ret != SQLITE_OK)
3483       {
3484 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3485 	  sqlite3_free (errMsg);
3486 	  sqlite3_free (sql);
3487 	  return 0;
3488       }
3489     sqlite3_free (sql);
3490     prefix = gaiaDoubleQuotedSql (db_prefix);
3491     sql =
3492 	sqlite3_mprintf
3493 	("CREATE TRIGGER IF NOT EXISTS \"%s\".geometry_columns_f_table_name_update\n"
3494 	 "BEFORE UPDATE OF 'f_table_name' ON 'geometry_columns'\n"
3495 	 "FOR EACH ROW BEGIN\n"
3496 	 "SELECT RAISE(ABORT,'update on geometry_columns violates constraint: "
3497 	 "f_table_name value must not contain a single quote')\n"
3498 	 "WHERE NEW.f_table_name LIKE ('%%''%%');\n"
3499 	 "SELECT RAISE(ABORT,'update on geometry_columns violates constraint: "
3500 	 "f_table_name value must not contain a double quote')\n"
3501 	 "WHERE NEW.f_table_name LIKE ('%%\"%%');\n"
3502 	 "SELECT RAISE(ABORT,'update on geometry_columns violates constraint: "
3503 	 "f_table_name value must be lower case')\n"
3504 	 "WHERE NEW.f_table_name <> lower(NEW.f_table_name);\n" "END", prefix);
3505     free (prefix);
3506     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3507     if (ret != SQLITE_OK)
3508       {
3509 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3510 	  sqlite3_free (errMsg);
3511 	  sqlite3_free (sql);
3512 	  return 0;
3513       }
3514     sqlite3_free (sql);
3515     prefix = gaiaDoubleQuotedSql (db_prefix);
3516     sql =
3517 	sqlite3_mprintf
3518 	("CREATE TRIGGER IF NOT EXISTS \"%s\".geometry_columns_f_geometry_column_insert\n"
3519 	 "BEFORE INSERT ON 'geometry_columns'\n" "FOR EACH ROW BEGIN\n"
3520 	 "SELECT RAISE(ABORT,'insert on geometry_columns violates constraint: "
3521 	 "f_geometry_column value must not contain a single quote')\n"
3522 	 "WHERE NEW.f_geometry_column LIKE ('%%''%%');\n"
3523 	 "SELECT RAISE(ABORT,'insert on geometry_columns violates constraint: \n"
3524 	 "f_geometry_column value must not contain a double quote')\n"
3525 	 "WHERE NEW.f_geometry_column LIKE ('%%\"%%');\n"
3526 	 "SELECT RAISE(ABORT,'insert on geometry_columns violates constraint: "
3527 	 "f_geometry_column value must be lower case')\n"
3528 	 "WHERE NEW.f_geometry_column <> lower(NEW.f_geometry_column);\n" "END",
3529 	 prefix);
3530     free (prefix);
3531     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3532     if (ret != SQLITE_OK)
3533       {
3534 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3535 	  sqlite3_free (errMsg);
3536 	  sqlite3_free (sql);
3537 	  return 0;
3538       }
3539     sqlite3_free (sql);
3540     prefix = gaiaDoubleQuotedSql (db_prefix);
3541     sql =
3542 	sqlite3_mprintf
3543 	("CREATE TRIGGER IF NOT EXISTS \"%s\".geometry_columns_f_geometry_column_update\n"
3544 	 "BEFORE UPDATE OF 'f_geometry_column' ON 'geometry_columns'\n"
3545 	 "FOR EACH ROW BEGIN\n"
3546 	 "SELECT RAISE(ABORT,'update on geometry_columns violates constraint: "
3547 	 "f_geometry_column value must not contain a single quote')\n"
3548 	 "WHERE NEW.f_geometry_column LIKE ('%%''%%');\n"
3549 	 "SELECT RAISE(ABORT,'update on geometry_columns violates constraint: "
3550 	 "f_geometry_column value must not contain a double quote')\n"
3551 	 "WHERE NEW.f_geometry_column LIKE ('%%\"%%');\n"
3552 	 "SELECT RAISE(ABORT,'update on geometry_columns violates constraint: "
3553 	 "f_geometry_column value must be lower case')\n"
3554 	 "WHERE NEW.f_geometry_column <> lower(NEW.f_geometry_column);\n" "END",
3555 	 prefix);
3556     free (prefix);
3557     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3558     if (ret != SQLITE_OK)
3559       {
3560 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3561 	  sqlite3_free (errMsg);
3562 	  sqlite3_free (sql);
3563 	  return 0;
3564       }
3565     sqlite3_free (sql);
3566     prefix = gaiaDoubleQuotedSql (db_prefix);
3567     sql =
3568 	sqlite3_mprintf
3569 	("CREATE TRIGGER IF NOT EXISTS \"%s\".geometry_columns_geometry_type_insert\n"
3570 	 "BEFORE INSERT ON 'geometry_columns'\n" "FOR EACH ROW BEGIN\n"
3571 	 "SELECT RAISE(ABORT,'geometry_type must be one of " "0,1,2,3,4,5,6,7,"
3572 	 "1000,1001,1002,1003,1004,1005,1006,1007,"
3573 	 "2000,2001,2002,2003,2004,2005,2006,2007,"
3574 	 "3000,3001,3002,3003,3004,3005,3006,3007')\n"
3575 	 "WHERE NOT(NEW.geometry_type IN (0,1,2,3,4,5,6,7,"
3576 	 "1000,1001,1002,1003,1004,1005,1006,1007,"
3577 	 "2000,2001,2002,2003,2004,2005,2006,2007,"
3578 	 "3000,3001,3002,3003,3004,3005,3006,3007));\n" "END", prefix);
3579     free (prefix);
3580     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3581     if (ret != SQLITE_OK)
3582       {
3583 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3584 	  sqlite3_free (errMsg);
3585 	  sqlite3_free (sql);
3586 	  return 0;
3587       }
3588     sqlite3_free (sql);
3589     prefix = gaiaDoubleQuotedSql (db_prefix);
3590     sql =
3591 	sqlite3_mprintf
3592 	("CREATE TRIGGER IF NOT EXISTS \"%s\".geometry_columns_geometry_type_update\n"
3593 	 "BEFORE UPDATE OF 'geometry_type' ON 'geometry_columns'\n"
3594 	 "FOR EACH ROW BEGIN\n"
3595 	 "SELECT RAISE(ABORT,'geometry_type must be one of " "0,1,2,3,4,5,6,7,"
3596 	 "1000,1001,1002,1003,1004,1005,1006,1007,"
3597 	 "2000,2001,2002,2003,2004,2005,2006,2007,"
3598 	 "3000,3001,3002,3003,3004,3005,3006,3007')\n"
3599 	 "WHERE NOT(NEW.geometry_type IN (0,1,2,3,4,5,6,7,"
3600 	 "1000,1001,1002,1003,1004,1005,1006,1007,"
3601 	 "2000,2001,2002,2003,2004,2005,2006,2007,"
3602 	 "3000,3001,3002,3003,3004,3005,3006,3007));\n" "END", prefix);
3603     free (prefix);
3604     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3605     if (ret != SQLITE_OK)
3606       {
3607 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3608 	  sqlite3_free (errMsg);
3609 	  sqlite3_free (sql);
3610 	  return 0;
3611       }
3612     sqlite3_free (sql);
3613     prefix = gaiaDoubleQuotedSql (db_prefix);
3614     sql =
3615 	sqlite3_mprintf
3616 	("CREATE TRIGGER IF NOT EXISTS \"%s\".geometry_columns_coord_dimension_insert\n"
3617 	 "BEFORE INSERT ON 'geometry_columns'\n" "FOR EACH ROW BEGIN\n"
3618 	 "SELECT RAISE(ABORT,'coord_dimension must be one of 2,3,4')\n"
3619 	 "WHERE NOT(NEW.coord_dimension IN (2,3,4));\n" "END", prefix);
3620     free (prefix);
3621     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3622     if (ret != SQLITE_OK)
3623       {
3624 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3625 	  sqlite3_free (errMsg);
3626 	  sqlite3_free (sql);
3627 	  return 0;
3628       }
3629     sqlite3_free (sql);
3630     prefix = gaiaDoubleQuotedSql (db_prefix);
3631     sql =
3632 	sqlite3_mprintf
3633 	("CREATE TRIGGER IF NOT EXISTS \"%s\".geometry_columns_coord_dimension_update\n"
3634 	 "BEFORE UPDATE OF 'coord_dimension' ON 'geometry_columns'\n"
3635 	 "FOR EACH ROW BEGIN\n"
3636 	 "SELECT RAISE(ABORT,'coord_dimension must be one of 2,3,4')\n"
3637 	 "WHERE NOT(NEW.coord_dimension IN (2,3,4));\n" "END", prefix);
3638     free (prefix);
3639     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &errMsg);
3640     if (ret != SQLITE_OK)
3641       {
3642 	  spatialite_e ("SQL error: %s: %s\n", sql, errMsg);
3643 	  sqlite3_free (errMsg);
3644 	  sqlite3_free (sql);
3645 	  return 0;
3646       }
3647     sqlite3_free (sql);
3648 
3649 /* attempting to create views_geometry_columns on the same TMP-DB */
3650     if (!createTemporaryViewsGeometryColumns (sqlite, db_prefix))
3651 	return 0;
3652     return 1;
3653 }
3654 
3655 SPATIALITE_PRIVATE int
upgradeGeometryTriggers(void * p_sqlite)3656 upgradeGeometryTriggers (void *p_sqlite)
3657 {
3658 /* upgrading all triggers for any Spatial Column */
3659     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
3660     int ret;
3661     sqlite3_stmt *stmt = NULL;
3662     char *sql_statement;
3663     int retcode = 0;
3664     int metadata_version = checkSpatialMetaData (sqlite);
3665     if (metadata_version < 3)
3666 	return 0;
3667 
3668     sql_statement =
3669 	sqlite3_mprintf ("SELECT f_table_name, f_geometry_column "
3670 			 "FROM geometry_columns");
3671 /* compiling SQL prepared statement */
3672     ret =
3673 	sqlite3_prepare_v2 (sqlite, sql_statement, strlen (sql_statement),
3674 			    &stmt, NULL);
3675     sqlite3_free (sql_statement);
3676     if (ret != SQLITE_OK)
3677       {
3678 	  spatialite_e ("upgradeGeometryTriggers: error %d \"%s\"\n",
3679 			sqlite3_errcode (sqlite), sqlite3_errmsg (sqlite));
3680 	  return 0;
3681       }
3682     while (1)
3683       {
3684 	  /* scrolling the result set rows */
3685 	  ret = sqlite3_step (stmt);
3686 	  if (ret == SQLITE_DONE)
3687 	      break;		/* end of result set */
3688 	  if (ret == SQLITE_ROW)
3689 	    {
3690 		const char *table =
3691 		    (const char *) sqlite3_column_text (stmt, 0);
3692 		const char *column =
3693 		    (const char *) sqlite3_column_text (stmt, 1);
3694 		updateGeometryTriggers (sqlite, table, column);
3695 		retcode = 1;
3696 	    }
3697 	  else
3698 	    {
3699 		retcode = 0;
3700 		break;
3701 	    }
3702       }
3703     ret = sqlite3_finalize (stmt);
3704     return retcode;
3705 }
3706 
3707 SPATIALITE_PRIVATE void
updateGeometryTriggers(void * p_sqlite,const char * table,const char * column)3708 updateGeometryTriggers (void *p_sqlite, const char *table, const char *column)
3709 {
3710 /* updates triggers for some Spatial Column */
3711     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
3712     int ret;
3713     int col_index;
3714     const char *col_dims;
3715     int index;
3716     int cached;
3717     int dims;
3718     char *txt_dims = NULL;
3719     int len;
3720     char *errMsg = NULL;
3721     char *sql_statement;
3722     char *raw;
3723     char *quoted_trigger;
3724     char *quoted_rtree;
3725     char *quoted_table;
3726     char *quoted_column;
3727     char *p_table = NULL;
3728     char *p_column = NULL;
3729     sqlite3_stmt *stmt;
3730     struct spatial_index_str *first_idx = NULL;
3731     struct spatial_index_str *last_idx = NULL;
3732     struct spatial_index_str *curr_idx;
3733     struct spatial_index_str *next_idx;
3734     int metadata_version = checkSpatialMetaData (sqlite);
3735 
3736     if (!getRealSQLnames (sqlite, table, column, &p_table, &p_column))
3737       {
3738 	  spatialite_e
3739 	      ("updateTableTriggers() error: not existing Table or Column\n");
3740 	  return;
3741       }
3742     if (metadata_version == 3)
3743       {
3744 	  /* current metadata style >= v.4.0.0 */
3745 	  sql_statement = sqlite3_mprintf ("SELECT spatial_index_enabled "
3746 					   "FROM geometry_columns WHERE Lower(f_table_name) = Lower(?) "
3747 					   "AND Lower(f_geometry_column) = Lower(?)");
3748       }
3749     else
3750       {
3751 	  /* legacy metadata style <= v.3.1.0 */
3752 	  sql_statement =
3753 	      sqlite3_mprintf ("SELECT spatial_index_enabled, coord_dimension "
3754 			       "FROM geometry_columns WHERE Lower(f_table_name) = Lower(?) "
3755 			       "AND Lower(f_geometry_column) = Lower(?)");
3756       }
3757 /* compiling SQL prepared statement */
3758     ret =
3759 	sqlite3_prepare_v2 (sqlite, sql_statement, strlen (sql_statement),
3760 			    &stmt, NULL);
3761     sqlite3_free (sql_statement);
3762     if (ret != SQLITE_OK)
3763       {
3764 	  spatialite_e ("updateTableTriggers: error %d \"%s\"\n",
3765 			sqlite3_errcode (sqlite), sqlite3_errmsg (sqlite));
3766 	  return;
3767       }
3768     sqlite3_reset (stmt);
3769     sqlite3_clear_bindings (stmt);
3770     sqlite3_bind_text (stmt, 1, table, strlen (table), SQLITE_STATIC);
3771     sqlite3_bind_text (stmt, 2, column, strlen (column), SQLITE_STATIC);
3772     while (1)
3773       {
3774 	  /* scrolling the result set rows */
3775 	  ret = sqlite3_step (stmt);
3776 	  if (ret == SQLITE_DONE)
3777 	      break;		/* end of result set */
3778 	  if (ret == SQLITE_ROW)
3779 	    {
3780 		col_index = sqlite3_column_int (stmt, 0);
3781 		if (metadata_version == 1)
3782 		  {
3783 		      /* legacy metadata style <= v.3.1.0 */
3784 		      col_dims = (const char *) sqlite3_column_text (stmt, 1);
3785 		      dims = GAIA_XY;
3786 		      if (strcasecmp (col_dims, "XYZ") == 0)
3787 			  dims = GAIA_XY_Z;
3788 		      if (strcasecmp (col_dims, "XYM") == 0)
3789 			  dims = GAIA_XY_M;
3790 		      if (strcasecmp (col_dims, "XYZM") == 0)
3791 			  dims = GAIA_XY_Z_M;
3792 		      switch (dims)
3793 			{
3794 			case GAIA_XY_Z:
3795 			    txt_dims = "XYZ";
3796 			    break;
3797 			case GAIA_XY_M:
3798 			    txt_dims = "XYM";
3799 			    break;
3800 			case GAIA_XY_Z_M:
3801 			    txt_dims = "XYZM";
3802 			    break;
3803 			default:
3804 			    txt_dims = "XY";
3805 			    break;
3806 			};
3807 		  }
3808 		index = 0;
3809 		cached = 0;
3810 		if (col_index == 1)
3811 		    index = 1;
3812 		if (col_index == 2)
3813 		    cached = 1;
3814 
3815 		/* trying to delete old versions [v2.0, v2.2] triggers[if any] */
3816 		raw = sqlite3_mprintf ("gti_%s_%s", p_table, p_column);
3817 		quoted_trigger = gaiaDoubleQuotedSql (raw);
3818 		sqlite3_free (raw);
3819 		sql_statement =
3820 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS main.\"%s\"",
3821 				     quoted_trigger);
3822 		free (quoted_trigger);
3823 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
3824 		sqlite3_free (sql_statement);
3825 		if (ret != SQLITE_OK)
3826 		    goto error;
3827 		raw = sqlite3_mprintf ("gtu_%s_%s", p_table, p_column);
3828 		quoted_trigger = gaiaDoubleQuotedSql (raw);
3829 		sqlite3_free (raw);
3830 		sql_statement =
3831 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS main.\"%s\"",
3832 				     quoted_trigger);
3833 		free (quoted_trigger);
3834 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
3835 		sqlite3_free (sql_statement);
3836 		if (ret != SQLITE_OK)
3837 		    goto error;
3838 		raw = sqlite3_mprintf ("gsi_%s_%s", p_table, p_column);
3839 		quoted_trigger = gaiaDoubleQuotedSql (raw);
3840 		sqlite3_free (raw);
3841 		sql_statement =
3842 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS main.\"%s\"",
3843 				     quoted_trigger);
3844 		free (quoted_trigger);
3845 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
3846 		sqlite3_free (sql_statement);
3847 		if (ret != SQLITE_OK)
3848 		    goto error;
3849 		raw = sqlite3_mprintf ("gsu_%s_%s", p_table, p_column);
3850 		quoted_trigger = gaiaDoubleQuotedSql (raw);
3851 		sqlite3_free (raw);
3852 		sql_statement =
3853 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS main.\"%s\"",
3854 				     quoted_trigger);
3855 		free (quoted_trigger);
3856 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
3857 		sqlite3_free (sql_statement);
3858 		if (ret != SQLITE_OK)
3859 		    goto error;
3860 		/* end deletion old versions [v2.0, v2.2] triggers[if any] */
3861 
3862 		/* deleting the old INSERT trigger TYPE [if any] */
3863 		raw = sqlite3_mprintf ("ggi_%s_%s", p_table, p_column);
3864 		quoted_trigger = gaiaDoubleQuotedSql (raw);
3865 		sqlite3_free (raw);
3866 		sql_statement =
3867 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS main.\"%s\"",
3868 				     quoted_trigger);
3869 		free (quoted_trigger);
3870 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
3871 		sqlite3_free (sql_statement);
3872 		if (ret != SQLITE_OK)
3873 		    goto error;
3874 
3875 		/* inserting the new INSERT trigger TYPE */
3876 		raw = sqlite3_mprintf ("ggi_%s_%s", p_table, p_column);
3877 		quoted_trigger = gaiaDoubleQuotedSql (raw);
3878 		sqlite3_free (raw);
3879 		quoted_table = gaiaDoubleQuotedSql (p_table);
3880 		quoted_column = gaiaDoubleQuotedSql (p_column);
3881 		if (metadata_version == 3)
3882 		  {
3883 		      /* current metadata style >= v.4.0.0 */
3884 		      sql_statement =
3885 			  sqlite3_mprintf
3886 			  ("CREATE TRIGGER \"%s\" BEFORE INSERT ON \"%s\"\n"
3887 			   "FOR EACH ROW BEGIN\n"
3888 			   "SELECT RAISE(ROLLBACK, '%q.%q violates Geometry constraint [geom-type or SRID not allowed]')\n"
3889 			   "WHERE (SELECT geometry_type FROM geometry_columns\n"
3890 			   "WHERE Lower(f_table_name) = Lower(%Q) AND "
3891 			   "Lower(f_geometry_column) = Lower(%Q)\n"
3892 			   "AND GeometryConstraints(NEW.\"%s\", geometry_type, srid) = 1) IS NULL;\nEND",
3893 			   quoted_trigger, quoted_table, p_table, p_column,
3894 			   p_table, p_column, quoted_column);
3895 		      free (quoted_trigger);
3896 		      free (quoted_table);
3897 		      free (quoted_column);
3898 		  }
3899 		else
3900 		  {
3901 		      /* legacy metadata style <= v.3.1.0 */
3902 		      sql_statement =
3903 			  sqlite3_mprintf
3904 			  ("CREATE TRIGGER \"%s\" BEFORE INSERT ON \"%s\"\n"
3905 			   "FOR EACH ROW BEGIN\n"
3906 			   "SELECT RAISE(ROLLBACK, '%q.%q violates Geometry constraint [geom-type or SRID not allowed]')\n"
3907 			   "WHERE (SELECT type FROM geometry_columns\n"
3908 			   "WHERE f_table_name = %Q AND f_geometry_column = %Q\n"
3909 			   "AND GeometryConstraints(NEW.\"%s\", type, srid, %Q) = 1) IS NULL;\nEND",
3910 			   quoted_trigger, quoted_table, p_table, p_column,
3911 			   p_table, p_column, quoted_column, txt_dims);
3912 		      free (quoted_trigger);
3913 		      free (quoted_table);
3914 		      free (quoted_column);
3915 		  }
3916 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
3917 		sqlite3_free (sql_statement);
3918 		if (ret != SQLITE_OK)
3919 		    goto error;
3920 		/* deleting the old UPDATE trigger TYPE [if any] */
3921 		raw = sqlite3_mprintf ("ggu_%s_%s", p_table, p_column);
3922 		quoted_trigger = gaiaDoubleQuotedSql (raw);
3923 		sqlite3_free (raw);
3924 		sql_statement =
3925 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS main.\"%s\"",
3926 				     quoted_trigger);
3927 		free (quoted_trigger);
3928 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
3929 		sqlite3_free (sql_statement);
3930 		if (ret != SQLITE_OK)
3931 		    goto error;
3932 
3933 		/* inserting the new UPDATE trigger TYPE */
3934 		raw = sqlite3_mprintf ("ggu_%s_%s", p_table, p_column);
3935 		quoted_trigger = gaiaDoubleQuotedSql (raw);
3936 		sqlite3_free (raw);
3937 		quoted_table = gaiaDoubleQuotedSql (p_table);
3938 		quoted_column = gaiaDoubleQuotedSql (p_column);
3939 		if (metadata_version == 3)
3940 		  {
3941 		      /* current metadata style >= v.4.0.0 */
3942 		      sql_statement =
3943 			  sqlite3_mprintf
3944 			  ("CREATE TRIGGER \"%s\" BEFORE UPDATE OF \"%s\" ON \"%s\"\n"
3945 			   "FOR EACH ROW BEGIN\n"
3946 			   "SELECT RAISE(ROLLBACK, '%q.%q violates Geometry constraint [geom-type or SRID not allowed]')\n"
3947 			   "WHERE (SELECT geometry_type FROM geometry_columns\n"
3948 			   "WHERE Lower(f_table_name) = Lower(%Q) AND "
3949 			   "Lower(f_geometry_column) = Lower(%Q)\n"
3950 			   "AND GeometryConstraints(NEW.\"%s\", geometry_type, srid) = 1) IS NULL;\nEND",
3951 			   quoted_trigger, quoted_column, quoted_table, p_table,
3952 			   p_column, p_table, p_column, quoted_column);
3953 		      free (quoted_trigger);
3954 		      free (quoted_table);
3955 		      free (quoted_column);
3956 		  }
3957 		else
3958 		  {
3959 		      /* legacy metadata style <= v.3.1.0 */
3960 		      sql_statement =
3961 			  sqlite3_mprintf
3962 			  ("CREATE TRIGGER \"%s\" BEFORE UPDATE ON \"%s\"\n"
3963 			   "FOR EACH ROW BEGIN\n"
3964 			   "SELECT RAISE(ROLLBACK, '%q.%q violates Geometry constraint [geom-type or SRID not allowed]')\n"
3965 			   "WHERE (SELECT type FROM geometry_columns\n"
3966 			   "WHERE f_table_name = %Q AND f_geometry_column = %Q\n"
3967 			   "AND GeometryConstraints(NEW.\"%s\", type, srid, %Q) = 1) IS NULL;\nEND",
3968 			   quoted_trigger, quoted_table, p_table, p_column,
3969 			   p_table, p_column, quoted_column, txt_dims);
3970 		      free (quoted_trigger);
3971 		      free (quoted_table);
3972 		      free (quoted_column);
3973 		  }
3974 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
3975 		sqlite3_free (sql_statement);
3976 		if (ret != SQLITE_OK)
3977 		    goto error;
3978 
3979 		/* inserting SpatialIndex information into the linked list */
3980 		curr_idx = malloc (sizeof (struct spatial_index_str));
3981 		len = strlen (p_table);
3982 		curr_idx->TableName = malloc (len + 1);
3983 		strcpy (curr_idx->TableName, p_table);
3984 		len = strlen (p_column);
3985 		curr_idx->ColumnName = malloc (len + 1);
3986 		strcpy (curr_idx->ColumnName, p_column);
3987 		curr_idx->ValidRtree = (char) index;
3988 		curr_idx->ValidCache = (char) cached;
3989 		curr_idx->Next = NULL;
3990 		if (!first_idx)
3991 		    first_idx = curr_idx;
3992 		if (last_idx)
3993 		    last_idx->Next = curr_idx;
3994 		last_idx = curr_idx;
3995 
3996 		/* deleting the old INSERT trigger SPATIAL_INDEX [if any] */
3997 		raw = sqlite3_mprintf ("gii_%s_%s", p_table, p_column);
3998 		quoted_trigger = gaiaDoubleQuotedSql (raw);
3999 		sqlite3_free (raw);
4000 		sql_statement =
4001 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS main.\"%s\"",
4002 				     quoted_trigger);
4003 		free (quoted_trigger);
4004 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4005 		sqlite3_free (sql_statement);
4006 		if (ret != SQLITE_OK)
4007 		    goto error;
4008 
4009 		if (metadata_version == 3)
4010 		  {
4011 		      /* deleting the old UPDATE (timestamp) trigger [if any] */
4012 		      raw = sqlite3_mprintf ("tmu_%s_%s", p_table, p_column);
4013 		      quoted_trigger = gaiaDoubleQuotedSql (raw);
4014 		      sqlite3_free (raw);
4015 		      sql_statement =
4016 			  sqlite3_mprintf ("DROP TRIGGER IF EXISTS main.\"%s\"",
4017 					   quoted_trigger);
4018 		      free (quoted_trigger);
4019 		      ret =
4020 			  sqlite3_exec (sqlite, sql_statement, NULL, NULL,
4021 					&errMsg);
4022 		      sqlite3_free (sql_statement);
4023 		      if (ret != SQLITE_OK)
4024 			  goto error;
4025 		      /* deleting the old INSERT (timestamp) trigger [if any] */
4026 		      raw = sqlite3_mprintf ("tmi_%s_%s", p_table, p_column);
4027 		      quoted_trigger = gaiaDoubleQuotedSql (raw);
4028 		      sqlite3_free (raw);
4029 		      sql_statement =
4030 			  sqlite3_mprintf ("DROP TRIGGER IF EXISTS main.\"%s\"",
4031 					   quoted_trigger);
4032 		      free (quoted_trigger);
4033 		      ret =
4034 			  sqlite3_exec (sqlite, sql_statement, NULL, NULL,
4035 					&errMsg);
4036 		      sqlite3_free (sql_statement);
4037 		      if (ret != SQLITE_OK)
4038 			  goto error;
4039 		      /* deleting the old DELETE (timestamp) trigger [if any] */
4040 		      raw = sqlite3_mprintf ("tmd_%s_%s", p_table, p_column);
4041 		      quoted_trigger = gaiaDoubleQuotedSql (raw);
4042 		      sqlite3_free (raw);
4043 		      sql_statement =
4044 			  sqlite3_mprintf ("DROP TRIGGER IF EXISTS main.\"%s\"",
4045 					   quoted_trigger);
4046 		      free (quoted_trigger);
4047 		      ret =
4048 			  sqlite3_exec (sqlite, sql_statement, NULL, NULL,
4049 					&errMsg);
4050 		      sqlite3_free (sql_statement);
4051 		      if (ret != SQLITE_OK)
4052 			  goto error;
4053 		  }
4054 
4055 		if (metadata_version == 3)
4056 		  {
4057 		      /* current metadata style >= v.4.0.0 */
4058 
4059 		      /* inserting the new UPDATE (timestamp) trigger */
4060 		      raw = sqlite3_mprintf ("tmu_%s_%s", p_table, p_column);
4061 		      quoted_trigger = gaiaDoubleQuotedSql (raw);
4062 		      sqlite3_free (raw);
4063 		      quoted_table = gaiaDoubleQuotedSql (p_table);
4064 		      sql_statement =
4065 			  sqlite3_mprintf
4066 			  ("CREATE TRIGGER \"%s\" AFTER UPDATE ON \"%s\"\n"
4067 			   "FOR EACH ROW BEGIN\n"
4068 			   "UPDATE geometry_columns_time SET last_update = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now')\n"
4069 			   "WHERE Lower(f_table_name) = Lower(%Q) AND "
4070 			   "Lower(f_geometry_column) = Lower(%Q);\nEND",
4071 			   quoted_trigger, quoted_table, p_table, p_column);
4072 		      free (quoted_trigger);
4073 		      free (quoted_table);
4074 		      ret =
4075 			  sqlite3_exec (sqlite, sql_statement, NULL, NULL,
4076 					&errMsg);
4077 		      sqlite3_free (sql_statement);
4078 		      if (ret != SQLITE_OK)
4079 			  goto error;
4080 
4081 		      /* inserting the new INSERT (timestamp) trigger */
4082 		      raw = sqlite3_mprintf ("tmi_%s_%s", p_table, p_column);
4083 		      quoted_trigger = gaiaDoubleQuotedSql (raw);
4084 		      sqlite3_free (raw);
4085 		      quoted_table = gaiaDoubleQuotedSql (p_table);
4086 		      sql_statement =
4087 			  sqlite3_mprintf
4088 			  ("CREATE TRIGGER \"%s\" AFTER INSERT ON \"%s\"\n"
4089 			   "FOR EACH ROW BEGIN\n"
4090 			   "UPDATE geometry_columns_time SET last_insert = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now')\n"
4091 			   "WHERE Lower(f_table_name) = Lower(%Q) AND "
4092 			   "Lower(f_geometry_column) = Lower(%Q);\nEND",
4093 			   quoted_trigger, quoted_table, p_table, p_column);
4094 		      free (quoted_trigger);
4095 		      free (quoted_table);
4096 		      ret =
4097 			  sqlite3_exec (sqlite, sql_statement, NULL, NULL,
4098 					&errMsg);
4099 		      sqlite3_free (sql_statement);
4100 		      if (ret != SQLITE_OK)
4101 			  goto error;
4102 
4103 		      /* inserting the new DELETE (timestamp) trigger */
4104 		      raw = sqlite3_mprintf ("tmd_%s_%s", p_table, p_column);
4105 		      quoted_trigger = gaiaDoubleQuotedSql (raw);
4106 		      sqlite3_free (raw);
4107 		      quoted_table = gaiaDoubleQuotedSql (p_table);
4108 		      sql_statement =
4109 			  sqlite3_mprintf
4110 			  ("CREATE TRIGGER \"%s\" AFTER DELETE ON \"%s\"\n"
4111 			   "FOR EACH ROW BEGIN\n"
4112 			   "UPDATE geometry_columns_time SET last_delete = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now')\n"
4113 			   "WHERE Lower(f_table_name) = Lower(%Q) AND "
4114 			   "Lower(f_geometry_column) = Lower(%Q);\nEND",
4115 			   quoted_trigger, quoted_table, p_table, p_column);
4116 		      free (quoted_trigger);
4117 		      free (quoted_table);
4118 		      ret =
4119 			  sqlite3_exec (sqlite, sql_statement, NULL, NULL,
4120 					&errMsg);
4121 		      sqlite3_free (sql_statement);
4122 		      if (ret != SQLITE_OK)
4123 			  goto error;
4124 		  }
4125 
4126 		/* deleting the old INSERT trigger SPATIAL_INDEX [if any] */
4127 		raw = sqlite3_mprintf ("gii_%s_%s", p_table, p_column);
4128 		quoted_trigger = gaiaDoubleQuotedSql (raw);
4129 		sqlite3_free (raw);
4130 		sql_statement =
4131 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS main.\"%s\"",
4132 				     quoted_trigger);
4133 		free (quoted_trigger);
4134 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4135 		sqlite3_free (sql_statement);
4136 		if (ret != SQLITE_OK)
4137 		    goto error;
4138 
4139 		/* deleting the old UPDATE trigger SPATIAL_INDEX [if any] */
4140 		raw = sqlite3_mprintf ("giu_%s_%s", p_table, p_column);
4141 		quoted_trigger = gaiaDoubleQuotedSql (raw);
4142 		sqlite3_free (raw);
4143 		sql_statement =
4144 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS main.\"%s\"",
4145 				     quoted_trigger);
4146 		free (quoted_trigger);
4147 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4148 		sqlite3_free (sql_statement);
4149 		if (ret != SQLITE_OK)
4150 		    goto error;
4151 
4152 		/* deleting the old DELETE trigger SPATIAL_INDEX [if any] */
4153 		raw = sqlite3_mprintf ("gid_%s_%s", p_table, p_column);
4154 		quoted_trigger = gaiaDoubleQuotedSql (raw);
4155 		sqlite3_free (raw);
4156 		sql_statement =
4157 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS main.\"%s\"",
4158 				     quoted_trigger);
4159 		free (quoted_trigger);
4160 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4161 		sqlite3_free (sql_statement);
4162 		if (ret != SQLITE_OK)
4163 		    goto error;
4164 
4165 		/* deleting the old INSERT trigger MBR_CACHE [if any] */
4166 		raw = sqlite3_mprintf ("gci_%s_%s", p_table, p_column);
4167 		quoted_trigger = gaiaDoubleQuotedSql (raw);
4168 		sqlite3_free (raw);
4169 		sql_statement =
4170 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS main.\"%s\"",
4171 				     quoted_trigger);
4172 		free (quoted_trigger);
4173 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4174 		sqlite3_free (sql_statement);
4175 		if (ret != SQLITE_OK)
4176 		    goto error;
4177 
4178 		/* deleting the old UPDATE trigger MBR_CACHE [if any] */
4179 		raw = sqlite3_mprintf ("gcu_%s_%s", p_table, p_column);
4180 		quoted_trigger = gaiaDoubleQuotedSql (raw);
4181 		sqlite3_free (raw);
4182 		sql_statement =
4183 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS main.\"%s\"",
4184 				     quoted_trigger);
4185 		free (quoted_trigger);
4186 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4187 		sqlite3_free (sql_statement);
4188 		if (ret != SQLITE_OK)
4189 		    goto error;
4190 
4191 		/* deleting the old UPDATE trigger MBR_CACHE [if any] */
4192 		raw = sqlite3_mprintf ("gcd_%s_%s", p_table, p_column);
4193 		quoted_trigger = gaiaDoubleQuotedSql (raw);
4194 		sqlite3_free (raw);
4195 		sql_statement =
4196 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS main.\"%s\"",
4197 				     quoted_trigger);
4198 		free (quoted_trigger);
4199 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4200 		sqlite3_free (sql_statement);
4201 		if (ret != SQLITE_OK)
4202 		    goto error;
4203 
4204 		if (index)
4205 		  {
4206 		      /* inserting the new INSERT trigger RTree */
4207 		      if (metadata_version == 3)
4208 			{
4209 			    /* current metadata style >= v.4.0.0 */
4210 			    raw =
4211 				sqlite3_mprintf ("gii_%s_%s", p_table,
4212 						 p_column);
4213 			    quoted_trigger = gaiaDoubleQuotedSql (raw);
4214 			    sqlite3_free (raw);
4215 			    raw =
4216 				sqlite3_mprintf ("idx_%s_%s", p_table,
4217 						 p_column);
4218 			    quoted_rtree = gaiaDoubleQuotedSql (raw);
4219 			    quoted_table = gaiaDoubleQuotedSql (p_table);
4220 			    quoted_column = gaiaDoubleQuotedSql (p_column);
4221 			    sql_statement =
4222 				sqlite3_mprintf
4223 				("CREATE TRIGGER \"%s\" AFTER INSERT ON \"%s\"\n"
4224 				 "FOR EACH ROW BEGIN\n"
4225 				 "DELETE FROM \"%s\" WHERE pkid=NEW.ROWID;\n"
4226 				 "SELECT RTreeAlign(%Q, NEW.ROWID, NEW.\"%s\");\nEND",
4227 				 quoted_trigger, quoted_table, quoted_rtree,
4228 				 raw, quoted_column);
4229 			    sqlite3_free (raw);
4230 			    free (quoted_trigger);
4231 			    free (quoted_rtree);
4232 			    free (quoted_table);
4233 			    free (quoted_column);
4234 			}
4235 		      else
4236 			{
4237 			    /* legacy metadata style <= v.3.1.0 */
4238 			    raw =
4239 				sqlite3_mprintf ("gii_%s_%s", p_table,
4240 						 p_column);
4241 			    quoted_trigger = gaiaDoubleQuotedSql (raw);
4242 			    sqlite3_free (raw);
4243 			    raw =
4244 				sqlite3_mprintf ("idx_%s_%s", p_table,
4245 						 p_column);
4246 			    quoted_rtree = gaiaDoubleQuotedSql (raw);
4247 			    quoted_table = gaiaDoubleQuotedSql (p_table);
4248 			    quoted_column = gaiaDoubleQuotedSql (p_column);
4249 			    sql_statement =
4250 				sqlite3_mprintf
4251 				("CREATE TRIGGER \"%s\" AFTER INSERT ON \"%s\"\n"
4252 				 "FOR EACH ROW BEGIN\n"
4253 				 "DELETE FROM \"%s\" WHERE pkid=NEW.ROWID;\n"
4254 				 "SELECT RTreeAlign(%Q, NEW.ROWID, NEW.\"%s\");\nEND",
4255 				 quoted_trigger, quoted_table, quoted_rtree,
4256 				 raw, quoted_column);
4257 			    sqlite3_free (raw);
4258 			    free (quoted_trigger);
4259 			    free (quoted_rtree);
4260 			    free (quoted_table);
4261 			    free (quoted_column);
4262 			}
4263 		      ret =
4264 			  sqlite3_exec (sqlite, sql_statement, NULL, NULL,
4265 					&errMsg);
4266 		      sqlite3_free (sql_statement);
4267 		      if (ret != SQLITE_OK)
4268 			  goto error;
4269 
4270 		      /* inserting the new UPDATE trigger RTree */
4271 		      if (metadata_version == 3)
4272 			{
4273 			    /* current metadata style >= v.4.0.0 */
4274 			    raw =
4275 				sqlite3_mprintf ("giu_%s_%s", p_table,
4276 						 p_column);
4277 			    quoted_trigger = gaiaDoubleQuotedSql (raw);
4278 			    sqlite3_free (raw);
4279 			    raw =
4280 				sqlite3_mprintf ("idx_%s_%s", p_table,
4281 						 p_column);
4282 			    quoted_rtree = gaiaDoubleQuotedSql (raw);
4283 			    quoted_table = gaiaDoubleQuotedSql (p_table);
4284 			    quoted_column = gaiaDoubleQuotedSql (p_column);
4285 			    sql_statement =
4286 				sqlite3_mprintf
4287 				("CREATE TRIGGER \"%s\" AFTER UPDATE OF \"%s\" ON \"%s\"\n"
4288 				 "FOR EACH ROW BEGIN\n"
4289 				 "DELETE FROM \"%s\" WHERE pkid=NEW.ROWID;\n"
4290 				 "SELECT RTreeAlign(%Q, NEW.ROWID, NEW.\"%s\");\nEND",
4291 				 quoted_trigger, quoted_column, quoted_table,
4292 				 quoted_rtree, raw, quoted_column);
4293 			    sqlite3_free (raw);
4294 			    free (quoted_trigger);
4295 			    free (quoted_rtree);
4296 			    free (quoted_table);
4297 			    free (quoted_column);
4298 			}
4299 		      else
4300 			{
4301 			    /* legacy metadata style <= v.3.1.0 */
4302 			    raw =
4303 				sqlite3_mprintf ("giu_%s_%s", p_table,
4304 						 p_column);
4305 			    quoted_trigger = gaiaDoubleQuotedSql (raw);
4306 			    sqlite3_free (raw);
4307 			    raw =
4308 				sqlite3_mprintf ("idx_%s_%s", p_table,
4309 						 p_column);
4310 			    quoted_rtree = gaiaDoubleQuotedSql (raw);
4311 			    quoted_table = gaiaDoubleQuotedSql (p_table);
4312 			    quoted_column = gaiaDoubleQuotedSql (p_column);
4313 			    sql_statement =
4314 				sqlite3_mprintf
4315 				("CREATE TRIGGER \"%s\" AFTER UPDATE ON \"%s\"\n"
4316 				 "FOR EACH ROW BEGIN\n"
4317 				 "DELETE FROM \"%s\" WHERE pkid=NEW.ROWID;\n"
4318 				 "SELECT RTreeAlign(%Q, NEW.ROWID, NEW.\"%s\");\nEND",
4319 				 quoted_trigger, quoted_table, quoted_rtree,
4320 				 raw, quoted_column);
4321 			    sqlite3_free (raw);
4322 			    free (quoted_trigger);
4323 			    free (quoted_rtree);
4324 			    free (quoted_table);
4325 			    free (quoted_column);
4326 			}
4327 		      ret =
4328 			  sqlite3_exec (sqlite, sql_statement, NULL, NULL,
4329 					&errMsg);
4330 		      sqlite3_free (sql_statement);
4331 		      if (ret != SQLITE_OK)
4332 			  goto error;
4333 
4334 		      /* inserting the new DELETE trigger RTree */
4335 		      if (metadata_version == 3)
4336 			{
4337 			    /* current metadata style >= v.4.0.0 */
4338 			    raw =
4339 				sqlite3_mprintf ("gid_%s_%s", p_table,
4340 						 p_column);
4341 			    quoted_trigger = gaiaDoubleQuotedSql (raw);
4342 			    sqlite3_free (raw);
4343 			    raw =
4344 				sqlite3_mprintf ("idx_%s_%s", p_table,
4345 						 p_column);
4346 			    quoted_rtree = gaiaDoubleQuotedSql (raw);
4347 			    sqlite3_free (raw);
4348 			    quoted_table = gaiaDoubleQuotedSql (p_table);
4349 			    quoted_column = gaiaDoubleQuotedSql (p_column);
4350 			    sql_statement =
4351 				sqlite3_mprintf
4352 				("CREATE TRIGGER \"%s\" AFTER DELETE ON \"%s\"\n"
4353 				 "FOR EACH ROW BEGIN\n"
4354 				 "DELETE FROM \"%s\" WHERE pkid=OLD.ROWID;\nEND",
4355 				 quoted_trigger, quoted_table, quoted_rtree);
4356 			    free (quoted_trigger);
4357 			    free (quoted_rtree);
4358 			    free (quoted_table);
4359 			    free (quoted_column);
4360 			}
4361 		      else
4362 			{
4363 			    /* legacy metadata style <= v.3.1.0 */
4364 			    raw =
4365 				sqlite3_mprintf ("gid_%s_%s", p_table,
4366 						 p_column);
4367 			    quoted_trigger = gaiaDoubleQuotedSql (raw);
4368 			    sqlite3_free (raw);
4369 			    raw =
4370 				sqlite3_mprintf ("idx_%s_%s", p_table,
4371 						 p_column);
4372 			    quoted_rtree = gaiaDoubleQuotedSql (raw);
4373 			    sqlite3_free (raw);
4374 			    quoted_table = gaiaDoubleQuotedSql (p_table);
4375 			    quoted_column = gaiaDoubleQuotedSql (p_column);
4376 			    sql_statement =
4377 				sqlite3_mprintf
4378 				("CREATE TRIGGER \"%s\" AFTER DELETE ON \"%s\"\n"
4379 				 "FOR EACH ROW BEGIN\n"
4380 				 "DELETE FROM \"%s\" WHERE pkid=OLD.ROWID;\nEND",
4381 				 quoted_trigger, quoted_table, quoted_rtree);
4382 			    free (quoted_trigger);
4383 			    free (quoted_rtree);
4384 			    free (quoted_table);
4385 			    free (quoted_column);
4386 			}
4387 		      ret =
4388 			  sqlite3_exec (sqlite, sql_statement, NULL, NULL,
4389 					&errMsg);
4390 		      sqlite3_free (sql_statement);
4391 		      if (ret != SQLITE_OK)
4392 			  goto error;
4393 		  }
4394 
4395 		if (cached)
4396 		  {
4397 		      /* inserting the new INSERT trigger MBRcache */
4398 		      if (metadata_version == 3)
4399 			{
4400 			    /* current metadata style >= v.4.0.0 */
4401 			    raw =
4402 				sqlite3_mprintf ("gci_%s_%s", p_table,
4403 						 p_column);
4404 			    quoted_trigger = gaiaDoubleQuotedSql (raw);
4405 			    sqlite3_free (raw);
4406 			    raw =
4407 				sqlite3_mprintf ("cache_%s_%s", p_table,
4408 						 p_column);
4409 			    quoted_rtree = gaiaDoubleQuotedSql (raw);
4410 			    sqlite3_free (raw);
4411 			    quoted_table = gaiaDoubleQuotedSql (p_table);
4412 			    quoted_column = gaiaDoubleQuotedSql (p_column);
4413 			    sql_statement =
4414 				sqlite3_mprintf
4415 				("CREATE TRIGGER \"%s\" AFTER INSERT ON \"%s\"\n"
4416 				 "FOR EACH ROW BEGIN\n"
4417 				 "INSERT INTO \"%s\" (rowid, mbr) VALUES (NEW.ROWID,\nBuildMbrFilter("
4418 				 "MbrMinX(NEW.\"%s\"), MbrMinY(NEW.\"%s\"), MbrMaxX(NEW.\"%s\"), MbrMaxY(NEW.\"%s\")));\nEND",
4419 				 quoted_trigger, quoted_table, quoted_rtree,
4420 				 quoted_column, quoted_column, quoted_column,
4421 				 quoted_column);
4422 			    free (quoted_trigger);
4423 			    free (quoted_rtree);
4424 			    free (quoted_table);
4425 			    free (quoted_column);
4426 			}
4427 		      else
4428 			{
4429 			    /* legacy metadata style <= v.3.1.0 */
4430 			    raw =
4431 				sqlite3_mprintf ("gci_%s_%s", p_table,
4432 						 p_column);
4433 			    quoted_trigger = gaiaDoubleQuotedSql (raw);
4434 			    sqlite3_free (raw);
4435 			    raw =
4436 				sqlite3_mprintf ("cache_%s_%s", p_table,
4437 						 p_column);
4438 			    quoted_rtree = gaiaDoubleQuotedSql (raw);
4439 			    sqlite3_free (raw);
4440 			    quoted_table = gaiaDoubleQuotedSql (p_table);
4441 			    quoted_column = gaiaDoubleQuotedSql (p_column);
4442 			    sql_statement =
4443 				sqlite3_mprintf
4444 				("CREATE TRIGGER \"%s\" AFTER INSERT ON \"%s\"\n"
4445 				 "FOR EACH ROW BEGIN\n"
4446 				 "INSERT INTO \"%s\" (rowid, mbr) VALUES (NEW.ROWID,\nBuildMbrFilter("
4447 				 "MbrMinX(NEW.\"%s\"), MbrMinY(NEW.\"%s\"), MbrMaxX(NEW.\"%s\"), MbrMaxY(NEW.\"%s\")));\nEND",
4448 				 quoted_trigger, quoted_table, quoted_rtree,
4449 				 quoted_column, quoted_column, quoted_column,
4450 				 quoted_column);
4451 			    free (quoted_trigger);
4452 			    free (quoted_rtree);
4453 			    free (quoted_table);
4454 			    free (quoted_column);
4455 			}
4456 		      ret =
4457 			  sqlite3_exec (sqlite, sql_statement, NULL, NULL,
4458 					&errMsg);
4459 		      sqlite3_free (sql_statement);
4460 		      if (ret != SQLITE_OK)
4461 			  goto error;
4462 
4463 		      /* inserting the new UPDATE trigger MBRcache */
4464 		      if (metadata_version == 3)
4465 			{
4466 			    /* current metadata style >= v.4.0.0 */
4467 			    raw =
4468 				sqlite3_mprintf ("gcu_%s_%s", p_table,
4469 						 p_column);
4470 			    quoted_trigger = gaiaDoubleQuotedSql (raw);
4471 			    sqlite3_free (raw);
4472 			    raw =
4473 				sqlite3_mprintf ("cache_%s_%s", p_table,
4474 						 p_column);
4475 			    quoted_rtree = gaiaDoubleQuotedSql (raw);
4476 			    sqlite3_free (raw);
4477 			    quoted_table = gaiaDoubleQuotedSql (p_table);
4478 			    quoted_column = gaiaDoubleQuotedSql (p_column);
4479 			    sql_statement =
4480 				sqlite3_mprintf
4481 				("CREATE TRIGGER \"%s\" AFTER UPDATE OF \"%s\" ON \"%s\"\n"
4482 				 "FOR EACH ROW BEGIN\n"
4483 				 "UPDATE \"%s\" SET mbr = BuildMbrFilter("
4484 				 "MbrMinX(NEW.\"%s\"), MbrMinY(NEW.\"%s\"), MbrMaxX(NEW.\"%s\"), MbrMaxY(NEW.\"%s\"))\n"
4485 				 "WHERE rowid = NEW.ROWID;\nEND",
4486 				 quoted_trigger, quoted_column, quoted_table,
4487 				 quoted_rtree, quoted_column, quoted_column,
4488 				 quoted_column, quoted_column);
4489 			    free (quoted_trigger);
4490 			    free (quoted_rtree);
4491 			    free (quoted_table);
4492 			    free (quoted_column);
4493 			}
4494 		      else
4495 			{
4496 			    /* legacy metadata style <= v.3.1.0 */
4497 			    raw =
4498 				sqlite3_mprintf ("gcu_%s_%s", p_table,
4499 						 p_column);
4500 			    quoted_trigger = gaiaDoubleQuotedSql (raw);
4501 			    sqlite3_free (raw);
4502 			    raw =
4503 				sqlite3_mprintf ("cache_%s_%s", p_table,
4504 						 p_column);
4505 			    quoted_rtree = gaiaDoubleQuotedSql (raw);
4506 			    sqlite3_free (raw);
4507 			    quoted_table = gaiaDoubleQuotedSql (p_table);
4508 			    quoted_column = gaiaDoubleQuotedSql (p_column);
4509 			    sql_statement =
4510 				sqlite3_mprintf
4511 				("CREATE TRIGGER \"%s\" AFTER UPDATE ON \"%s\"\n"
4512 				 "FOR EACH ROW BEGIN\n"
4513 				 "UPDATE \"%s\" SET mbr = BuildMbrFilter("
4514 				 "MbrMinX(NEW.\"%s\"), MbrMinY(NEW.\"%s\"), MbrMaxX(NEW.\"%s\"), MbrMaxY(NEW.\"%s\"))\n"
4515 				 "WHERE rowid = NEW.ROWID;\nEND",
4516 				 quoted_trigger, quoted_table, quoted_rtree,
4517 				 quoted_column, quoted_column, quoted_column,
4518 				 quoted_column);
4519 			    free (quoted_trigger);
4520 			    free (quoted_rtree);
4521 			    free (quoted_table);
4522 			    free (quoted_column);
4523 			}
4524 		      ret =
4525 			  sqlite3_exec (sqlite, sql_statement, NULL, NULL,
4526 					&errMsg);
4527 		      sqlite3_free (sql_statement);
4528 		      if (ret != SQLITE_OK)
4529 			  goto error;
4530 
4531 		      /* inserting the new DELETE trigger MBRcache */
4532 		      if (metadata_version == 3)
4533 			{
4534 			    /* current metadata style >= v.4.0.0 */
4535 			    raw =
4536 				sqlite3_mprintf ("gcd_%s_%s", p_table,
4537 						 p_column);
4538 			    quoted_trigger = gaiaDoubleQuotedSql (raw);
4539 			    sqlite3_free (raw);
4540 			    raw =
4541 				sqlite3_mprintf ("cache_%s_%s", p_table,
4542 						 p_column);
4543 			    quoted_rtree = gaiaDoubleQuotedSql (raw);
4544 			    sqlite3_free (raw);
4545 			    quoted_table = gaiaDoubleQuotedSql (p_table);
4546 			    sql_statement =
4547 				sqlite3_mprintf
4548 				("CREATE TRIGGER \"%s\" AFTER DELETE ON \"%s\"\n"
4549 				 "FOR EACH ROW BEGIN\n"
4550 				 "DELETE FROM \"%s\" WHERE rowid = OLD.ROWID;\nEND",
4551 				 quoted_trigger, quoted_table, quoted_rtree);
4552 			    free (quoted_trigger);
4553 			    free (quoted_rtree);
4554 			    free (quoted_table);
4555 			}
4556 		      else
4557 			{
4558 			    /* legacy metadata style <= v.3.1.0 */
4559 			    raw =
4560 				sqlite3_mprintf ("gcd_%s_%s", p_table,
4561 						 p_column);
4562 			    quoted_trigger = gaiaDoubleQuotedSql (raw);
4563 			    sqlite3_free (raw);
4564 			    raw =
4565 				sqlite3_mprintf ("cache_%s_%s", p_table,
4566 						 p_column);
4567 			    quoted_rtree = gaiaDoubleQuotedSql (raw);
4568 			    sqlite3_free (raw);
4569 			    quoted_table = gaiaDoubleQuotedSql (p_table);
4570 			    quoted_column = gaiaDoubleQuotedSql (p_column);
4571 			    sql_statement =
4572 				sqlite3_mprintf
4573 				("CREATE TRIGGER \"%s\" AFTER DELETE ON \"%s\"\n"
4574 				 "FOR EACH ROW BEGIN\n"
4575 				 "DELETE FROM \"%s\" WHERE rowid = OLD.ROWID;\nEND",
4576 				 quoted_trigger, quoted_table, quoted_rtree);
4577 			    free (quoted_trigger);
4578 			    free (quoted_rtree);
4579 			    free (quoted_table);
4580 			}
4581 		      ret =
4582 			  sqlite3_exec (sqlite, sql_statement, NULL, NULL,
4583 					&errMsg);
4584 		      sqlite3_free (sql_statement);
4585 		      if (ret != SQLITE_OK)
4586 			  goto error;
4587 		  }
4588 
4589 	    }
4590       }
4591     ret = sqlite3_finalize (stmt);
4592 /* now we'll adjust any related SpatialIndex as required */
4593     curr_idx = first_idx;
4594     while (curr_idx)
4595       {
4596 	  if (curr_idx->ValidRtree)
4597 	    {
4598 		/* building RTree SpatialIndex */
4599 		int status;
4600 		raw = sqlite3_mprintf ("idx_%s_%s", curr_idx->TableName,
4601 				       curr_idx->ColumnName);
4602 		quoted_rtree = gaiaDoubleQuotedSql (raw);
4603 		sqlite3_free (raw);
4604 		sql_statement = sqlite3_mprintf ("CREATE VIRTUAL TABLE \"%s\" "
4605 						 "USING rtree(pkid, xmin, xmax, ymin, ymax)",
4606 						 quoted_rtree);
4607 		free (quoted_rtree);
4608 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4609 		sqlite3_free (sql_statement);
4610 		if (ret != SQLITE_OK)
4611 		    goto error;
4612 		status = buildSpatialIndexEx (sqlite,
4613 					      (unsigned char
4614 					       *) (curr_idx->TableName),
4615 					      curr_idx->ColumnName);
4616 		if (status == 0)
4617 		    ;
4618 		else
4619 		  {
4620 		      if (status == -2)
4621 			  errMsg =
4622 			      sqlite3_mprintf
4623 			      ("SpatialIndex error: a physical column named ROWID shadows the real ROWID");
4624 		      else
4625 			  errMsg =
4626 			      sqlite3_mprintf
4627 			      ("SpatialIndex error: unable to rebuild the T*Tree");
4628 		      goto error;
4629 		  }
4630 	    }
4631 	  if (curr_idx->ValidCache)
4632 	    {
4633 		/* building MbrCache SpatialIndex */
4634 		raw = sqlite3_mprintf ("cache_%s_%s", curr_idx->TableName,
4635 				       curr_idx->ColumnName);
4636 		quoted_rtree = gaiaDoubleQuotedSql (raw);
4637 		sqlite3_free (raw);
4638 		quoted_table = gaiaDoubleQuotedSql (curr_idx->TableName);
4639 		quoted_column = gaiaDoubleQuotedSql (curr_idx->ColumnName);
4640 		sql_statement = sqlite3_mprintf ("CREATE VIRTUAL TABLE \"%s\" "
4641 						 "USING MbrCache(\"%s\", \"%s\")",
4642 						 quoted_rtree, quoted_table,
4643 						 quoted_column);
4644 		free (quoted_rtree);
4645 		free (quoted_table);
4646 		free (quoted_column);
4647 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4648 		sqlite3_free (sql_statement);
4649 		if (ret != SQLITE_OK)
4650 		    goto error;
4651 	    }
4652 	  curr_idx = curr_idx->Next;
4653       }
4654     goto index_cleanup;
4655   error:
4656     spatialite_e ("updateTableTriggers: \"%s\"\n", errMsg);
4657     sqlite3_free (errMsg);
4658   index_cleanup:
4659     curr_idx = first_idx;
4660     while (curr_idx)
4661       {
4662 	  next_idx = curr_idx->Next;
4663 	  if (curr_idx->TableName)
4664 	      free (curr_idx->TableName);
4665 	  if (curr_idx->ColumnName)
4666 	      free (curr_idx->ColumnName);
4667 	  free (curr_idx);
4668 	  curr_idx = next_idx;
4669       }
4670     if (p_table)
4671 	free (p_table);
4672     if (p_column)
4673 	free (p_column);
4674 }
4675 
4676 SPATIALITE_PRIVATE void
updateTemporaryGeometryTriggers(void * p_sqlite,const char * db_prefix,const char * table,const char * column)4677 updateTemporaryGeometryTriggers (void *p_sqlite, const char *db_prefix,
4678 				 const char *table, const char *column)
4679 {
4680 /* updates triggers for some Spatial Column - only on Attached DB based on :memory: */
4681     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
4682     int ret;
4683     int col_index;
4684     int index;
4685     int len;
4686     char *errMsg = NULL;
4687     char *sql_statement;
4688     char *raw;
4689     char *quoted_trigger;
4690     char *quoted_rtree;
4691     char *quoted_prefix;
4692     char *quoted_table;
4693     char *quoted_column;
4694     char *p_table = NULL;
4695     char *p_column = NULL;
4696     sqlite3_stmt *stmt;
4697     struct spatial_index_str *first_idx = NULL;
4698     struct spatial_index_str *last_idx = NULL;
4699     struct spatial_index_str *curr_idx;
4700     struct spatial_index_str *next_idx;
4701 
4702     if (!getRealSQLnamesTemporary
4703 	(sqlite, db_prefix, table, column, &p_table, &p_column))
4704       {
4705 	  spatialite_e
4706 	      ("updateTemporaryTableTriggers() error: not existing Table or Column\n");
4707 	  return;
4708       }
4709     quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
4710     sql_statement = sqlite3_mprintf ("SELECT spatial_index_enabled "
4711 				     "FROM \"%s\".geometry_columns WHERE Lower(f_table_name) = Lower(?) "
4712 				     "AND Lower(f_geometry_column) = Lower(?)",
4713 				     quoted_prefix);
4714     free (quoted_prefix);
4715 /* compiling SQL prepared statement */
4716     ret =
4717 	sqlite3_prepare_v2 (sqlite, sql_statement, strlen (sql_statement),
4718 			    &stmt, NULL);
4719     sqlite3_free (sql_statement);
4720     if (ret != SQLITE_OK)
4721       {
4722 	  spatialite_e ("updateTemporaryTableTriggers: error %d \"%s\"\n",
4723 			sqlite3_errcode (sqlite), sqlite3_errmsg (sqlite));
4724 	  return;
4725       }
4726     sqlite3_reset (stmt);
4727     sqlite3_clear_bindings (stmt);
4728     sqlite3_bind_text (stmt, 1, table, strlen (table), SQLITE_STATIC);
4729     sqlite3_bind_text (stmt, 2, column, strlen (column), SQLITE_STATIC);
4730     while (1)
4731       {
4732 	  /* scrolling the result set rows */
4733 	  ret = sqlite3_step (stmt);
4734 	  if (ret == SQLITE_DONE)
4735 	      break;		/* end of result set */
4736 	  if (ret == SQLITE_ROW)
4737 	    {
4738 		col_index = sqlite3_column_int (stmt, 0);
4739 		index = 0;
4740 		if (col_index == 1)
4741 		    index = 1;
4742 
4743 		/* deleting the old INSERT trigger TYPE [if any] */
4744 		raw = sqlite3_mprintf ("ggi_%s_%s", p_table, p_column);
4745 		quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
4746 		quoted_trigger = gaiaDoubleQuotedSql (raw);
4747 		sqlite3_free (raw);
4748 		sql_statement =
4749 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS \"%s\".\"%s\"",
4750 				     quoted_prefix, quoted_trigger);
4751 		free (quoted_prefix);
4752 		free (quoted_trigger);
4753 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4754 		sqlite3_free (sql_statement);
4755 		if (ret != SQLITE_OK)
4756 		    goto error;
4757 
4758 		/* inserting the INSERT trigger TYPE */
4759 		raw = sqlite3_mprintf ("ggi_%s_%s", p_table, p_column);
4760 		quoted_trigger = gaiaDoubleQuotedSql (raw);
4761 		sqlite3_free (raw);
4762 		quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
4763 		quoted_table = gaiaDoubleQuotedSql (p_table);
4764 		quoted_column = gaiaDoubleQuotedSql (p_column);
4765 		sql_statement =
4766 		    sqlite3_mprintf
4767 		    ("CREATE TRIGGER \"%s\".\"%s\" BEFORE INSERT ON \"%s\"\n"
4768 		     "FOR EACH ROW BEGIN\n"
4769 		     "SELECT RAISE(ROLLBACK, '%q.%q violates Geometry constraint [geom-type or SRID not allowed]')\n"
4770 		     "WHERE (SELECT geometry_type FROM \"%s\".geometry_columns\n"
4771 		     "WHERE Lower(f_table_name) = Lower(%Q) AND "
4772 		     "Lower(f_geometry_column) = Lower(%Q)\n"
4773 		     "AND GeometryConstraints(NEW.\"%s\", geometry_type, srid) = 1) IS NULL;\nEND",
4774 		     quoted_prefix, quoted_trigger, quoted_table, p_table,
4775 		     p_column, db_prefix, p_table, p_column, quoted_column);
4776 		free (quoted_prefix);
4777 		free (quoted_trigger);
4778 		free (quoted_table);
4779 		free (quoted_column);
4780 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4781 		sqlite3_free (sql_statement);
4782 		if (ret != SQLITE_OK)
4783 		    goto error;
4784 
4785 		/* deleting the old UPDATE trigger TYPE [if any] */
4786 		raw = sqlite3_mprintf ("ggu_%s_%s", p_table, p_column);
4787 		quoted_trigger = gaiaDoubleQuotedSql (raw);
4788 		quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
4789 		sqlite3_free (raw);
4790 		sql_statement =
4791 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS \"%s\".\"%s\"",
4792 				     quoted_prefix, quoted_trigger);
4793 		free (quoted_prefix);
4794 		free (quoted_trigger);
4795 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4796 		sqlite3_free (sql_statement);
4797 		if (ret != SQLITE_OK)
4798 		    goto error;
4799 
4800 		/* inserting the new UPDATE trigger TYPE */
4801 		raw = sqlite3_mprintf ("ggu_%s_%s", p_table, p_column);
4802 		quoted_trigger = gaiaDoubleQuotedSql (raw);
4803 		sqlite3_free (raw);
4804 		quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
4805 		quoted_table = gaiaDoubleQuotedSql (p_table);
4806 		quoted_column = gaiaDoubleQuotedSql (p_column);
4807 		sql_statement =
4808 		    sqlite3_mprintf
4809 		    ("CREATE TRIGGER \"%s\".\"%s\" BEFORE UPDATE OF \"%s\" ON \"%s\"\n"
4810 		     "FOR EACH ROW BEGIN\n"
4811 		     "SELECT RAISE(ROLLBACK, '%q.%q violates Geometry constraint [geom-type or SRID not allowed]')\n"
4812 		     "WHERE (SELECT geometry_type FROM \"%s\".geometry_columns\n"
4813 		     "WHERE Lower(f_table_name) = Lower(%Q) AND "
4814 		     "Lower(f_geometry_column) = Lower(%Q)\n"
4815 		     "AND GeometryConstraints(NEW.\"%s\", geometry_type, srid) = 1) IS NULL;\nEND",
4816 		     quoted_prefix, quoted_trigger, quoted_column, quoted_table,
4817 		     p_table, p_column, db_prefix, p_table, p_column,
4818 		     quoted_column);
4819 		free (quoted_prefix);
4820 		free (quoted_trigger);
4821 		free (quoted_table);
4822 		free (quoted_column);
4823 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4824 		sqlite3_free (sql_statement);
4825 		if (ret != SQLITE_OK)
4826 		    goto error;
4827 
4828 		/* inserting SpatialIndex information into the linked list */
4829 		curr_idx = malloc (sizeof (struct spatial_index_str));
4830 		len = strlen (p_table);
4831 		curr_idx->TableName = malloc (len + 1);
4832 		strcpy (curr_idx->TableName, p_table);
4833 		len = strlen (p_column);
4834 		curr_idx->ColumnName = malloc (len + 1);
4835 		strcpy (curr_idx->ColumnName, p_column);
4836 		curr_idx->ValidRtree = (char) index;
4837 		curr_idx->ValidCache = '\0';
4838 		curr_idx->Next = NULL;
4839 		if (!first_idx)
4840 		    first_idx = curr_idx;
4841 		if (last_idx)
4842 		    last_idx->Next = curr_idx;
4843 		last_idx = curr_idx;
4844 
4845 		/* deleting the old INSERT trigger SPATIAL_INDEX [if any] */
4846 		raw = sqlite3_mprintf ("gii_%s_%s", p_table, p_column);
4847 		quoted_trigger = gaiaDoubleQuotedSql (raw);
4848 		quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
4849 		sqlite3_free (raw);
4850 		sql_statement =
4851 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS \"%s\".\"%s\"",
4852 				     quoted_prefix, quoted_trigger);
4853 		free (quoted_prefix);
4854 		free (quoted_trigger);
4855 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4856 		sqlite3_free (sql_statement);
4857 		if (ret != SQLITE_OK)
4858 		    goto error;
4859 
4860 
4861 		/* deleting the old UPDATE trigger SPATIAL_INDEX [if any] */
4862 		raw = sqlite3_mprintf ("giu_%s_%s", p_table, p_column);
4863 		quoted_trigger = gaiaDoubleQuotedSql (raw);
4864 		quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
4865 		sqlite3_free (raw);
4866 		sql_statement =
4867 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS \"%s\".\"%s\"",
4868 				     quoted_prefix, quoted_trigger);
4869 		free (quoted_prefix);
4870 		free (quoted_trigger);
4871 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4872 		sqlite3_free (sql_statement);
4873 		if (ret != SQLITE_OK)
4874 		    goto error;
4875 
4876 		/* deleting the old DELETE trigger SPATIAL_INDEX [if any] */
4877 		raw = sqlite3_mprintf ("gid_%s_%s", p_table, p_column);
4878 		quoted_trigger = gaiaDoubleQuotedSql (raw);
4879 		quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
4880 		sqlite3_free (raw);
4881 		sql_statement =
4882 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS \"%s\".\"%s\"",
4883 				     quoted_prefix, quoted_trigger);
4884 		free (quoted_prefix);
4885 		free (quoted_trigger);
4886 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4887 		sqlite3_free (sql_statement);
4888 		if (ret != SQLITE_OK)
4889 		    goto error;
4890 
4891 		/* deleting the old INSERT trigger MBR_CACHE [if any] */
4892 		raw = sqlite3_mprintf ("gci_%s_%s", p_table, p_column);
4893 		quoted_trigger = gaiaDoubleQuotedSql (raw);
4894 		quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
4895 		sqlite3_free (raw);
4896 		sql_statement =
4897 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS \"%s\".\"%s\"",
4898 				     quoted_prefix, quoted_trigger);
4899 		free (quoted_prefix);
4900 		free (quoted_trigger);
4901 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4902 		sqlite3_free (sql_statement);
4903 		if (ret != SQLITE_OK)
4904 		    goto error;
4905 
4906 		/* deleting the old UPDATE trigger MBR_CACHE [if any] */
4907 		raw = sqlite3_mprintf ("gcu_%s_%s", p_table, p_column);
4908 		quoted_trigger = gaiaDoubleQuotedSql (raw);
4909 		quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
4910 		sqlite3_free (raw);
4911 		sql_statement =
4912 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS \"%s\".\"%s\"",
4913 				     quoted_prefix, quoted_trigger);
4914 		free (quoted_prefix);
4915 		free (quoted_trigger);
4916 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4917 		sqlite3_free (sql_statement);
4918 		if (ret != SQLITE_OK)
4919 		    goto error;
4920 
4921 		/* deleting the old UPDATE trigger MBR_CACHE [if any] */
4922 		raw = sqlite3_mprintf ("gcd_%s_%s", p_table, p_column);
4923 		quoted_trigger = gaiaDoubleQuotedSql (raw);
4924 		quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
4925 		sqlite3_free (raw);
4926 		sql_statement =
4927 		    sqlite3_mprintf ("DROP TRIGGER IF EXISTS \"%s\".\"%s\"",
4928 				     quoted_prefix, quoted_trigger);
4929 		free (quoted_prefix);
4930 		free (quoted_trigger);
4931 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
4932 		sqlite3_free (sql_statement);
4933 		if (ret != SQLITE_OK)
4934 		    goto error;
4935 
4936 		if (index)
4937 		  {
4938 		      /* inserting the new INSERT trigger RTree */
4939 		      raw = sqlite3_mprintf ("gii_%s_%s", p_table, p_column);
4940 		      quoted_trigger = gaiaDoubleQuotedSql (raw);
4941 		      sqlite3_free (raw);
4942 		      raw = sqlite3_mprintf ("idx_%s_%s", p_table, p_column);
4943 		      quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
4944 		      quoted_rtree = gaiaDoubleQuotedSql (raw);
4945 		      quoted_table = gaiaDoubleQuotedSql (p_table);
4946 		      quoted_column = gaiaDoubleQuotedSql (p_column);
4947 		      sql_statement =
4948 			  sqlite3_mprintf
4949 			  ("CREATE TRIGGER \"%s\".\"%s\" AFTER INSERT ON \"%s\"\n"
4950 			   "FOR EACH ROW BEGIN\n"
4951 			   "DELETE FROM \"%s\" WHERE pkid=NEW.ROWID;\n"
4952 			   "SELECT TemporaryRTreeAlign(%Q, %Q, NEW.ROWID, NEW.\"%s\");\nEND",
4953 			   quoted_prefix, quoted_trigger, quoted_table,
4954 			   quoted_rtree, db_prefix, raw, quoted_column);
4955 		      sqlite3_free (raw);
4956 		      free (quoted_prefix);
4957 		      free (quoted_trigger);
4958 		      free (quoted_rtree);
4959 		      free (quoted_table);
4960 		      free (quoted_column);
4961 		      ret =
4962 			  sqlite3_exec (sqlite, sql_statement, NULL, NULL,
4963 					&errMsg);
4964 		      sqlite3_free (sql_statement);
4965 		      if (ret != SQLITE_OK)
4966 			  goto error;
4967 
4968 		      /* inserting the new UPDATE trigger RTree */
4969 		      raw = sqlite3_mprintf ("giu_%s_%s", p_table, p_column);
4970 		      quoted_trigger = gaiaDoubleQuotedSql (raw);
4971 		      sqlite3_free (raw);
4972 		      raw = sqlite3_mprintf ("idx_%s_%s", p_table, p_column);
4973 		      quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
4974 		      quoted_rtree = gaiaDoubleQuotedSql (raw);
4975 		      quoted_table = gaiaDoubleQuotedSql (p_table);
4976 		      quoted_column = gaiaDoubleQuotedSql (p_column);
4977 		      sql_statement =
4978 			  sqlite3_mprintf
4979 			  ("CREATE TRIGGER \"%s\".\"%s\" AFTER UPDATE OF \"%s\" ON \"%s\"\n"
4980 			   "FOR EACH ROW BEGIN\n"
4981 			   "DELETE FROM \"%s\" WHERE pkid=NEW.ROWID;\n"
4982 			   "SELECT TemporaryRTreeAlign(%Q, %Q, NEW.ROWID, NEW.\"%s\");\nEND",
4983 			   quoted_prefix, quoted_trigger, quoted_column,
4984 			   quoted_table, quoted_rtree, db_prefix, raw,
4985 			   quoted_column);
4986 		      sqlite3_free (raw);
4987 		      free (quoted_prefix);
4988 		      free (quoted_trigger);
4989 		      free (quoted_rtree);
4990 		      free (quoted_table);
4991 		      free (quoted_column);
4992 		      ret =
4993 			  sqlite3_exec (sqlite, sql_statement, NULL, NULL,
4994 					&errMsg);
4995 		      sqlite3_free (sql_statement);
4996 		      if (ret != SQLITE_OK)
4997 			  goto error;
4998 
4999 		      /* inserting the new DELETE trigger RTree */
5000 		      raw = sqlite3_mprintf ("gid_%s_%s", p_table, p_column);
5001 		      quoted_trigger = gaiaDoubleQuotedSql (raw);
5002 		      sqlite3_free (raw);
5003 		      raw = sqlite3_mprintf ("idx_%s_%s", p_table, p_column);
5004 		      quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
5005 		      quoted_rtree = gaiaDoubleQuotedSql (raw);
5006 		      sqlite3_free (raw);
5007 		      quoted_table = gaiaDoubleQuotedSql (p_table);
5008 		      quoted_column = gaiaDoubleQuotedSql (p_column);
5009 		      sql_statement =
5010 			  sqlite3_mprintf
5011 			  ("CREATE TRIGGER \"%s\".\"%s\" AFTER DELETE ON \"%s\"\n"
5012 			   "FOR EACH ROW BEGIN\n"
5013 			   "DELETE FROM \"%s\" WHERE pkid=OLD.ROWID;\nEND",
5014 			   quoted_prefix, quoted_trigger, quoted_table,
5015 			   quoted_rtree);
5016 		      free (quoted_prefix);
5017 		      free (quoted_trigger);
5018 		      free (quoted_rtree);
5019 		      free (quoted_table);
5020 		      free (quoted_column);
5021 		      ret =
5022 			  sqlite3_exec (sqlite, sql_statement, NULL, NULL,
5023 					&errMsg);
5024 		      sqlite3_free (sql_statement);
5025 		      if (ret != SQLITE_OK)
5026 			  goto error;
5027 		  }
5028 	    }
5029       }
5030     ret = sqlite3_finalize (stmt);
5031 /* now we'll adjust any related SpatialIndex as required */
5032     curr_idx = first_idx;
5033     while (curr_idx)
5034       {
5035 	  if (curr_idx->ValidRtree)
5036 	    {
5037 		/* building RTree SpatialIndex */
5038 		int status;
5039 		raw = sqlite3_mprintf ("idx_%s_%s", curr_idx->TableName,
5040 				       curr_idx->ColumnName);
5041 		quoted_rtree = gaiaDoubleQuotedSql (raw);
5042 		quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
5043 		sqlite3_free (raw);
5044 		sql_statement =
5045 		    sqlite3_mprintf ("CREATE VIRTUAL TABLE \"%s\".\"%s\" "
5046 				     "USING rtree(pkid, xmin, xmax, ymin, ymax)",
5047 				     quoted_prefix, quoted_rtree);
5048 		free (quoted_prefix);
5049 		free (quoted_rtree);
5050 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
5051 		sqlite3_free (sql_statement);
5052 		if (ret != SQLITE_OK)
5053 		    goto error;
5054 		status = buildTemporarySpatialIndex (sqlite, db_prefix,
5055 						     (unsigned char
5056 						      *) (curr_idx->TableName),
5057 						     curr_idx->ColumnName);
5058 		if (status == 0)
5059 		    ;
5060 		else
5061 		  {
5062 		      if (status == -2)
5063 			  errMsg =
5064 			      sqlite3_mprintf
5065 			      ("TemporarySpatialIndex error: a physical column named ROWID shadows the real ROWID");
5066 		      else
5067 			  errMsg =
5068 			      sqlite3_mprintf
5069 			      ("TemporarySpatialIndex error: unable to rebuild the T*Tree");
5070 		      goto error;
5071 		  }
5072 	    }
5073 	  if (curr_idx->ValidCache)
5074 	    {
5075 		/* building MbrCache SpatialIndex */
5076 		raw = sqlite3_mprintf ("cache_%s_%s", curr_idx->TableName,
5077 				       curr_idx->ColumnName);
5078 		quoted_rtree = gaiaDoubleQuotedSql (raw);
5079 		sqlite3_free (raw);
5080 		quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
5081 		quoted_table = gaiaDoubleQuotedSql (curr_idx->TableName);
5082 		quoted_column = gaiaDoubleQuotedSql (curr_idx->ColumnName);
5083 		sql_statement =
5084 		    sqlite3_mprintf ("CREATE VIRTUAL TABLE \"%s\".\"%s\" "
5085 				     "USING MbrCache(\"%s\", \"%s\")",
5086 				     quoted_prefix, quoted_rtree, quoted_table,
5087 				     quoted_column);
5088 		free (quoted_prefix);
5089 		free (quoted_rtree);
5090 		free (quoted_table);
5091 		free (quoted_column);
5092 		ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
5093 		sqlite3_free (sql_statement);
5094 		if (ret != SQLITE_OK)
5095 		    goto error;
5096 	    }
5097 	  curr_idx = curr_idx->Next;
5098       }
5099     goto index_cleanup;
5100   error:
5101     spatialite_e ("updateTemporaryTableTriggers: \"%s\"\n", errMsg);
5102     sqlite3_free (errMsg);
5103   index_cleanup:
5104     curr_idx = first_idx;
5105     while (curr_idx)
5106       {
5107 	  next_idx = curr_idx->Next;
5108 	  if (curr_idx->TableName)
5109 	      free (curr_idx->TableName);
5110 	  if (curr_idx->ColumnName)
5111 	      free (curr_idx->ColumnName);
5112 	  free (curr_idx);
5113 	  curr_idx = next_idx;
5114       }
5115     if (p_table)
5116 	free (p_table);
5117     if (p_column)
5118 	free (p_column);
5119 }
5120 
5121 SPATIALITE_PRIVATE void
buildSpatialIndex(void * p_sqlite,const unsigned char * table,const char * column)5122 buildSpatialIndex (void *p_sqlite, const unsigned char *table,
5123 		   const char *column)
5124 {
5125 /* DEPRECATED - always use buildSpatialIndexEx as a safer replacement */
5126     buildSpatialIndexEx (p_sqlite, table, column);
5127 }
5128 
5129 SPATIALITE_PRIVATE int
validateRowid(void * p_sqlite,const char * table)5130 validateRowid (void *p_sqlite, const char *table)
5131 {
5132 /* check for tables containing a physical column named ROWID */
5133     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
5134     int rowid = 0;
5135     char *sql;
5136     int ret;
5137     const char *name;
5138     const char *type;
5139     const char *pk;
5140     int rowid_pk = 0;
5141     int int_pk = 0;
5142     int pk_cols = 0;
5143     int i;
5144     char **results;
5145     int rows;
5146     int columns;
5147     char *quoted_table = gaiaDoubleQuotedSql (table);
5148     sql = sqlite3_mprintf ("PRAGMA table_info(\"%s\")", quoted_table);
5149     ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, NULL);
5150     sqlite3_free (sql);
5151     free (quoted_table);
5152     if (ret != SQLITE_OK)
5153 	return 0;
5154     if (rows < 1)
5155 	;
5156     else
5157       {
5158 	  for (i = 1; i <= rows; i++)
5159 	    {
5160 		name = results[(i * columns) + 1];
5161 		if (strcasecmp (name, "rowid") == 0)
5162 		    rowid = 1;
5163 		type = results[(i * columns) + 2];
5164 		if (strcasecmp (type, "INTEGER") == 0)
5165 		    int_pk = 1;
5166 		pk = results[(i * columns) + 5];
5167 		if (atoi (pk) != 0)
5168 		    pk_cols++;
5169 		if (strcasecmp (name, "rowid") == 0 && atoi (pk) != 0)
5170 		    rowid_pk = 1;
5171 	    }
5172       }
5173     sqlite3_free_table (results);
5174     if (rowid == 0)
5175 	return 1;
5176     if (rowid_pk == 1 && pk_cols == 1 && int_pk == 1)
5177       {
5178 	  /* OK, found: ROWID INTEGER PRIMARY KEY */
5179 	  return 1;
5180       }
5181     return 0;
5182 }
5183 
5184 SPATIALITE_PRIVATE int
validateTemporaryRowid(void * p_sqlite,const char * db_prefix,const char * table)5185 validateTemporaryRowid (void *p_sqlite, const char *db_prefix,
5186 			const char *table)
5187 {
5188 /* check for tables containing a physical column named ROWID */
5189     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
5190     int rowid = 0;
5191     char *sql;
5192     int ret;
5193     const char *name;
5194     const char *type;
5195     const char *pk;
5196     int rowid_pk = 0;
5197     int int_pk = 0;
5198     int pk_cols = 0;
5199     int i;
5200     char **results;
5201     int rows;
5202     int columns;
5203     char *quoted_prefix;
5204     char *quoted_table;
5205 
5206     if (db_prefix == NULL)
5207 	return 0;
5208 
5209     quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
5210     quoted_table = gaiaDoubleQuotedSql (table);
5211     sql =
5212 	sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", quoted_prefix,
5213 			 quoted_table);
5214     ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, NULL);
5215     sqlite3_free (sql);
5216     free (quoted_prefix);
5217     free (quoted_table);
5218     if (ret != SQLITE_OK)
5219 	return 0;
5220     if (rows < 1)
5221 	;
5222     else
5223       {
5224 	  for (i = 1; i <= rows; i++)
5225 	    {
5226 		name = results[(i * columns) + 1];
5227 		if (strcasecmp (name, "rowid") == 0)
5228 		    rowid = 1;
5229 		type = results[(i * columns) + 2];
5230 		if (strcasecmp (type, "INTEGER") == 0)
5231 		    int_pk = 1;
5232 		pk = results[(i * columns) + 5];
5233 		if (atoi (pk) != 0)
5234 		    pk_cols++;
5235 		if (strcasecmp (name, "rowid") == 0 && atoi (pk) != 0)
5236 		    rowid_pk = 1;
5237 	    }
5238       }
5239     sqlite3_free_table (results);
5240     if (rowid == 0)
5241 	return 1;
5242     if (rowid_pk == 1 && pk_cols == 1 && int_pk == 1)
5243       {
5244 	  /* OK, found: ROWID INTEGER PRIMARY KEY */
5245 	  return 1;
5246       }
5247     return 0;
5248 }
5249 
5250 SPATIALITE_PRIVATE int
buildSpatialIndexEx(void * p_sqlite,const unsigned char * table,const char * column)5251 buildSpatialIndexEx (void *p_sqlite, const unsigned char *table,
5252 		     const char *column)
5253 {
5254 /* loading a SpatialIndex [RTree] */
5255     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
5256     char *raw;
5257     char *quoted_rtree;
5258     char *quoted_table;
5259     char *quoted_column;
5260     char *sql_statement;
5261     char *errMsg = NULL;
5262     int ret;
5263 
5264     if (!validateRowid (sqlite, (const char *) table))
5265       {
5266 	  /* a physical column named "rowid" shadows the real ROWID */
5267 	  spatialite_e
5268 	      ("buildSpatialIndex error: a physical column named ROWID shadows the real ROWID\n");
5269 	  return -2;
5270       }
5271 
5272     raw = sqlite3_mprintf ("idx_%s_%s", table, column);
5273     quoted_rtree = gaiaDoubleQuotedSql (raw);
5274     sqlite3_free (raw);
5275     quoted_table = gaiaDoubleQuotedSql ((const char *) table);
5276     quoted_column = gaiaDoubleQuotedSql (column);
5277     sql_statement = sqlite3_mprintf ("INSERT INTO \"%s\" "
5278 				     "(pkid, xmin, xmax, ymin, ymax) "
5279 				     "SELECT ROWID, MbrMinX(\"%s\"), MbrMaxX(\"%s\"), MbrMinY(\"%s\"), MbrMaxY(\"%s\") "
5280 				     "FROM \"%s\" WHERE MbrMinX(\"%s\") IS NOT NULL",
5281 				     quoted_rtree, quoted_column, quoted_column,
5282 				     quoted_column, quoted_column, quoted_table,
5283 				     quoted_column);
5284     free (quoted_rtree);
5285     free (quoted_table);
5286     free (quoted_column);
5287     ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
5288     sqlite3_free (sql_statement);
5289     if (ret != SQLITE_OK)
5290       {
5291 	  spatialite_e ("buildSpatialIndex error: \"%s\"\n", errMsg);
5292 	  sqlite3_free (errMsg);
5293 	  return -1;
5294       }
5295     return 0;
5296 }
5297 
5298 SPATIALITE_PRIVATE int
buildTemporarySpatialIndex(void * p_sqlite,const char * db_prefix,const unsigned char * table,const char * column)5299 buildTemporarySpatialIndex (void *p_sqlite, const char *db_prefix,
5300 			    const unsigned char *table, const char *column)
5301 {
5302 /* loading a SpatialIndex [RTree] */
5303     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
5304     char *raw;
5305     char *quoted_prefix;
5306     char *quoted_rtree;
5307     char *quoted_table;
5308     char *quoted_column;
5309     char *sql_statement;
5310     char *errMsg = NULL;
5311     int ret;
5312 
5313     if (!validateTemporaryRowid (sqlite, db_prefix, (const char *) table))
5314       {
5315 	  /* a physical column named "rowid" shadows the real ROWID */
5316 	  spatialite_e
5317 	      ("buildTemporarySpatialIndex error: a physical column named ROWID shadows the real ROWID\n");
5318 	  return -2;
5319       }
5320 
5321     raw = sqlite3_mprintf ("idx_%s_%s", table, column);
5322     quoted_rtree = gaiaDoubleQuotedSql (raw);
5323     sqlite3_free (raw);
5324     quoted_prefix = gaiaDoubleQuotedSql (db_prefix);
5325     quoted_table = gaiaDoubleQuotedSql ((const char *) table);
5326     quoted_column = gaiaDoubleQuotedSql (column);
5327     sql_statement = sqlite3_mprintf ("INSERT INTO \"%s\".\"%s\" "
5328 				     "(pkid, xmin, xmax, ymin, ymax) "
5329 				     "SELECT ROWID, MbrMinX(\"%s\"), MbrMaxX(\"%s\"), MbrMinY(\"%s\"), MbrMaxY(\"%s\") "
5330 				     "FROM \"%s\".\"%s\" WHERE MbrMinX(\"%s\") IS NOT NULL",
5331 				     quoted_prefix, quoted_rtree, quoted_column,
5332 				     quoted_column, quoted_column,
5333 				     quoted_column, quoted_prefix, quoted_table,
5334 				     quoted_column);
5335     free (quoted_prefix);
5336     free (quoted_rtree);
5337     free (quoted_table);
5338     free (quoted_column);
5339     ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
5340     sqlite3_free (sql_statement);
5341     if (ret != SQLITE_OK)
5342       {
5343 	  spatialite_e ("buildTemporarySpatialIndex error: \"%s\"\n", errMsg);
5344 	  sqlite3_free (errMsg);
5345 	  return -1;
5346       }
5347     return 0;
5348 }
5349 
5350 SPATIALITE_PRIVATE int
getRealSQLnames(void * p_sqlite,const char * table,const char * column,char ** real_table,char ** real_column)5351 getRealSQLnames (void *p_sqlite, const char *table, const char *column,
5352 		 char **real_table, char **real_column)
5353 {
5354 /* attempting to retrieve the "real" table and column names (upper/lowercase) */
5355     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
5356     char *p_table = NULL;
5357     char *p_column = NULL;
5358     char *sql_statement;
5359     char *quoted;
5360     const char *name;
5361     int len;
5362     sqlite3_stmt *stmt;
5363     int ret;
5364 
5365     sql_statement = sqlite3_mprintf ("SELECT name "
5366 				     "FROM sqlite_master WHERE type = 'table' "
5367 				     "AND Lower(name) = Lower(?)");
5368 /* compiling SQL prepared statement */
5369     ret =
5370 	sqlite3_prepare_v2 (sqlite, sql_statement, strlen (sql_statement),
5371 			    &stmt, NULL);
5372     sqlite3_free (sql_statement);
5373     if (ret != SQLITE_OK)
5374       {
5375 	  spatialite_e ("real_names: error %d \"%s\"\n",
5376 			sqlite3_errcode (sqlite), sqlite3_errmsg (sqlite));
5377 	  return 0;
5378       }
5379     sqlite3_reset (stmt);
5380     sqlite3_clear_bindings (stmt);
5381     sqlite3_bind_text (stmt, 1, table, strlen (table), SQLITE_STATIC);
5382     while (1)
5383       {
5384 	  /* scrolling the result set rows */
5385 	  ret = sqlite3_step (stmt);
5386 	  if (ret == SQLITE_DONE)
5387 	      break;		/* end of result set */
5388 	  if (ret == SQLITE_ROW)
5389 	    {
5390 		name = (const char *) sqlite3_column_text (stmt, 0);
5391 		len = sqlite3_column_bytes (stmt, 0);
5392 		if (p_table)
5393 		    free (p_table);
5394 		p_table = malloc (len + 1);
5395 		strcpy (p_table, name);
5396 	    }
5397       }
5398     sqlite3_finalize (stmt);
5399 
5400     if (p_table == NULL)
5401 	return 0;
5402 
5403     quoted = gaiaDoubleQuotedSql (p_table);
5404     sql_statement = sqlite3_mprintf ("PRAGMA table_info(\"%s\")", quoted);
5405     free (quoted);
5406 /* compiling SQL prepared statement */
5407     ret =
5408 	sqlite3_prepare_v2 (sqlite, sql_statement, strlen (sql_statement),
5409 			    &stmt, NULL);
5410     sqlite3_free (sql_statement);
5411     if (ret != SQLITE_OK)
5412       {
5413 	  spatialite_e ("real_names: error %d \"%s\"\n",
5414 			sqlite3_errcode (sqlite), sqlite3_errmsg (sqlite));
5415 	  free (p_table);
5416 	  return 0;
5417       }
5418     while (1)
5419       {
5420 	  /* scrolling the result set rows */
5421 	  ret = sqlite3_step (stmt);
5422 	  if (ret == SQLITE_DONE)
5423 	      break;		/* end of result set */
5424 	  if (ret == SQLITE_ROW)
5425 	    {
5426 		name = (const char *) sqlite3_column_text (stmt, 1);
5427 		len = sqlite3_column_bytes (stmt, 1);
5428 		if (strcasecmp (name, column) == 0)
5429 		  {
5430 		      if (p_column)
5431 			  free (p_column);
5432 		      p_column = malloc (len + 1);
5433 		      strcpy (p_column, name);
5434 		  }
5435 	    }
5436       }
5437     sqlite3_finalize (stmt);
5438 
5439     if (p_column == NULL)
5440       {
5441 	  free (p_table);
5442 	  return 0;
5443       }
5444 
5445     *real_table = p_table;
5446     *real_column = p_column;
5447     return 1;
5448 }
5449 
5450 SPATIALITE_PRIVATE int
getRealSQLnamesTemporary(void * p_sqlite,const char * db_prefix,const char * table,const char * column,char ** real_table,char ** real_column)5451 getRealSQLnamesTemporary (void *p_sqlite, const char *db_prefix,
5452 			  const char *table, const char *column,
5453 			  char **real_table, char **real_column)
5454 {
5455 /* attempting to retrieve the "real" table and column names (upper/lowercase) */
5456     sqlite3 *sqlite = (sqlite3 *) p_sqlite;
5457     char *p_table = NULL;
5458     char *p_column = NULL;
5459     char *sql_statement;
5460     char *prefix;
5461     char *quoted;
5462     const char *name;
5463     int len;
5464     sqlite3_stmt *stmt;
5465     int ret;
5466 
5467     if (db_prefix == NULL)
5468 	return 0;
5469 
5470     prefix = gaiaDoubleQuotedSql (db_prefix);
5471     sql_statement = sqlite3_mprintf ("SELECT name "
5472 				     "FROM \"%s\".sqlite_master WHERE type = 'table' "
5473 				     "AND Lower(name) = Lower(?)", prefix);
5474     free (prefix);
5475 /* compiling SQL prepared statement */
5476     ret =
5477 	sqlite3_prepare_v2 (sqlite, sql_statement, strlen (sql_statement),
5478 			    &stmt, NULL);
5479     sqlite3_free (sql_statement);
5480     if (ret != SQLITE_OK)
5481       {
5482 	  spatialite_e ("real_names temporary: error %d \"%s\"\n",
5483 			sqlite3_errcode (sqlite), sqlite3_errmsg (sqlite));
5484 	  return 0;
5485       }
5486     sqlite3_reset (stmt);
5487     sqlite3_clear_bindings (stmt);
5488     sqlite3_bind_text (stmt, 1, table, strlen (table), SQLITE_STATIC);
5489     while (1)
5490       {
5491 	  /* scrolling the result set rows */
5492 	  ret = sqlite3_step (stmt);
5493 	  if (ret == SQLITE_DONE)
5494 	      break;		/* end of result set */
5495 	  if (ret == SQLITE_ROW)
5496 	    {
5497 		name = (const char *) sqlite3_column_text (stmt, 0);
5498 		len = sqlite3_column_bytes (stmt, 0);
5499 		if (p_table)
5500 		    free (p_table);
5501 		p_table = malloc (len + 1);
5502 		strcpy (p_table, name);
5503 	    }
5504       }
5505     sqlite3_finalize (stmt);
5506 
5507     if (p_table == NULL)
5508 	return 0;
5509 
5510     prefix = gaiaDoubleQuotedSql (db_prefix);
5511     quoted = gaiaDoubleQuotedSql (p_table);
5512     sql_statement =
5513 	sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", prefix, quoted);
5514     free (prefix);
5515     free (quoted);
5516 /* compiling SQL prepared statement */
5517     ret =
5518 	sqlite3_prepare_v2 (sqlite, sql_statement, strlen (sql_statement),
5519 			    &stmt, NULL);
5520     sqlite3_free (sql_statement);
5521     if (ret != SQLITE_OK)
5522       {
5523 	  spatialite_e ("real_names temporary: error %d \"%s\"\n",
5524 			sqlite3_errcode (sqlite), sqlite3_errmsg (sqlite));
5525 	  free (p_table);
5526 	  return 0;
5527       }
5528     while (1)
5529       {
5530 	  /* scrolling the result set rows */
5531 	  ret = sqlite3_step (stmt);
5532 	  if (ret == SQLITE_DONE)
5533 	      break;		/* end of result set */
5534 	  if (ret == SQLITE_ROW)
5535 	    {
5536 		name = (const char *) sqlite3_column_text (stmt, 1);
5537 		len = sqlite3_column_bytes (stmt, 1);
5538 		if (strcasecmp (name, column) == 0)
5539 		  {
5540 		      if (p_column)
5541 			  free (p_column);
5542 		      p_column = malloc (len + 1);
5543 		      strcpy (p_column, name);
5544 		  }
5545 	    }
5546       }
5547     sqlite3_finalize (stmt);
5548 
5549     if (p_column == NULL)
5550       {
5551 	  free (p_table);
5552 	  return 0;
5553       }
5554 
5555     *real_table = p_table;
5556     *real_column = p_column;
5557     return 1;
5558 }
5559 
5560 SPATIALITE_PRIVATE void
addLayerAttributeField(void * x_list,const char * table_name,const char * geometry_column,int ordinal,const char * column_name,int null_values,int integer_values,int double_values,int text_values,int blob_values,int null_max_size,int max_size,int null_int_range,void * x_integer_min,void * x_integer_max,int null_double_range,double double_min,double double_max)5561 addLayerAttributeField (void *x_list, const char *table_name,
5562 			const char *geometry_column, int ordinal,
5563 			const char *column_name, int null_values,
5564 			int integer_values, int double_values, int text_values,
5565 			int blob_values, int null_max_size, int max_size,
5566 			int null_int_range, void *x_integer_min,
5567 			void *x_integer_max, int null_double_range,
5568 			double double_min, double double_max)
5569 {
5570 /* adding some AttributeFiled to a VectorLayer */
5571     gaiaVectorLayersListPtr list = (gaiaVectorLayersListPtr) x_list;
5572     sqlite3_int64 integer_min = *((sqlite3_int64 *) x_integer_min);
5573     sqlite3_int64 integer_max = *((sqlite3_int64 *) x_integer_max);
5574     gaiaLayerAttributeFieldPtr fld;
5575     int len;
5576     gaiaVectorLayerPtr lyr = list->Current;
5577     if (lyr)
5578       {
5579 	  if (strcasecmp (lyr->TableName, table_name) == 0
5580 	      && strcasecmp (lyr->GeometryName, geometry_column) == 0)
5581 	      goto valid_pointer;
5582       }
5583     list->Current = NULL;
5584     lyr = list->First;
5585     while (lyr)
5586       {
5587 	  if (strcasecmp (lyr->TableName, table_name) == 0
5588 	      && strcasecmp (lyr->GeometryName, geometry_column) == 0)
5589 	    {
5590 		list->Current = lyr;
5591 		goto valid_pointer;
5592 	    }
5593 	  lyr = lyr->Next;
5594       }
5595   valid_pointer:
5596     lyr = list->Current;
5597     if (lyr == NULL)
5598 	return;
5599     fld = malloc (sizeof (gaiaLayerAttributeField));
5600     fld->Ordinal = ordinal;
5601     len = strlen (column_name);
5602     fld->AttributeFieldName = malloc (len + 1);
5603     strcpy (fld->AttributeFieldName, column_name);
5604     fld->NullValuesCount = null_values;
5605     fld->IntegerValuesCount = integer_values;
5606     fld->DoubleValuesCount = double_values;
5607     fld->TextValuesCount = text_values;
5608     fld->BlobValuesCount = blob_values;
5609     fld->MaxSize = NULL;
5610     fld->IntRange = NULL;
5611     fld->DoubleRange = NULL;
5612     if (!null_max_size)
5613       {
5614 	  fld->MaxSize = malloc (sizeof (gaiaAttributeFieldMaxSize));
5615 	  fld->MaxSize->MaxSize = max_size;
5616       }
5617     if (!null_int_range)
5618       {
5619 	  fld->IntRange = malloc (sizeof (gaiaAttributeFieldIntRange));
5620 	  fld->IntRange->MinValue = integer_min;
5621 	  fld->IntRange->MaxValue = integer_max;
5622       }
5623     if (!null_double_range)
5624       {
5625 	  fld->DoubleRange = malloc (sizeof (gaiaAttributeFieldDoubleRange));
5626 	  fld->DoubleRange->MinValue = double_min;
5627 	  fld->DoubleRange->MaxValue = double_max;
5628       }
5629     fld->Next = NULL;
5630     if (lyr->First == NULL)
5631 	lyr->First = fld;
5632     if (lyr->Last != NULL)
5633 	lyr->Last->Next = fld;
5634     lyr->Last = fld;
5635 }
5636 
5637 SPATIALITE_PRIVATE void
addVectorLayer(void * x_list,const char * layer_type,const char * table_name,const char * geometry_column,int geometry_type,int srid,int spatial_index)5638 addVectorLayer (void *x_list, const char *layer_type,
5639 		const char *table_name, const char *geometry_column,
5640 		int geometry_type, int srid, int spatial_index)
5641 {
5642 /* adding a Layer to a VectorLayersList */
5643     gaiaVectorLayersListPtr list = (gaiaVectorLayersListPtr) x_list;
5644     int len;
5645     gaiaVectorLayerPtr lyr = malloc (sizeof (gaiaVectorLayer));
5646     lyr->LayerType = GAIA_VECTOR_UNKNOWN;
5647     if (strcasecmp (layer_type, "SpatialTable") == 0)
5648 	lyr->LayerType = GAIA_VECTOR_TABLE;
5649     if (strcasecmp (layer_type, "SpatialView") == 0)
5650 	lyr->LayerType = GAIA_VECTOR_VIEW;
5651     if (strcasecmp (layer_type, "VirtualShape") == 0)
5652 	lyr->LayerType = GAIA_VECTOR_VIRTUAL;
5653     len = strlen (table_name);
5654     lyr->TableName = malloc (len + 1);
5655     strcpy (lyr->TableName, table_name);
5656     len = strlen (geometry_column);
5657     lyr->GeometryName = malloc (len + 1);
5658     strcpy (lyr->GeometryName, geometry_column);
5659     lyr->Srid = srid;
5660     switch (geometry_type)
5661       {
5662       case 0:
5663 	  lyr->GeometryType = GAIA_VECTOR_GEOMETRY;
5664 	  lyr->Dimensions = GAIA_XY;
5665 	  break;
5666       case 1000:
5667 	  lyr->GeometryType = GAIA_VECTOR_GEOMETRY;
5668 	  lyr->Dimensions = GAIA_XY_Z;
5669 	  break;
5670       case 2000:
5671 	  lyr->GeometryType = GAIA_VECTOR_GEOMETRY;
5672 	  lyr->Dimensions = GAIA_XY_M;
5673 	  break;
5674       case 3000:
5675 	  lyr->GeometryType = GAIA_VECTOR_GEOMETRY;
5676 	  lyr->Dimensions = GAIA_XY_Z_M;
5677 	  break;
5678       case 1:
5679 	  lyr->GeometryType = GAIA_VECTOR_POINT;
5680 	  lyr->Dimensions = GAIA_XY;
5681 	  break;
5682       case 1001:
5683 	  lyr->GeometryType = GAIA_VECTOR_POINT;
5684 	  lyr->Dimensions = GAIA_XY_Z;
5685 	  break;
5686       case 2001:
5687 	  lyr->GeometryType = GAIA_VECTOR_POINT;
5688 	  lyr->Dimensions = GAIA_XY_M;
5689 	  break;
5690       case 3001:
5691 	  lyr->GeometryType = GAIA_VECTOR_POINT;
5692 	  lyr->Dimensions = GAIA_XY_Z_M;
5693 	  break;
5694       case 2:
5695 	  lyr->GeometryType = GAIA_VECTOR_LINESTRING;
5696 	  lyr->Dimensions = GAIA_XY;
5697 	  break;
5698       case 1002:
5699 	  lyr->GeometryType = GAIA_VECTOR_LINESTRING;
5700 	  lyr->Dimensions = GAIA_XY_Z;
5701 	  break;
5702       case 2002:
5703 	  lyr->GeometryType = GAIA_VECTOR_LINESTRING;
5704 	  lyr->Dimensions = GAIA_XY_M;
5705 	  break;
5706       case 3002:
5707 	  lyr->GeometryType = GAIA_VECTOR_LINESTRING;
5708 	  lyr->Dimensions = GAIA_XY_Z_M;
5709 	  break;
5710       case 3:
5711 	  lyr->GeometryType = GAIA_VECTOR_POLYGON;
5712 	  lyr->Dimensions = GAIA_XY;
5713 	  break;
5714       case 1003:
5715 	  lyr->GeometryType = GAIA_VECTOR_POLYGON;
5716 	  lyr->Dimensions = GAIA_XY_Z;
5717 	  break;
5718       case 2003:
5719 	  lyr->GeometryType = GAIA_VECTOR_POLYGON;
5720 	  lyr->Dimensions = GAIA_XY_M;
5721 	  break;
5722       case 3003:
5723 	  lyr->GeometryType = GAIA_VECTOR_POLYGON;
5724 	  lyr->Dimensions = GAIA_XY_Z_M;
5725 	  break;
5726       case 4:
5727 	  lyr->GeometryType = GAIA_VECTOR_MULTIPOINT;
5728 	  lyr->Dimensions = GAIA_XY;
5729 	  break;
5730       case 1004:
5731 	  lyr->GeometryType = GAIA_VECTOR_MULTIPOINT;
5732 	  lyr->Dimensions = GAIA_XY_Z;
5733 	  break;
5734       case 2004:
5735 	  lyr->GeometryType = GAIA_VECTOR_MULTIPOINT;
5736 	  lyr->Dimensions = GAIA_XY_M;
5737 	  break;
5738       case 3004:
5739 	  lyr->GeometryType = GAIA_VECTOR_MULTIPOINT;
5740 	  lyr->Dimensions = GAIA_XY_Z_M;
5741 	  break;
5742       case 5:
5743 	  lyr->GeometryType = GAIA_VECTOR_MULTILINESTRING;
5744 	  lyr->Dimensions = GAIA_XY;
5745 	  break;
5746       case 1005:
5747 	  lyr->GeometryType = GAIA_VECTOR_MULTILINESTRING;
5748 	  lyr->Dimensions = GAIA_XY_Z;
5749 	  break;
5750       case 2005:
5751 	  lyr->GeometryType = GAIA_VECTOR_MULTILINESTRING;
5752 	  lyr->Dimensions = GAIA_XY_M;
5753 	  break;
5754       case 3005:
5755 	  lyr->GeometryType = GAIA_VECTOR_MULTILINESTRING;
5756 	  lyr->Dimensions = GAIA_XY_Z_M;
5757 	  break;
5758       case 6:
5759 	  lyr->GeometryType = GAIA_VECTOR_MULTIPOLYGON;
5760 	  lyr->Dimensions = GAIA_XY;
5761 	  break;
5762       case 1006:
5763 	  lyr->GeometryType = GAIA_VECTOR_MULTIPOLYGON;
5764 	  lyr->Dimensions = GAIA_XY_Z;
5765 	  break;
5766       case 2006:
5767 	  lyr->GeometryType = GAIA_VECTOR_MULTIPOLYGON;
5768 	  lyr->Dimensions = GAIA_XY_M;
5769 	  break;
5770       case 3006:
5771 	  lyr->GeometryType = GAIA_VECTOR_MULTIPOLYGON;
5772 	  lyr->Dimensions = GAIA_XY_Z_M;
5773 	  break;
5774       case 7:
5775 	  lyr->GeometryType = GAIA_VECTOR_GEOMETRYCOLLECTION;
5776 	  lyr->Dimensions = GAIA_XY;
5777 	  break;
5778       case 1007:
5779 	  lyr->GeometryType = GAIA_VECTOR_GEOMETRYCOLLECTION;
5780 	  lyr->Dimensions = GAIA_XY_Z;
5781 	  break;
5782       case 2007:
5783 	  lyr->GeometryType = GAIA_VECTOR_GEOMETRYCOLLECTION;
5784 	  lyr->Dimensions = GAIA_XY_M;
5785 	  break;
5786       case 3007:
5787 	  lyr->GeometryType = GAIA_VECTOR_GEOMETRYCOLLECTION;
5788 	  lyr->Dimensions = GAIA_XY_Z_M;
5789 	  break;
5790       default:
5791 	  lyr->GeometryType = GAIA_VECTOR_UNKNOWN;
5792 	  lyr->Dimensions = GAIA_VECTOR_UNKNOWN;
5793 	  break;
5794       };
5795     switch (spatial_index)
5796       {
5797       case 0:
5798 	  lyr->SpatialIndex = GAIA_SPATIAL_INDEX_NONE;
5799 	  break;
5800       case 1:
5801 	  lyr->SpatialIndex = GAIA_SPATIAL_INDEX_RTREE;
5802 	  break;
5803       case 2:
5804 	  lyr->SpatialIndex = GAIA_SPATIAL_INDEX_MBRCACHE;
5805 	  break;
5806       default:
5807 	  lyr->SpatialIndex = GAIA_VECTOR_UNKNOWN;
5808 	  break;
5809       };
5810     lyr->ExtentInfos = NULL;
5811     lyr->AuthInfos = NULL;
5812     lyr->First = NULL;
5813     lyr->Last = NULL;
5814     lyr->Next = NULL;
5815     list->Current = NULL;
5816     if (list->First == NULL)
5817 	list->First = lyr;
5818     if (list->Last != NULL)
5819 	list->Last->Next = lyr;
5820     list->Last = lyr;
5821 }
5822 
5823 SPATIALITE_PRIVATE void
addVectorLayerExtent(void * x_list,const char * table_name,const char * geometry_column,int count,double min_x,double min_y,double max_x,double max_y)5824 addVectorLayerExtent (void *x_list, const char *table_name,
5825 		      const char *geometry_column, int count, double min_x,
5826 		      double min_y, double max_x, double max_y)
5827 {
5828 /* appending a LayerExtent object to the corresponding VectorLayer */
5829     gaiaVectorLayersListPtr list = (gaiaVectorLayersListPtr) x_list;
5830     gaiaVectorLayerPtr lyr = list->First;
5831     while (lyr)
5832       {
5833 	  if (strcasecmp (lyr->TableName, table_name) == 0
5834 	      && strcasecmp (lyr->GeometryName, geometry_column) == 0)
5835 	    {
5836 		lyr->ExtentInfos = malloc (sizeof (gaiaLayerExtent));
5837 		lyr->ExtentInfos->Count = count;
5838 		lyr->ExtentInfos->MinX = min_x;
5839 		lyr->ExtentInfos->MinY = min_y;
5840 		lyr->ExtentInfos->MaxX = max_x;
5841 		lyr->ExtentInfos->MaxY = max_y;
5842 		return;
5843 	    }
5844 	  lyr = lyr->Next;
5845       }
5846 }
5847 
5848 static void
doCheckWritableSpatialView(sqlite3 * handle,const char * view_name,int * has_trigger_insert,int * has_trigger_update,int * has_trigger_delete,int * is_read_only)5849 doCheckWritableSpatialView (sqlite3 * handle, const char *view_name,
5850 			    int *has_trigger_insert, int *has_trigger_update,
5851 			    int *has_trigger_delete, int *is_read_only)
5852 {
5853 /*
5854 * checking if a supposed Writable Spatial View do
5855 * effectively declares all expected Triggers
5856 *
5857 * patch kindly submitted by Mark Johnson <mj10777@googlemail.com>
5858 * see ticket: https://www.gaia-gis.it/fossil/libspatialite/tktview/597fce55f2884668a24b591840162ffebda390e1
5859 */
5860     int ret;
5861     char *sql;
5862     sqlite3_stmt *stmt;
5863 
5864 /* Claims to be a Writable SpatialView, we shall see ... */
5865     *has_trigger_insert = 0;
5866     *has_trigger_update = 0;
5867     *has_trigger_delete = 0;
5868     *is_read_only = 1;
5869 
5870     sql =
5871 	sqlite3_mprintf ("SELECT "
5872 			 "(SELECT Exists(SELECT rootpage FROM  sqlite_master "
5873 			 "WHERE (type = 'trigger' AND Lower(tbl_name) = Lower(%Q) AND "
5874 			 "(instr(upper(sql),'INSTEAD OF INSERT') > 0)))), "
5875 			 "(SELECT Exists(SELECT rootpage FROM  sqlite_master "
5876 			 "WHERE (type = 'trigger' AND Lower(tbl_name) = Lower(%Q) AND "
5877 			 "(instr(upper(sql),'INSTEAD OF UPDATE') > 0)))), "
5878 			 "(SELECT Exists(SELECT rootpage FROM  sqlite_master "
5879 			 "WHERE (type = 'trigger' AND Lower(tbl_name) = Lower(%Q) AND "
5880 			 "(instr(upper(sql),'INSTEAD OF DELETE') > 0))))",
5881 			 view_name, view_name, view_name);
5882     ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
5883     sqlite3_free (sql);
5884     if (ret == SQLITE_OK)
5885       {
5886 	  while (sqlite3_step (stmt) == SQLITE_ROW)
5887 	    {
5888 		if (sqlite3_column_type (stmt, 0) != SQLITE_NULL)
5889 		  {
5890 		      if (sqlite3_column_int (stmt, 0) == 1)
5891 			  *has_trigger_insert = 1;
5892 		  }
5893 		if (sqlite3_column_type (stmt, 1) != SQLITE_NULL)
5894 		  {
5895 		      if (sqlite3_column_int (stmt, 1) == 1)
5896 			  *has_trigger_update = 1;
5897 		  }
5898 		if (sqlite3_column_type (stmt, 2) != SQLITE_NULL)
5899 		  {
5900 		      if (sqlite3_column_int (stmt, 2) == 1)
5901 			  *has_trigger_delete = 1;
5902 		  }
5903 	    }
5904 	  ret = sqlite3_finalize (stmt);
5905       }
5906     if (*has_trigger_insert || *has_trigger_update || *has_trigger_delete)
5907 	*is_read_only = 0;	/* Yes, this could be a functional Writable SpatialView */
5908 }
5909 
5910 static void
addVectorLayerAuth(sqlite3 * handle,gaiaVectorLayersListPtr list,const char * table_name,const char * geometry_column,int read_only,int hidden)5911 addVectorLayerAuth (sqlite3 * handle, gaiaVectorLayersListPtr list,
5912 		    const char *table_name, const char *geometry_column,
5913 		    int read_only, int hidden)
5914 {
5915 /* appending a LayerAuth object to the corresponding VectorLayer */
5916     gaiaVectorLayerPtr lyr = list->First;
5917     while (lyr)
5918       {
5919 	  if (strcasecmp (lyr->TableName, table_name) == 0
5920 	      && strcasecmp (lyr->GeometryName, geometry_column) == 0)
5921 	    {
5922 		gaiaLayerAuthPtr auth = malloc (sizeof (gaiaLayerAuth));
5923 		lyr->AuthInfos = auth;
5924 		auth->IsReadOnly = read_only;
5925 		auth->IsHidden = hidden;
5926 		auth->HasTriggerInsert = 0;
5927 		auth->HasTriggerUpdate = 0;
5928 		auth->HasTriggerDelete = 0;
5929 		if ((lyr->LayerType == GAIA_VECTOR_VIEW) && (!auth->IsReadOnly))
5930 		  {
5931 		      int has_trigger_insert = 0;
5932 		      int has_trigger_update = 0;
5933 		      int has_trigger_delete = 0;
5934 		      int is_read_only = 1;
5935 		      doCheckWritableSpatialView (handle, table_name,
5936 						  &has_trigger_insert,
5937 						  &has_trigger_update,
5938 						  &has_trigger_delete,
5939 						  &is_read_only);
5940 		      auth->HasTriggerInsert = has_trigger_insert;
5941 		      auth->HasTriggerUpdate = has_trigger_update;
5942 		      auth->HasTriggerDelete = has_trigger_delete;
5943 		      auth->IsReadOnly = is_read_only;
5944 		  }
5945 		return;
5946 	    }
5947 	  lyr = lyr->Next;
5948       }
5949 }
5950 
5951 static void
freeLayerAttributeField(gaiaLayerAttributeFieldPtr fld)5952 freeLayerAttributeField (gaiaLayerAttributeFieldPtr fld)
5953 {
5954 /* destroying an AttributeField */
5955     if (fld->AttributeFieldName)
5956 	free (fld->AttributeFieldName);
5957     if (fld->MaxSize)
5958 	free (fld->MaxSize);
5959     if (fld->IntRange)
5960 	free (fld->IntRange);
5961     if (fld->DoubleRange)
5962 	free (fld->DoubleRange);
5963     free (fld);
5964 }
5965 
5966 static void
freeVectorLayer(gaiaVectorLayerPtr lyr)5967 freeVectorLayer (gaiaVectorLayerPtr lyr)
5968 {
5969 /* destroying a VectorLayer object */
5970     gaiaLayerAttributeFieldPtr fld;
5971     gaiaLayerAttributeFieldPtr fldn;
5972     if (!lyr)
5973 	return;
5974     if (lyr->TableName)
5975 	free (lyr->TableName);
5976     if (lyr->GeometryName)
5977 	free (lyr->GeometryName);
5978     if (lyr->ExtentInfos)
5979 	free (lyr->ExtentInfos);
5980     if (lyr->AuthInfos)
5981 	free (lyr->AuthInfos);
5982     fld = lyr->First;
5983     while (fld)
5984       {
5985 	  fldn = fld->Next;
5986 	  freeLayerAttributeField (fld);
5987 	  fld = fldn;
5988       }
5989     free (lyr);
5990 }
5991 
5992 SPATIALITE_DECLARE void
gaiaFreeVectorLayersList(gaiaVectorLayersListPtr list)5993 gaiaFreeVectorLayersList (gaiaVectorLayersListPtr list)
5994 {
5995 /* destroying a VectorLayersList object */
5996     gaiaVectorLayerPtr lyr;
5997     gaiaVectorLayerPtr lyr_n;
5998     if (!list)
5999 	return;
6000     lyr = list->First;
6001     while (lyr)
6002       {
6003 	  /* destroying each layer */
6004 	  lyr_n = lyr->Next;
6005 	  freeVectorLayer (lyr);
6006 	  lyr = lyr_n;
6007       }
6008     free (list);
6009 }
6010 
6011 static int
gaiaGetVectorLayersList_v4(sqlite3 * handle,const char * table,const char * geometry,gaiaVectorLayersListPtr list)6012 gaiaGetVectorLayersList_v4 (sqlite3 * handle, const char *table,
6013 			    const char *geometry, gaiaVectorLayersListPtr list)
6014 {
6015 /* creating a VectorLayersList object - v.4.0.0 DB layout */
6016     char *sql;
6017     int ret;
6018     sqlite3_stmt *stmt;
6019     int error = 0;
6020 
6021 /*
6022 * attempting first to recover all SpatialViews registered into
6023 * views_geometry_columns but not into views_geometry_columns_auth
6024 */
6025     sql = "INSERT OR IGNORE INTO views_geometry_columns_auth "
6026 	"(view_name, view_geometry, hidden) "
6027 	"SELECT view_name, view_geometry, 0 FROM views_geometry_columns";
6028     sqlite3_exec (handle, sql, NULL, NULL, NULL);
6029 
6030 /* querying the vector_layers view */
6031     if (table == NULL)
6032 	sql =
6033 	    sqlite3_mprintf
6034 	    ("SELECT layer_type, table_name, geometry_column, geometry_type, "
6035 	     "srid, spatial_index_enabled FROM vector_layers");
6036     else
6037       {
6038 	  if (geometry == NULL)
6039 	      sql =
6040 		  sqlite3_mprintf
6041 		  ("SELECT layer_type, table_name, geometry_column, geometry_type, "
6042 		   "srid, spatial_index_enabled FROM vector_layers "
6043 		   "WHERE Lower(table_name) = Lower(%Q)", table);
6044 	  else
6045 	      sql =
6046 		  sqlite3_mprintf
6047 		  ("SELECT layer_type, table_name, geometry_column, geometry_type, "
6048 		   "srid, spatial_index_enabled FROM vector_layers "
6049 		   "WHERE Lower(table_name) = Lower(%Q) AND "
6050 		   "Lower(geometry_column) = Lower(%Q)", table, geometry);
6051       }
6052 /* compiling SQL prepared statement */
6053     ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
6054     sqlite3_free (sql);
6055     if (ret != SQLITE_OK)
6056       {
6057 	  error = 1;
6058 	  goto stop;
6059       }
6060     while (1)
6061       {
6062 	  /* scrolling the result set rows */
6063 	  ret = sqlite3_step (stmt);
6064 	  if (ret == SQLITE_DONE)
6065 	      break;		/* end of result set */
6066 	  if (ret == SQLITE_ROW)
6067 	    {
6068 		/* processing a VectorLayer row */
6069 		const char *layer_type =
6070 		    (const char *) sqlite3_column_text (stmt, 0);
6071 		const char *table_name =
6072 		    (const char *) sqlite3_column_text (stmt, 1);
6073 		const char *geometry_column =
6074 		    (const char *) sqlite3_column_text (stmt, 2);
6075 		int geometry_type = sqlite3_column_int (stmt, 3);
6076 		int srid = sqlite3_column_int (stmt, 4);
6077 		int spatial_index = sqlite3_column_int (stmt, 5);
6078 		addVectorLayer (list, layer_type, table_name, geometry_column,
6079 				geometry_type, srid, spatial_index);
6080 	    }
6081 	  else
6082 	      error = 1;
6083       }
6084     ret = sqlite3_finalize (stmt);
6085 
6086   stop:
6087     if (error)
6088 	return 0;
6089 
6090 /* querying the vector_layers_statistics view */
6091     if (table == NULL)
6092 	sql =
6093 	    sqlite3_mprintf
6094 	    ("SELECT table_name, geometry_column, row_count, extent_min_x, "
6095 	     "extent_min_y, extent_max_x, extent_max_y FROM vector_layers_statistics");
6096     else
6097       {
6098 	  if (geometry == NULL)
6099 	      sql =
6100 		  sqlite3_mprintf
6101 		  ("SELECT table_name, geometry_column, row_count, extent_min_x, "
6102 		   "extent_min_y, extent_max_x, extent_max_y FROM vector_layers_statistics "
6103 		   "WHERE Lower(table_name) = Lower(%Q)", table);
6104 	  else
6105 	      sql =
6106 		  sqlite3_mprintf
6107 		  ("SELECT table_name, geometry_column, row_count, extent_min_x, "
6108 		   "extent_min_y, extent_max_x, extent_max_y FROM vector_layers_statistics "
6109 		   "WHERE Lower(table_name) = Lower(%Q) AND "
6110 		   "Lower(geometry_column) = Lower(%Q)", table, geometry);
6111       }
6112 /* compiling SQL prepared statement */
6113     ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
6114     sqlite3_free (sql);
6115     if (ret != SQLITE_OK)
6116       {
6117 	  error = 1;
6118 	  goto stop2;
6119       }
6120     while (1)
6121       {
6122 	  /* scrolling the result set rows */
6123 	  ret = sqlite3_step (stmt);
6124 	  if (ret == SQLITE_DONE)
6125 	      break;		/* end of result set */
6126 	  if (ret == SQLITE_ROW)
6127 	    {
6128 		/* processing a VectorLayer row */
6129 		int is_null = 0;
6130 		const char *table_name =
6131 		    (const char *) sqlite3_column_text (stmt, 0);
6132 		const char *geometry_column =
6133 		    (const char *) sqlite3_column_text (stmt, 1);
6134 		int count = 0;
6135 		double min_x = DBL_MAX;
6136 		double min_y = DBL_MAX;
6137 		double max_x = 0.0 - DBL_MAX;
6138 		double max_y = 0.0 - DBL_MAX;
6139 		if (sqlite3_column_type (stmt, 2) == SQLITE_NULL)
6140 		    is_null = 1;
6141 		else
6142 		    count = sqlite3_column_int (stmt, 2);
6143 		if (sqlite3_column_type (stmt, 3) == SQLITE_NULL)
6144 		    is_null = 1;
6145 		else
6146 		    min_x = sqlite3_column_double (stmt, 3);
6147 		if (sqlite3_column_type (stmt, 4) == SQLITE_NULL)
6148 		    is_null = 1;
6149 		else
6150 		    min_y = sqlite3_column_double (stmt, 4);
6151 		if (sqlite3_column_type (stmt, 5) == SQLITE_NULL)
6152 		    is_null = 1;
6153 		else
6154 		    max_x = sqlite3_column_double (stmt, 5);
6155 		if (sqlite3_column_type (stmt, 6) == SQLITE_NULL)
6156 		    is_null = 1;
6157 		else
6158 		    max_y = sqlite3_column_double (stmt, 6);
6159 		if (!is_null)
6160 		    addVectorLayerExtent (list, table_name, geometry_column,
6161 					  count, min_x, min_y, max_x, max_y);
6162 	    }
6163       }
6164     ret = sqlite3_finalize (stmt);
6165 
6166   stop2:
6167 /* querying the vector_layers_auth view */
6168     if (table == NULL)
6169 	sql =
6170 	    sqlite3_mprintf
6171 	    ("SELECT table_name, geometry_column, read_only, hidden "
6172 	     "FROM vector_layers_auth");
6173     else
6174       {
6175 	  if (geometry == NULL)
6176 	      sql =
6177 		  sqlite3_mprintf
6178 		  ("SELECT table_name, geometry_column, read_only, hidden "
6179 		   "FROM vector_layers_auth WHERE Lower(table_name) = Lower(%Q)",
6180 		   table, geometry);
6181 	  else
6182 	      sql =
6183 		  sqlite3_mprintf
6184 		  ("SELECT table_name, geometry_column, read_only, hidden "
6185 		   "FROM vector_layers_auth "
6186 		   "WHERE Lower(table_name) = Lower(%Q) AND "
6187 		   "Lower(geometry_column) = Lower(%Q)", table, geometry);
6188       }
6189 /* compiling SQL prepared statement */
6190     ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
6191     sqlite3_free (sql);
6192     if (ret != SQLITE_OK)
6193       {
6194 	  error = 1;
6195 	  goto stop3;
6196       }
6197     while (1)
6198       {
6199 	  /* scrolling the result set rows */
6200 	  ret = sqlite3_step (stmt);
6201 	  if (ret == SQLITE_DONE)
6202 	      break;		/* end of result set */
6203 	  if (ret == SQLITE_ROW)
6204 	    {
6205 		/* processing a VectorLayer row */
6206 		int is_null = 0;
6207 		const char *table_name =
6208 		    (const char *) sqlite3_column_text (stmt, 0);
6209 		const char *geometry_column =
6210 		    (const char *) sqlite3_column_text (stmt, 1);
6211 		int read_only = 0;
6212 		int hidden = 0;
6213 		if (sqlite3_column_type (stmt, 2) == SQLITE_NULL)
6214 		    is_null = 1;
6215 		else
6216 		    read_only = sqlite3_column_int (stmt, 2);
6217 		if (sqlite3_column_type (stmt, 3) == SQLITE_NULL)
6218 		    is_null = 1;
6219 		else
6220 		    hidden = sqlite3_column_int (stmt, 3);
6221 		if (!is_null)
6222 		    addVectorLayerAuth (handle, list, table_name,
6223 					geometry_column, read_only, hidden);
6224 	    }
6225       }
6226     ret = sqlite3_finalize (stmt);
6227 
6228   stop3:
6229 /* querying the vector_layers_field_infos view */
6230     if (table == NULL)
6231       {
6232 	  /* if no "table" is set, we'll never return AttributeField Infos */
6233 	  goto stop4;
6234       }
6235     else
6236       {
6237 	  if (geometry == NULL)
6238 	      sql =
6239 		  sqlite3_mprintf
6240 		  ("SELECT table_name, geometry_column, ordinal, column_name, "
6241 		   "null_values, integer_values, double_values, text_values, blob_values,"
6242 		   "max_size, integer_min, integer_max, double_min, double_max "
6243 		   "FROM vector_layers_field_infos WHERE Lower(table_name) = Lower(%Q)",
6244 		   table, geometry);
6245 	  else
6246 	      sql =
6247 		  sqlite3_mprintf
6248 		  ("SELECT table_name, geometry_column, ordinal, column_name, "
6249 		   "null_values, integer_values, double_values, text_values, blob_values,"
6250 		   "max_size, integer_min, integer_max, double_min, double_max "
6251 		   "FROM vector_layers_field_infos "
6252 		   "WHERE Lower(table_name) = Lower(%Q) AND "
6253 		   "Lower(geometry_column) = Lower(%Q)", table, geometry);
6254       }
6255 /* compiling SQL prepared statement */
6256     ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
6257     sqlite3_free (sql);
6258     if (ret != SQLITE_OK)
6259       {
6260 	  error = 1;
6261 	  goto stop4;
6262       }
6263     while (1)
6264       {
6265 	  /* scrolling the result set rows */
6266 	  ret = sqlite3_step (stmt);
6267 	  if (ret == SQLITE_DONE)
6268 	      break;		/* end of result set */
6269 	  if (ret == SQLITE_ROW)
6270 	    {
6271 		/* processing a VectorLayer row */
6272 		int null_max_size = 0;
6273 		int null_int_range = 0;
6274 		int null_double_range = 0;
6275 		int max_size = 0;
6276 		sqlite3_int64 integer_min;
6277 		sqlite3_int64 integer_max;
6278 		double double_min = DBL_MAX;
6279 		double double_max = 0.0 - DBL_MAX;
6280 		const char *table_name =
6281 		    (const char *) sqlite3_column_text (stmt, 0);
6282 		const char *geometry_column =
6283 		    (const char *) sqlite3_column_text (stmt, 1);
6284 		int ordinal = sqlite3_column_int (stmt, 2);
6285 		const char *column_name =
6286 		    (const char *) sqlite3_column_text (stmt, 3);
6287 		int null_values = sqlite3_column_int (stmt, 4);
6288 		int integer_values = sqlite3_column_int (stmt, 5);
6289 		int double_values = sqlite3_column_int (stmt, 6);
6290 		int text_values = sqlite3_column_int (stmt, 7);
6291 		int blob_values = sqlite3_column_int (stmt, 8);
6292 		if (sqlite3_column_type (stmt, 9) == SQLITE_NULL)
6293 		    null_max_size = 1;
6294 		else
6295 		    max_size = sqlite3_column_int (stmt, 9);
6296 		if (sqlite3_column_type (stmt, 10) == SQLITE_NULL
6297 		    || sqlite3_column_type (stmt, 11) == SQLITE_NULL)
6298 		    null_int_range = 1;
6299 		else
6300 		  {
6301 		      integer_min = sqlite3_column_int64 (stmt, 10);
6302 		      integer_max = sqlite3_column_int64 (stmt, 11);
6303 		  }
6304 		if (sqlite3_column_type (stmt, 12) == SQLITE_NULL
6305 		    || sqlite3_column_type (stmt, 13) == SQLITE_NULL)
6306 		    null_double_range = 1;
6307 		else
6308 		  {
6309 		      double_min = sqlite3_column_double (stmt, 12);
6310 		      double_max = sqlite3_column_double (stmt, 13);
6311 		  }
6312 		addLayerAttributeField (list, table_name, geometry_column,
6313 					ordinal, column_name, null_values,
6314 					integer_values, double_values,
6315 					text_values, blob_values, null_max_size,
6316 					max_size, null_int_range, &integer_min,
6317 					&integer_max, null_double_range,
6318 					double_min, double_max);
6319 	    }
6320       }
6321     ret = sqlite3_finalize (stmt);
6322 
6323   stop4:
6324     if (error)
6325 	return 0;
6326     return 1;
6327 }
6328 
6329 static int
get_table_layers_legacy(sqlite3 * handle,const char * table,const char * geometry,gaiaVectorLayersListPtr list)6330 get_table_layers_legacy (sqlite3 * handle, const char *table,
6331 			 const char *geometry, gaiaVectorLayersListPtr list)
6332 {
6333 /* fetching Table-based geometries */
6334     int ret;
6335     char *sql;
6336     const char *name;
6337     int i;
6338     char **results;
6339     int rows;
6340     int columns;
6341     int f_table = 0;
6342     int f_geometry = 0;
6343     int type = 0;
6344     int dims = 0;
6345     int srid = 0;
6346     int spatial_index = 0;
6347     sqlite3_stmt *stmt;
6348     int error = 0;
6349 
6350 /* checking the GEOMETRY_COLUMN table */
6351     sql = "PRAGMA table_info(geometry_columns)";
6352     ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
6353     if (ret != SQLITE_OK)
6354 	return 0;
6355     if (rows < 1)
6356 	;
6357     else
6358       {
6359 	  for (i = 1; i <= rows; i++)
6360 	    {
6361 		name = results[(i * columns) + 1];
6362 		if (strcasecmp (name, "f_table_name") == 0)
6363 		    f_table = 1;
6364 		if (strcasecmp (name, "f_geometry_column") == 0)
6365 		    f_geometry = 1;
6366 		if (strcasecmp (name, "type") == 0)
6367 		    type = 1;
6368 		if (strcasecmp (name, "coord_dimension") == 0)
6369 		    dims = 1;
6370 		if (strcasecmp (name, "srid") == 0)
6371 		    srid = 1;
6372 		if (strcasecmp (name, "spatial_index_enabled") == 0)
6373 		    spatial_index = 1;
6374 	    }
6375       }
6376     sqlite3_free_table (results);
6377     if (f_table && f_geometry && type && dims && srid && spatial_index)
6378 	;
6379     else
6380 	return 1;
6381 
6382     if (table == NULL)
6383 	sql =
6384 	    sqlite3_mprintf
6385 	    ("SELECT f_table_name, f_geometry_column, type, coord_dimension, "
6386 	     "srid, spatial_index_enabled FROM geometry_columns");
6387     else
6388       {
6389 	  if (geometry == NULL)
6390 	      sql =
6391 		  sqlite3_mprintf
6392 		  ("SELECT f_table_name, f_geometry_column, type, coord_dimension, "
6393 		   "srid, spatial_index_enabled FROM geometry_columns "
6394 		   "WHERE Lower(f_table_name) = Lower(%Q)", table);
6395 	  else
6396 	      sql =
6397 		  sqlite3_mprintf
6398 		  ("SELECT f_table_name, f_geometry_column, type, coord_dimension, "
6399 		   "srid, spatial_index_enabled FROM geometry_columns "
6400 		   "WHERE Lower(f_table_name) = Lower(%Q) AND "
6401 		   "Lower(f_geometry_column) = Lower(%Q)", table, geometry);
6402       }
6403 /* compiling SQL prepared statement */
6404     ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
6405     sqlite3_free (sql);
6406     if (ret != SQLITE_OK)
6407       {
6408 	  error = 1;
6409 	  goto stop;
6410       }
6411     while (1)
6412       {
6413 	  /* scrolling the result set rows */
6414 	  ret = sqlite3_step (stmt);
6415 	  if (ret == SQLITE_DONE)
6416 	      break;		/* end of result set */
6417 	  if (ret == SQLITE_ROW)
6418 	    {
6419 		/* processing a VectorLayer row */
6420 		const char *table_name =
6421 		    (const char *) sqlite3_column_text (stmt, 0);
6422 		const char *geometry_column =
6423 		    (const char *) sqlite3_column_text (stmt, 1);
6424 		const char *type = (const char *) sqlite3_column_text (stmt, 2);
6425 		const char *dims = (const char *) sqlite3_column_text (stmt, 3);
6426 		int srid = sqlite3_column_int (stmt, 4);
6427 		int spatial_index = sqlite3_column_int (stmt, 5);
6428 		int geometry_type = -1;
6429 		if (strcasecmp (type, "POINT") == 0)
6430 		    geometry_type = 1;
6431 		if (strcasecmp (type, "LINESTRING") == 0)
6432 		    geometry_type = 2;
6433 		if (strcasecmp (type, "POLYGON") == 0)
6434 		    geometry_type = 3;
6435 		if (strcasecmp (type, "MULTIPOINT") == 0)
6436 		    geometry_type = 4;
6437 		if (strcasecmp (type, "MULTILINESTRING") == 0)
6438 		    geometry_type = 5;
6439 		if (strcasecmp (type, "MULTIPOLYGON") == 0)
6440 		    geometry_type = 6;
6441 		if (strcasecmp (type, "GEOMETRYCOLLECTION") == 0)
6442 		    geometry_type = 7;
6443 		if (strcasecmp (type, "GEOMETRY") == 0)
6444 		    geometry_type = 0;
6445 		if (strcasecmp (dims, "XYZ") == 0
6446 		    || strcasecmp (dims, "3") == 0)
6447 		    geometry_type += 1000;
6448 		if (strcasecmp (dims, "XYM") == 0)
6449 		    geometry_type += 2000;
6450 		if (strcasecmp (dims, "XYZM") == 0
6451 		    || strcasecmp (dims, "4") == 0)
6452 		    geometry_type += 3000;
6453 		addVectorLayer (list, "SpatialTable", table_name,
6454 				geometry_column, geometry_type, srid,
6455 				spatial_index);
6456 		addVectorLayerAuth (handle, list, table_name, geometry_column,
6457 				    1, 0);
6458 	    }
6459 	  else
6460 	      error = 1;
6461       }
6462     ret = sqlite3_finalize (stmt);
6463 
6464   stop:
6465     if (error)
6466 	return 0;
6467     return 1;
6468 }
6469 
6470 static int
get_view_layers_legacy(sqlite3 * handle,const char * table,const char * geometry,gaiaVectorLayersListPtr list)6471 get_view_layers_legacy (sqlite3 * handle, const char *table,
6472 			const char *geometry, gaiaVectorLayersListPtr list)
6473 {
6474 /* fetching View-based geometries */
6475     int ret;
6476     char *sql;
6477     const char *name;
6478     int i;
6479     char **results;
6480     int rows;
6481     int columns;
6482     int f_table = 0;
6483     int f_geometry = 0;
6484     int type = 0;
6485     int dims = 0;
6486     int srid = 0;
6487     int spatial_index = 0;
6488     int view_name = 0;
6489     int view_geometry = 0;
6490     int fvw_table = 0;
6491     int fvw_geometry = 0;
6492     sqlite3_stmt *stmt;
6493     int error = 0;
6494 
6495 /* checking the GEOMETRY_COLUMN table */
6496     sql = "PRAGMA table_info(geometry_columns)";
6497     ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
6498     if (ret != SQLITE_OK)
6499 	return 0;
6500     if (rows < 1)
6501 	;
6502     else
6503       {
6504 	  for (i = 1; i <= rows; i++)
6505 	    {
6506 		name = results[(i * columns) + 1];
6507 		if (strcasecmp (name, "f_table_name") == 0)
6508 		    f_table = 1;
6509 		if (strcasecmp (name, "f_geometry_column") == 0)
6510 		    f_geometry = 1;
6511 		if (strcasecmp (name, "type") == 0)
6512 		    type = 1;
6513 		if (strcasecmp (name, "coord_dimension") == 0)
6514 		    dims = 1;
6515 		if (strcasecmp (name, "srid") == 0)
6516 		    srid = 1;
6517 		if (strcasecmp (name, "spatial_index_enabled") == 0)
6518 		    spatial_index = 1;
6519 	    }
6520       }
6521     sqlite3_free_table (results);
6522     if (f_table && f_geometry && type && dims && srid && spatial_index)
6523 	;
6524     else
6525 	return 1;
6526 
6527 /* checking the VIEWS_GEOMETRY_COLUMN table */
6528     sql = "PRAGMA table_info(views_geometry_columns)";
6529     ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
6530     if (ret != SQLITE_OK)
6531 	return 0;
6532     if (rows < 1)
6533 	;
6534     else
6535       {
6536 	  for (i = 1; i <= rows; i++)
6537 	    {
6538 		name = results[(i * columns) + 1];
6539 		if (strcasecmp (name, "view_name") == 0)
6540 		    view_name = 1;
6541 		if (strcasecmp (name, "view_geometry") == 0)
6542 		    view_geometry = 1;
6543 		if (strcasecmp (name, "f_table_name") == 0)
6544 		    fvw_table = 1;
6545 		if (strcasecmp (name, "f_geometry_column") == 0)
6546 		    fvw_geometry = 1;
6547 	    }
6548       }
6549     sqlite3_free_table (results);
6550     if (view_name && view_geometry && fvw_table && fvw_geometry)
6551 	;
6552     else
6553 	return 1;
6554 
6555     if (table == NULL)
6556 	sql =
6557 	    sqlite3_mprintf
6558 	    ("SELECT a.view_name, a.view_geometry, b.type, b.coord_dimension, "
6559 	     "b.srid, b.spatial_index_enabled FROM views_geometry_columns AS a "
6560 	     "JOIN geometry_columns AS b ON (Lower(a.f_table_name) = Lower(b.f_table_name) "
6561 	     "AND Lower(a.f_geometry_column) = Lower(b.f_geometry_column))");
6562     else
6563       {
6564 	  if (geometry == NULL)
6565 	      sql =
6566 		  sqlite3_mprintf
6567 		  ("SELECT a.view_name, a.view_geometry, b.type, b.coord_dimension, "
6568 		   "b.srid, b.spatial_index_enabled FROM views_geometry_columns AS a "
6569 		   "JOIN geometry_columns AS b ON (Lower(a.f_table_name) = Lower(b.f_table_name) "
6570 		   "AND Lower(a.f_geometry_column) = Lower(b.f_geometry_column)) "
6571 		   "WHERE Lower(a.view_name) = Lower(%Q)", table);
6572 	  else
6573 	      sql =
6574 		  sqlite3_mprintf
6575 		  ("SELECT a.view_name, a.view_geometry, b.type, b.coord_dimension, "
6576 		   "b.srid, b.spatial_index_enabled FROM views_geometry_columns AS a "
6577 		   "JOIN geometry_columns AS b ON (Lower(a.f_table_name) = Lower(b.f_table_name) "
6578 		   "AND Lower(a.f_geometry_column) = Lower(b.f_geometry_column)) "
6579 		   "WHERE Lower(a.view_name) = Lower(%Q) AND "
6580 		   "Lower(a.view_geometry) = Lower(%Q)", table, geometry);
6581       }
6582 /* compiling SQL prepared statement */
6583     ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
6584     sqlite3_free (sql);
6585     if (ret != SQLITE_OK)
6586       {
6587 	  error = 1;
6588 	  goto stop;
6589       }
6590     while (1)
6591       {
6592 	  /* scrolling the result set rows */
6593 	  ret = sqlite3_step (stmt);
6594 	  if (ret == SQLITE_DONE)
6595 	      break;		/* end of result set */
6596 	  if (ret == SQLITE_ROW)
6597 	    {
6598 		/* processing a VectorLayer row */
6599 		const char *table_name =
6600 		    (const char *) sqlite3_column_text (stmt, 0);
6601 		const char *geometry_column =
6602 		    (const char *) sqlite3_column_text (stmt, 1);
6603 		const char *type = (const char *) sqlite3_column_text (stmt, 2);
6604 		const char *dims = (const char *) sqlite3_column_text (stmt, 3);
6605 		int srid = sqlite3_column_int (stmt, 4);
6606 		int spatial_index = sqlite3_column_int (stmt, 5);
6607 		int geometry_type = -1;
6608 		if (strcasecmp (type, "POINT") == 0)
6609 		    geometry_type = 1;
6610 		if (strcasecmp (type, "LINESTRING") == 0)
6611 		    geometry_type = 2;
6612 		if (strcasecmp (type, "POLYGON") == 0)
6613 		    geometry_type = 3;
6614 		if (strcasecmp (type, "MULTIPOINT") == 0)
6615 		    geometry_type = 4;
6616 		if (strcasecmp (type, "MULTILINESTRING") == 0)
6617 		    geometry_type = 5;
6618 		if (strcasecmp (type, "MULTIPOLYGON") == 0)
6619 		    geometry_type = 6;
6620 		if (strcasecmp (type, "GEOMETRYCOLLECTION") == 0)
6621 		    geometry_type = 7;
6622 		if (strcasecmp (type, "GEOMETRY") == 0)
6623 		    geometry_type = 0;
6624 		if (strcasecmp (dims, "XYZ") == 0
6625 		    || strcasecmp (dims, "3") == 0)
6626 		    geometry_type += 1000;
6627 		if (strcasecmp (dims, "XYM") == 0)
6628 		    geometry_type += 2000;
6629 		if (strcasecmp (dims, "XYZM") == 0
6630 		    || strcasecmp (dims, "4") == 0)
6631 		    geometry_type += 3000;
6632 		addVectorLayer (list, "SpatialView", table_name,
6633 				geometry_column, geometry_type, srid,
6634 				spatial_index);
6635 	    }
6636 	  else
6637 	      error = 1;
6638       }
6639     ret = sqlite3_finalize (stmt);
6640 
6641   stop:
6642     if (error)
6643 	return 0;
6644     return 1;
6645 }
6646 
6647 static int
get_table_extent_legacy(sqlite3 * handle,const char * table,const char * geometry,gaiaVectorLayersListPtr list)6648 get_table_extent_legacy (sqlite3 * handle, const char *table,
6649 			 const char *geometry, gaiaVectorLayersListPtr list)
6650 {
6651 /* fetching Table-based extents */
6652     int ret;
6653     char *sql;
6654     const char *name;
6655     int i;
6656     char **results;
6657     int rows;
6658     int columns;
6659     int f_table = 0;
6660     int f_geometry = 0;
6661     int count = 0;
6662     int minx = 0;
6663     int miny = 0;
6664     int maxx = 0;
6665     int maxy = 0;
6666     sqlite3_stmt *stmt;
6667 
6668 /* checking the LAYER_STATISTICS table */
6669     sql = "PRAGMA table_info(layer_statistics)";
6670     ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
6671     if (ret != SQLITE_OK)
6672 	return 0;
6673     if (rows < 1)
6674 	;
6675     else
6676       {
6677 	  for (i = 1; i <= rows; i++)
6678 	    {
6679 		name = results[(i * columns) + 1];
6680 		if (strcasecmp (name, "table_name") == 0)
6681 		    f_table = 1;
6682 		if (strcasecmp (name, "geometry_column") == 0)
6683 		    f_geometry = 1;
6684 		if (strcasecmp (name, "row_count") == 0)
6685 		    count = 1;
6686 		if (strcasecmp (name, "extent_min_x") == 0)
6687 		    minx = 1;
6688 		if (strcasecmp (name, "extent_min_y") == 0)
6689 		    miny = 1;
6690 		if (strcasecmp (name, "extent_max_x") == 0)
6691 		    maxx = 1;
6692 		if (strcasecmp (name, "extent_max_y") == 0)
6693 		    maxy = 1;
6694 	    }
6695       }
6696     sqlite3_free_table (results);
6697     if (f_table && f_geometry && count && minx && miny && maxx && maxy)
6698 	;
6699     else
6700 	return 1;
6701 
6702 /* querying the layer_statistics table */
6703     if (table == NULL)
6704 	sql =
6705 	    sqlite3_mprintf
6706 	    ("SELECT table_name, geometry_column, row_count, extent_min_x, "
6707 	     "extent_min_y, extent_max_x, extent_max_y FROM layer_statistics");
6708     else
6709       {
6710 	  if (geometry == NULL)
6711 	      sql =
6712 		  sqlite3_mprintf
6713 		  ("SELECT table_name, geometry_column, row_count, extent_min_x, "
6714 		   "extent_min_y, extent_max_x, extent_max_y FROM layer_statistics "
6715 		   "WHERE Lower(table_name) = Lower(%Q)", table);
6716 	  else
6717 	      sql =
6718 		  sqlite3_mprintf
6719 		  ("SELECT table_name, geometry_column, row_count, extent_min_x, "
6720 		   "extent_min_y, extent_max_x, extent_max_y FROM layer_statistics "
6721 		   "WHERE Lower(table_name) = Lower(%Q) AND "
6722 		   "Lower(geometry_column) = Lower(%Q)", table, geometry);
6723       }
6724 /* compiling SQL prepared statement */
6725     ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
6726     sqlite3_free (sql);
6727     if (ret != SQLITE_OK)
6728 	goto stop;
6729     while (1)
6730       {
6731 	  /* scrolling the result set rows */
6732 	  ret = sqlite3_step (stmt);
6733 	  if (ret == SQLITE_DONE)
6734 	      break;		/* end of result set */
6735 	  if (ret == SQLITE_ROW)
6736 	    {
6737 		/* processing a VectorLayer row */
6738 		int is_null = 0;
6739 		const char *table_name =
6740 		    (const char *) sqlite3_column_text (stmt, 0);
6741 		const char *geometry_column =
6742 		    (const char *) sqlite3_column_text (stmt, 1);
6743 		int count = 0;
6744 		double min_x = DBL_MAX;
6745 		double min_y = DBL_MAX;
6746 		double max_x = 0.0 - DBL_MAX;
6747 		double max_y = 0.0 - DBL_MAX;
6748 		if (sqlite3_column_type (stmt, 2) == SQLITE_NULL)
6749 		    is_null = 1;
6750 		else
6751 		    count = sqlite3_column_int (stmt, 2);
6752 		if (sqlite3_column_type (stmt, 3) == SQLITE_NULL)
6753 		    is_null = 1;
6754 		else
6755 		    min_x = sqlite3_column_double (stmt, 3);
6756 		if (sqlite3_column_type (stmt, 4) == SQLITE_NULL)
6757 		    is_null = 1;
6758 		else
6759 		    min_y = sqlite3_column_double (stmt, 4);
6760 		if (sqlite3_column_type (stmt, 5) == SQLITE_NULL)
6761 		    is_null = 1;
6762 		else
6763 		    max_x = sqlite3_column_double (stmt, 5);
6764 		if (sqlite3_column_type (stmt, 6) == SQLITE_NULL)
6765 		    is_null = 1;
6766 		else
6767 		    max_y = sqlite3_column_double (stmt, 6);
6768 		if (!is_null)
6769 		    addVectorLayerExtent (list, table_name, geometry_column,
6770 					  count, min_x, min_y, max_x, max_y);
6771 	    }
6772       }
6773     ret = sqlite3_finalize (stmt);
6774   stop:
6775     return 1;
6776 }
6777 
6778 static int
get_view_extent_legacy(sqlite3 * handle,const char * table,const char * geometry,gaiaVectorLayersListPtr list)6779 get_view_extent_legacy (sqlite3 * handle, const char *table,
6780 			const char *geometry, gaiaVectorLayersListPtr list)
6781 {
6782 /* fetching View-based extents */
6783     int ret;
6784     char *sql;
6785     const char *name;
6786     int i;
6787     char **results;
6788     int rows;
6789     int columns;
6790     int f_table = 0;
6791     int f_geometry = 0;
6792     int count = 0;
6793     int minx = 0;
6794     int miny = 0;
6795     int maxx = 0;
6796     int maxy = 0;
6797     sqlite3_stmt *stmt;
6798 
6799 /* checking the VIEWS_LAYER_STATISTICS table */
6800     sql = "PRAGMA table_info(views_layer_statistics)";
6801     ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
6802     if (ret != SQLITE_OK)
6803 	return 0;
6804     if (rows < 1)
6805 	;
6806     else
6807       {
6808 	  for (i = 1; i <= rows; i++)
6809 	    {
6810 		name = results[(i * columns) + 1];
6811 		if (strcasecmp (name, "view_name") == 0)
6812 		    f_table = 1;
6813 		if (strcasecmp (name, "view_geometry") == 0)
6814 		    f_geometry = 1;
6815 		if (strcasecmp (name, "row_count") == 0)
6816 		    count = 1;
6817 		if (strcasecmp (name, "extent_min_x") == 0)
6818 		    minx = 1;
6819 		if (strcasecmp (name, "extent_min_y") == 0)
6820 		    miny = 1;
6821 		if (strcasecmp (name, "extent_max_x") == 0)
6822 		    maxx = 1;
6823 		if (strcasecmp (name, "extent_max_y") == 0)
6824 		    maxy = 1;
6825 	    }
6826       }
6827     sqlite3_free_table (results);
6828     if (f_table && f_geometry && count && minx && miny && maxx && maxy)
6829 	;
6830     else
6831 	return 1;
6832 
6833 /* querying the views_layer_statistics table */
6834     if (table == NULL)
6835 	sql =
6836 	    sqlite3_mprintf
6837 	    ("SELECT view_name, view_geometry, row_count, extent_min_x, "
6838 	     "extent_min_y, extent_max_x, extent_max_y FROM views_layer_statistics");
6839     else
6840       {
6841 	  if (geometry == NULL)
6842 	      sql =
6843 		  sqlite3_mprintf
6844 		  ("SELECT view_name, view_geometry, row_count, extent_min_x, "
6845 		   "extent_min_y, extent_max_x, extent_max_y FROM views_layer_statistics "
6846 		   "WHERE Lower(view_name) = Lower(%Q)", table);
6847 	  else
6848 	      sql =
6849 		  sqlite3_mprintf
6850 		  ("SELECT view_name, view_geometry, row_count, extent_min_x, "
6851 		   "extent_min_y, extent_max_x, extent_max_y FROM views_layer_statistics "
6852 		   "WHERE Lower(view_name) = Lower(%Q) AND "
6853 		   "Lower(view_geometry) = Lower(%Q)", table, geometry);
6854       }
6855 /* compiling SQL prepared statement */
6856     ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
6857     sqlite3_free (sql);
6858     if (ret != SQLITE_OK)
6859 	goto stop;
6860     while (1)
6861       {
6862 	  /* scrolling the result set rows */
6863 	  ret = sqlite3_step (stmt);
6864 	  if (ret == SQLITE_DONE)
6865 	      break;		/* end of result set */
6866 	  if (ret == SQLITE_ROW)
6867 	    {
6868 		/* processing a VectorLayer row */
6869 		int is_null = 0;
6870 		const char *table_name =
6871 		    (const char *) sqlite3_column_text (stmt, 0);
6872 		const char *geometry_column =
6873 		    (const char *) sqlite3_column_text (stmt, 1);
6874 		int count = 0;
6875 		double min_x = DBL_MAX;
6876 		double min_y = DBL_MAX;
6877 		double max_x = 0.0 - DBL_MAX;
6878 		double max_y = 0.0 - DBL_MAX;
6879 		if (sqlite3_column_type (stmt, 2) == SQLITE_NULL)
6880 		    is_null = 1;
6881 		else
6882 		    count = sqlite3_column_int (stmt, 2);
6883 		if (sqlite3_column_type (stmt, 3) == SQLITE_NULL)
6884 		    is_null = 1;
6885 		else
6886 		    min_x = sqlite3_column_double (stmt, 3);
6887 		if (sqlite3_column_type (stmt, 4) == SQLITE_NULL)
6888 		    is_null = 1;
6889 		else
6890 		    min_y = sqlite3_column_double (stmt, 4);
6891 		if (sqlite3_column_type (stmt, 5) == SQLITE_NULL)
6892 		    is_null = 1;
6893 		else
6894 		    max_x = sqlite3_column_double (stmt, 5);
6895 		if (sqlite3_column_type (stmt, 6) == SQLITE_NULL)
6896 		    is_null = 1;
6897 		else
6898 		    max_y = sqlite3_column_double (stmt, 6);
6899 		if (!is_null)
6900 		    addVectorLayerExtent (list, table_name, geometry_column,
6901 					  count, min_x, min_y, max_x, max_y);
6902 	    }
6903       }
6904     ret = sqlite3_finalize (stmt);
6905   stop:
6906     return 1;
6907 }
6908 
6909 static int
get_table_auth_legacy(sqlite3 * handle,const char * table,const char * geometry,gaiaVectorLayersListPtr list)6910 get_table_auth_legacy (sqlite3 * handle, const char *table,
6911 		       const char *geometry, gaiaVectorLayersListPtr list)
6912 {
6913 /* fetching Table-based Auth */
6914     int ret;
6915     char *sql;
6916     const char *name;
6917     int i;
6918     char **results;
6919     int rows;
6920     int columns;
6921     int f_table = 0;
6922     int f_geometry = 0;
6923     int read_only = 0;
6924     int hidden = 0;
6925     sqlite3_stmt *stmt;
6926 
6927 /* checking the GEOMETRY_COLUMNS_AUTH table */
6928     sql = "PRAGMA table_info(geometry_columns_auth)";
6929     ret = sqlite3_get_table (handle, sql, &results, &rows, &columns, NULL);
6930     if (ret != SQLITE_OK)
6931 	return 0;
6932     if (rows < 1)
6933 	;
6934     else
6935       {
6936 	  for (i = 1; i <= rows; i++)
6937 	    {
6938 		name = results[(i * columns) + 1];
6939 		if (strcasecmp (name, "f_table_name") == 0)
6940 		    f_table = 1;
6941 		if (strcasecmp (name, "f_geometry_column") == 0)
6942 		    f_geometry = 1;
6943 		if (strcasecmp (name, "read_only") == 0)
6944 		    read_only = 1;
6945 		if (strcasecmp (name, "hidden") == 0)
6946 		    hidden = 1;
6947 	    }
6948       }
6949     sqlite3_free_table (results);
6950     if (f_table && f_geometry && read_only && hidden)
6951 	;
6952     else
6953 	return 1;
6954 
6955 /* querying the geometry_columns_auth table */
6956     if (table == NULL)
6957 	sql =
6958 	    sqlite3_mprintf
6959 	    ("SELECT f_table_name, f_geometry_column, read_only, hidden "
6960 	     "FROM geometry_columns_auth");
6961     else
6962       {
6963 	  if (geometry == NULL)
6964 	      sql =
6965 		  sqlite3_mprintf
6966 		  ("SELECT f_table_name, f_geometry_column, read_only, hidden "
6967 		   "FROM geometry_columns_auth "
6968 		   "WHERE Lower(f_table_name) = Lower(%Q)", table);
6969 	  else
6970 	      sql =
6971 		  sqlite3_mprintf
6972 		  ("SELECT f_table_name, f_geometry_column, read_only, hidden "
6973 		   "FROM geometry_columns_auth "
6974 		   "WHERE Lower(f_table_name) = Lower(%Q) AND "
6975 		   "Lower(f_geometry_column) = Lower(%Q)", table, geometry);
6976       }
6977 /* compiling SQL prepared statement */
6978     ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
6979     sqlite3_free (sql);
6980     if (ret != SQLITE_OK)
6981 	goto stop;
6982     while (1)
6983       {
6984 	  /* scrolling the result set rows */
6985 	  ret = sqlite3_step (stmt);
6986 	  if (ret == SQLITE_DONE)
6987 	      break;		/* end of result set */
6988 	  if (ret == SQLITE_ROW)
6989 	    {
6990 		/* processing a VectorLayer row */
6991 		int is_null = 0;
6992 		const char *table_name =
6993 		    (const char *) sqlite3_column_text (stmt, 0);
6994 		const char *geometry_column =
6995 		    (const char *) sqlite3_column_text (stmt, 1);
6996 		int read_only = 0;
6997 		int hidden = 0;
6998 		if (sqlite3_column_type (stmt, 2) == SQLITE_NULL)
6999 		    is_null = 1;
7000 		else
7001 		    read_only = sqlite3_column_int (stmt, 2);
7002 		if (sqlite3_column_type (stmt, 3) == SQLITE_NULL)
7003 		    is_null = 1;
7004 		else
7005 		    hidden = sqlite3_column_int (stmt, 3);
7006 		if (!is_null)
7007 		    addVectorLayerAuth (handle, list, table_name,
7008 					geometry_column, read_only, hidden);
7009 	    }
7010       }
7011     ret = sqlite3_finalize (stmt);
7012   stop:
7013     return 1;
7014 }
7015 
7016 static int
compute_table_fields_statistics(sqlite3 * handle,const char * table,const char * geometry,gaiaVectorLayersListPtr list)7017 compute_table_fields_statistics (sqlite3 * handle, const char *table,
7018 				 const char *geometry,
7019 				 gaiaVectorLayersListPtr list)
7020 {
7021 /* computing field statistics - legacy */
7022     gaiaVectorLayerPtr lyr;
7023     lyr = list->First;
7024     while (lyr)
7025       {
7026 	  /* testing if the Table/Geometry is already defined */
7027 	  if (geometry == NULL)
7028 	    {
7029 		if (strcasecmp (lyr->TableName, table) == 0)
7030 		  {
7031 		      if (!doComputeFieldInfos
7032 			  (handle, lyr->TableName, lyr->GeometryName,
7033 			   SPATIALITE_STATISTICS_LEGACY, lyr))
7034 			  return 0;
7035 		  }
7036 	    }
7037 	  else
7038 	    {
7039 		if (strcasecmp (lyr->TableName, table) == 0
7040 		    && strcasecmp (lyr->GeometryName, geometry) == 0)
7041 		  {
7042 		      if (!doComputeFieldInfos
7043 			  (handle, lyr->TableName, lyr->GeometryName,
7044 			   SPATIALITE_STATISTICS_LEGACY, lyr))
7045 			  return 0;
7046 		  }
7047 	    }
7048 	  lyr = lyr->Next;
7049       }
7050     return 1;
7051 }
7052 
7053 static int
check_v4_statistics(sqlite3 * handle)7054 check_v4_statistics (sqlite3 * handle)
7055 {
7056 /* checking if v.4.0.0 statistics tables are supported */
7057     char *sql_statement;
7058     int ret;
7059     char **results;
7060     int rows;
7061     int columns;
7062 
7063 /* testing the SQL Query */
7064     sql_statement =
7065 	sqlite3_mprintf ("SELECT g.table_name, g.geometry_column, "
7066 			 "s.row_count, s.extent_min_x, s.extent_min_y, "
7067 			 "s.extent_max_x, s.extent_max_y "
7068 			 "FROM vector_layers AS g "
7069 			 "LEFT JOIN vector_layers_statistics AS s ON "
7070 			 "(g.table_name = s.table_name AND "
7071 			 "g.geometry_column = s.geometry_column) LIMIT 1");
7072     ret =
7073 	sqlite3_get_table (handle, sql_statement, &results, &rows, &columns,
7074 			   NULL);
7075     sqlite3_free (sql_statement);
7076     if (ret != SQLITE_OK)
7077 	return 0;
7078     sqlite3_free_table (results);
7079 
7080     return 1;
7081 }
7082 
7083 static int
check_v3_statistics(sqlite3 * handle)7084 check_v3_statistics (sqlite3 * handle)
7085 {
7086 /* checking if v.3.0.0 statistics tables are supported */
7087     char *sql_statement;
7088     int ret;
7089     char **results;
7090     int rows;
7091     int columns;
7092 
7093     if (!check_layer_statistics (handle))
7094 	return 0;
7095 /* testing the SQL Query - Table-based Geometries */
7096     sql_statement =
7097 	sqlite3_mprintf ("SELECT g.f_table_name, g.f_geometry_column, "
7098 			 "s.row_count, s.extent_min_x, s.extent_min_y, "
7099 			 "s.extent_max_x, s.extent_max_y "
7100 			 "FROM geometry_columns AS g "
7101 			 "LEFT JOIN layer_statistics AS s ON "
7102 			 "(g.f_table_name = s.table_name AND "
7103 			 "g.f_geometry_column = s.geometry_column) LIMIT 1");
7104     ret =
7105 	sqlite3_get_table (handle, sql_statement, &results, &rows, &columns,
7106 			   NULL);
7107     sqlite3_free (sql_statement);
7108     if (ret != SQLITE_OK)
7109 	return 0;
7110     sqlite3_free_table (results);
7111 
7112     if (!check_views_layer_statistics (handle))
7113 	return 0;
7114 /* testing the SQL Query - View-based Geometries */
7115     sql_statement =
7116 	sqlite3_mprintf ("SELECT g.view_name, g.view_geometry, "
7117 			 "s.row_count, s.extent_min_x, s.extent_min_y, "
7118 			 "s.extent_max_x, s.extent_max_y "
7119 			 "FROM views_geometry_columns AS g "
7120 			 "LEFT JOIN views_layer_statistics AS s ON "
7121 			 "(g.view_name = s.view_name AND "
7122 			 "g.view_geometry = s.view_geometry) LIMIT 1");
7123     ret =
7124 	sqlite3_get_table (handle, sql_statement, &results, &rows, &columns,
7125 			   NULL);
7126     sqlite3_free (sql_statement);
7127     if (ret != SQLITE_OK)
7128 	return 0;
7129     sqlite3_free_table (results);
7130 
7131     if (!check_virts_layer_statistics (handle))
7132 	return 0;
7133 /* testing the SQL Query - VirtualShape-based Geometries */
7134     sql_statement =
7135 	sqlite3_mprintf ("SELECT g.virt_name, g.virt_geometry, "
7136 			 "s.row_count, s.extent_min_x, s.extent_min_y, "
7137 			 "s.extent_max_x, s.extent_max_y "
7138 			 "FROM virts_geometry_columns AS g "
7139 			 "LEFT JOIN virts_layer_statistics AS s ON "
7140 			 "(g.virt_name = s.virt_name AND "
7141 			 "g.virt_geometry = s.virt_geometry) LIMIT 1");
7142     ret =
7143 	sqlite3_get_table (handle, sql_statement, &results, &rows, &columns,
7144 			   NULL);
7145     sqlite3_free (sql_statement);
7146     if (ret != SQLITE_OK)
7147 	return 0;
7148     sqlite3_free_table (results);
7149 
7150     return 1;
7151 }
7152 
7153 static int
check_v2_statistics(sqlite3 * handle)7154 check_v2_statistics (sqlite3 * handle)
7155 {
7156 /* checking if v.2.0.0 statistics tables are supported */
7157     char *sql_statement;
7158     int ret;
7159     char **results;
7160     int rows;
7161     int columns;
7162 
7163     if (!check_layer_statistics (handle))
7164 	return 0;
7165 /* testing the SQL Query - Table-based Geometries */
7166     sql_statement =
7167 	sqlite3_mprintf ("SELECT g.f_table_name, g.f_geometry_column, "
7168 			 "s.row_count, s.extent_min_x, s.extent_min_y, "
7169 			 "s.extent_max_x, s.extent_max_y "
7170 			 "FROM geometry_columns AS g "
7171 			 "LEFT JOIN layer_statistics AS s ON "
7172 			 "(g.f_table_name = s.table_name AND "
7173 			 "g.f_geometry_column = s.geometry_column) LIMIT 1");
7174     ret =
7175 	sqlite3_get_table (handle, sql_statement, &results, &rows, &columns,
7176 			   NULL);
7177     sqlite3_free (sql_statement);
7178     if (ret != SQLITE_OK)
7179 	return 0;
7180     sqlite3_free_table (results);
7181 
7182     return 1;
7183 }
7184 
7185 static int
optimistic_layer_statistics_v4(sqlite3 * handle,const char * table,const char * geometry)7186 optimistic_layer_statistics_v4 (sqlite3 * handle, const char *table,
7187 				const char *geometry)
7188 {
7189 /* selective statistics update - v.4.0.0 layout */
7190     char *sql_statement;
7191     int ret;
7192     const char *f_table_name;
7193     const char *f_geometry_column;
7194     int i;
7195     char **results;
7196     int rows;
7197     int columns;
7198     int error = 0;
7199 
7200     if (table == NULL && geometry == NULL)
7201       {
7202 	  /* processing any table/geometry found in GEOMETRY_COLUMNS */
7203 	  sql_statement =
7204 	      sqlite3_mprintf ("SELECT g.table_name, g.geometry_column "
7205 			       "FROM vector_layers AS g "
7206 			       "LEFT JOIN vector_layers_statistics AS s ON "
7207 			       "(g.table_name = s.table_name AND "
7208 			       "g.geometry_column = s.geometry_column) "
7209 			       "WHERE s.row_count IS NULL OR s.extent_min_x IS NULL "
7210 			       "OR s.extent_min_y IS NULL OR s.extent_max_y IS NULL "
7211 			       "OR s.extent_max_y IS NULL");
7212       }
7213     else if (geometry == NULL)
7214       {
7215 	  /* processing any geometry belonging to this table */
7216 	  sql_statement =
7217 	      sqlite3_mprintf ("SELECT g.table_name, g.geometry_column "
7218 			       "FROM vector_layers AS g "
7219 			       "LEFT JOIN vector_layers_statistics AS s ON "
7220 			       "(g.table_name = s.table_name AND "
7221 			       "g.geometry_column = s.geometry_column) "
7222 			       "WHERE Lower(g.table_name) = Lower(%Q) AND "
7223 			       "(s.row_count IS NULL OR s.extent_min_x IS NULL "
7224 			       "OR s.extent_min_y IS NULL OR s.extent_max_y IS NULL "
7225 			       "OR s.extent_max_y IS NULL)", table);
7226       }
7227     else
7228       {
7229 	  /* processing a single table/geometry entry */
7230 	  sql_statement =
7231 	      sqlite3_mprintf ("SELECT g.table_name, g.geometry_column "
7232 			       "FROM vector_layers AS g "
7233 			       "LEFT JOIN vector_layers_statistics AS s ON "
7234 			       "(g.table_name = s.table_name AND "
7235 			       "g.geometry_column = s.geometry_column) "
7236 			       "WHERE Lower(g.table_name) = Lower(%Q) AND "
7237 			       "Lower(g.geometry_column) = Lower(%Q) AND "
7238 			       "(s.row_count IS NULL OR s.extent_min_x IS NULL "
7239 			       "OR s.extent_min_y IS NULL OR s.extent_max_y IS NULL "
7240 			       "OR s.extent_max_y IS NULL)", table, geometry);
7241       }
7242     ret =
7243 	sqlite3_get_table (handle, sql_statement, &results, &rows, &columns,
7244 			   NULL);
7245     sqlite3_free (sql_statement);
7246     if (ret != SQLITE_OK)
7247 	return 0;
7248 
7249     if (rows < 1)
7250 	;
7251     else
7252       {
7253 	  for (i = 1; i <= rows; i++)
7254 	    {
7255 		f_table_name = results[(i * columns) + 0];
7256 		f_geometry_column = results[(i * columns) + 1];
7257 		if (!update_layer_statistics
7258 		    (handle, f_table_name, f_geometry_column))
7259 		  {
7260 		      error = 1;
7261 		      break;
7262 		  }
7263 	    }
7264       }
7265     sqlite3_free_table (results);
7266     if (error)
7267 	return 0;
7268     return 1;
7269 }
7270 
7271 static int
optimistic_layer_statistics_v3(sqlite3 * handle,const char * table,const char * geometry)7272 optimistic_layer_statistics_v3 (sqlite3 * handle, const char *table,
7273 				const char *geometry)
7274 {
7275 /* selective statistics update - v.3.0.0 layout */
7276     char *sql_statement;
7277     int ret;
7278     const char *f_table_name;
7279     const char *f_geometry_column;
7280     int i;
7281     char **results;
7282     int rows;
7283     int columns;
7284     int error = 0;
7285 
7286 /* genuine Table-based Geometries */
7287     if (table == NULL && geometry == NULL)
7288       {
7289 	  /* processing any table/geometry found in GEOMETRY_COLUMNS */
7290 	  sql_statement =
7291 	      sqlite3_mprintf ("SELECT g.f_table_name, g.f_geometry_column "
7292 			       "FROM geometry_columns AS g "
7293 			       "LEFT JOIN layer_statistics AS s ON "
7294 			       "(g.f_table_name = s.table_name AND "
7295 			       "g.f_geometry_column = s.geometry_column) "
7296 			       "WHERE s.row_count IS NULL OR s.extent_min_x IS NULL "
7297 			       "OR s.extent_min_y IS NULL OR s.extent_max_y IS NULL "
7298 			       "OR s.extent_max_y IS NULL");
7299       }
7300     else if (geometry == NULL)
7301       {
7302 	  /* processing any geometry belonging to this table */
7303 	  sql_statement =
7304 	      sqlite3_mprintf ("SELECT g.f_table_name, g.f_geometry_column "
7305 			       "FROM geometry_columns AS g "
7306 			       "LEFT JOIN layer_statistics AS s ON "
7307 			       "(g.f_table_name = s.table_name AND "
7308 			       "g.f_geometry_column = s.geometry_column) "
7309 			       "WHERE Lower(g.f_table_name) = Lower(%Q) AND "
7310 			       "(s.row_count IS NULL OR s.extent_min_x IS NULL "
7311 			       "OR s.extent_min_y IS NULL OR s.extent_max_y IS NULL "
7312 			       "OR s.extent_max_y IS NULL)", table);
7313       }
7314     else
7315       {
7316 	  /* processing a single table/geometry entry */
7317 	  sql_statement =
7318 	      sqlite3_mprintf ("SELECT g.f_table_name, g.f_geometry_column "
7319 			       "FROM geometry_columns AS g "
7320 			       "LEFT JOIN layer_statistics AS s ON "
7321 			       "(g.f_table_name = s.table_name AND "
7322 			       "g.f_geometry_column = s.geometry_column) "
7323 			       "WHERE Lower(g.f_table_name) = Lower(%Q) AND "
7324 			       "Lower(g.f_geometry_column) = Lower(%Q) AND "
7325 			       "(s.row_count IS NULL OR s.extent_min_x IS NULL "
7326 			       "OR s.extent_min_y IS NULL OR s.extent_max_y IS NULL "
7327 			       "OR s.extent_max_y IS NULL)", table, geometry);
7328       }
7329     ret =
7330 	sqlite3_get_table (handle, sql_statement, &results, &rows, &columns,
7331 			   NULL);
7332     sqlite3_free (sql_statement);
7333     if (ret != SQLITE_OK)
7334 	return 0;
7335 
7336     if (rows < 1)
7337 	;
7338     else
7339       {
7340 	  for (i = 1; i <= rows; i++)
7341 	    {
7342 		f_table_name = results[(i * columns) + 0];
7343 		f_geometry_column = results[(i * columns) + 1];
7344 		if (!update_layer_statistics
7345 		    (handle, f_table_name, f_geometry_column))
7346 		  {
7347 		      error = 1;
7348 		      break;
7349 		  }
7350 	    }
7351       }
7352     sqlite3_free_table (results);
7353     if (error)
7354 	return 0;
7355 
7356 /* View Based Geometries */
7357     if (table == NULL && geometry == NULL)
7358       {
7359 	  /* processing any table/geometry found in GEOMETRY_COLUMNS */
7360 	  sql_statement =
7361 	      sqlite3_mprintf ("SELECT g.view_name, g.view_geometry "
7362 			       "FROM views_geometry_columns AS g "
7363 			       "LEFT JOIN views_layer_statistics AS s ON "
7364 			       "(g.view_name = s.view_name AND "
7365 			       "g.view_geometry = s.view_geometry) "
7366 			       "WHERE s.row_count IS NULL OR s.extent_min_x IS NULL "
7367 			       "OR s.extent_min_y IS NULL OR s.extent_max_y IS NULL "
7368 			       "OR s.extent_max_y IS NULL");
7369       }
7370     else if (geometry == NULL)
7371       {
7372 	  /* processing any geometry belonging to this table */
7373 	  sql_statement =
7374 	      sqlite3_mprintf ("SELECT g.view_name, g.view_geometry "
7375 			       "FROM views_geometry_columns AS g "
7376 			       "LEFT JOIN views_layer_statistics AS s ON "
7377 			       "(g.view_name = s.view_name AND "
7378 			       "g.view_geometry = s.view_geometry) "
7379 			       "WHERE Lower(g.view_name) = Lower(%Q) AND "
7380 			       "(s.row_count IS NULL OR s.extent_min_x IS NULL "
7381 			       "OR s.extent_min_y IS NULL OR s.extent_max_y IS NULL "
7382 			       "OR s.extent_max_y IS NULL)", table);
7383       }
7384     else
7385       {
7386 	  /* processing a single table/geometry entry */
7387 	  sql_statement =
7388 	      sqlite3_mprintf ("SELECT g.view_name, g.view_geometry "
7389 			       "FROM views_geometry_columns AS g "
7390 			       "LEFT JOIN views_layer_statistics AS s ON "
7391 			       "(g.view_name = s.view_name AND "
7392 			       "g.view_geometry = s.view_geometry) "
7393 			       "WHERE Lower(g.view_name) = Lower(%Q) AND "
7394 			       "Lower(g.view_geometry) = Lower(%Q) AND "
7395 			       "(s.row_count IS NULL OR s.extent_min_x IS NULL "
7396 			       "OR s.extent_min_y IS NULL OR s.extent_max_y IS NULL "
7397 			       "OR s.extent_max_y IS NULL)", table, geometry);
7398       }
7399     ret =
7400 	sqlite3_get_table (handle, sql_statement, &results, &rows, &columns,
7401 			   NULL);
7402     sqlite3_free (sql_statement);
7403     if (ret != SQLITE_OK)
7404 	return 0;
7405 
7406     if (rows < 1)
7407 	;
7408     else
7409       {
7410 	  for (i = 1; i <= rows; i++)
7411 	    {
7412 		f_table_name = results[(i * columns) + 0];
7413 		f_geometry_column = results[(i * columns) + 1];
7414 		if (!update_layer_statistics
7415 		    (handle, f_table_name, f_geometry_column))
7416 		  {
7417 		      error = 1;
7418 		      break;
7419 		  }
7420 	    }
7421       }
7422     sqlite3_free_table (results);
7423     if (error)
7424 	return 0;
7425 
7426 /* VirtualShape Based Geometries */
7427     if (table == NULL && geometry == NULL)
7428       {
7429 	  /* processing any table/geometry found in GEOMETRY_COLUMNS */
7430 	  sql_statement =
7431 	      sqlite3_mprintf ("SELECT g.virt_name, g.virt_geometry "
7432 			       "FROM virts_geometry_columns AS g "
7433 			       "LEFT JOIN virts_layer_statistics AS s ON "
7434 			       "(g.virt_name = s.virt_name AND "
7435 			       "g.virt_geometry = s.virt_geometry) "
7436 			       "WHERE s.row_count IS NULL OR s.extent_min_x IS NULL "
7437 			       "OR s.extent_min_y IS NULL OR s.extent_max_y IS NULL "
7438 			       "OR s.extent_max_y IS NULL");
7439       }
7440     else if (geometry == NULL)
7441       {
7442 	  /* processing any geometry belonging to this table */
7443 	  sql_statement =
7444 	      sqlite3_mprintf ("SELECT g.virt_name, g.virt_geometry "
7445 			       "FROM virts_geometry_columns AS g "
7446 			       "LEFT JOIN virts_layer_statistics AS s ON "
7447 			       "(g.virt_name = s.virt_name AND "
7448 			       "g.virt_geometry = s.virt_geometry) "
7449 			       "WHERE Lower(g.virt_name) = Lower(%Q) AND "
7450 			       "(s.row_count IS NULL OR s.extent_min_x IS NULL "
7451 			       "OR s.extent_min_y IS NULL OR s.extent_max_y IS NULL "
7452 			       "OR s.extent_max_y IS NULL)", table);
7453       }
7454     else
7455       {
7456 	  /* processing a single table/geometry entry */
7457 	  sql_statement =
7458 	      sqlite3_mprintf ("SELECT g.virt_name, g.virt_geometry "
7459 			       "FROM virts_geometry_columns AS g "
7460 			       "LEFT JOIN virts_layer_statistics AS s ON "
7461 			       "(g.virt_name = s.virt_name AND "
7462 			       "g.virt_geometry = s.virt_geometry) "
7463 			       "WHERE Lower(g.virt_name) = Lower(%Q) AND "
7464 			       "Lower(g.virt_geometry) = Lower(%Q) AND "
7465 			       "(s.row_count IS NULL OR s.extent_min_x IS NULL "
7466 			       "OR s.extent_min_y IS NULL OR s.extent_max_y IS NULL "
7467 			       "OR s.extent_max_y IS NULL)", table, geometry);
7468       }
7469     ret =
7470 	sqlite3_get_table (handle, sql_statement, &results, &rows, &columns,
7471 			   NULL);
7472     sqlite3_free (sql_statement);
7473     if (ret != SQLITE_OK)
7474 	return 0;
7475 
7476     if (rows < 1)
7477 	;
7478     else
7479       {
7480 	  for (i = 1; i <= rows; i++)
7481 	    {
7482 		f_table_name = results[(i * columns) + 0];
7483 		f_geometry_column = results[(i * columns) + 1];
7484 		if (!update_layer_statistics
7485 		    (handle, f_table_name, f_geometry_column))
7486 		  {
7487 		      error = 1;
7488 		      break;
7489 		  }
7490 	    }
7491       }
7492     sqlite3_free_table (results);
7493     if (error)
7494 	return 0;
7495     return 1;
7496 }
7497 
7498 static int
optimistic_layer_statistics_v2(sqlite3 * handle,const char * table,const char * geometry)7499 optimistic_layer_statistics_v2 (sqlite3 * handle, const char *table,
7500 				const char *geometry)
7501 {
7502 /* selective statistics update - v.2.0.0 layout */
7503     char *sql_statement;
7504     int ret;
7505     const char *f_table_name;
7506     const char *f_geometry_column;
7507     int i;
7508     char **results;
7509     int rows;
7510     int columns;
7511     int error = 0;
7512 
7513 /* genuine Table-based Geometries */
7514     if (table == NULL && geometry == NULL)
7515       {
7516 	  /* processing any table/geometry found in GEOMETRY_COLUMNS */
7517 	  sql_statement =
7518 	      sqlite3_mprintf ("SELECT g.f_table_name, g.f_geometry_column "
7519 			       "FROM geometry_columns AS g "
7520 			       "LEFT JOIN layer_statistics AS s ON "
7521 			       "(g.f_table_name = s.table_name AND "
7522 			       "g.f_geometry_column = s.geometry_column) "
7523 			       "WHERE s.row_count IS NULL OR s.extent_min_x IS NULL "
7524 			       "OR s.extent_min_y IS NULL OR s.extent_max_y IS NULL "
7525 			       "OR s.extent_max_y IS NULL");
7526       }
7527     else if (geometry == NULL)
7528       {
7529 	  /* processing any geometry belonging to this table */
7530 	  sql_statement =
7531 	      sqlite3_mprintf ("SELECT g.f_table_name, g.f_geometry_column "
7532 			       "FROM geometry_columns AS g "
7533 			       "LEFT JOIN layer_statistics AS s ON "
7534 			       "(g.f_table_name = s.table_name AND "
7535 			       "g.f_geometry_column = s.geometry_column) "
7536 			       "WHERE Lower(g.f_table_name) = Lower(%Q) AND "
7537 			       "(s.row_count IS NULL OR s.extent_min_x IS NULL "
7538 			       "OR s.extent_min_y IS NULL OR s.extent_max_y IS NULL "
7539 			       "OR s.extent_max_y IS NULL)", table);
7540       }
7541     else
7542       {
7543 	  /* processing a single table/geometry entry */
7544 	  sql_statement =
7545 	      sqlite3_mprintf ("SELECT g.f_table_name, g.f_geometry_column "
7546 			       "FROM geometry_columns AS g "
7547 			       "LEFT JOIN layer_statistics AS s ON "
7548 			       "(g.f_table_name = s.table_name AND "
7549 			       "g.f_geometry_column = s.geometry_column) "
7550 			       "WHERE Lower(g.f_table_name) = Lower(%Q) AND "
7551 			       "Lower(g.f_geometry_column) = Lower(%Q) AND "
7552 			       "(s.row_count IS NULL OR s.extent_min_x IS NULL "
7553 			       "OR s.extent_min_y IS NULL OR s.extent_max_y IS NULL "
7554 			       "OR s.extent_max_y IS NULL)", table, geometry);
7555       }
7556     ret =
7557 	sqlite3_get_table (handle, sql_statement, &results, &rows, &columns,
7558 			   NULL);
7559     sqlite3_free (sql_statement);
7560     if (ret != SQLITE_OK)
7561 	return 0;
7562 
7563     if (rows < 1)
7564 	;
7565     else
7566       {
7567 	  for (i = 1; i <= rows; i++)
7568 	    {
7569 		f_table_name = results[(i * columns) + 0];
7570 		f_geometry_column = results[(i * columns) + 1];
7571 		if (!update_layer_statistics
7572 		    (handle, f_table_name, f_geometry_column))
7573 		  {
7574 		      error = 1;
7575 		      break;
7576 		  }
7577 	    }
7578       }
7579     sqlite3_free_table (results);
7580     if (error)
7581 	return 0;
7582     return 1;
7583 }
7584 
7585 static int
optimistic_layer_statistics(sqlite3 * handle,const char * table,const char * geometry)7586 optimistic_layer_statistics (sqlite3 * handle, const char *table,
7587 			     const char *geometry)
7588 {
7589 /* selective statistics update */
7590     if (check_v4_statistics (handle))
7591 	return optimistic_layer_statistics_v4 (handle, table, geometry);
7592     else if (check_v3_statistics (handle))
7593 	return optimistic_layer_statistics_v3 (handle, table, geometry);
7594     else if (check_v2_statistics (handle))
7595 	return optimistic_layer_statistics_v2 (handle, table, geometry);
7596     else
7597 	return 0;
7598 }
7599 
7600 SPATIALITE_DECLARE gaiaVectorLayersListPtr
gaiaGetVectorLayersList(sqlite3 * handle,const char * table,const char * geometry,int mode)7601 gaiaGetVectorLayersList (sqlite3 * handle, const char *table,
7602 			 const char *geometry, int mode)
7603 {
7604 /* creating a VectorLayersList object */
7605     gaiaVectorLayersListPtr list;
7606     int metadata_version;
7607 
7608     if (mode == GAIA_VECTORS_LIST_PESSIMISTIC)
7609       {
7610 	  /* updating anyway the statistics before querying */
7611 	  if (!update_layer_statistics (handle, table, geometry))
7612 	      return NULL;
7613       }
7614     if (mode == GAIA_VECTORS_LIST_OPTIMISTIC)
7615       {
7616 	  /* selectively updating the statistics before querying */
7617 	  if (!optimistic_layer_statistics (handle, table, geometry))
7618 	    {
7619 		/* failure: defaulting to Pessimistic */
7620 		if (!update_layer_statistics (handle, table, geometry))
7621 		    return NULL;
7622 	    }
7623       }
7624 
7625 /* allocating an empty VectorLayersList */
7626     list = malloc (sizeof (gaiaVectorLayersList));
7627     list->First = NULL;
7628     list->Last = NULL;
7629     list->Current = NULL;
7630 
7631     metadata_version = checkSpatialMetaData (handle);
7632     if (metadata_version == 3)
7633       {
7634 	  /* current metadata style >= v.4.0.0 */
7635 	  if (!gaiaGetVectorLayersList_v4 (handle, table, geometry, list))
7636 	    {
7637 		gaiaFreeVectorLayersList (list);
7638 		return NULL;
7639 	    }
7640 	  if (list->First == NULL)
7641 	    {
7642 		gaiaFreeVectorLayersList (list);
7643 		return NULL;
7644 	    }
7645 	  return list;
7646       }
7647 
7648 /* legacy metadata style <= v.3.x.x */
7649     if (!get_table_layers_legacy (handle, table, geometry, list))
7650 	goto error;
7651     if (!get_view_layers_legacy (handle, table, geometry, list))
7652 	goto error;
7653     if (!get_table_extent_legacy (handle, table, geometry, list))
7654 	goto error;
7655     if (!get_view_extent_legacy (handle, table, geometry, list))
7656 	goto error;
7657     if (!get_table_auth_legacy (handle, table, geometry, list))
7658 	goto error;
7659     if (table != NULL && mode == GAIA_VECTORS_LIST_PESSIMISTIC)
7660       {
7661 	  if (!compute_table_fields_statistics (handle, table, geometry, list))
7662 	      goto error;
7663       }
7664 
7665     if (list->First == NULL)
7666       {
7667 	  gaiaFreeVectorLayersList (list);
7668 	  return NULL;
7669       }
7670     return list;
7671 
7672   error:
7673     gaiaFreeVectorLayersList (list);
7674     return NULL;
7675 }
7676 
7677 SPATIALITE_DECLARE gaiaGeomCollPtr
gaiaGetLayerExtent(sqlite3 * handle,const char * table,const char * geometry,int mode)7678 gaiaGetLayerExtent (sqlite3 * handle, const char *table,
7679 		    const char *geometry, int mode)
7680 {
7681 /* attempting to get a Layer Full Extent (Envelope) */
7682     gaiaVectorLayersListPtr list;
7683     gaiaVectorLayerPtr lyr;
7684     double minx = -DBL_MAX;
7685     double miny = -DBL_MAX;
7686     double maxx = DBL_MAX;
7687     double maxy = DBL_MAX;
7688     int srid = 0;
7689     gaiaGeomCollPtr bbox;
7690     gaiaPolygonPtr polyg;
7691     gaiaRingPtr rect;
7692     int md = GAIA_VECTORS_LIST_OPTIMISTIC;
7693 
7694     if (table == NULL)
7695 	return NULL;
7696     if (mode)
7697 	md = GAIA_VECTORS_LIST_PESSIMISTIC;
7698 
7699     list = gaiaGetVectorLayersList (handle, table, geometry, md);
7700     if (list == NULL)
7701 	return NULL;
7702     lyr = list->First;
7703     if (lyr == list->Last && lyr != NULL)
7704       {
7705 	  srid = lyr->Srid;
7706 	  if (lyr->ExtentInfos)
7707 	    {
7708 		minx = lyr->ExtentInfos->MinX;
7709 		miny = lyr->ExtentInfos->MinY;
7710 		maxx = lyr->ExtentInfos->MaxX;
7711 		maxy = lyr->ExtentInfos->MaxY;
7712 	    }
7713       }
7714     gaiaFreeVectorLayersList (list);
7715 
7716     if (minx == -DBL_MIN || miny == -DBL_MAX || maxx == DBL_MAX
7717 	|| maxy == DBL_MAX)
7718 	return NULL;
7719 
7720 /* building the Envelope */
7721     bbox = gaiaAllocGeomColl ();
7722     bbox->Srid = srid;
7723     polyg = gaiaAddPolygonToGeomColl (bbox, 5, 0);
7724     rect = polyg->Exterior;
7725     gaiaSetPoint (rect->Coords, 0, minx, miny);	/* vertex # 1 */
7726     gaiaSetPoint (rect->Coords, 1, maxx, miny);	/* vertex # 2 */
7727     gaiaSetPoint (rect->Coords, 2, maxx, maxy);	/* vertex # 3 */
7728     gaiaSetPoint (rect->Coords, 3, minx, maxy);	/* vertex # 4 */
7729     gaiaSetPoint (rect->Coords, 4, minx, miny);	/* vertex # 5 [same as vertex # 1 to close the polygon] */
7730     return bbox;
7731 }
7732 
7733 SPATIALITE_DECLARE int
gaiaStatisticsInvalidate(sqlite3 * sqlite,const char * table,const char * geometry)7734 gaiaStatisticsInvalidate (sqlite3 * sqlite, const char *table,
7735 			  const char *geometry)
7736 {
7737 /* attempting to immediately and unconditionally invalidate Statistics */
7738     int metadata_version = checkSpatialMetaData (sqlite);
7739 
7740     if (metadata_version == 3)
7741       {
7742 	  /* current metadata style >= v.4.0.0 */
7743 	  int ret;
7744 	  char *errMsg = NULL;
7745 	  char *sql_statement;
7746 	  if (table != NULL && geometry != NULL)
7747 	      sql_statement =
7748 		  sqlite3_mprintf ("UPDATE geometry_columns_time SET "
7749 				   "last_insert = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now'), "
7750 				   "last_update = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now'), "
7751 				   "last_delete = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
7752 				   "WHERE Lower(f_table_name) = Lower(%Q) AND "
7753 				   "Lower(f_geometry_column) = Lower(%Q)",
7754 				   table, geometry);
7755 	  else if (table != NULL)
7756 	      sql_statement =
7757 		  sqlite3_mprintf ("UPDATE geometry_columns_time SET "
7758 				   "last_insert = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now'), "
7759 				   "last_update = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now'), "
7760 				   "last_delete = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
7761 				   "WHERE Lower(f_table_name) = Lower(%Q)",
7762 				   table);
7763 	  else
7764 	      sql_statement =
7765 		  sqlite3_mprintf ("UPDATE geometry_columns_time SET "
7766 				   "last_insert = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now'), "
7767 				   "last_update = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now'), "
7768 				   "last_delete = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now')");
7769 	  ret = sqlite3_exec (sqlite, sql_statement, NULL, NULL, &errMsg);
7770 	  sqlite3_free (sql_statement);
7771 	  if (ret != SQLITE_OK)
7772 	    {
7773 		spatialite_e ("SQL error: %s: %s\n", sql_statement, errMsg);
7774 		sqlite3_free (errMsg);
7775 		return 0;
7776 	    }
7777 	  return 1;
7778       }
7779     else
7780 	return 0;
7781 }
7782 
7783 static int
rtree_bbox_callback(sqlite3_rtree_query_info * info)7784 rtree_bbox_callback (sqlite3_rtree_query_info * info)
7785 {
7786 /*
7787 
7788  R*Tree Query Callback function
7789 
7790 ----------------------------------------------------------
7791 
7792  this function will evaluate all first-level R*Tree Nodes
7793  (direct children of the Root Node) so to get the Full
7794  Extent of the R*Tree as a whole.
7795 
7796  further descending in the Tree's hierarchy will be
7797  carefully avoided, so to ensure that also in the case
7798  of an R*Tree containing many million entries just few
7799  dozens of top level Nodes will require to be evaluated.
7800 
7801 */
7802     double minx;
7803     double maxx;
7804     double miny;
7805     double maxy;
7806     struct rtree_envelope *data = (struct rtree_envelope *) (info->pContext);
7807     if (info->nCoord != 4)
7808       {
7809 	  /* invalid RTree; not 2D */
7810 	  goto end;
7811       }
7812 
7813 /* fetching the Node's BBOX */
7814     minx = info->aCoord[0];
7815     maxx = info->aCoord[1];
7816     miny = info->aCoord[2];
7817     maxy = info->aCoord[3];
7818 
7819 /* updating the Full Extent BBOX */
7820     if (data->valid == 0)
7821       {
7822 	  /* first Node retrieved */
7823 	  data->valid = 1;
7824 	  data->minx = minx;
7825 	  data->maxx = maxx;
7826 	  data->miny = miny;
7827 	  data->maxy = maxy;
7828       }
7829     else
7830       {
7831 	  /* any other further Node */
7832 	  if (minx < data->minx)
7833 	      data->minx = minx;
7834 	  if (maxx > data->maxx)
7835 	      data->maxx = maxx;
7836 	  if (miny < data->miny)
7837 	      data->miny = miny;
7838 	  if (maxy > data->maxy)
7839 	      data->maxy = maxy;
7840       }
7841 
7842   end:
7843 /* setting NOT_WITHIN so to stop further descending into the tree */
7844     info->eWithin = NOT_WITHIN;
7845     return SQLITE_OK;
7846 }
7847 
7848 SPATIALITE_DECLARE gaiaGeomCollPtr
gaiaGetRTreeFullExtent(sqlite3 * db_handle,const char * db_prefix,const char * name,int srid)7849 gaiaGetRTreeFullExtent (sqlite3 * db_handle, const char *db_prefix,
7850 			const char *name, int srid)
7851 {
7852 /* Will attempt to retrieve the Full Extent from an R*Tree - SpatiaLite */
7853     char *sql;
7854     int ret;
7855     char *xprefix;
7856     char *xname;
7857     gaiaGeomCollPtr envelope;
7858     gaiaPolygonPtr polyg;
7859     gaiaRingPtr rect;
7860     struct rtree_envelope data;
7861 
7862     data.valid = 0;
7863 
7864 /* registering the Geometry Query Callback SQL function */
7865     sqlite3_rtree_query_callback (db_handle, "rtree_bbox",
7866 				  rtree_bbox_callback, &data, NULL);
7867 
7868 /* executing the SQL Query statement */
7869     xprefix = gaiaDoubleQuotedSql (db_prefix);
7870     xname = gaiaDoubleQuotedSql (name);
7871     sql =
7872 	sqlite3_mprintf
7873 	("SELECT pkid FROM \"%s\".\"%s\" WHERE pkid MATCH rtree_bbox(1)",
7874 	 xprefix, xname);
7875     free (xprefix);
7876     free (xname);
7877     ret = sqlite3_exec (db_handle, sql, NULL, NULL, NULL);
7878     sqlite3_free (sql);
7879     if (ret != SQLITE_OK)
7880 	return NULL;
7881     if (data.valid == 0)
7882 	return NULL;
7883 
7884 /* building the Envelope of the R*Tree */
7885     envelope = gaiaAllocGeomColl ();
7886     envelope->Srid = srid;
7887     polyg = gaiaAddPolygonToGeomColl (envelope, 5, 0);
7888     rect = polyg->Exterior;
7889     gaiaSetPoint (rect->Coords, 0, data.minx, data.miny);	/* vertex # 1 */
7890     gaiaSetPoint (rect->Coords, 1, data.maxx, data.miny);	/* vertex # 2 */
7891     gaiaSetPoint (rect->Coords, 2, data.maxx, data.maxy);	/* vertex # 3 */
7892     gaiaSetPoint (rect->Coords, 3, data.minx, data.maxy);	/* vertex # 4 */
7893     gaiaSetPoint (rect->Coords, 4, data.minx, data.miny);	/* vertex # 5 [same as vertex # 1 to close the polygon] */
7894     return envelope;
7895 }
7896 
7897 SPATIALITE_DECLARE gaiaGeomCollPtr
gaiaGetGpkgRTreeFullExtent(sqlite3 * db_handle,const char * db_prefix,const char * name,int srid)7898 gaiaGetGpkgRTreeFullExtent (sqlite3 * db_handle, const char *db_prefix,
7899 			    const char *name, int srid)
7900 {
7901 /* Will attempt to retrieve the Full Extent from an R*Tree - GeoPacage */
7902     char *sql;
7903     int ret;
7904     char *xprefix;
7905     char *xname;
7906     gaiaGeomCollPtr envelope;
7907     gaiaPolygonPtr polyg;
7908     gaiaRingPtr rect;
7909     struct rtree_envelope data;
7910 
7911     data.valid = 0;
7912 
7913 /* registering the Geometry Query Callback SQL function */
7914     sqlite3_rtree_query_callback (db_handle, "rtree_bbox",
7915 				  rtree_bbox_callback, &data, NULL);
7916 
7917 /* executing the SQL Query statement */
7918     xprefix = gaiaDoubleQuotedSql (db_prefix);
7919     xname = gaiaDoubleQuotedSql (name);
7920     sql =
7921 	sqlite3_mprintf
7922 	("SELECT id FROM \"%s\".\"%s\" WHERE id MATCH rtree_bbox(1)",
7923 	 xprefix, xname);
7924     free (xprefix);
7925     free (xname);
7926     ret = sqlite3_exec (db_handle, sql, NULL, NULL, NULL);
7927     sqlite3_free (sql);
7928     if (ret != SQLITE_OK)
7929 	return NULL;
7930     if (data.valid == 0)
7931 	return NULL;
7932 
7933 /* building the Envelope of the R*Tree */
7934     envelope = gaiaAllocGeomColl ();
7935     envelope->Srid = srid;
7936     polyg = gaiaAddPolygonToGeomColl (envelope, 5, 0);
7937     rect = polyg->Exterior;
7938     gaiaSetPoint (rect->Coords, 0, data.minx, data.miny);	/* vertex # 1 */
7939     gaiaSetPoint (rect->Coords, 1, data.maxx, data.miny);	/* vertex # 2 */
7940     gaiaSetPoint (rect->Coords, 2, data.maxx, data.maxy);	/* vertex # 3 */
7941     gaiaSetPoint (rect->Coords, 3, data.minx, data.maxy);	/* vertex # 4 */
7942     gaiaSetPoint (rect->Coords, 4, data.minx, data.miny);	/* vertex # 5 [same as vertex # 1 to close the polygon] */
7943     return envelope;
7944 }
7945