1 /*
2 
3  table_cloner.c -- Cloning a Table
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 
32 Alternatively, the contents of this file may be used under the terms of
33 either the GNU General Public License Version 2 or later (the "GPL"), or
34 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
35 in which case the provisions of the GPL or the LGPL are applicable instead
36 of those above. If you wish to allow use of your version of this file only
37 under the terms of either the GPL or the LGPL, and not to allow others to
38 use your version of this file under the terms of the MPL, indicate your
39 decision by deleting the provisions above and replace them with the notice
40 and other provisions required by the GPL or the LGPL. If you do not delete
41 the provisions above, a recipient may use your version of this file under
42 the terms of any one of the MPL, the GPL or the LGPL.
43 
44 */
45 
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <string.h>
49 
50 #if defined(_WIN32) && !defined(__MINGW32__)
51 #include "config-msvc.h"
52 #else
53 #include "config.h"
54 #endif
55 
56 #include <spatialite/sqlite.h>
57 #include <spatialite/debug.h>
58 
59 #include <spatialite.h>
60 #include <spatialite_private.h>
61 #include <spatialite/gaiaaux.h>
62 
63 #ifdef _WIN32
64 #define strcasecmp	_stricmp
65 #define strncasecmp	_strnicmp
66 #endif /* not WIN32 */
67 
68 struct aux_geometry
69 {
70 /* a Geometry column object */
71     int type;
72     int dims;
73     int srid;
74     int spatial_index;
75     int cast2multi;
76     int already_existing;
77 };
78 
79 struct aux_trigger
80 {
81 /* a Trigger object */
82     char *name;
83     char *sql;
84     int already_existing;
85     struct aux_trigger *next;
86 };
87 
88 struct aux_fk_columns
89 {
90 /* a Foreign Key Columns object */
91     char *from;
92     char *to;
93     struct aux_fk_columns *next;
94 };
95 
96 struct aux_foreign_key
97 {
98 /* a Foreign Key object */
99     int id;
100     char *name;
101     char *references;
102     char *on_update;
103     char *on_delete;
104     char *match;
105     struct aux_fk_columns *first;
106     struct aux_fk_columns *last;
107     struct aux_foreign_key *next;
108 };
109 
110 struct aux_index
111 {
112 /* a Table Index object */
113     char *name;
114     int unique;
115     char *create_sql;
116     struct aux_index *next;
117 };
118 
119 struct aux_column
120 {
121 /* a Table Column object */
122     char *name;
123     char *type;
124     int notnull;
125     char *deflt;
126     int pk;
127     int fk;
128     int idx;
129     struct aux_geometry *geometry;
130     int ignore;
131     int already_existing;
132     int mismatching;
133     struct aux_column *next;
134 };
135 
136 struct aux_pk_column
137 {
138 /* Primary Key Columns */
139     struct aux_column *column;
140     struct aux_pk_column *next;
141 };
142 
143 struct aux_cloner
144 {
145 /* the main Cloner object */
146     sqlite3 *sqlite;
147     char *db_prefix;
148     char *in_table;
149     char *out_table;
150     struct aux_column *first_col;
151     struct aux_column *last_col;
152     struct aux_pk_column *first_pk;
153     struct aux_pk_column *last_pk;
154     struct aux_index *first_idx;
155     struct aux_index *last_idx;
156     struct aux_foreign_key *first_fk;
157     struct aux_foreign_key *last_fk;
158     struct aux_trigger *first_trigger;
159     struct aux_trigger *last_trigger;
160     struct aux_pk_column **sorted_pks;
161     int pk_count;
162     int autoincrement;
163     int resequence;
164     int with_fks;
165     int with_triggers;
166     int append;
167     int already_existing;
168     int create_only;
169 };
170 
171 static int
create_column(sqlite3 * sqlite,const char * table,struct aux_column * column)172 create_column (sqlite3 * sqlite, const char *table, struct aux_column *column)
173 {
174 /* creating a further ordinary Column */
175     char *sql;
176     char *err_msg = NULL;
177     int ret;
178     char *xtable;
179     char *xcolumn;
180 
181     xtable = gaiaDoubleQuotedSql (table);
182     xcolumn = gaiaDoubleQuotedSql (column->name);
183     if (column->notnull)
184       {
185 	  if (column->deflt != NULL)
186 	      sql = sqlite3_mprintf ("ALTER TABLE main.\"%s\" "
187 				     "ADD COLUMN \"%s\" %s NOT NULL DEFAULT %s",
188 				     xtable, xcolumn, column->type,
189 				     column->deflt);
190 	  else
191 	      sql = sqlite3_mprintf ("ALTER TABLE main.\"%s\" "
192 				     "ADD COLUMN \"%s\" %s NOT NULL", xtable,
193 				     xcolumn, column->type);
194       }
195     else
196       {
197 	  if (column->deflt != NULL)
198 	      sql = sqlite3_mprintf ("ALTER TABLE main.\"%s\" "
199 				     "ADD COLUMN \"%s\" %s DEFAULT %s", xtable,
200 				     xcolumn, column->type, column->deflt);
201 	  else
202 	      sql = sqlite3_mprintf ("ALTER TABLE main.\"%s\" "
203 				     "ADD COLUMN \"%s\" %s", xtable, xcolumn,
204 				     column->type);
205       }
206     free (xtable);
207     free (xcolumn);
208     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
209     sqlite3_free (sql);
210     if (ret != SQLITE_OK)
211       {
212 	  spatialite_e ("ALTER TABLE ADD COLUMN error: %s\n", err_msg);
213 	  sqlite3_free (err_msg);
214 	  return 0;
215       }
216     return 1;
217 }
218 
219 static int
create_geometry(sqlite3 * sqlite,const char * table,struct aux_column * column)220 create_geometry (sqlite3 * sqlite, const char *table, struct aux_column *column)
221 {
222 /* creating a further Geometry Column */
223     char *sql;
224     char *err_msg = NULL;
225     int ret;
226     char *xtable;
227     char *xcolumn;
228     const char *type = "GEOMETRY";
229     const char *dims = "XY";
230     int gtype = column->geometry->type;
231 
232     if (column->geometry->cast2multi)
233       {
234 	  /* promoting to the corresponding MultiType */
235 	  switch (column->geometry->type)
236 	    {
237 	    case 1:
238 		gtype = 4;
239 		break;
240 	    case 1001:
241 		gtype = 1004;
242 		break;
243 	    case 2001:
244 		gtype = 2004;
245 		break;
246 	    case 3001:
247 		gtype = 3004;
248 		break;
249 	    case 2:
250 		gtype = 5;
251 		break;
252 	    case 1002:
253 		gtype = 1005;
254 		break;
255 	    case 2002:
256 		gtype = 2005;
257 		break;
258 	    case 3002:
259 		gtype = 3005;
260 		break;
261 	    case 3:
262 		gtype = 6;
263 		break;
264 	    case 1003:
265 		gtype = 1006;
266 		break;
267 	    case 2003:
268 		gtype = 2006;
269 		break;
270 	    case 3003:
271 		gtype = 3006;
272 		break;
273 	    };
274       }
275 
276     switch (gtype)
277       {
278       case 1:
279 	  type = "POINT";
280 	  dims = "XY";
281 	  break;
282       case 1001:
283 	  type = "POINT";
284 	  dims = "XYZ";
285 	  break;
286       case 2001:
287 	  type = "POINT";
288 	  dims = "XYM";
289 	  break;
290       case 3001:
291 	  type = "POINT";
292 	  dims = "XYZM";
293 	  break;
294       case 2:
295 	  type = "LINESTRING";
296 	  dims = "XY";
297 	  break;
298       case 1002:
299 	  type = "LINESTRING";
300 	  dims = "XYZ";
301 	  break;
302       case 2002:
303 	  type = "LINESTRING";
304 	  dims = "XYM";
305 	  break;
306       case 3002:
307 	  type = "LINESTRING";
308 	  dims = "XYZM";
309 	  break;
310       case 3:
311 	  type = "POLYGON";
312 	  dims = "XY";
313 	  break;
314       case 1003:
315 	  type = "POLYGON";
316 	  dims = "XYZ";
317 	  break;
318       case 2003:
319 	  type = "POLYGON";
320 	  dims = "XYM";
321 	  break;
322       case 3003:
323 	  type = "POLYGON";
324 	  dims = "XYZM";
325 	  break;
326       case 4:
327 	  type = "MULTIPOINT";
328 	  dims = "XY";
329 	  break;
330       case 1004:
331 	  type = "MULTIPOINT";
332 	  dims = "XYZ";
333 	  break;
334       case 2004:
335 	  type = "MULTIPOINT";
336 	  dims = "XYM";
337 	  break;
338       case 3004:
339 	  type = "MULTIPOINT";
340 	  dims = "XYZM";
341 	  break;
342       case 5:
343 	  type = "MULTILINESTRING";
344 	  dims = "XY";
345 	  break;
346       case 1005:
347 	  type = "MULTILINESTRING";
348 	  dims = "XYZ";
349 	  break;
350       case 2005:
351 	  type = "MULTILINESTRING";
352 	  dims = "XYM";
353 	  break;
354       case 3005:
355 	  type = "MULTILINESTRING";
356 	  dims = "XYZM";
357 	  break;
358       case 6:
359 	  type = "MULTIPOLYGON";
360 	  dims = "XY";
361 	  break;
362       case 1006:
363 	  type = "MULTIPOLYGON";
364 	  dims = "XYZ";
365 	  break;
366       case 2006:
367 	  type = "MULTIPOLYGON";
368 	  dims = "XYM";
369 	  break;
370       case 3006:
371 	  type = "MULTIPOLYGON";
372 	  dims = "XYZM";
373 	  break;
374       case 7:
375 	  type = "GEOMETRYCOLLECTION";
376 	  dims = "XY";
377 	  break;
378       case 1007:
379 	  type = "GEOMETRYCOLLECTION";
380 	  dims = "XYZ";
381 	  break;
382       case 2007:
383 	  type = "GEOMETRYCOLLECTION";
384 	  dims = "XYM";
385 	  break;
386       case 3007:
387 	  type = "GEOMETRYCOLLECTION";
388 	  dims = "XYZM";
389 	  break;
390       case 0:
391 	  type = "GEOMETRY";
392 	  dims = "XY";
393 	  break;
394       case 1000:
395 	  type = "GEOMETRY";
396 	  dims = "XYZ";
397 	  break;
398       case 2000:
399 	  type = "GEOMETRY";
400 	  dims = "XYM";
401 	  break;
402       case 3000:
403 	  type = "GEOMETRY";
404 	  dims = "XYZM";
405 	  break;
406       };
407 
408     xtable = gaiaDoubleQuotedSql (table);
409     xcolumn = gaiaDoubleQuotedSql (column->name);
410     if (column->notnull)
411       {
412 	  sql = sqlite3_mprintf ("SELECT AddGeometryColumn(Lower(%Q), "
413 				 "Lower(%Q), %d, %Q, %Q, 1)", xtable, xcolumn,
414 				 column->geometry->srid, type, dims);
415       }
416     else
417       {
418 	  sql = sqlite3_mprintf ("SELECT AddGeometryColumn(Lower(%Q), "
419 				 "Lower(%Q), %d, %Q, %Q)", xtable, xcolumn,
420 				 column->geometry->srid, type, dims);
421       }
422     free (xtable);
423     free (xcolumn);
424     ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
425     sqlite3_free (sql);
426     if (ret != SQLITE_OK)
427       {
428 	  spatialite_e ("ADD GEOMETRY COLUMN error: %s\n", err_msg);
429 	  sqlite3_free (err_msg);
430 	  return 0;
431       }
432 
433     if (column->geometry->spatial_index)
434       {
435 	  /* creating the corresponding Spatial Index */
436 	  xtable = gaiaDoubleQuotedSql (table);
437 	  xcolumn = gaiaDoubleQuotedSql (column->name);
438 	  sql = sqlite3_mprintf ("SELECT CreateSpatialIndex("
439 				 "Lower(%Q), Lower(%Q))", xtable, xcolumn);
440 	  free (xtable);
441 	  free (xcolumn);
442 	  ret = sqlite3_exec (sqlite, sql, NULL, NULL, &err_msg);
443 	  sqlite3_free (sql);
444 	  if (ret != SQLITE_OK)
445 	    {
446 		spatialite_e ("CREATE SPATIAL INDEX error: %s\n", err_msg);
447 		sqlite3_free (err_msg);
448 		return 0;
449 	    }
450       }
451     return 1;
452 }
453 
454 static int
upgrade_output_table(struct aux_cloner * cloner)455 upgrade_output_table (struct aux_cloner *cloner)
456 {
457 /* creating any new Column required by APPEND */
458     struct aux_column *column = cloner->first_col;
459     while (column != NULL)
460       {
461 	  if (column->ignore)
462 	    {
463 		/* skipping columns marked to be ignored */
464 		column = column->next;
465 		continue;
466 	    }
467 	  if (column->already_existing == 0)
468 	    {
469 		if (column->geometry != NULL)
470 		  {
471 		      /* creating a Geometry */
472 		      if (!create_geometry
473 			  (cloner->sqlite, cloner->out_table, column))
474 			{
475 			    spatialite_e
476 				("CloneTable: unable to ADD Geometry COLUMN \"%s\" on Table \"%s\"\n",
477 				 column->name, cloner->out_table);
478 			    return 0;
479 			}
480 		  }
481 		else
482 		  {
483 		      /* creating an ordinary Column */
484 		      if (!create_column
485 			  (cloner->sqlite, cloner->out_table, column))
486 			{
487 			    spatialite_e
488 				("CloneTable: unable to ADD COLUMN \"%s\" on Table \"%s\"\n",
489 				 column->name, cloner->out_table);
490 			    return 0;
491 			}
492 		  }
493 	    }
494 	  column = column->next;
495       }
496     return 1;
497 }
498 
499 static void
sort_pk_columns(struct aux_cloner * cloner)500 sort_pk_columns (struct aux_cloner *cloner)
501 {
502 /* sorting the PK columns (if required) */
503     struct aux_pk_column *ppk;
504     int cnt;
505     int ok;
506     if (cloner->pk_count <= 1)
507 	return;
508     cloner->sorted_pks =
509 	malloc (sizeof (struct aux_pk_column *) * cloner->pk_count);
510     cnt = 0;
511     ppk = cloner->first_pk;
512     while (ppk != NULL)
513       {
514 	  /* copying pointers to PK cols */
515 	  *(cloner->sorted_pks + cnt++) = ppk;
516 	  ppk = ppk->next;
517       }
518     ok = 1;
519     while (ok)
520       {
521 	  /* bubble sorting */
522 	  ok = 0;
523 	  for (cnt = 1; cnt < cloner->pk_count; cnt++)
524 	    {
525 		struct aux_pk_column *ppk1 = *(cloner->sorted_pks + cnt - 1);
526 		ppk = *(cloner->sorted_pks + cnt);
527 		if (ppk1->column->pk > ppk->column->pk)
528 		  {
529 		      /* swapping */
530 		      *(cloner->sorted_pks + cnt - 1) = ppk;
531 		      *(cloner->sorted_pks + cnt) = ppk1;
532 		      ok = 1;
533 		  }
534 	    }
535       }
536 }
537 
538 static void
adjust_ignore(struct aux_cloner * cloner)539 adjust_ignore (struct aux_cloner *cloner)
540 {
541 /* adjusting Ignore columns */
542     struct aux_column *column = cloner->first_col;
543     while (column != NULL)
544       {
545 	  if (column->ignore)
546 	    {
547 		if (column->pk)
548 		    column->ignore = 0;
549 		if (column->fk && cloner->with_fks)
550 		    column->ignore = 0;
551 		if (column->idx)
552 		    column->ignore = 0;
553 	    }
554 	  column = column->next;
555       }
556 }
557 
558 static const char *
get_pk_column(struct aux_cloner * cloner,int index)559 get_pk_column (struct aux_cloner *cloner, int index)
560 {
561 /* returning a PK column name (by sorted index) */
562     struct aux_pk_column *ppk;
563     if (cloner->sorted_pks == NULL)
564 	return NULL;
565     if (index < 0 || index >= cloner->pk_count)
566 	return NULL;
567     ppk = *(cloner->sorted_pks + index);
568     return ppk->column->name;
569 }
570 
571 static void
mark_existing_trigger(struct aux_cloner * cloner,const char * name)572 mark_existing_trigger (struct aux_cloner *cloner, const char *name)
573 {
574 /* marking an existing Trigger */
575     struct aux_trigger *trigger = cloner->first_trigger;
576     while (trigger != NULL)
577       {
578 	  if (strcasecmp (trigger->name, name) == 0)
579 	    {
580 		trigger->already_existing = 1;
581 		return;
582 	    }
583 	  trigger = trigger->next;
584       }
585 }
586 
587 static void
check_existing_triggers(struct aux_cloner * cloner)588 check_existing_triggers (struct aux_cloner *cloner)
589 {
590 /* exploring the output table - already existing Triggers */
591     char *sql;
592     int ret;
593     int i;
594     char **results;
595     int rows;
596     int columns;
597     const char *name;
598 
599     sql = sqlite3_mprintf ("SELECT name FROM main.sqlite_master "
600 			   "WHERE type = 'trigger' AND Lower(tbl_name) = Lower(%Q)",
601 			   cloner->in_table);
602     ret =
603 	sqlite3_get_table (cloner->sqlite, sql, &results, &rows, &columns,
604 			   NULL);
605     sqlite3_free (sql);
606     if (ret != SQLITE_OK)
607 	return;
608     if (rows < 1)
609 	;
610     else
611       {
612 	  for (i = 1; i <= rows; i++)
613 	    {
614 		name = results[(i * columns) + 0];
615 		mark_existing_trigger (cloner, name);
616 	    }
617       }
618     sqlite3_free_table (results);
619 }
620 
621 static const char *
do_find_index_list(const char * create_sql)622 do_find_index_list (const char *create_sql)
623 {
624 /* attempting to extract the columns list or expression from a CREATE INDEX Sql Statement */
625     int i;
626     int len;
627     int count = 0;
628     if (create_sql == NULL)
629 	return NULL;
630 
631     len = strlen (create_sql);
632     if (*(create_sql + len - 1) != ')')
633 	return NULL;
634     for (i = len - 1; i >= 0; i--)
635       {
636 	  if (*(create_sql + i) == ')')
637 	      count++;
638 	  if (*(create_sql + i) == '(')
639 	      count--;
640 	  if (count == 0)
641 	      return create_sql + i;
642       }
643     return NULL;
644 }
645 
646 static int
create_output_table(struct aux_cloner * cloner)647 create_output_table (struct aux_cloner *cloner)
648 {
649 /* creating the output Table */
650     char *err_msg = NULL;
651     int ret;
652     struct aux_column *column;
653     struct aux_foreign_key *fk;
654     struct aux_fk_columns *fk_col;
655     struct aux_index *index;
656     char *sql;
657     char *prev_sql;
658     char *xtable;
659     char *xcolumn;
660     char *constraint;
661     char *xconstraint;
662     int first = 1;
663     int i;
664     int fk_no;
665 
666     sort_pk_columns (cloner);
667     adjust_ignore (cloner);
668     xtable = gaiaDoubleQuotedSql (cloner->out_table);
669     sql = sqlite3_mprintf ("CREATE TABLE main.\"%s\"", xtable);
670     free (xtable);
671     prev_sql = sql;
672 
673     column = cloner->first_col;
674     while (column != NULL)
675       {
676 	  if (column->ignore)
677 	    {
678 		/* IGNORE requested */
679 		column = column->next;
680 		continue;
681 	    }
682 	  if (column->geometry != NULL)
683 	    {
684 		/* skipping any Geometry column */
685 		column = column->next;
686 		continue;
687 	    }
688 	  if (first)
689 	    {
690 		sql = sqlite3_mprintf ("%s (\n", prev_sql);
691 		first = 0;
692 	    }
693 	  else
694 	      sql = sqlite3_mprintf ("%s,\n", prev_sql);
695 	  sqlite3_free (prev_sql);
696 	  prev_sql = sql;
697 	  xcolumn = gaiaDoubleQuotedSql (column->name);
698 	  if (cloner->pk_count == 1 && column->pk)
699 	    {
700 		/* immediately declaring a single column Primary Key */
701 		if (cloner->autoincrement)
702 		  {
703 		      if (column->notnull)
704 			{
705 			    if (column->deflt != NULL)
706 				sql =
707 				    sqlite3_mprintf
708 				    ("%s\t\"%s\" %s NOT NULL PRIMARY KEY AUTOINCREMENT DEFAULT %s",
709 				     prev_sql, xcolumn, column->type,
710 				     column->deflt);
711 			    else
712 				sql =
713 				    sqlite3_mprintf
714 				    ("%s\t\"%s\" %s NOT NULL PRIMARY KEY AUTOINCREMENT",
715 				     prev_sql, xcolumn, column->type);
716 			}
717 		      else
718 			{
719 			    if (column->deflt != NULL)
720 				sql =
721 				    sqlite3_mprintf
722 				    ("%s\t\"%s\" %s PRIMARY KEY AUTOINCREMENT DEFAULT %s",
723 				     prev_sql, xcolumn, column->type,
724 				     column->deflt);
725 			    else
726 				sql =
727 				    sqlite3_mprintf
728 				    ("%s\t\"%s\" %s PRIMARY KEY AUTOINCREMENT",
729 				     prev_sql, xcolumn, column->type);
730 			}
731 		  }
732 		else
733 		  {
734 		      if (column->notnull)
735 			{
736 			    if (column->deflt != NULL)
737 				sql =
738 				    sqlite3_mprintf
739 				    ("%s\t\"%s\" %s NOT NULL PRIMARY KEY DEFAULT %s",
740 				     prev_sql, xcolumn, column->type,
741 				     column->deflt);
742 			    else
743 				sql =
744 				    sqlite3_mprintf
745 				    ("%s\t\"%s\" %s NOT NULL PRIMARY KEY",
746 				     prev_sql, xcolumn, column->type);
747 			}
748 		      else
749 			{
750 			    if (column->deflt != NULL)
751 				sql =
752 				    sqlite3_mprintf
753 				    ("%s\t\"%s\" %s PRIMARY KEY DEFAULT %s",
754 				     prev_sql, xcolumn, column->type,
755 				     column->deflt);
756 			    else
757 				sql =
758 				    sqlite3_mprintf
759 				    ("%s\t\"%s\" %s PRIMARY KEY", prev_sql,
760 				     xcolumn, column->type);
761 			}
762 		  }
763 		free (xcolumn);
764 		sqlite3_free (prev_sql);
765 		prev_sql = sql;
766 		column = column->next;
767 		continue;
768 	    }
769 	  if (column->notnull)
770 	    {
771 		if (column->deflt != NULL)
772 		    sql = sqlite3_mprintf ("%s\t\"%s\" %s NOT NULL DEFAULT %s",
773 					   prev_sql, xcolumn, column->type,
774 					   column->deflt);
775 		else
776 		    sql = sqlite3_mprintf ("%s\t\"%s\" %s NOT NULL",
777 					   prev_sql, xcolumn, column->type);
778 	    }
779 	  else
780 	    {
781 		if (column->deflt != NULL)
782 		    sql = sqlite3_mprintf ("%s\t\"%s\" %s DEFAULT %s",
783 					   prev_sql, xcolumn, column->type,
784 					   column->deflt);
785 		else
786 		    sql = sqlite3_mprintf ("%s\t\"%s\" %s",
787 					   prev_sql, xcolumn, column->type);
788 	    }
789 	  free (xcolumn);
790 	  sqlite3_free (prev_sql);
791 	  prev_sql = sql;
792 	  column = column->next;
793       }
794 
795     if (cloner->pk_count > 1)
796       {
797 	  /* declaring a PRIMARY KEY CONSTRAINT */
798 	  sql = sqlite3_mprintf ("%s,\n", prev_sql);
799 	  sqlite3_free (prev_sql);
800 	  prev_sql = sql;
801 	  constraint = sqlite3_mprintf ("pk_%s", cloner->out_table);
802 	  xconstraint = gaiaDoubleQuotedSql (constraint);
803 	  sqlite3_free (constraint);
804 	  sql =
805 	      sqlite3_mprintf ("%s\tCONSTRAINT \"%s\" PRIMARY KEY (", prev_sql,
806 			       xconstraint);
807 	  free (xconstraint);
808 	  sqlite3_free (prev_sql);
809 	  prev_sql = sql;
810 	  for (i = 0; i < cloner->pk_count; i++)
811 	    {
812 		xconstraint = gaiaDoubleQuotedSql (get_pk_column (cloner, i));
813 		if (i == 0)
814 		    sql = sqlite3_mprintf ("%s%s", prev_sql, xconstraint);
815 		else
816 		    sql = sqlite3_mprintf ("%s, %s", prev_sql, xconstraint);
817 		free (xconstraint);
818 		sqlite3_free (prev_sql);
819 		prev_sql = sql;
820 	    }
821 	  sql = sqlite3_mprintf ("%s)", prev_sql);
822 	  sqlite3_free (prev_sql);
823 	  prev_sql = sql;
824       }
825 
826     if (cloner->with_fks)
827       {
828 	  /* cloning all Foreign Key definitions */
829 	  fk = cloner->first_fk;
830 	  fk_no = 1;
831 	  while (fk != NULL)
832 	    {
833 		/* declaring all FOREIGN KEY CONSTRAINTs */
834 		sql = sqlite3_mprintf ("%s,\n", prev_sql);
835 		sqlite3_free (prev_sql);
836 		prev_sql = sql;
837 		constraint =
838 		    sqlite3_mprintf ("fk_%s_%d", cloner->out_table, fk_no++);
839 		xconstraint = gaiaDoubleQuotedSql (constraint);
840 		sqlite3_free (constraint);
841 		sql =
842 		    sqlite3_mprintf ("%s\tCONSTRAINT \"%s\" FOREIGN KEY (",
843 				     prev_sql, xconstraint);
844 		free (xconstraint);
845 		sqlite3_free (prev_sql);
846 		prev_sql = sql;
847 		fk_col = fk->first;
848 		while (fk_col != NULL)
849 		  {
850 		      xconstraint = gaiaDoubleQuotedSql (fk_col->from);
851 		      if (fk_col == fk->first)
852 			  sql = sqlite3_mprintf ("%s%s", prev_sql, xconstraint);
853 		      else
854 			  sql =
855 			      sqlite3_mprintf ("%s, %s", prev_sql, xconstraint);
856 		      free (xconstraint);
857 		      sqlite3_free (prev_sql);
858 		      prev_sql = sql;
859 		      fk_col = fk_col->next;
860 		  }
861 		xtable = gaiaDoubleQuotedSql (fk->references);
862 		sql =
863 		    sqlite3_mprintf ("%s) REFERENCES \"%s\" (", prev_sql,
864 				     xtable);
865 		free (xtable);
866 		sqlite3_free (prev_sql);
867 		prev_sql = sql;
868 		fk_col = fk->first;
869 		while (fk_col != NULL)
870 		  {
871 		      xconstraint = gaiaDoubleQuotedSql (fk_col->to);
872 		      if (fk_col == fk->first)
873 			  sql = sqlite3_mprintf ("%s%s", prev_sql, xconstraint);
874 		      else
875 			  sql =
876 			      sqlite3_mprintf ("%s, %s", prev_sql, xconstraint);
877 		      free (xconstraint);
878 		      sqlite3_free (prev_sql);
879 		      prev_sql = sql;
880 		      fk_col = fk_col->next;
881 		  }
882 		sql = sqlite3_mprintf ("%s)", prev_sql);
883 		sqlite3_free (prev_sql);
884 		prev_sql = sql;
885 		fk = fk->next;
886 	    }
887       }
888     sql = sqlite3_mprintf ("%s\n)", prev_sql);
889     sqlite3_free (prev_sql);
890 
891     ret = sqlite3_exec (cloner->sqlite, sql, NULL, NULL, &err_msg);
892     sqlite3_free (sql);
893     if (ret != SQLITE_OK)
894       {
895 	  spatialite_e ("CREATE TABLE error: %s\n", err_msg);
896 	  sqlite3_free (err_msg);
897 	  return 0;
898       }
899 
900     column = cloner->first_col;
901     while (column != NULL)
902       {
903 	  if (column->geometry != NULL && !(column->ignore))
904 	    {
905 		/* adding a Geometry Column */
906 		if (!create_geometry
907 		    (cloner->sqlite, cloner->out_table, column))
908 		    return 0;
909 	    }
910 	  column = column->next;
911       }
912 
913     index = cloner->first_idx;
914     fk_no = 1;
915     while (index != NULL)
916       {
917 	  /* creating an Index */
918 	  const char *list;
919 	  constraint =
920 	      sqlite3_mprintf ("idx_%s_%d", cloner->out_table, fk_no++);
921 	  xconstraint = gaiaDoubleQuotedSql (constraint);
922 	  sqlite3_free (constraint);
923 	  xtable = gaiaDoubleQuotedSql (cloner->out_table);
924 	  if (index->unique)
925 	      sql =
926 		  sqlite3_mprintf ("CREATE UNIQUE INDEX main.\"%s\" ON \"%s\"",
927 				   xconstraint, xtable);
928 	  else
929 	      sql =
930 		  sqlite3_mprintf ("CREATE INDEX main.\"%s\" ON \"%s\"",
931 				   xconstraint, xtable);
932 	  free (xconstraint);
933 	  free (xtable);
934 	  prev_sql = sql;
935 	  list = do_find_index_list (index->create_sql);
936 	  if (list != NULL)
937 	    {
938 		sql = sqlite3_mprintf ("%s %s", prev_sql, list);
939 		sqlite3_free (prev_sql);
940 	    }
941 
942 	  ret = sqlite3_exec (cloner->sqlite, sql, NULL, NULL, &err_msg);
943 	  sqlite3_free (sql);
944 	  if (ret != SQLITE_OK)
945 	    {
946 		spatialite_e ("CREATE INDEX error: %s\n", err_msg);
947 		sqlite3_free (err_msg);
948 		return 0;
949 	    }
950 	  index = index->next;
951       }
952 
953     if (cloner->with_triggers)
954       {
955 	  struct aux_trigger *trigger;
956 	  check_existing_triggers (cloner);
957 	  trigger = cloner->first_trigger;
958 	  while (trigger != NULL)
959 	    {
960 		if (trigger->already_existing)
961 		  {
962 		      /* skipping already defined triggers */
963 		      trigger = trigger->next;
964 		      continue;
965 		  }
966 		/* adding a trigger */
967 		ret =
968 		    sqlite3_exec (cloner->sqlite, trigger->sql, NULL, NULL,
969 				  &err_msg);
970 		if (ret != SQLITE_OK)
971 		  {
972 		      spatialite_e ("CREATE TRIGGER error: %s\n", err_msg);
973 		      sqlite3_free (err_msg);
974 		      return 0;
975 		  }
976 		trigger = trigger->next;
977 	    }
978       }
979     return 1;
980 }
981 
982 static int
copy_rows(struct aux_cloner * cloner)983 copy_rows (struct aux_cloner *cloner)
984 {
985 /* copying all rows from the origin into the destination Table */
986     sqlite3_stmt *stmt_in = NULL;
987     sqlite3_stmt *stmt_out = NULL;
988     int ret;
989     struct aux_column *column;
990     char *sql;
991     char *prev_sql;
992     char *xcolumn;
993     char *xtable;
994     char *xdb_prefix;
995     int first = 1;
996 
997 /* composing the SELECT statement */
998     sql = sqlite3_mprintf ("SELECT ");
999     column = cloner->first_col;
1000     while (column != NULL)
1001       {
1002 	  if (column->ignore)
1003 	    {
1004 		/* skipping columns to be IGNORED */
1005 		column = column->next;
1006 		continue;
1007 	    }
1008 	  xcolumn = gaiaDoubleQuotedSql (column->name);
1009 	  prev_sql = sql;
1010 	  if (first)
1011 	    {
1012 		sql = sqlite3_mprintf ("%s\"%s\"", prev_sql, xcolumn);
1013 		first = 0;
1014 	    }
1015 	  else
1016 	      sql = sqlite3_mprintf ("%s, \"%s\"", prev_sql, xcolumn);
1017 	  free (xcolumn);
1018 	  sqlite3_free (prev_sql);
1019 	  prev_sql = sql;
1020 	  column = column->next;
1021       }
1022     xdb_prefix = gaiaDoubleQuotedSql (cloner->db_prefix);
1023     xtable = gaiaDoubleQuotedSql (cloner->in_table);
1024     prev_sql = sql;
1025     sql =
1026 	sqlite3_mprintf ("%s FROM \"%s\".\"%s\"", prev_sql, xdb_prefix, xtable);
1027     sqlite3_free (prev_sql);
1028     free (xdb_prefix);
1029     free (xtable);
1030 /* compiling the SELECT FROM statement */
1031     ret =
1032 	sqlite3_prepare_v2 (cloner->sqlite, sql, strlen (sql), &stmt_in, NULL);
1033     sqlite3_free (sql);
1034     if (ret != SQLITE_OK)
1035       {
1036 	  spatialite_e ("SELECT FROM: \"%s\"\n",
1037 			sqlite3_errmsg (cloner->sqlite));
1038 	  goto error;
1039       }
1040 
1041 /* composing the INSERT INTO statement */
1042     xtable = gaiaDoubleQuotedSql (cloner->out_table);
1043     sql = sqlite3_mprintf ("INSERT INTO \"%s\" (", xtable);
1044     free (xtable);
1045     prev_sql = sql;
1046     first = 1;
1047     column = cloner->first_col;
1048     while (column != NULL)
1049       {
1050 	  if (column->ignore)
1051 	    {
1052 		/* skipping columns to be IGNORED */
1053 		column = column->next;
1054 		continue;
1055 	    }
1056 	  xcolumn = gaiaDoubleQuotedSql (column->name);
1057 	  if (first)
1058 	    {
1059 		sql = sqlite3_mprintf ("%s\"%s\"", prev_sql, xcolumn);
1060 		first = 0;
1061 	    }
1062 	  else
1063 	      sql = sqlite3_mprintf ("%s, \"%s\"", prev_sql, xcolumn);
1064 	  free (xcolumn);
1065 	  sqlite3_free (prev_sql);
1066 	  prev_sql = sql;
1067 	  column = column->next;
1068       }
1069     sql = sqlite3_mprintf ("%s) VALUES (", prev_sql);
1070     sqlite3_free (prev_sql);
1071     prev_sql = sql;
1072     first = 1;
1073     column = cloner->first_col;
1074     while (column != NULL)
1075       {
1076 	  if (column->ignore)
1077 	    {
1078 		/* skipping columns to be IGNORED */
1079 		column = column->next;
1080 		continue;
1081 	    }
1082 	  if (column->geometry != NULL)
1083 	    {
1084 		/* Geometry column */
1085 		if (column->geometry->cast2multi)
1086 		  {
1087 		      /* casting to MultiType */
1088 		      const char *expr = "CastToMulti(?)";
1089 		      if (first)
1090 			{
1091 			    sql = sqlite3_mprintf ("%s%s", prev_sql, expr);
1092 			    first = 0;
1093 			}
1094 		      else
1095 			  sql = sqlite3_mprintf ("%s, %s", prev_sql, expr);
1096 		      sqlite3_free (prev_sql);
1097 		      prev_sql = sql;
1098 		      column = column->next;
1099 		      continue;
1100 		  }
1101 	    }
1102 	  if (first)
1103 	    {
1104 		sql = sqlite3_mprintf ("%s?", prev_sql);
1105 		first = 0;
1106 	    }
1107 	  else
1108 	      sql = sqlite3_mprintf ("%s, ?", prev_sql);
1109 	  sqlite3_free (prev_sql);
1110 	  prev_sql = sql;
1111 	  column = column->next;
1112       }
1113     sql = sqlite3_mprintf ("%s)", prev_sql);
1114     sqlite3_free (prev_sql);
1115 /* compiling the INSERT INTO statement */
1116     ret =
1117 	sqlite3_prepare_v2 (cloner->sqlite, sql, strlen (sql), &stmt_out, NULL);
1118     sqlite3_free (sql);
1119     if (ret != SQLITE_OK)
1120       {
1121 	  spatialite_e ("INSERT INTO: \"%s\"\n",
1122 			sqlite3_errmsg (cloner->sqlite));
1123 	  goto error;
1124       }
1125 
1126     while (1)
1127       {
1128 	  /* scrolling the result set rows */
1129 	  ret = sqlite3_step (stmt_in);
1130 	  if (ret == SQLITE_DONE)
1131 	      break;		/* end of result set */
1132 	  if (ret == SQLITE_ROW)
1133 	    {
1134 		/* copying values between input and output tables */
1135 		int pos = 0;
1136 		sqlite3_reset (stmt_out);
1137 		sqlite3_clear_bindings (stmt_out);
1138 		column = cloner->first_col;
1139 		while (column != NULL)
1140 		  {
1141 		      if (column->ignore)
1142 			{
1143 			    /* skipping columns to be IGNORED */
1144 			    column = column->next;
1145 			    continue;
1146 			}
1147 		      if (cloner->resequence && cloner->pk_count == 1
1148 			  && cloner->autoincrement && column->pk)
1149 			{
1150 			    /* resequencing an AUTOINCREMENT PK */
1151 			    sqlite3_bind_null (stmt_out, pos + 1);
1152 			    pos++;
1153 			    column = column->next;
1154 			    continue;
1155 			}
1156 		      if (sqlite3_column_type (stmt_in, pos) == SQLITE_INTEGER)
1157 			  sqlite3_bind_int64 (stmt_out, pos + 1,
1158 					      sqlite3_column_int64 (stmt_in,
1159 								    pos));
1160 		      else if (sqlite3_column_type (stmt_in, pos) ==
1161 			       SQLITE_FLOAT)
1162 			  sqlite3_bind_double (stmt_out, pos + 1,
1163 					       sqlite3_column_double (stmt_in,
1164 								      pos));
1165 		      else if (sqlite3_column_type (stmt_in, pos) ==
1166 			       SQLITE_TEXT)
1167 			  sqlite3_bind_text (stmt_out, pos + 1,
1168 					     (const char *)
1169 					     sqlite3_column_text (stmt_in, pos),
1170 					     sqlite3_column_bytes (stmt_in,
1171 								   pos),
1172 					     SQLITE_STATIC);
1173 		      else if (sqlite3_column_type (stmt_in, pos) ==
1174 			       SQLITE_BLOB)
1175 			  sqlite3_bind_blob (stmt_out, pos + 1,
1176 					     sqlite3_column_blob (stmt_in, pos),
1177 					     sqlite3_column_bytes (stmt_in,
1178 								   pos),
1179 					     SQLITE_STATIC);
1180 		      else
1181 			  sqlite3_bind_null (stmt_out, pos + 1);
1182 		      pos++;
1183 		      column = column->next;
1184 		  }
1185 		/* inserting into the output table */
1186 		ret = sqlite3_step (stmt_out);
1187 		if (ret == SQLITE_DONE || ret == SQLITE_ROW)
1188 		    ;
1189 		else
1190 		  {
1191 		      spatialite_e ("OUTPUT step error: <%s>\n",
1192 				    sqlite3_errmsg (cloner->sqlite));
1193 		      goto error;
1194 		  }
1195 	    }
1196 	  else
1197 	    {
1198 		spatialite_e ("INPUT step error: <%s>\n",
1199 			      sqlite3_errmsg (cloner->sqlite));
1200 		goto error;
1201 	    }
1202       }
1203     sqlite3_finalize (stmt_in);
1204     sqlite3_finalize (stmt_out);
1205     return 1;
1206 
1207   error:
1208     if (stmt_in != NULL)
1209 	sqlite3_finalize (stmt_in);
1210     if (stmt_out != NULL)
1211 	sqlite3_finalize (stmt_out);
1212     return 0;
1213 }
1214 
1215 static void
add_geometry(struct aux_cloner * cloner,const char * name,int type,int dims,int srid,int spatial_index)1216 add_geometry (struct aux_cloner *cloner, const char *name, int type, int dims,
1217 	      int srid, int spatial_index)
1218 {
1219 /* adding a Geometry Column definition */
1220     struct aux_column *pc = cloner->first_col;
1221     while (pc != NULL)
1222       {
1223 	  if (strcasecmp (pc->name, name) == 0)
1224 	    {
1225 		struct aux_geometry *geom =
1226 		    malloc (sizeof (struct aux_geometry));
1227 		geom->type = type;
1228 		geom->dims = dims;
1229 		geom->srid = srid;
1230 		geom->spatial_index = spatial_index;
1231 		geom->cast2multi = 0;
1232 		geom->already_existing = 0;
1233 		if (pc->geometry != NULL)
1234 		    free (pc->geometry);
1235 		pc->geometry = geom;
1236 		return;
1237 	    }
1238 	  pc = pc->next;
1239       }
1240 }
1241 
1242 static void
mark_existing_geometry(struct aux_cloner * cloner,const char * name,int type,int dims,int srid)1243 mark_existing_geometry (struct aux_cloner *cloner, const char *name, int type,
1244 			int dims, int srid)
1245 {
1246 /* marking an existing Geometry Column definition */
1247     struct aux_column *pc = cloner->first_col;
1248     while (pc != NULL)
1249       {
1250 	  if (strcasecmp (pc->name, name) == 0)
1251 	    {
1252 		if (pc->geometry == NULL)
1253 		  {
1254 		      /* gosh, it's not a Geometry */
1255 		      pc->mismatching = 1;
1256 		      return;
1257 		  }
1258 		if (pc->geometry->type == type && pc->geometry->dims == dims
1259 		    && pc->geometry->srid == srid)
1260 		  {
1261 		      /* matching arguments: confirmed */
1262 		      pc->geometry->already_existing = 1;
1263 		      return;
1264 		  }
1265 		/* different arguments: invalid */
1266 		pc->mismatching = 1;
1267 		return;
1268 	    }
1269 	  pc = pc->next;
1270       }
1271 }
1272 
1273 static void
add_trigger(struct aux_cloner * cloner,const char * name,const char * sql)1274 add_trigger (struct aux_cloner *cloner, const char *name, const char *sql)
1275 {
1276 /* adding a Trigger definition */
1277     int len;
1278     struct aux_trigger *trigger = malloc (sizeof (struct aux_trigger));
1279     len = strlen (name);
1280     trigger->name = malloc (len + 1);
1281     strcpy (trigger->name, name);
1282     len = strlen (sql);
1283     trigger->sql = malloc (len + 1);
1284     strcpy (trigger->sql, sql);
1285     trigger->already_existing = 0;
1286     trigger->next = NULL;
1287 /* updating the linked list */
1288     if (cloner->first_trigger == NULL)
1289 	cloner->first_trigger = trigger;
1290     if (cloner->last_trigger != NULL)
1291 	cloner->last_trigger->next = trigger;
1292     cloner->last_trigger = trigger;
1293 }
1294 
1295 static void
add_fk_columns(struct aux_foreign_key * fk,struct aux_column * first_col,const char * from,const char * to)1296 add_fk_columns (struct aux_foreign_key *fk, struct aux_column *first_col,
1297 		const char *from, const char *to)
1298 {
1299 /* adding Columns correspondencies into a Foreign Key definition */
1300     int len;
1301     struct aux_column *column;
1302     struct aux_fk_columns *col = malloc (sizeof (struct aux_fk_columns));
1303     len = strlen (from);
1304     col->from = malloc (len + 1);
1305     strcpy (col->from, from);
1306     len = strlen (to);
1307     col->to = malloc (len + 1);
1308     strcpy (col->to, to);
1309     col->next = NULL;
1310 /* updating the linked list */
1311     if (fk->first == NULL)
1312 	fk->first = col;
1313     if (fk->last != NULL)
1314 	fk->last->next = col;
1315     fk->last = col;
1316 /* marking the column as a Foreign Key */
1317     column = first_col;
1318     while (column != NULL)
1319       {
1320 	  if (strcasecmp (column->name, from) == 0)
1321 	    {
1322 		column->fk = 1;
1323 		break;
1324 	    }
1325 	  column = column->next;
1326       }
1327 }
1328 
1329 static void
add_foreign_key(struct aux_cloner * cloner,int id,const char * references,const char * from,const char * to,const char * on_update,const char * on_delete,const char * match)1330 add_foreign_key (struct aux_cloner *cloner, int id, const char *references,
1331 		 const char *from, const char *to, const char *on_update,
1332 		 const char *on_delete, const char *match)
1333 {
1334 /* adding a Foreign Key definition */
1335     int len;
1336     struct aux_foreign_key *fk;
1337     if (cloner->last_fk != NULL)
1338       {
1339 	  if (cloner->last_fk->id == id)
1340 	    {
1341 		/* continuing with the latest FK */
1342 		add_fk_columns (cloner->last_fk, cloner->first_col, from, to);
1343 		return;
1344 	    }
1345       }
1346     fk = malloc (sizeof (struct aux_foreign_key));
1347     fk->id = id;
1348     fk->name = NULL;
1349     len = strlen (references);
1350     fk->references = malloc (len + 1);
1351     strcpy (fk->references, references);
1352     fk->on_update = NULL;
1353     fk->on_delete = NULL;
1354     fk->match = NULL;
1355     if (on_update != NULL)
1356       {
1357 	  len = strlen (on_update);
1358 	  fk->on_update = malloc (len + 1);
1359 	  strcpy (fk->on_update, on_update);
1360       }
1361     if (on_delete != NULL)
1362       {
1363 	  len = strlen (on_delete);
1364 	  fk->on_delete = malloc (len + 1);
1365 	  strcpy (fk->on_delete, on_delete);
1366       }
1367     if (match != NULL)
1368       {
1369 	  len = strlen (match);
1370 	  fk->match = malloc (len + 1);
1371 	  strcpy (fk->match, match);
1372       }
1373     fk->first = NULL;
1374     fk->last = NULL;
1375     fk->next = NULL;
1376     add_fk_columns (fk, cloner->first_col, from, to);
1377 /* updating the linked list */
1378     if (cloner->first_fk == NULL)
1379 	cloner->first_fk = fk;
1380     if (cloner->last_fk != NULL)
1381 	cloner->last_fk->next = fk;
1382     cloner->last_fk = fk;
1383 }
1384 
1385 static void
add_index_column(struct aux_column * first_col,const char * name)1386 add_index_column (struct aux_column *first_col, const char *name)
1387 {
1388     struct aux_column *col;
1389 /* marking the column as a Foreign Key */
1390     col = first_col;
1391     while (col != NULL)
1392       {
1393 	  if (strcasecmp (col->name, name) == 0)
1394 	    {
1395 		col->idx = 1;
1396 		break;
1397 	    }
1398 	  col = col->next;
1399       }
1400 }
1401 
1402 static struct aux_index *
add_index(struct aux_cloner * cloner,const char * name,int unique)1403 add_index (struct aux_cloner *cloner, const char *name, int unique)
1404 {
1405 /* adding an Index definition */
1406     int len;
1407     struct aux_index *index = malloc (sizeof (struct aux_index));
1408     len = strlen (name);
1409     index->name = malloc (len + 1);
1410     strcpy (index->name, name);
1411     index->unique = unique;
1412     index->create_sql = NULL;
1413     index->next = NULL;
1414 /* updating the linked list */
1415     if (cloner->first_idx == NULL)
1416 	cloner->first_idx = index;
1417     if (cloner->last_idx != NULL)
1418 	cloner->last_idx->next = index;
1419     cloner->last_idx = index;
1420     return index;
1421 }
1422 
1423 static void
add_column(struct aux_cloner * cloner,const char * name,const char * type,int notnull,const char * deflt,int pk)1424 add_column (struct aux_cloner *cloner, const char *name, const char *type,
1425 	    int notnull, const char *deflt, int pk)
1426 {
1427 /* adding a Column definition */
1428     int len;
1429     struct aux_column *column = malloc (sizeof (struct aux_column));
1430     len = strlen (name);
1431     column->name = malloc (len + 1);
1432     strcpy (column->name, name);
1433     len = strlen (type);
1434     column->type = malloc (len + 1);
1435     strcpy (column->type, type);
1436     column->notnull = notnull;
1437     if (deflt == NULL)
1438 	column->deflt = NULL;
1439     else
1440       {
1441 	  len = strlen (deflt);
1442 	  column->deflt = malloc (len + 1);
1443 	  strcpy (column->deflt, deflt);
1444       }
1445     column->pk = pk;
1446     column->fk = 0;
1447     column->idx = 0;
1448     column->geometry = NULL;
1449     column->ignore = 0;
1450     column->already_existing = 0;
1451     column->mismatching = 0;
1452     column->next = NULL;
1453 /* updating the linked list */
1454     if (cloner->first_col == NULL)
1455 	cloner->first_col = column;
1456     if (cloner->last_col != NULL)
1457 	cloner->last_col->next = column;
1458     cloner->last_col = column;
1459     if (pk)
1460       {
1461 	  struct aux_pk_column *ppk = malloc (sizeof (struct aux_pk_column));
1462 	  ppk->column = column;
1463 	  ppk->next = NULL;
1464 	  /* updating the linked list */
1465 	  if (cloner->first_pk == NULL)
1466 	      cloner->first_pk = ppk;
1467 	  if (cloner->last_pk != NULL)
1468 	      cloner->last_pk->next = ppk;
1469 	  cloner->last_pk = ppk;
1470 	  cloner->pk_count += 1;
1471       }
1472 }
1473 
1474 static void
mark_existing_column(struct aux_cloner * cloner,const char * name)1475 mark_existing_column (struct aux_cloner *cloner, const char *name)
1476 {
1477 /* marking an existing Column */
1478     struct aux_column *column = cloner->first_col;
1479     while (column != NULL)
1480       {
1481 	  if (strcasecmp (column->name, name) == 0)
1482 	    {
1483 		column->already_existing = 1;
1484 		return;
1485 	    }
1486 	  column = column->next;
1487       }
1488 }
1489 
1490 static int
check_input_table_columns(struct aux_cloner * cloner)1491 check_input_table_columns (struct aux_cloner *cloner)
1492 {
1493 /* exploring the input table - Columns */
1494     char *sql;
1495     int ret;
1496     int i;
1497     char **results;
1498     int rows;
1499     int columns;
1500     const char *name;
1501     const char *type;
1502     int notnull;
1503     const char *deflt;
1504     int pk;
1505     char *xprefix;
1506     char *xtable;
1507 
1508     xprefix = gaiaDoubleQuotedSql (cloner->db_prefix);
1509     xtable = gaiaDoubleQuotedSql (cloner->in_table);
1510     sql = sqlite3_mprintf ("PRAGMA \"%s\".table_info(\"%s\")", xprefix, xtable);
1511     free (xprefix);
1512     free (xtable);
1513     ret =
1514 	sqlite3_get_table (cloner->sqlite, sql, &results, &rows, &columns,
1515 			   NULL);
1516     sqlite3_free (sql);
1517     if (ret != SQLITE_OK)
1518 	return 0;
1519     if (rows < 1)
1520 	;
1521     else
1522       {
1523 	  for (i = 1; i <= rows; i++)
1524 	    {
1525 		name = results[(i * columns) + 1];
1526 		type = results[(i * columns) + 2];
1527 		notnull = atoi (results[(i * columns) + 3]);
1528 		deflt = results[(i * columns) + 4];
1529 		pk = atoi (results[(i * columns) + 5]);
1530 		add_column (cloner, name, type, notnull, deflt, pk);
1531 	    }
1532       }
1533     sqlite3_free_table (results);
1534 
1535     if (cloner->first_col == NULL)
1536       {
1537 	  spatialite_e
1538 	      ("CloneTable: input table \"%s\".\"%s\" does not exist\n",
1539 	       cloner->db_prefix, cloner->in_table);
1540 	  goto error;
1541       }
1542     return 1;
1543 
1544   error:
1545     return 0;
1546 }
1547 
1548 static void
check_input_table_autoincrement(struct aux_cloner * cloner)1549 check_input_table_autoincrement (struct aux_cloner *cloner)
1550 {
1551 /* exploring the input table AUTOINCREMENT property */
1552     char *sql;
1553     int ret;
1554     int i;
1555     char **results;
1556     int rows;
1557     int columns;
1558     char *xprefix;
1559 
1560     if (cloner->pk_count != 1)
1561 	return;
1562 
1563     xprefix = gaiaDoubleQuotedSql (cloner->db_prefix);
1564     sql = sqlite3_mprintf ("SELECT Count(*) FROM \"%s\".sqlite_sequence "
1565 			   "WHERE Lower(name) = Lower(%Q)",
1566 			   xprefix, cloner->in_table);
1567     free (xprefix);
1568     ret =
1569 	sqlite3_get_table (cloner->sqlite, sql, &results, &rows, &columns,
1570 			   NULL);
1571     sqlite3_free (sql);
1572     if (ret != SQLITE_OK)
1573 	return;
1574     if (rows < 1)
1575 	;
1576     else
1577       {
1578 	  for (i = 1; i <= rows; i++)
1579 	    {
1580 		if (atoi (results[(i * columns) + 0]) > 0)
1581 		    cloner->autoincrement = 1;
1582 	    }
1583       }
1584     sqlite3_free_table (results);
1585 }
1586 
1587 static void
check_output_table_columns(struct aux_cloner * cloner)1588 check_output_table_columns (struct aux_cloner *cloner)
1589 {
1590 /* exploring the output table - Columns */
1591     char *sql;
1592     int ret;
1593     int i;
1594     char **results;
1595     int rows;
1596     int columns;
1597     const char *name;
1598     char *xtable;
1599 
1600     xtable = gaiaDoubleQuotedSql (cloner->out_table);
1601     sql = sqlite3_mprintf ("PRAGMA main.table_info(\"%s\")", xtable);
1602     free (xtable);
1603     ret =
1604 	sqlite3_get_table (cloner->sqlite, sql, &results, &rows, &columns,
1605 			   NULL);
1606     sqlite3_free (sql);
1607     if (ret != SQLITE_OK)
1608 	return;
1609     if (rows < 1)
1610 	;
1611     else
1612       {
1613 	  for (i = 1; i <= rows; i++)
1614 	    {
1615 		name = results[(i * columns) + 1];
1616 		mark_existing_column (cloner, name);
1617 	    }
1618       }
1619     sqlite3_free_table (results);
1620 }
1621 
1622 static void
expand_index(struct aux_cloner * cloner,struct aux_index * index)1623 expand_index (struct aux_cloner *cloner, struct aux_index *index)
1624 {
1625 /* expanding an Index definitions */
1626     char *sql;
1627     int ret;
1628     int i;
1629     char **results;
1630     int rows;
1631     int columns;
1632     const char *name;
1633     char *xprefix;
1634     char *xindex;
1635 
1636 /* retrieving the column names */
1637     xprefix = gaiaDoubleQuotedSql (cloner->db_prefix);
1638     xindex = gaiaDoubleQuotedSql (index->name);
1639     sql = sqlite3_mprintf ("PRAGMA \"%s\".index_info(\"%s\")", xprefix, xindex);
1640     free (xprefix);
1641     free (xindex);
1642     ret =
1643 	sqlite3_get_table (cloner->sqlite, sql, &results, &rows, &columns,
1644 			   NULL);
1645     sqlite3_free (sql);
1646     if (ret != SQLITE_OK)
1647 	return;
1648     if (rows < 1)
1649 	;
1650     else
1651       {
1652 	  for (i = 1; i <= rows; i++)
1653 	    {
1654 		name = results[(i * columns) + 2];
1655 		if (name != NULL)
1656 		  {
1657 		      /* indexes based on Expressions have a NULL column name !!! */
1658 		      add_index_column (cloner->first_col, name);
1659 		  }
1660 	    }
1661       }
1662     sqlite3_free_table (results);
1663 
1664 /* retrieving the initial CREATE INDEX Sql Statement */
1665     xprefix = gaiaDoubleQuotedSql (cloner->db_prefix);
1666     sql = sqlite3_mprintf ("SELECT sql FROM \"%s\".sqlite_master "
1667 			   "WHERE type = 'index' AND name = %Q", xprefix,
1668 			   index->name);
1669     free (xprefix);
1670     ret =
1671 	sqlite3_get_table (cloner->sqlite, sql, &results, &rows, &columns,
1672 			   NULL);
1673     sqlite3_free (sql);
1674     if (ret != SQLITE_OK)
1675 	return;
1676     if (rows < 1)
1677 	;
1678     else
1679       {
1680 	  for (i = 1; i <= rows; i++)
1681 	    {
1682 		const char *create_sql = results[(i * columns) + 0];
1683 		if (index->create_sql != NULL)
1684 		    free (index->create_sql);
1685 		if (create_sql == NULL)
1686 		    index->create_sql = NULL;
1687 		else
1688 		  {
1689 		      int len = strlen (create_sql);
1690 		      index->create_sql = malloc (len + 1);
1691 		      strcpy (index->create_sql, create_sql);
1692 		  }
1693 	    }
1694       }
1695     sqlite3_free_table (results);
1696 }
1697 
1698 static void
check_input_table_index_defs(struct aux_cloner * cloner)1699 check_input_table_index_defs (struct aux_cloner *cloner)
1700 {
1701 /* exploring the input table - Index definitions */
1702     char *sql;
1703     int ret;
1704     int i;
1705     char **results;
1706     int rows;
1707     int columns;
1708     const char *name;
1709     int unique;
1710     char *xprefix;
1711     char *xtable;
1712     struct aux_index *idx;
1713 
1714     xprefix = gaiaDoubleQuotedSql (cloner->db_prefix);
1715     xtable = gaiaDoubleQuotedSql (cloner->in_table);
1716     sql = sqlite3_mprintf ("PRAGMA \"%s\".index_list(\"%s\")", xprefix, xtable);
1717     free (xprefix);
1718     free (xtable);
1719     ret =
1720 	sqlite3_get_table (cloner->sqlite, sql, &results, &rows, &columns,
1721 			   NULL);
1722     sqlite3_free (sql);
1723     if (ret != SQLITE_OK)
1724 	return;
1725     if (rows < 1)
1726 	;
1727     else
1728       {
1729 	  for (i = 1; i <= rows; i++)
1730 	    {
1731 		name = results[(i * columns) + 1];
1732 		if (strncasecmp (name, "sqlite_autoindex_", 17) == 0)
1733 		  {
1734 		      /* ignoring any AUTOINDEX defined by SQLite */
1735 		      continue;
1736 		  }
1737 		unique = atoi (results[(i * columns) + 2]);
1738 		idx = add_index (cloner, name, unique);
1739 		expand_index (cloner, idx);
1740 	    }
1741       }
1742     sqlite3_free_table (results);
1743 }
1744 
1745 static void
check_input_table_foreign_keys(struct aux_cloner * cloner)1746 check_input_table_foreign_keys (struct aux_cloner *cloner)
1747 {
1748 /* exploring the input table - Foreign Keys */
1749     char *sql;
1750     int ret;
1751     int i;
1752     char **results;
1753     int rows;
1754     int columns;
1755     int id;
1756     const char *references;
1757     const char *from;
1758     const char *to;
1759     const char *on_update;
1760     const char *on_delete;
1761     const char *match;
1762     char *xprefix;
1763     char *xtable;
1764 
1765     xprefix = gaiaDoubleQuotedSql (cloner->db_prefix);
1766     xtable = gaiaDoubleQuotedSql (cloner->in_table);
1767     sql =
1768 	sqlite3_mprintf ("PRAGMA \"%s\".foreign_key_list(\"%s\")", xprefix,
1769 			 xtable);
1770     free (xprefix);
1771     free (xtable);
1772     ret =
1773 	sqlite3_get_table (cloner->sqlite, sql, &results, &rows, &columns,
1774 			   NULL);
1775     sqlite3_free (sql);
1776     if (ret != SQLITE_OK)
1777 	return;
1778     if (rows < 1)
1779 	;
1780     else
1781       {
1782 	  for (i = 1; i <= rows; i++)
1783 	    {
1784 		id = atoi (results[(i * columns) + 0]);
1785 		references = results[(i * columns) + 2];
1786 		from = results[(i * columns) + 3];
1787 		to = results[(i * columns) + 4];
1788 		if (to == NULL)
1789 		    to = from;
1790 		on_update = results[(i * columns) + 5];
1791 		on_delete = results[(i * columns) + 6];
1792 		match = results[(i * columns) + 7];
1793 		if (strcasecmp (on_update, "NO ACTION") == 0)
1794 		    on_update = NULL;
1795 		if (strcasecmp (on_delete, "NO ACTION") == 0)
1796 		    on_delete = NULL;
1797 		if (strcasecmp (match, "NONE") == 0)
1798 		    match = NULL;
1799 		add_foreign_key (cloner, id, references, from, to, on_update,
1800 				 on_delete, match);
1801 	    }
1802       }
1803     sqlite3_free_table (results);
1804 }
1805 
1806 static void
check_input_table_triggers(struct aux_cloner * cloner)1807 check_input_table_triggers (struct aux_cloner *cloner)
1808 {
1809 /* exploring the input table - Triggers */
1810     char *sql;
1811     int ret;
1812     int i;
1813     char **results;
1814     int rows;
1815     int columns;
1816     const char *name;
1817     const char *sqlx;
1818     char *xprefix;
1819 
1820     xprefix = gaiaDoubleQuotedSql (cloner->db_prefix);
1821     sql = sqlite3_mprintf ("SELECT name, sql FROM \"%s\".sqlite_master "
1822 			   "WHERE type = 'trigger' AND Lower(tbl_name) = Lower(%Q)",
1823 			   xprefix, cloner->in_table);
1824     free (xprefix);
1825     ret =
1826 	sqlite3_get_table (cloner->sqlite, sql, &results, &rows, &columns,
1827 			   NULL);
1828     sqlite3_free (sql);
1829     if (ret != SQLITE_OK)
1830 	return;
1831     if (rows < 1)
1832 	;
1833     else
1834       {
1835 	  for (i = 1; i <= rows; i++)
1836 	    {
1837 		name = results[(i * columns) + 0];
1838 		sqlx = results[(i * columns) + 1];
1839 		add_trigger (cloner, name, sqlx);
1840 	    }
1841       }
1842     sqlite3_free_table (results);
1843 }
1844 
1845 static void
check_input_table_geometries(struct aux_cloner * cloner)1846 check_input_table_geometries (struct aux_cloner *cloner)
1847 {
1848 /* exploring the input table - Geometries */
1849     char *sql;
1850     int ret;
1851     int i;
1852     char **results;
1853     int rows;
1854     int columns;
1855     const char *name;
1856     int type;
1857     int dims;
1858     int srid;
1859     int spatial_index;
1860     char *xprefix;
1861 
1862     xprefix = gaiaDoubleQuotedSql (cloner->db_prefix);
1863     sql = sqlite3_mprintf ("SELECT f_geometry_column, geometry_type, "
1864 			   "coord_dimension, srid, spatial_index_enabled "
1865 			   "FROM \"%s\".geometry_columns "
1866 			   "WHERE Lower(f_table_name) = Lower(%Q)",
1867 			   xprefix, cloner->in_table);
1868     free (xprefix);
1869     ret =
1870 	sqlite3_get_table (cloner->sqlite, sql, &results, &rows, &columns,
1871 			   NULL);
1872     sqlite3_free (sql);
1873     if (ret != SQLITE_OK)
1874 	return;
1875     if (rows < 1)
1876 	;
1877     else
1878       {
1879 	  for (i = 1; i <= rows; i++)
1880 	    {
1881 		name = results[(i * columns) + 0];
1882 		type = atoi (results[(i * columns) + 1]);
1883 		dims = atoi (results[(i * columns) + 2]);
1884 		srid = atoi (results[(i * columns) + 3]);
1885 		spatial_index = atoi (results[(i * columns) + 4]);
1886 		add_geometry (cloner, name, type, dims, srid, spatial_index);
1887 	    }
1888       }
1889     sqlite3_free_table (results);
1890 }
1891 
1892 static void
check_output_table_geometries(struct aux_cloner * cloner)1893 check_output_table_geometries (struct aux_cloner *cloner)
1894 {
1895 /* exploring the output table - Geometries */
1896     char *sql;
1897     int ret;
1898     int i;
1899     char **results;
1900     int rows;
1901     int columns;
1902     const char *name;
1903     int type;
1904     int dims;
1905     int srid;
1906 
1907     sql = sqlite3_mprintf ("SELECT f_geometry_column, geometry_type, "
1908 			   "coord_dimension, srid, spatial_index_enabled "
1909 			   "FROM main.geometry_columns "
1910 			   "WHERE Lower(f_table_name) = Lower(%Q)",
1911 			   cloner->out_table);
1912     ret =
1913 	sqlite3_get_table (cloner->sqlite, sql, &results, &rows, &columns,
1914 			   NULL);
1915     sqlite3_free (sql);
1916     if (ret != SQLITE_OK)
1917 	return;
1918     if (rows < 1)
1919 	;
1920     else
1921       {
1922 	  for (i = 1; i <= rows; i++)
1923 	    {
1924 		name = results[(i * columns) + 0];
1925 		type = atoi (results[(i * columns) + 1]);
1926 		dims = atoi (results[(i * columns) + 2]);
1927 		srid = atoi (results[(i * columns) + 3]);
1928 		mark_existing_geometry (cloner, name, type, dims, srid);
1929 	    }
1930       }
1931     sqlite3_free_table (results);
1932 }
1933 
1934 static void
free_trigger(struct aux_trigger * trigger)1935 free_trigger (struct aux_trigger *trigger)
1936 {
1937 /* memory cleanup - destroying a Trigger object */
1938     if (trigger == NULL)
1939 	return;
1940     if (trigger->name != NULL)
1941 	free (trigger->name);
1942     if (trigger->sql != NULL)
1943 	free (trigger->sql);
1944     free (trigger);
1945 }
1946 
1947 static void
free_fk_columns(struct aux_fk_columns * col)1948 free_fk_columns (struct aux_fk_columns *col)
1949 {
1950 /* memory cleanup - destroying a Foreign Key Columns object */
1951     if (col == NULL)
1952 	return;
1953     if (col->from != NULL)
1954 	free (col->from);
1955     if (col->to != NULL)
1956 	free (col->to);
1957     free (col);
1958 }
1959 
1960 static void
free_foreign_key(struct aux_foreign_key * fk)1961 free_foreign_key (struct aux_foreign_key *fk)
1962 {
1963 /* memory cleanup - destroying a Foreign Key object */
1964     struct aux_fk_columns *pc;
1965     struct aux_fk_columns *pcn;
1966     if (fk == NULL)
1967 	return;
1968     if (fk->name != NULL)
1969 	free (fk->name);
1970     if (fk->references != NULL)
1971 	free (fk->references);
1972     if (fk->on_update != NULL)
1973 	free (fk->on_update);
1974     if (fk->on_delete != NULL)
1975 	free (fk->on_delete);
1976     if (fk->match != NULL)
1977 	free (fk->match);
1978     pc = fk->first;
1979     while (pc != NULL)
1980       {
1981 	  pcn = pc->next;
1982 	  free_fk_columns (pc);
1983 	  pc = pcn;
1984       }
1985     free (fk);
1986 }
1987 
1988 static void
free_index(struct aux_index * index)1989 free_index (struct aux_index *index)
1990 {
1991 /* memory cleanup - destroying an Index object */
1992     if (index == NULL)
1993 	return;
1994     if (index->name != NULL)
1995 	free (index->name);
1996     if (index->create_sql != NULL)
1997 	free (index->create_sql);
1998     free (index);
1999 }
2000 
2001 static void
free_column(struct aux_column * column)2002 free_column (struct aux_column *column)
2003 {
2004 /* memory cleanup - destroying a Column object */
2005     if (column == NULL)
2006 	return;
2007     if (column->name != NULL)
2008 	free (column->name);
2009     if (column->type != NULL)
2010 	free (column->type);
2011     if (column->deflt != NULL)
2012 	free (column->deflt);
2013     if (column->geometry != NULL)
2014 	free (column->geometry);
2015     free (column);
2016 }
2017 
2018 static void
free_cloner(struct aux_cloner * cloner)2019 free_cloner (struct aux_cloner *cloner)
2020 {
2021 /* memory cleanup - destroying a Cloner object */
2022     struct aux_column *pc;
2023     struct aux_column *pcn;
2024     struct aux_pk_column *ppk;
2025     struct aux_pk_column *ppkn;
2026     struct aux_index *pi;
2027     struct aux_index *pin;
2028     struct aux_foreign_key *pfk;
2029     struct aux_foreign_key *pfkn;
2030     struct aux_trigger *ptrg;
2031     struct aux_trigger *ptrgn;
2032     if (cloner == NULL)
2033 	return;
2034     if (cloner->db_prefix != NULL)
2035 	free (cloner->db_prefix);
2036     if (cloner->in_table != NULL)
2037 	free (cloner->in_table);
2038     if (cloner->out_table != NULL)
2039 	free (cloner->out_table);
2040     pc = cloner->first_col;
2041     while (pc != NULL)
2042       {
2043 	  pcn = pc->next;
2044 	  free_column (pc);
2045 	  pc = pcn;
2046       }
2047     ppk = cloner->first_pk;
2048     while (ppk != NULL)
2049       {
2050 	  ppkn = ppk->next;
2051 	  free (ppk);
2052 	  ppk = ppkn;
2053       }
2054     pi = cloner->first_idx;
2055     while (pi != NULL)
2056       {
2057 	  pin = pi->next;
2058 	  free_index (pi);
2059 	  pi = pin;
2060       }
2061     pfk = cloner->first_fk;
2062     while (pfk != NULL)
2063       {
2064 	  pfkn = pfk->next;
2065 	  free_foreign_key (pfk);
2066 	  pfk = pfkn;
2067       }
2068     ptrg = cloner->first_trigger;
2069     while (ptrg != NULL)
2070       {
2071 	  ptrgn = ptrg->next;
2072 	  free_trigger (ptrg);
2073 	  ptrg = ptrgn;
2074       }
2075     if (cloner->sorted_pks != NULL)
2076 	free (cloner->sorted_pks);
2077     free (cloner);
2078 }
2079 
2080 static int
already_existing_table(sqlite3 * sqlite,const char * table)2081 already_existing_table (sqlite3 * sqlite, const char *table)
2082 {
2083 /* testing if the target Table is already defined */
2084     char *sql;
2085     int ret;
2086     int i;
2087     char **results;
2088     int rows;
2089     int columns;
2090     int count = 0;
2091 
2092     sql = sqlite3_mprintf ("SELECT Count(*) FROM main.sqlite_master "
2093 			   "WHERE type = 'table' AND Lower(name) = Lower(%Q)",
2094 			   table);
2095     ret = sqlite3_get_table (sqlite, sql, &results, &rows, &columns, NULL);
2096     sqlite3_free (sql);
2097     if (ret != SQLITE_OK)
2098 	goto stop;
2099     if (rows < 1)
2100 	;
2101     else
2102       {
2103 	  for (i = 1; i <= rows; i++)
2104 	      count = atoi (results[(i * columns) + 0]);
2105       }
2106     sqlite3_free_table (results);
2107   stop:
2108     return count;
2109 }
2110 
2111 SPATIALITE_PRIVATE const void *
gaiaAuxClonerCreateEx(const void * sqlite,const char * db_prefix,const char * in_table,const char * out_table,int create_only)2112 gaiaAuxClonerCreateEx (const void *sqlite, const char *db_prefix,
2113 		       const char *in_table, const char *out_table,
2114 		       int create_only)
2115 {
2116 /* creating a Cloner object */
2117     int len;
2118     struct aux_cloner *cloner;
2119     if (checkSpatialMetaData ((sqlite3 *) sqlite) < 3)
2120       {
2121 	  spatialite_e ("CloneTable: obsolete DB-layout (< 4.0.0)\n");
2122 	  return NULL;
2123       }
2124 
2125     cloner = malloc (sizeof (struct aux_cloner));
2126     if (cloner == NULL)
2127 	return NULL;
2128     cloner->sqlite = (sqlite3 *) sqlite;
2129     cloner->db_prefix = NULL;
2130     cloner->in_table = NULL;
2131     cloner->out_table = NULL;
2132     len = strlen (db_prefix);
2133     cloner->db_prefix = malloc (len + 1);
2134     strcpy (cloner->db_prefix, db_prefix);
2135     len = strlen (in_table);
2136     cloner->in_table = malloc (len + 1);
2137     strcpy (cloner->in_table, in_table);
2138     len = strlen (out_table);
2139     cloner->out_table = malloc (len + 1);
2140     strcpy (cloner->out_table, out_table);
2141     cloner->first_col = NULL;
2142     cloner->last_col = NULL;
2143     cloner->first_pk = NULL;
2144     cloner->last_pk = NULL;
2145     cloner->first_idx = NULL;
2146     cloner->last_idx = NULL;
2147     cloner->first_fk = NULL;
2148     cloner->last_fk = NULL;
2149     cloner->first_trigger = NULL;
2150     cloner->last_trigger = NULL;
2151     cloner->pk_count = 0;
2152     cloner->sorted_pks = NULL;
2153     cloner->autoincrement = 0;
2154     cloner->resequence = 0;
2155     cloner->with_fks = 0;
2156     cloner->with_triggers = 0;
2157     cloner->append = 0;
2158     cloner->already_existing = 0;
2159     cloner->create_only = create_only;
2160 
2161 /* exploring the input table - Columns */
2162     if (!check_input_table_columns (cloner))
2163 	goto error;
2164 /* exploring PRIMARY KEY AUTOINCREMENT */
2165     check_input_table_autoincrement (cloner);
2166 /* exploring the input table - Index definitions */
2167     check_input_table_index_defs (cloner);
2168 /* exploring the input table - Foreign Key definitions */
2169     check_input_table_foreign_keys (cloner);
2170 /* exploring the input table - Trigger definitions */
2171     check_input_table_triggers (cloner);
2172 /* exploring the input table - Geometry definitions */
2173     check_input_table_geometries (cloner);
2174 
2175     if (already_existing_table (cloner->sqlite, out_table))
2176 	cloner->already_existing = 1;
2177     return cloner;
2178   error:
2179     free_cloner (cloner);
2180     return NULL;
2181 }
2182 
2183 SPATIALITE_PRIVATE const void *
gaiaAuxClonerCreate(const void * sqlite,const char * db_prefix,const char * in_table,const char * out_table)2184 gaiaAuxClonerCreate (const void *sqlite, const char *db_prefix,
2185 		     const char *in_table, const char *out_table)
2186 {
2187 /* creating a Cloner object */
2188     return gaiaAuxClonerCreateEx (sqlite, db_prefix, in_table, out_table, 0);
2189 }
2190 
2191 SPATIALITE_PRIVATE void
gaiaAuxClonerDestroy(const void * handle)2192 gaiaAuxClonerDestroy (const void *handle)
2193 {
2194 /* destroying a Cloner object */
2195     struct aux_cloner *cloner = (struct aux_cloner *) handle;
2196     if (handle == NULL)
2197 	return;
2198     free_cloner (cloner);
2199 }
2200 
2201 static void
ignore_column(struct aux_cloner * cloner,const char * column)2202 ignore_column (struct aux_cloner *cloner, const char *column)
2203 {
2204 /* marking a Column to be ignored */
2205     struct aux_column *pc = cloner->first_col;
2206     while (pc != NULL)
2207       {
2208 	  if (strcasecmp (pc->name, column) == 0)
2209 	    {
2210 		pc->ignore = 1;
2211 		return;
2212 	    }
2213 	  pc = pc->next;
2214       }
2215 }
2216 
2217 static int
check_append(struct aux_cloner * cloner)2218 check_append (struct aux_cloner *cloner)
2219 {
2220 /* cheching for APPEND validity */
2221     int error = 0;
2222     struct aux_column *column = cloner->first_col;
2223     while (column != NULL)
2224       {
2225 	  if (column->mismatching)
2226 	      error = 1;
2227 	  column = column->next;
2228       }
2229     if (error)
2230 	return 0;
2231     return 1;
2232 }
2233 
2234 static void
cast2multi_column(struct aux_cloner * cloner,const char * column)2235 cast2multi_column (struct aux_cloner *cloner, const char *column)
2236 {
2237 /* marking a Geometry Column to be casted to MultiType */
2238     struct aux_column *pc = cloner->first_col;
2239     while (pc != NULL)
2240       {
2241 	  if (strcasecmp (pc->name, column) == 0 && pc->geometry != NULL)
2242 	    {
2243 		pc->geometry->cast2multi = 1;
2244 		return;
2245 	    }
2246 	  pc = pc->next;
2247       }
2248 }
2249 
2250 SPATIALITE_PRIVATE void
gaiaAuxClonerAddOption(const void * handle,const char * option)2251 gaiaAuxClonerAddOption (const void *handle, const char *option)
2252 {
2253 /* parsing an Option */
2254     struct aux_cloner *cloner = (struct aux_cloner *) handle;
2255     if (handle == NULL)
2256 	return;
2257     if (strncasecmp (option, "::ignore::", 10) == 0)
2258 	ignore_column (cloner, option + 10);
2259     if (strncasecmp (option, "::cast2multi::", 14) == 0)
2260 	cast2multi_column (cloner, option + 14);
2261     if (strncasecmp (option, "::resequence::", 14) == 0)
2262 	cloner->resequence = 1;
2263     if (strncasecmp (option, "::with-foreign-keys::", 21) == 0)
2264 	cloner->with_fks = 1;
2265     if (strncasecmp (option, "::with-triggers::", 17) == 0)
2266 	cloner->with_triggers = 1;
2267     if (strncasecmp (option, "::append::", 10) == 0)
2268       {
2269 	  cloner->append = 1;
2270 	  cloner->resequence = 1;
2271       }
2272     return;
2273 }
2274 
2275 SPATIALITE_PRIVATE int
gaiaAuxClonerCheckValidTarget(const void * handle)2276 gaiaAuxClonerCheckValidTarget (const void *handle)
2277 {
2278 /* checking the Target Table for validity */
2279     struct aux_cloner *cloner = (struct aux_cloner *) handle;
2280     if (handle == NULL)
2281 	return 0;
2282 
2283     if (cloner->already_existing)
2284       {
2285 	  if (cloner->append)
2286 	    {
2287 		/* exploring the output table - Columns */
2288 		check_output_table_columns (cloner);
2289 		/* exploring the output table - Geometries */
2290 		check_output_table_geometries (cloner);
2291 		/* checking for validity */
2292 		if (!check_append (cloner))
2293 		  {
2294 		      spatialite_e
2295 			  ("CloneTable: output table \"%s\" can't support APPEND\n",
2296 			   cloner->out_table);
2297 		      return 0;
2298 		  }
2299 	    }
2300 	  else
2301 	    {
2302 		spatialite_e
2303 		    ("CloneTable: output table \"%s\" already exists and APPEND is not enabled\n",
2304 		     cloner->out_table);
2305 		return 0;
2306 	    }
2307       }
2308     return 1;
2309 }
2310 
2311 SPATIALITE_PRIVATE int
gaiaAuxClonerExecute(const void * handle)2312 gaiaAuxClonerExecute (const void *handle)
2313 {
2314 /* executing the actual work */
2315     struct aux_cloner *cloner = (struct aux_cloner *) handle;
2316     if (handle == NULL)
2317 	return 0;
2318     if (cloner->already_existing)
2319       {
2320 	  /* creating any further column if required */
2321 	  if (!upgrade_output_table (cloner))
2322 	    {
2323 		spatialite_e
2324 		    ("CloneTable: unable to upgrade the output table \"%s\"\n",
2325 		     cloner->out_table);
2326 		return 0;
2327 	    }
2328       }
2329     else
2330       {
2331 	  /* creating the output table */
2332 	  if (!create_output_table (cloner))
2333 	    {
2334 		spatialite_e
2335 		    ("CloneTable: unable to create the output table \"%s\"\n",
2336 		     cloner->out_table);
2337 		return 0;
2338 	    }
2339       }
2340     if (cloner->create_only == 0)
2341       {
2342 	  if (!copy_rows (cloner))
2343 	    {
2344 		spatialite_e ("CloneTable: unable to copy Table rows\n");
2345 		return 0;
2346 	    }
2347       }
2348     return 1;
2349 }
2350