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