[GRASS-SVN] r51133 - in grass/trunk: include/vect lib/vector/Vlib
svn_grass at osgeo.org
svn_grass at osgeo.org
Wed Mar 21 17:13:05 EDT 2012
Author: martinl
Date: 2012-03-21 14:13:05 -0700 (Wed, 21 Mar 2012)
New Revision: 51133
Modified:
grass/trunk/include/vect/dig_structs.h
grass/trunk/lib/vector/Vlib/build_pg.c
grass/trunk/lib/vector/Vlib/close_pg.c
grass/trunk/lib/vector/Vlib/open.c
grass/trunk/lib/vector/Vlib/open_pg.c
grass/trunk/lib/vector/Vlib/read_pg.c
grass/trunk/lib/vector/Vlib/write_ogr.c
grass/trunk/lib/vector/Vlib/write_pg.c
Log:
vlib(pg): implement writing attributes
various minor improvements
Modified: grass/trunk/include/vect/dig_structs.h
===================================================================
--- grass/trunk/include/vect/dig_structs.h 2012-03-21 21:12:19 UTC (rev 51132)
+++ grass/trunk/include/vect/dig_structs.h 2012-03-21 21:13:05 UTC (rev 51133)
@@ -489,6 +489,10 @@
\brief Feature id
*/
long fid;
+ /*!
+ \brief Simple feature type (currently used only by PG format)
+ */
+ SF_FeatureType sf_type;
};
/*!
@@ -617,6 +621,19 @@
\brief SRS ID
*/
int srid;
+
+ /*!
+ \brief Open DB driver when writing attributes
+
+ This driver is open by V2_open_new_pg() and closed by
+ V1_close_pg().
+ */
+ dbDriver *dbdriver;
+
+ /*!
+ \brief Start/Finish transaction
+ */
+ int inTransaction;
#ifdef HAVE_POSTGRES
/*!
\brief PGconn object (generated by PQconnectdb)
Modified: grass/trunk/lib/vector/Vlib/build_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/build_pg.c 2012-03-21 21:12:19 UTC (rev 51132)
+++ grass/trunk/lib/vector/Vlib/build_pg.c 2012-03-21 21:13:05 UTC (rev 51133)
@@ -23,7 +23,7 @@
#include <grass/glocale.h>
#ifdef HAVE_POSTGRES
-#include <libpq-fe.h>
+#include "pg_local_proto.h"
static int build_topo(struct Map_info *, int);
#endif
@@ -78,7 +78,14 @@
"Unable to build topology."));
return 0;
}
+
+ /* commit transaction block (update mode only) */
+ if (pg_info->inTransaction &&
+ execute(pg_info->conn, "COMMIT") == -1)
+ return -1;
+ pg_info->inTransaction = FALSE;
+
if (build > GV_BUILD_NONE)
G_message(_("Using external data format '%s' (feature type '%s')"),
Vect_get_finfo_format_info(Map),
Modified: grass/trunk/lib/vector/Vlib/close_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/close_pg.c 2012-03-21 21:12:19 UTC (rev 51132)
+++ grass/trunk/lib/vector/Vlib/close_pg.c 2012-03-21 21:13:05 UTC (rev 51133)
@@ -63,6 +63,11 @@
PQfinish(pg_info->conn);
+ /* close DB connection (for atgtributes) */
+ if (pg_info->dbdriver) {
+ db_close_database_shutdown_driver(pg_info->dbdriver);
+ }
+
/* free allocated space */
for (i = 0; i < pg_info->cache.lines_alloc; i++) {
Vect_destroy_line_struct(pg_info->cache.lines[i]);
Modified: grass/trunk/lib/vector/Vlib/open.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open.c 2012-03-21 21:12:19 UTC (rev 51132)
+++ grass/trunk/lib/vector/Vlib/open.c 2012-03-21 21:13:05 UTC (rev 51133)
@@ -839,8 +839,8 @@
Map->open = VECT_OPEN_CODE;
Map->level = 1;
- Map->head_only = 0;
- Map->support_updated = 0;
+ Map->head_only = FALSE;
+ Map->support_updated = FALSE;
Map->plus.built = GV_BUILD_NONE;
Map->mode = GV_MODE_RW;
Map->plus.uplist.do_uplist = FALSE;
Modified: grass/trunk/lib/vector/Vlib/open_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open_pg.c 2012-03-21 21:12:19 UTC (rev 51132)
+++ grass/trunk/lib/vector/Vlib/open_pg.c 2012-03-21 21:13:05 UTC (rev 51133)
@@ -111,18 +111,17 @@
/* feature type */
pg_info->feature_type = ftype_from_string(PQgetvalue(res, 0, 3));
}
+ PQclear(res);
/* no feature in cache */
pg_info->cache.fid = -1;
-
- PQclear(res);
-
+
if (!found) {
G_warning(_("Feature table <%s> not found in 'geometry_columns'"),
pg_info->table_name);
return -1;
}
-
+
return 0;
#else
G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
@@ -467,25 +466,107 @@
key_val = G_fread_key_value(fp);
fclose(fp);
- /* spatial index */
+ /* disable spatial index ? */
p = G_find_key_value("spatial_index", key_val);
if (p && G_strcasecmp(p, "off") == 0)
spatial_index = FALSE;
- /* primary key */
+ /* disable primary key ? */
p = G_find_key_value("primary_key", key_val);
if (p && G_strcasecmp(p, "off") == 0)
primary_key = FALSE;
}
- /* begin transaction */
+ /* prepare CREATE TABLE statement */
+ sprintf(stmt, "CREATE TABLE \"%s\".\"%s\" (%s SERIAL",
+ pg_info->schema_name, pg_info->table_name,
+ pg_info->fid_column);
+
+ if (Fi) {
+ /* append attributes */
+ int col, ncols, sqltype, length, ctype;
+ char stmt_col[DB_SQL_MAX];
+ const char *colname;
+
+ dbString dbstmt;
+ dbHandle handle;
+ dbDriver *driver;
+ dbCursor cursor;
+ dbTable *table;
+ dbColumn *column;
+
+ db_init_string(&dbstmt);
+ db_init_handle(&handle);
+
+ pg_info->dbdriver = driver = db_start_driver(Fi->driver);
+ if (!driver) {
+ G_warning(_("Unable to start driver <%s>"), Fi->driver);
+ return -1;
+ }
+ db_set_handle(&handle, Fi->database, NULL);
+ if (db_open_database(driver, &handle) != DB_OK) {
+ G_warning(_("Unable to open database <%s> by driver <%s>"),
+ Fi->database, Fi->driver);
+ db_close_database_shutdown_driver(driver);
+ pg_info->dbdriver = NULL;
+ return -1;
+ }
+
+ /* describe table */
+ db_set_string(&dbstmt, "select * from ");
+ db_append_string(&dbstmt, Fi->table);
+ db_append_string(&dbstmt, " where 0 = 1");
+
+ if (db_open_select_cursor(driver, &dbstmt,
+ &cursor, DB_SEQUENTIAL) != DB_OK) {
+ G_warning(_("Unable to open select cursor: '%s'"),
+ db_get_string(&dbstmt));
+ db_close_database_shutdown_driver(driver);
+ pg_info->dbdriver = NULL;
+ return -1;
+ }
+
+ table = db_get_cursor_table(&cursor);
+ ncols = db_get_table_number_of_columns(table);
+
+ G_debug(3, "copying attributes: driver = %s database = %s table = %s cols = %d",
+ Fi->driver, Fi->database, Fi->table, ncols);
+
+ for (col = 0; col < ncols; col++) {
+ column = db_get_table_column(table, col);
+ colname = db_get_column_name(column);
+ sqltype = db_get_column_sqltype(column);
+ ctype = db_sqltype_to_Ctype(sqltype);
+ length = db_get_column_length(column);
+
+ G_debug(3, "\tcolumn = %d name = %s type = %d length = %d",
+ col, colname, sqltype, length);
+
+ if (strcmp(pg_info->fid_column, colname) == 0) {
+ /* skip fid column if exists */
+ G_debug(3, "\t%s skipped", pg_info->fid_column);
+ continue;
+ }
+
+ /* append column */
+ sprintf(stmt_col, ",%s %s", colname, db_sqltype_name(sqltype));
+ strcat(stmt, stmt_col);
+ if (ctype == DB_C_TYPE_STRING) {
+ /* length only for string columns */
+ sprintf(stmt_col, "(%d)", length);
+ strcat(stmt, stmt_col);
+ }
+ }
+
+ db_free_string(&dbstmt);
+ }
+ strcat(stmt, ")"); /* close CREATE TABLE statement */
+
+ /* begin transaction (create table) */
if (execute(pg_info->conn, "BEGIN") == -1) {
return -1;
}
/* create table */
- sprintf(stmt, "CREATE TABLE \"%s\".\"%s\" (%s SERIAL)",
- pg_info->schema_name, pg_info->table_name,
- pg_info->fid_column);
G_debug(2, "SQL: %s", stmt);
if (execute(pg_info->conn, stmt) == -1) {
execute(pg_info->conn, "ROLLBACK");
@@ -549,7 +630,7 @@
}
}
- /* close transaction */
+ /* close transaction (create table) */
if (execute(pg_info->conn, "COMMIT") == -1) {
return -1;
}
Modified: grass/trunk/lib/vector/Vlib/read_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_pg.c 2012-03-21 21:12:19 UTC (rev 51132)
+++ grass/trunk/lib/vector/Vlib/read_pg.c 2012-03-21 21:13:05 UTC (rev 51133)
@@ -219,8 +219,7 @@
#ifdef HAVE_POSTGRES
long fid;
int ipart, type;
- static SF_FeatureType sf_type;
-
+
struct Format_info_pg *pg_info;
pg_info = &(Map->fInfo.pg);
@@ -241,25 +240,30 @@
/* read feature to cache if necessary */
if (pg_info->cache.fid != fid) {
- G_debug(4, "read feature (fid = %ld) to cache", fid);
- sf_type = get_feature(pg_info, fid);
+ int type;
- if (sf_type == SF_NONE) {
+ G_debug(3, "read (%s) feature (fid = %ld) to cache",
+ pg_info->table_name, fid);
+ get_feature(pg_info, fid);
+
+ if (pg_info->cache.sf_type == SF_NONE) {
G_warning(_("Feature %d without geometry skipped"), fid);
return -1;
}
-
- if ((int) sf_type < 0) /* -1 || - 2 */
- return (int) sf_type;
+
+ type = (int) pg_info->cache.sf_type;
+ if (type < 0) /* -1 || - 2 */
+ return type;
}
/* get data from cache */
- if (sf_type == SF_POINT || sf_type == SF_LINESTRING)
+ if (pg_info->cache.sf_type == SF_POINT ||
+ pg_info->cache.sf_type == SF_LINESTRING)
ipart = 0;
else
ipart = pg_info->offset.array[offset + 1];
type = pg_info->cache.lines_types[ipart];
- G_debug(4, "read feature part: %d -> type = %d",
+ G_debug(3, "read feature part: %d -> type = %d",
ipart, type);
if (line_p)
@@ -394,7 +398,6 @@
{
char *data;
char stmt[DB_SQL_MAX];
- SF_FeatureType ftype;
if (!pg_info->geom_column) {
G_warning(_("No geometry column defined"));
@@ -468,7 +471,7 @@
}
data = (char *)PQgetvalue(pg_info->res, pg_info->next_line, 0);
- ftype = cache_feature(data, FALSE, &(pg_info->cache), NULL);
+ pg_info->cache.sf_type = cache_feature(data, FALSE, &(pg_info->cache), NULL);
if (fid < 0) {
pg_info->cache.fid = atoi(PQgetvalue(pg_info->res, pg_info->next_line, 1));
pg_info->next_line++;
@@ -490,7 +493,7 @@
return -1;
}
- return ftype;
+ return pg_info->cache.sf_type;
}
/*!
@@ -567,7 +570,7 @@
unsigned char *wkb_data;
unsigned int wkb_flags;
SF_FeatureType ftype;
-
+
/* reset cache */
cache->lines_num = 0;
cache->fid = -1;
Modified: grass/trunk/lib/vector/Vlib/write_ogr.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write_ogr.c 2012-03-21 21:12:19 UTC (rev 51132)
+++ grass/trunk/lib/vector/Vlib/write_ogr.c 2012-03-21 21:13:05 UTC (rev 51133)
@@ -383,6 +383,9 @@
OGR_F_SetFieldString(Ogr_feature, ogrfieldnum,
db_get_string(&dbstring));
break;
+ default:
+ G_warning(_("Unsupported column type %d"), ctype);
+ break;
}
}
}
Modified: grass/trunk/lib/vector/Vlib/write_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write_pg.c 2012-03-21 21:12:19 UTC (rev 51132)
+++ grass/trunk/lib/vector/Vlib/write_pg.c 2012-03-21 21:13:05 UTC (rev 51133)
@@ -38,8 +38,11 @@
int, int*);
static unsigned char *polygon_to_wkb(int, const struct line_pnts *,
int, int*);
-static int write_feature(const struct Format_info_pg *,
- int, const struct line_pnts *, int, int);
+static int write_feature(struct Format_info_pg *,
+ int, const struct line_pnts *, int,
+ int, const struct field_info *);
+static char *build_insert_stmt(const struct Format_info_pg *, const char *,
+ int, const struct field_info *);
#endif
/*!
@@ -92,7 +95,8 @@
return -1;
}
- cat = -1; /* no attributes to be written */
+ Fi = NULL; /* no attributes to be written */
+ cat = -1;
if (cats->n_cats > 0 && Vect_get_num_dblinks(Map) > 0) {
/* check for attributes */
Fi = Vect_get_dblink(Map, 0);
@@ -156,20 +160,14 @@
}
}
- if (execute(pg_info->conn, "BEGIN") == -1)
- return -1;
-
/* write feature's geometry and fid */
if (-1 == write_feature(pg_info, type, points,
- Vect_is_3d(Map) ? WITH_Z : WITHOUT_Z, cat))
+ Vect_is_3d(Map) ? WITH_Z : WITHOUT_Z,
+ cat, Fi)) {
+ execute(pg_info->conn, "ROLLBACK");
return -1;
+ }
- /* write attributes */
- /* ? */
-
- if (execute(pg_info->conn, "COMMIT") == -1)
- return -1;
-
/* update offset array */
if (offset_info->array_num >= offset_info->array_alloc) {
offset_info->array_alloc += 1000;
@@ -263,21 +261,23 @@
G_debug(3, "V1_delete_line_pg(), offset = %lu -> fid = %ld",
(unsigned long) offset, fid);
- if (execute(pg_info->conn, "BEGIN") == -1)
- return -1;
-
+ if (!pg_info->inTransaction) {
+ /* start transaction */
+ pg_info->inTransaction = TRUE;
+ if (execute(pg_info->conn, "BEGIN") == -1)
+ return -1;
+ }
+
sprintf(stmt, "DELETE FROM %s WHERE %s = %ld",
pg_info->table_name, pg_info->fid_column, fid);
G_debug(2, "SQL: %s", stmt);
if (execute(pg_info->conn, stmt) == -1) {
G_warning(_("Unable to delete feature"));
+ execute(pg_info->conn, "ROLLBACK");
return -1;
}
- if (execute(pg_info->conn, "COMMIT") == -1)
- return -1;
-
return 0;
#else
G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
@@ -544,6 +544,7 @@
return wkb_data;
}
+
/*!
\brief Insert feature into table
@@ -551,14 +552,15 @@
\param type feature type (GV_POINT, GV_LINE, ...)
\param points pointer to line_pnts struct
\param with_z WITH_Z for 3D data
- \param fid feature id
+ \param cat category number (-1 for no category)
+ \param Fi pointer to field_info (attributes to copy, NULL for no attributes)
\return -1 on error
\retirn 0 on success
*/
-int write_feature(const struct Format_info_pg *pg_info,
+int write_feature(struct Format_info_pg *pg_info,
int type, const struct line_pnts *points, int with_z,
- int fid)
+ int cat, const struct field_info *Fi)
{
int byte_order, nbytes, nsize;
unsigned int sf_type;
@@ -641,16 +643,19 @@
G_free(hex_data);
/* build INSERT statement */
- stmt = NULL;
- G_asprintf(&stmt, "INSERT INTO \"%s\".\"%s\" (%s) VALUES "
- "('%s'::GEOMETRY)",
- pg_info->schema_name, pg_info->table_name,
- pg_info->geom_column, text_data);
+ stmt = build_insert_stmt(pg_info, text_data, cat, Fi);
G_debug(2, "SQL: %s", stmt);
+ if (!pg_info->inTransaction) {
+ /* start transaction */
+ pg_info->inTransaction = TRUE;
+ if (execute(pg_info->conn, "BEGIN") == -1)
+ return -1;
+ }
+
if (execute(pg_info->conn, stmt) == -1) {
- /* close transaction */
- execute(pg_info->conn, "COMMIT");
+ /* rollback transaction */
+ execute(pg_info->conn, "ROLLBACK");
return -1;
}
@@ -660,4 +665,139 @@
return 0;
}
+
+/*!
+ \brief Build INSERT statement to insert new feature to the table
+
+ \param pg_info pointer to Format_info_pg structure
+ \param cat category number (or -1 for no category)
+ \param Fi pointer to field_info structure (NULL for no attributes)
+
+ \return allocated string with INSERT statement
+*/
+char *build_insert_stmt(const struct Format_info_pg *pg_info,
+ const char *geom_data,
+ int cat, const struct field_info *Fi)
+{
+ char *stmt, buf[DB_SQL_MAX];
+
+ stmt = NULL;
+ if (Fi && cat > -1) {
+ int col, ncol, more;
+ int sqltype, ctype;
+ char buf_val[DB_SQL_MAX], buf_tmp[DB_SQL_MAX];
+ char *str_val;
+
+ const char *colname;
+
+ dbString dbstmt;
+ dbCursor cursor;
+ dbTable *table;
+ dbColumn *column;
+ dbValue *value;
+
+ db_init_string(&dbstmt);
+ buf_val[0] = '\0';
+
+ /* read & set attributes */
+ sprintf(buf, "SELECT * FROM %s WHERE %s = %d", Fi->table, Fi->key,
+ cat);
+ G_debug(4, "SQL: %s", buf);
+ db_set_string(&dbstmt, buf);
+
+ /* prepare INSERT statement */
+ sprintf(buf, "INSERT INTO \"%s\".\"%s\" (%s",
+ pg_info->schema_name, pg_info->table_name,
+ pg_info->geom_column);
+
+ /* select data */
+ if (db_open_select_cursor(pg_info->dbdriver, &dbstmt,
+ &cursor, DB_SEQUENTIAL) != DB_OK) {
+ G_warning(_("Unable to select attributes for category %d"),
+ cat);
+ }
+ else {
+ if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) {
+ G_warning(_("Unable to fetch data from table <%s>"),
+ Fi->table);
+ }
+
+ if (!more) {
+ G_warning(_("No database record for category %d, "
+ "no attributes will be written"), cat);
+ }
+ else {
+ table = db_get_cursor_table(&cursor);
+ ncol = db_get_table_number_of_columns(table);
+
+ for (col = 0; col < ncol; col++) {
+ column = db_get_table_column(table, col);
+ colname = db_get_column_name(column);
+
+ /* skip fid column */
+ if (strcmp(pg_info->fid_column, colname) == 0)
+ continue;
+
+ /* -> columns */
+ sprintf(buf_tmp, ",%s", colname);
+ strcat(buf, buf_tmp);
+
+ /* -> values */
+ value = db_get_column_value(column);
+ /* for debug only */
+ db_convert_column_value_to_string(column, &dbstmt);
+ G_debug(2, "col %d : val = %s", col,
+ db_get_string(&dbstmt));
+
+ sqltype = db_get_column_sqltype(column);
+ ctype = db_sqltype_to_Ctype(sqltype);
+
+ /* prevent writing NULL values */
+ if (!db_test_value_isnull(value)) {
+ switch (ctype) {
+ case DB_C_TYPE_INT:
+ sprintf(buf_tmp, ",%d", db_get_value_int(value));
+ break;
+ case DB_C_TYPE_DOUBLE:
+ sprintf(buf_tmp, ",%.14f", db_get_value_double(value));
+ break;
+ case DB_C_TYPE_STRING:
+ str_val = G_store(db_get_value_string(value));
+ G_str_to_sql(str_val);
+ sprintf(buf_tmp, ",'%s'", str_val);
+ G_free(str_val);
+ break;
+ case DB_C_TYPE_DATETIME:
+ db_convert_column_value_to_string(column,
+ &dbstmt);
+ sprintf(buf_tmp, ",%s", db_get_string(&dbstmt));
+ break;
+ default:
+ G_warning(_("Unsupported column type %d"), ctype);
+ sprintf(buf_tmp, ",NULL");
+ break;
+ }
+ }
+ else {
+ sprintf(buf_tmp, ",NULL");
+ }
+ strcat(buf_val, buf_tmp);
+ }
+
+ G_asprintf(&stmt, "%s) VALUES ('%s'::GEOMETRY%s)",
+ buf, geom_data, buf_val);
+ }
+ }
+ }
+
+ if (!stmt) {
+ /* no attributes */
+ G_asprintf(&stmt, "INSERT INTO \"%s\".\"%s\" (%s) VALUES "
+ "('%s'::GEOMETRY)",
+ pg_info->schema_name, pg_info->table_name,
+ pg_info->geom_column, geom_data);
+ }
+
+ return stmt;
+}
#endif
More information about the grass-commit
mailing list