[GRASS-SVN] r73237 - grass/branches/releasebranch_7_6/vector/v.to.db

svn_grass at osgeo.org svn_grass at osgeo.org
Mon Sep 3 13:17:54 PDT 2018


Author: mmetz
Date: 2018-09-03 13:17:54 -0700 (Mon, 03 Sep 2018)
New Revision: 73237

Modified:
   grass/branches/releasebranch_7_6/vector/v.to.db/main.c
   grass/branches/releasebranch_7_6/vector/v.to.db/query.c
Log:
v.to.db: check if column(s) exist before updating, includes check for correct column type, create column(s) of not existing, see #3466 (backport trunk r73236)

Modified: grass/branches/releasebranch_7_6/vector/v.to.db/main.c
===================================================================
--- grass/branches/releasebranch_7_6/vector/v.to.db/main.c	2018-09-03 20:17:12 UTC (rev 73236)
+++ grass/branches/releasebranch_7_6/vector/v.to.db/main.c	2018-09-03 20:17:54 UTC (rev 73237)
@@ -16,6 +16,7 @@
  *****************************************************************************/
 
 #include <stdlib.h>
+#include <grass/dbmi.h>
 #include <grass/glocale.h>
 #include "global.h"
 
@@ -28,7 +29,8 @@
     int n, i, j, cat, lastcat, type, id, findex;
     struct Map_info Map;
     struct GModule *module;
-    struct field_info *Fi;
+    struct field_info *Fi, *qFi;
+    int ncols;
 
     G_gisinit(argv[0]);
 
@@ -73,6 +75,206 @@
 		      options.field);
     }
 
