GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-f13a4924e1
copy_tab.c
Go to the documentation of this file.
1 /*!
2  \file db/dbmi_client/copy_tab.c
3 
4  \brief DBMI Library (client) - copy table
5 
6  (C) 1999-2008 by the GRASS Development Team
7 
8  This program is free software under the GNU General Public
9  License (>=v2). Read the file COPYING that comes with GRASS
10  for details.
11 
12  \author Joel Jones (CERL/UIUC), Radim Blazek
13  */
14 
15 #include <stdlib.h>
16 #include <string.h>
17 #include <grass/dbmi.h>
18 #include <grass/glocale.h>
19 #include "macros.h"
20 
21 static int cmp(const void *pa, const void *pb)
22 {
23  int *p1 = (int *)pa;
24  int *p2 = (int *)pb;
25 
26  if (*p1 < *p2)
27  return -1;
28  if (*p1 > *p2)
29  return 1;
30  return 0;
31 }
32 
33 /*!
34  \brief Copy table, used by various db_copy_table* (internal use only)
35 
36  Use either 'where' or 'select' or 'selcol'+'ivals'+'nvals' but
37  never more than one.
38 
39  Warning: driver opened as second must be closed as first, otherwise
40  it hangs, not sure why.
41 
42  \param from_dvrname name of driver from table is copied
43  \param from_dbname name of database from table is copied
44  \param from_tbl_name name of table to be copied
45  \param to_dvrname name of driver to - where table is copied to
46  \param to_dbname name of database to - where table is copied to
47  \param to_dbname name of copied table
48  \param where WHERE SQL condition (without where key word) or NULL
49  \param select full select statement
50  \param selcol name of column used to select records by values in ivals or
51  NULL \param ivals pointer to array of integer values or NULL \param nvals
52  number of values in ivals
53 
54  \return DB_OK on success
55  \return DB_FAILED on failure
56  */
57 static int copy_table(const char *from_drvname, const char *from_dbname,
58  const char *from_tblname, const char *to_drvname,
59  const char *to_dbname, const char *to_tblname,
60  const char *where, const char *select, const char *selcol,
61  int *ivals, int nvals)
62 {
63  int col, ncols, sqltype, ctype, more, selcol_found;
64  char buf[1000];
65  int *ivalues;
66  dbHandle from_handle, to_handle;
67  dbString tblname, sql;
68  dbString value_string;
69  dbString *tblnames;
70  dbTable *table, *out_table;
71  dbCursor cursor;
72  dbColumn *column;
73  dbValue *value;
74  const char *colname;
75  dbDriver *from_driver, *to_driver;
76  int count, i;
77 
78  G_debug(3,
79  "db_copy_table():\n from driver = %s, db = %s, table = %s\n"
80  " to driver = %s, db = %s, table = %s, where = %s, select = %s",
81  from_drvname, from_dbname, from_tblname, to_drvname, to_dbname,
82  to_tblname, where, select);
83 
84  db_init_handle(&from_handle);
85  db_init_handle(&to_handle);
86  db_init_string(&tblname);
87  db_init_string(&sql);
88  db_init_string(&value_string);
89 
90  if (selcol) {
91  if (!ivals || (ivals && nvals == 0)) {
92  G_warning(_("Array of values to select from column <%s> is empty"),
93  selcol);
94  return DB_FAILED;
95  }
96  /* Make a copy of input values and sort it */
97  if (ivals) {
98  ivalues = (int *)G_malloc(nvals * sizeof(int));
99  memcpy(ivalues, ivals, nvals * sizeof(int));
100  qsort((void *)ivalues, nvals, sizeof(int), cmp);
101  }
102  }
103  else
104  ivalues = NULL;
105 
106  /* Open input driver and database */
107  from_driver = db_start_driver(from_drvname);
108  if (from_driver == NULL) {
109  G_warning(_("Unable to start driver <%s>"), from_drvname);
110  return DB_FAILED;
111  }
112  db_set_handle(&from_handle, from_dbname, NULL);
113  if (db_open_database(from_driver, &from_handle) != DB_OK) {
114  G_warning(_("Unable to open database <%s> by driver <%s>"), from_dbname,
115  from_drvname);
117  return DB_FAILED;
118  }
119 
120  /* Open output driver and database */
121  if (strcmp(from_drvname, to_drvname) == 0 &&
122  strcmp(from_dbname, to_dbname) == 0) {
123  G_debug(3, "Use the same driver");
124  to_driver = from_driver;
125  }
126  else {
127  to_driver = db_start_driver(to_drvname);
128  if (to_driver == NULL) {
129  G_warning(_("Unable to start driver <%s>"), to_drvname);
131  return DB_FAILED;
132  }
133  db_set_handle(&to_handle, to_dbname, NULL);
134  if (db_open_database(to_driver, &to_handle) != DB_OK) {
135  G_warning(_("Unable to open database <%s> by driver <%s>"),
136  to_dbname, to_drvname);
138  if (from_driver != to_driver) {
140  }
141  return DB_FAILED;
142  }
143  }
144 
145  db_begin_transaction(to_driver);
146 
147  /* Because in SQLite3 an opened cursor is no more valid
148  if 'schema' is modified (create table), we have to open
149  cursor twice */
150 
151  /* test if the table exists */
152  if (db_list_tables(to_driver, &tblnames, &count, 0) != DB_OK) {
153  G_warning(_("Unable to get list tables in database <%s>"), to_dbname);
155  if (from_driver != to_driver)
157 
158  return DB_FAILED;
159  }
160 
161  for (i = 0; i < count; i++) {
162  int ret;
163  char *tblname_i;
164 
165  tblname_i = NULL;
166  if (strcmp(to_drvname, "pg") == 0) {
167  char *p, *tbl;
168  dbConnection connection;
169 
170  tbl = db_get_string(&tblnames[i]);
171  db_get_connection(&connection);
172  p = strstr(tbl, ".");
173 
174  if (p) {
175  char buf[GNAME_MAX];
176 
177  sprintf(buf, "%s.%s",
178  connection.schemaName ? connection.schemaName
179  : "public",
180  to_tblname);
181  if (strcmp(buf, tbl) == 0)
182  tblname_i = G_store(p + 1); /* skip dot */
183  }
184  }
185  if (!tblname_i) {
186  tblname_i = G_store(db_get_string(&tblnames[i]));
187  }
188 
189  ret = DB_FAILED;
190  if (strcmp(to_tblname, tblname_i) == 0) {
191  if (G_get_overwrite()) {
192  G_warning(_("Table <%s> already exists in database and will be "
193  "overwritten"),
194  to_tblname);
195  ret = db_drop_table(to_driver, &tblnames[i]);
196  }
197  else {
198  G_warning(_("Table <%s> already exists in database <%s>"),
199  to_tblname, to_dbname);
200  }
201 
202  if (ret != DB_OK) {
204  if (from_driver != to_driver)
206 
207  return DB_FAILED;
208  }
209  }
210 
211  G_free(tblname_i);
212  }
213 
214  /* Create new table */
215  /* Open cursor for data structure */
216  if (select) {
217  db_set_string(&sql, select);
218 
219  /* TODO!: cannot use this because it will not work if a query
220  * ends with 'group by' for example */
221  /*
222  tmp = strdup ( select );
223  G_tolcase ( tmp );
224 
225  if ( !strstr( tmp,"where") )
226  {
227  db_append_string ( &sql, " where 0 = 1");
228  }
229  else
230  {
231  db_append_string ( &sql, " and 0 = 1");
232  }
233 
234  free (tmp);
235  */
236  }
237  else {
238  db_set_string(&sql, "select * from ");
239  db_append_string(&sql, from_tblname);
240  db_append_string(&sql, " where 0 = 1"); /* to get no data */
241  }
242 
243  G_debug(3, "db__copy_table: %s", db_get_string(&sql));
244  if (db_open_select_cursor(from_driver, &sql, &cursor, DB_SEQUENTIAL) !=
245  DB_OK) {
246  G_warning(_("Unable to open select cursor: '%s'"), db_get_string(&sql));
248  if (from_driver != to_driver) {
250  }
251  return DB_FAILED;
252  }
253  G_debug(3, "Select cursor opened");
254 
255  table = db_get_cursor_table(&cursor);
256  ncols = db_get_table_number_of_columns(table);
257  G_debug(3, "ncols = %d", ncols);
258 
259  out_table = db_alloc_table(ncols);
260  db_set_table_name(out_table, to_tblname);
261 
262  selcol_found = 0;
263  for (col = 0; col < ncols; col++) {
264  dbColumn *out_column;
265 
266  column = db_get_table_column(table, col);
267  colname = db_get_column_name(column);
268  sqltype = db_get_column_sqltype(column);
269  ctype = db_sqltype_to_Ctype(sqltype);
270 
271  G_debug(3, "%s (%s)", colname, db_sqltype_name(sqltype));
272 
273  out_column = db_get_table_column(out_table, col);
274 
275  if (selcol && G_strcasecmp(colname, selcol) == 0) {
276  if (ctype != DB_C_TYPE_INT)
277  G_fatal_error(_("Column <%s> is not integer"), colname);
278  selcol_found = 1;
279  }
280 
281  db_set_column_name(out_column, db_get_column_name(column));
282  db_set_column_description(out_column,
283  db_get_column_description(column));
284  db_set_column_sqltype(out_column, db_get_column_sqltype(column));
285  db_set_column_length(out_column, db_get_column_length(column));
287  db_set_column_scale(out_column, db_get_column_scale(column));
288  }
289 
290  db_close_cursor(&cursor);
291 
292  if (selcol && !selcol_found)
293  G_fatal_error(_("Column <%s> not found"), selcol);
294 
295  if (db_create_table(to_driver, out_table) != DB_OK) {
296  G_warning(_("Unable to create table <%s>"), to_tblname);
298  if (from_driver != to_driver) {
300  }
301  return DB_FAILED;
302  }
303 
304  /* Open cursor with data */
305  if (select) {
306  db_set_string(&sql, select);
307  }
308  else {
309  db_set_string(&sql, "select * from ");
310  db_append_string(&sql, from_tblname);
311  if (where) {
312  db_append_string(&sql, " where ");
313  db_append_string(&sql, where);
314  }
315  }
316 
317  G_debug(3, "db__copy_table: %s", db_get_string(&sql));
318  if (db_open_select_cursor(from_driver, &sql, &cursor, DB_SEQUENTIAL) !=
319  DB_OK) {
320  G_warning(_("Unable to open select cursor: '%s'"), db_get_string(&sql));
322  if (from_driver != to_driver) {
324  }
325  return DB_FAILED;
326  }
327  G_debug(3, "Select cursor opened");
328 
329  table = db_get_cursor_table(&cursor);
330  ncols = db_get_table_number_of_columns(table);
331  G_debug(3, "ncols = %d", ncols);
332 
333  /* Copy all rows */
334  while (1) {
335  int select;
336 
337  if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) {
338  G_warning(_("Unable to fetch data from table <%s>"), from_tblname);
339  db_close_cursor(&cursor);
341  if (from_driver != to_driver) {
343  }
344  return DB_FAILED;
345  }
346  if (!more)
347  break;
348 
349  sprintf(buf, "insert into %s values ( ", to_tblname);
350  db_set_string(&sql, buf);
351  select = 1;
352  for (col = 0; col < ncols; col++) {
353  column = db_get_table_column(table, col);
354  colname = db_get_column_name(column);
355  sqltype = db_get_column_sqltype(column);
356  ctype = db_sqltype_to_Ctype(sqltype);
357  value = db_get_column_value(column);
358 
359  if (selcol && G_strcasecmp(colname, selcol) == 0) {
360  if (db_test_value_isnull(value))
361  continue;
362  if (!bsearch(&(value->i), ivalues, nvals, sizeof(int), cmp)) {
363  select = 0;
364  break;
365  }
366  }
367  if (col > 0)
368  db_append_string(&sql, ", ");
369  db_convert_value_to_string(value, sqltype, &value_string);
370  switch (ctype) {
371  case DB_C_TYPE_STRING:
372  case DB_C_TYPE_DATETIME:
373  if (db_test_value_isnull(value)) {
374  db_append_string(&sql, "null");
375  }
376  else {
377  db_double_quote_string(&value_string);
378  db_append_string(&sql, "'");
379  db_append_string(&sql, db_get_string(&value_string));
380  db_append_string(&sql, "'");
381  }
382  break;
383  case DB_C_TYPE_INT:
384  case DB_C_TYPE_DOUBLE:
385  if (db_test_value_isnull(value)) {
386  db_append_string(&sql, "null");
387  }
388  else {
389  db_append_string(&sql, db_get_string(&value_string));
390  }
391  break;
392  default:
393  G_warning(_("Unknown column type (column <%s>)"), colname);
394  db_close_cursor(&cursor);
396  if (from_driver != to_driver) {
398  }
399  return DB_FAILED;
400  }
401  }
402  if (!select)
403  continue;
404  db_append_string(&sql, ")");
405  G_debug(3, "db__copy_table: %s", db_get_string(&sql));
406  if (db_execute_immediate(to_driver, &sql) != DB_OK) {
407  G_warning("Unable to insert new record: '%s'", db_get_string(&sql));
408  db_close_cursor(&cursor);
410  if (from_driver != to_driver) {
412  }
413  return DB_FAILED;
414  }
415  }
416  if (selcol)
417  G_free(ivalues);
418  G_debug(3, "Table copy OK");
419 
420  db_close_cursor(&cursor);
421  db_commit_transaction(to_driver);
423  if (from_driver != to_driver) {
425  }
426 
427  return DB_OK;
428 }
429 
430 /*!
431  \brief Copy a table
432 
433  \param from_drvname name of driver from table is copied
434  \param from_dbname name of database from table is copied
435  \param from_tblname name of table to be copied
436  \param to_drvname name of driver to - where table is copied to
437  \param to_dbname name of database to - where table is copied to
438  \param to_tblname name of copied table
439 
440  \return DB_OK on success
441  \return DB_FAILED on failure
442  */
443 int db_copy_table(const char *from_drvname, const char *from_dbname,
444  const char *from_tblname, const char *to_drvname,
445  const char *to_dbname, const char *to_tblname)
446 {
447  return copy_table(from_drvname, from_dbname, from_tblname, to_drvname,
448  to_dbname, to_tblname, NULL, NULL, NULL, NULL, 0);
449 }
450 
451 /*!
452  \brief Copy a table (by where statement)
453 
454  \param from_drvname name of driver from table is copied
455  \param from_dbname name of database from table is copied
456  \param from_tblname name of table to be copied
457  \param to_drvname name of driver to - where table is copied to
458  \param to_dbname name of database to - where table is copied to
459  \param to_tblname name of copied table
460  \param where WHERE SQL condition (without where key word)
461 
462  \return DB_OK on success
463  \return DB_FAILED on failure
464  */
465 int db_copy_table_where(const char *from_drvname, const char *from_dbname,
466  const char *from_tblname, const char *to_drvname,
467  const char *to_dbname, const char *to_tblname,
468  const char *where)
469 {
470  return copy_table(from_drvname, from_dbname, from_tblname, to_drvname,
471  to_dbname, to_tblname, where, NULL, NULL, NULL, 0);
472 }
473 
474 /*!
475  \brief Copy a table (by select statement)
476 
477  \param from_drvname name of driver from table is copied
478  \param from_dbname name of database from table is copied
479  \param from_dbname name of table to be copied
480  \param to_drvname name of driver to - where table is copied to
481  \param to_dbname name of database to - where table is copied to
482  \param to_tblname name of copied table
483  \param select full select statement
484 
485  \return DB_OK on success
486  \return DB_FAILED on failure
487  */
488 int db_copy_table_select(const char *from_drvname, const char *from_dbname,
489  const char *from_tblname, const char *to_drvname,
490  const char *to_dbname, const char *to_tblname,
491  const char *select)
492 {
493  return copy_table(from_drvname, from_dbname, from_tblname, to_drvname,
494  to_dbname, to_tblname, NULL, select, NULL, NULL, 0);
495 }
496 
497 /*!
498  \brief Copy a table (by keys)
499 
500  \param from_drvname name of driver from table is copied
501  \param from_dbname name of database from table is copied
502  \param from_tblname name of table to be copied
503  \param to_drvname name of driver to - where table is copied to
504  \param to_dbname name of database to - where table is copied to
505  \param to_tblname name of copied table
506  \param selcol name of column used to select records by values in ivals or
507  NULL \param ivals pointer to array of integer values or NULL \param nvals
508  number of values in ivals
509 
510  \return DB_OK on success
511  \return DB_FAILED on failure
512  */
513 int db_copy_table_by_ints(const char *from_drvname, const char *from_dbname,
514  const char *from_tblname, const char *to_drvname,
515  const char *to_dbname, const char *to_tblname,
516  const char *selcol, int *ivals, int nvals)
517 {
518  return copy_table(from_drvname, from_dbname, from_tblname, to_drvname,
519  to_dbname, to_tblname, NULL, NULL, selcol, ivals, nvals);
520 }
#define NULL
Definition: ccmath.h:32
int db_copy_table_where(const char *from_drvname, const char *from_dbname, const char *from_tblname, const char *to_drvname, const char *to_dbname, const char *to_tblname, const char *where)
Copy a table (by where statement)
Definition: copy_tab.c:465
int db_copy_table(const char *from_drvname, const char *from_dbname, const char *from_tblname, const char *to_drvname, const char *to_dbname, const char *to_tblname)
Copy a table.
Definition: copy_tab.c:443
int db_copy_table_by_ints(const char *from_drvname, const char *from_dbname, const char *from_tblname, const char *to_drvname, const char *to_dbname, const char *to_tblname, const char *selcol, int *ivals, int nvals)
Copy a table (by keys)
Definition: copy_tab.c:513
int db_copy_table_select(const char *from_drvname, const char *from_dbname, const char *from_tblname, const char *to_drvname, const char *to_dbname, const char *to_tblname, const char *select)
Copy a table (by select statement)
Definition: copy_tab.c:488
#define DB_C_TYPE_INT
Definition: dbmi.h:108
#define DB_SEQUENTIAL
Definition: dbmi.h:123
#define DB_FAILED
Definition: dbmi.h:72
#define DB_C_TYPE_STRING
Definition: dbmi.h:107
#define DB_C_TYPE_DOUBLE
Definition: dbmi.h:109
#define DB_OK
Definition: dbmi.h:71
#define DB_C_TYPE_DATETIME
Definition: dbmi.h:110
#define DB_NEXT
Definition: dbmi.h:114
const char * db_sqltype_name(int)
Get SQL data type description.
Definition: sqltype.c:25
int db_test_value_isnull(dbValue *)
Check of value is null.
Definition: value.c:26
dbValue * db_get_column_value(dbColumn *)
Returns column value for given column structure.
dbColumn * db_get_table_column(dbTable *, int)
Returns column structure for given table and column number.
int db_convert_value_to_string(dbValue *, int, dbString *)
Convert value to string.
Definition: valuefmt.c:68
int db_commit_transaction(dbDriver *)
Commit transaction.
Definition: c_execute.c:82
int db_get_column_length(dbColumn *)
Get column's length.
int db_sqltype_to_Ctype(int)
Get C data type based on given SQL data type.
Definition: sqlCtype.c:24
dbDriver * db_start_driver(const char *)
Initialize a new dbDriver for db transaction.
Definition: start.c:51
void db_set_column_length(dbColumn *, int)
Set column's length.
int db_get_column_sqltype(dbColumn *)
Returns column sqltype for column.
void db_set_column_sqltype(dbColumn *, int)
Define column sqltype for column.
void db_set_column_precision(dbColumn *, int)
Set column precision.
int db_open_database(dbDriver *, dbHandle *)
Open database connection.
Definition: c_opendb.c:27
dbTable * db_get_cursor_table(dbCursor *)
Get table allocated by cursor.
Definition: cursor.c:67
int db_close_database_shutdown_driver(dbDriver *)
Close driver/database connection.
Definition: db.c:61
int db_begin_transaction(dbDriver *)
Begin transaction.
Definition: c_execute.c:56
int db_drop_table(dbDriver *, dbString *)
Drop table.
Definition: c_drop_tab.c:28
int db_get_connection(dbConnection *)
Get default DB connection settings for the current mapset.
int db_set_column_description(dbColumn *, const char *)
Set column description.
int db_set_table_name(dbTable *, const char *)
Set the name of the table.
int db_set_string(dbString *, const char *)
Inserts string to dbString (enlarge string)
Definition: string.c:41
int db_set_handle(dbHandle *, const char *, const char *)
Set handle (database and schema name)
Definition: handle.c:39
int db_execute_immediate(dbDriver *, dbString *)
Execute SQL statements.
Definition: c_execute.c:27
dbTable * db_alloc_table(int)
Allocate a table with a specific number of columns.
int db_get_column_scale(dbColumn *)
Get column scale.
int db_list_tables(dbDriver *, dbString **, int *, int)
List available tables for given connection.
Definition: c_list_tabs.c:39
void db_double_quote_string(dbString *)
Replace each ' is replaced by ''.
Definition: string.c:240
void db_init_handle(dbHandle *)
Initialize handle (i.e database/schema)
Definition: handle.c:23
void db_init_string(dbString *)
Initialize dbString.
Definition: string.c:25
int db_close_cursor(dbCursor *)
Close cursor.
Definition: c_close_cur.c:27
int db_open_select_cursor(dbDriver *, dbString *, dbCursor *, int)
Open select cursor.
Definition: c_openselect.c:37
int db_set_column_name(dbColumn *, const char *)
Set column name.
int db_get_column_precision(dbColumn *)
Get column precision.
void db_set_column_scale(dbColumn *, int)
Set column scale.
const char * db_get_column_name(dbColumn *)
Returns column name for given column.
int db_append_string(dbString *, const char *)
Append string to dbString.
Definition: string.c:205
char * db_get_string(const dbString *)
Get string.
Definition: string.c:140
int db_create_table(dbDriver *, dbTable *)
Create table.
Definition: c_create_tab.c:27
int db_fetch(dbCursor *, int, int *)
Fetch data from open cursor.
Definition: c_fetch.c:28
const char * db_get_column_description(dbColumn *)
Returns column description for given column.
int db_get_table_number_of_columns(dbTable *)
Return the number of columns of the table.
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition: defs/gis.h:94
int G_get_overwrite(void)
Get overwrite value.
Definition: parser.c:957
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
Definition: strings.c:47
int G_debug(int, const char *,...) __attribute__((format(printf
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
#define GNAME_MAX
Definition: gis.h:191
#define _(str)
Definition: glocale.h:10
int count
char * schemaName
Definition: dbmi.h:281
int i
Definition: dbmi.h:189