+    qFi = Vect_get_field(&Map, options.qfield);
+    if (options.option == O_QUERY && qFi == NULL)
+        G_fatal_error(_("Database connection not defined for layer %d. Use v.db.connect first."),
+                      options.qfield);
+
+    if (!options.print) {
+	dbDriver *driver = NULL;
+	dbString table_name;
+	dbTable *table;
+	dbColumn *column;
+	const char *colname;
+	int col, fncols, icol;
+	int col_sqltype[4];
+	int create_col[4], create_cols;
+	int qlength;
+
+	/* get required column types */
+	col_sqltype[0] = col_sqltype[1] = col_sqltype[2] = col_sqltype[3] = -1;
+	ncols = 1;
+	qlength = 0;
+
+	switch (options.option) {
+	case O_CAT:
+	case O_COUNT:
+	    col_sqltype[0] = DB_SQL_TYPE_INTEGER;
+	    break;
+
+	case O_LENGTH:
+	case O_AREA:
+	case O_PERIMETER:
+	case O_SLOPE:
+	case O_SINUOUS:
+	case O_AZIMUTH:
+	case O_COMPACT:
+	case O_FD:
+	    col_sqltype[0] = DB_SQL_TYPE_DOUBLE_PRECISION;
+	    break;
+	
+	case O_BBOX:
+	    col_sqltype[0] = col_sqltype[1] = col_sqltype[2] = col_sqltype[3] = DB_SQL_TYPE_DOUBLE_PRECISION;
+	    ncols = 4;
+	    break;
+
+	case O_COOR:
+	case O_START:
+	case O_END:
+	    col_sqltype[0] = col_sqltype[1] = col_sqltype[2] = DB_SQL_TYPE_DOUBLE_PRECISION;
+	    ncols = 2;
+	    if (options.col[2])
+		ncols = 3;
+	    break;
+
+	case O_SIDES:
+	    col_sqltype[0] = col_sqltype[1] = DB_SQL_TYPE_INTEGER;
+	    ncols = 2;
+	    break;
+
+	case O_QUERY:
+	    driver = db_start_driver_open_database(qFi->driver, qFi->database);
+	    db_init_string(&table_name);
+	    db_set_string(&table_name, qFi->table);
+	    if (db_describe_table(driver, &table_name, &table) != DB_OK)
+		G_fatal_error(_("Unable to describe table <%s>"),
+			      qFi->table);
+
+	    fncols = db_get_table_number_of_columns(table);
+	    for (col = 0; col < fncols; col++) {
+		column = db_get_table_column(table, col);
+		colname = db_get_column_name(column);
+		if (strcmp(options.qcol, colname) == 0) {
+		    col_sqltype[0] = db_get_column_sqltype(column);
+		    qlength = db_get_column_length(column);
+		    break;
+		}
+	    }
+	    db_close_database_shutdown_driver(driver);
+	    driver = NULL;
+	    db_free_string(&table_name);
+	    break;
+	}
+
+	/* check if columns exist */
+	create_col[0] = create_col[1] = create_col[2] = create_col[3] = 0;
+	create_cols = 0;
+	driver = db_start_driver_open_database(Fi->driver, Fi->database);
+	db_init_string(&table_name);
+	db_set_string(&table_name, Fi->table);
+	if (db_describe_table(driver, &table_name, &table) != DB_OK)
+	    G_fatal_error(_("Unable to describe table <%s>"),
+			  qFi->table);
+
+	fncols = db_get_table_number_of_columns(table);
+	for (col = 0; col < ncols; col++) {
+	    int col_exists = 0;
+
+	    if (options.col[col] == NULL)
+		G_fatal_error(_("Missing column name for input column number %d"), col + 1);
+
+	    for (icol = 0; icol < fncols; icol++) {
+		column = db_get_table_column(table, icol);
+		colname = db_get_column_name(column);
+		if (colname == NULL)
+		    G_fatal_error(_("Missing column name for table column number %d"), col + 1);
+		if (strcmp(options.col[col], colname) == 0) {
+		    int isqltype;
+
+		    col_exists = 1;
+		    isqltype = db_get_column_sqltype(column);
+
+		    if (isqltype != col_sqltype[col]) {
+			int ctype1, ctype2;
+
+			ctype1 = db_sqltype_to_Ctype(isqltype);
+			ctype2 = db_sqltype_to_Ctype(col_sqltype[col]);
+			
+			if (ctype1 == ctype2) {
+			    G_warning(_("Existing column <%s> has a different but maybe compatible type"),
+					  options.col[col]);
+			}
+			else {
+			    G_fatal_error(_("Existing column <%s> has the wrong type"),
+					  options.col[col]);
+			}
+		    }
+
+		    G_warning(_("Values in column <%s> will be overwritten"),
+			      options.col[col]);
+
+		    break;
+		}
+	    }
+	    if (!col_exists) {
+		create_col[col] = 1;
+		create_cols = 1;
+	    }
+	}
+	db_close_database_shutdown_driver(driver);
+	driver = NULL;
+	db_free_string(&table_name);
+
+	/* create columns if not existing */
+	if (create_cols) {
+	    char sqlbuf[4096];
+	    dbString stmt;
+
+	    db_init_string(&stmt);
+	    driver = db_start_driver_open_database(Fi->driver, Fi->database);
+	    db_begin_transaction(driver);
+	    for (col = 0; col < ncols; col++) {
+		if (!create_col[col])
+		    continue;
+
+		if (col_sqltype[col] == DB_SQL_TYPE_INTEGER) {
+		    sprintf(sqlbuf, "ALTER TABLE %s ADD COLUMN %s integer",
+			    Fi->table, options.col[col]);
+		}
+		else if (col_sqltype[col] == DB_SQL_TYPE_DOUBLE_PRECISION ||
+		         col_sqltype[col] == DB_SQL_TYPE_REAL) {
+		    sprintf(sqlbuf, "ALTER TABLE %s ADD COLUMN %s double precision",
+			    Fi->table, options.col[col]);
+		}
+		else if (col_sqltype[col] == DB_SQL_TYPE_CHARACTER) {
+		    if (qlength > 0) {
+			sprintf(sqlbuf, "ALTER TABLE %s ADD COLUMN %s varchar(%d)",
+				Fi->table, options.col[col], qlength);
+		    }
+		    else {
+			sprintf(sqlbuf, "ALTER TABLE %s ADD COLUMN %s text",
+				Fi->table, options.col[col]);
+		    }
+		}
+		else if (col_sqltype[col] == DB_SQL_TYPE_TEXT) {
+		    sprintf(sqlbuf, "ALTER TABLE %s ADD COLUMN %s text",
+			    Fi->table, options.col[col]);
+		}
+		else if (col_sqltype[col] == DB_SQL_TYPE_DATE) {
+		    sprintf(sqlbuf, "ALTER TABLE %s ADD COLUMN %s date",
+			    Fi->table, options.col[col]);
+		}
+		else if (col_sqltype[col] == DB_SQL_TYPE_TIME) {
+		    sprintf(sqlbuf, "ALTER TABLE %s ADD COLUMN %s time",
+			    Fi->table, options.col[col]);
+		}
+		else {
+		    sprintf(sqlbuf, "ALTER TABLE %s ADD COLUMN %s %s",
+			    Fi->table, options.col[col],
+			    db_sqltype_name(col_sqltype[col]));
+		}
+		db_set_string(&stmt, sqlbuf);
+		if (db_execute_immediate(driver, &stmt) != DB_OK) {
+		    G_fatal_error(_("Unable to create column <%s>"),
+				  options.col[col]);
+		}
+	    }
+	    db_commit_transaction(driver);
+	    db_close_database_shutdown_driver(driver);
+	    db_free_string(&stmt);
+	}
+    }
+
     /* allocate array for values */
     /* (+1 is for cat -1 (no category) reported at the end ) */
     findex = Vect_cidx_get_field_index(&Map, options.field);

Modified: grass/branches/releasebranch_7_6/vector/v.to.db/query.c
===================================================================
--- grass/branches/releasebranch_7_6/vector/v.to.db/query.c	2018-09-03 20:17:12 UTC (rev 73236)
+++ grass/branches/releasebranch_7_6/vector/v.to.db/query.c	2018-09-03 20:17:54 UTC (rev 73237)
@@ -92,7 +92,7 @@
     /* Query the database for each category */
     G_message(_("Querying database... "));
     for (i = 0; i < vstat.rcat; i++) {
-	int j, ctype, nrows, more;
+	int ctype, nrows, more;
 	char buf[2000];
 	dbCursor cursor;
 	dbTable *table;



More information about the grass-commit mailing list