[GRASS-SVN] r51126 - in grass/trunk: include/defs lib/vector/Vlib

svn_grass at osgeo.org svn_grass at osgeo.org
Wed Mar 21 07:08:56 EDT 2012


Author: martinl
Date: 2012-03-21 04:08:56 -0700 (Wed, 21 Mar 2012)
New Revision: 51126

Modified:
   grass/trunk/include/defs/vector.h
   grass/trunk/lib/vector/Vlib/build_pg.c
   grass/trunk/lib/vector/Vlib/close_ogr.c
   grass/trunk/lib/vector/Vlib/open.c
   grass/trunk/lib/vector/Vlib/open_ogr.c
   grass/trunk/lib/vector/Vlib/open_pg.c
   grass/trunk/lib/vector/Vlib/write.c
   grass/trunk/lib/vector/Vlib/write_pg.c
Log:
vlib(pg): implement V2_open_new_pg()
	  various improvements when writing creating new PostGIS layer
	  cosmetics in OGR interface (use OGR_L_GetName)


Modified: grass/trunk/include/defs/vector.h
===================================================================
--- grass/trunk/include/defs/vector.h	2012-03-21 11:05:18 UTC (rev 51125)
+++ grass/trunk/include/defs/vector.h	2012-03-21 11:08:56 UTC (rev 51126)
@@ -477,6 +477,7 @@
 int V1_open_new_ogr(struct Map_info *, const char *, int);
 int V1_open_new_pg(struct Map_info *, const char *, int);
 int V2_open_new_ogr(struct Map_info *, int);
+int V2_open_new_pg(struct Map_info *, int);
 int V1_rewind_nat(struct Map_info *);
 int V1_rewind_ogr(struct Map_info *);
 int V1_rewind_pg(struct Map_info *);

Modified: grass/trunk/lib/vector/Vlib/build_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/build_pg.c	2012-03-21 11:05:18 UTC (rev 51125)
+++ grass/trunk/lib/vector/Vlib/build_pg.c	2012-03-21 11:08:56 UTC (rev 51126)
@@ -74,7 +74,7 @@
     if (!pg_info->fid_column) {
 	G_warning(_("Feature table <%s> has no primary key defined"),
 		  pg_info->table_name);
-	G_warning(_("Random read is not supported by OGR for this layer. "
+	G_warning(_("Random read is not supported for this layer. "
 		    "Unable to build topology."));
 	return 0;
     }

Modified: grass/trunk/lib/vector/Vlib/close_ogr.c
===================================================================
--- grass/trunk/lib/vector/Vlib/close_ogr.c	2012-03-21 11:05:18 UTC (rev 51125)
+++ grass/trunk/lib/vector/Vlib/close_ogr.c	2012-03-21 11:08:56 UTC (rev 51126)
@@ -68,6 +68,8 @@
     G_free(ogr_info->driver_name);
     G_free(ogr_info->dsn);
     G_free(ogr_info->layer_name);
+    if (ogr_info->layer_options)
+	G_free_tokens(ogr_info->layer_options);
 
     return 0;
 #else

Modified: grass/trunk/lib/vector/Vlib/open.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open.c	2012-03-21 11:05:18 UTC (rev 51125)
+++ grass/trunk/lib/vector/Vlib/open.c	2012-03-21 11:08:56 UTC (rev 51126)
@@ -693,29 +693,97 @@
     }
 
     /* determine output format native or ogr */
-    if (strcmp(G_program_name(), "v.external") != 0 &&
-	G_find_file2("", "OGR", G_mapset())) {
-	/* OGR */
-	FILE *fp;
-	struct Key_Value *key_val;
-	const char *p;
-
-	G_debug(2, " using OGR format");
-	Map->format = GV_FORMAT_OGR_DIRECT;
-	fp = G_fopen_old("", "OGR", G_mapset());
-	if (!fp) {
-	    G_warning(_("Unable to open OGR file"));
+    if (strcmp(G_program_name(), "v.external") != 0) {
+	if (G_find_file2("", "OGR", G_mapset())) {
+	    /* OGR */
+	    FILE *fp;
+	    const char *p;
+	    
+	    struct Key_Value *key_val;
+	    struct Format_info_ogr *ogr_info;
+	    
+	    G_debug(2, " using OGR format");
+	    Map->format = GV_FORMAT_OGR_DIRECT;
+	    fp = G_fopen_old("", "OGR", G_mapset());
+	    if (!fp) {
+		G_fatal_error(_("Unable to open OGR file"));
+	    }
+	    key_val = G_fread_key_value(fp);
+	    fclose(fp);
+	    
+	    ogr_info = &(Map->fInfo.ogr);
+	    /* format */
+	    p = G_find_key_value("format", key_val);
+	    if (p)
+		ogr_info->driver_name = G_store(p);
+	    /* dsn */
+	    p = G_find_key_value("dsn", key_val);
+	    if (p)
+		ogr_info->dsn = G_store(p);
+	    /* options */
+	    p = G_find_key_value("options", key_val);
+	    if (p)
+		ogr_info->layer_options = G_tokenize(p, ",");
+	    
+	    ogr_info->layer_name = G_store(name);
 	}
-	key_val = G_fread_key_value(fp);
-	fclose(fp);
-
-	p = G_find_key_value("format", key_val);
-	if (p)
-	    Map->fInfo.ogr.driver_name = G_store(p);
-       	p = G_find_key_value("dsn", key_val);
-	if (p)
-	    Map->fInfo.ogr.dsn = G_store(p);
-	Map->fInfo.ogr.layer_name = G_store(name);
+	if (G_find_file2("", "PG", G_mapset())) {
+	    /* PostGIS */
+	    if (Map->fInfo.ogr.driver_name) {
+		G_warning(_("OGR output also detected, using OGR"));
+	    }
+	    else {
+		FILE *fp;
+		const char *p;
+		
+		struct Key_Value *key_val;
+		struct Format_info_pg *pg_info;
+		
+		G_debug(2, " using PostGIS format");
+		Map->format = GV_FORMAT_POSTGIS;
+		fp = G_fopen_old("", "PG", G_mapset());
+		if (!fp) {
+		    G_fatal_error(_("Unable to open PG file"));
+		}
+		key_val = G_fread_key_value(fp);
+		fclose(fp);
+		
+		pg_info = &(Map->fInfo.pg);
+		/* conninfo */
+		p = G_find_key_value("conninfo", key_val);
+		if (p) {
+		    pg_info->conninfo = G_store(p);
+		    G_debug(1, "PG: conninfo = '%s'", pg_info->conninfo);
+		}
+		
+		/* schema (default: public) */
+		p = G_find_key_value("schema", key_val);
+		if (p)
+		    pg_info->schema_name = G_store(p);
+		else
+		    pg_info->schema_name = G_store("public");
+		G_debug(1, "PG: schema_name = '%s'", pg_info->schema_name);
+		
+		/* fid column (default: ogc_fid) */
+		p = G_find_key_value("fid", key_val);
+		if (p)
+		    pg_info->fid_column = G_store(p);
+		else
+		    pg_info->fid_column = G_store("ogc_fid");
+		G_debug(1, "PG: fid_column = '%s'", pg_info->fid_column);
+		
+		/* geometry column (default: wkb_geometry) */
+		p = G_find_key_value("geometry_name", key_val);
+		if (p)
+		    pg_info->geom_column = G_store(p);
+		else
+		    pg_info->geom_column = G_store("wkb_geometry");
+		G_debug(1, "PG: geom_column = '%s'", pg_info->geom_column);
+		
+                /* table name */
+		Map->fInfo.pg.table_name = G_store(name);
+	    }
+	}
     }
     else {
 	/* native */

Modified: grass/trunk/lib/vector/Vlib/open_ogr.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open_ogr.c	2012-03-21 11:05:18 UTC (rev 51125)
+++ grass/trunk/lib/vector/Vlib/open_ogr.c	2012-03-21 11:08:56 UTC (rev 51126)
@@ -54,7 +54,6 @@
     
     OGRDataSourceH Ogr_ds;
     OGRLayerH Ogr_layer;
-    OGRFeatureDefnH Ogr_featuredefn;
     OGRwkbGeometryType Ogr_geom_type;
     
     Ogr_layer = NULL;
@@ -90,9 +89,8 @@
 
     for (i = 0; i < nLayers; i++) {
 	Ogr_layer = OGR_DS_GetLayer(Ogr_ds, i);
-	Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer);
-	if (strcmp(OGR_FD_GetName(Ogr_featuredefn), ogr_info->layer_name) == 0) {
-	    Ogr_geom_type = OGR_FD_GetGeomType(Ogr_featuredefn);
+	if (strcmp(OGR_L_GetName(Ogr_layer), ogr_info->layer_name) == 0) {
+	    Ogr_geom_type = OGR_L_GetGeomType(Ogr_layer);
 	    layer = i;
 	    break;
 	}
@@ -180,7 +178,6 @@
     OGRSFDriverH    Ogr_driver;
     OGRDataSourceH  Ogr_ds;
     OGRLayerH       Ogr_layer;
-    OGRFeatureDefnH Ogr_featuredefn;
     
     OGRRegisterAll();
     
@@ -206,8 +203,7 @@
     nlayers = OGR_DS_GetLayerCount(Ogr_ds);
     for (i = 0; i < nlayers; i++) {
       	Ogr_layer = OGR_DS_GetLayer(Ogr_ds, i);
-	Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer);
-	if (strcmp(OGR_FD_GetName(Ogr_featuredefn), name) == 0) {	
+	if (strcmp(OGR_L_GetName(Ogr_layer), name) == 0) {	
 	    if (G_get_overwrite()) {
 		G_warning(_("OGR layer <%s> already exists and will be overwritten"),
 			  ogr_info->layer_name);
@@ -277,6 +273,7 @@
     G_free_key_value(projinfo);
     G_free_key_value(projunits);
     
+    /* determine geometry type */
     switch(type) {
     case GV_POINT:
 	Ogr_geom_type = wkbPoint;
@@ -292,6 +289,7 @@
 	return -1;
     }
     
+    /* check creation options */
     Ogr_layer_options = ogr_info->layer_options;
     if (Vect_is_3d(Map)) {
 	if (strcmp(ogr_info->driver_name, "PostgreSQL") == 0) {
@@ -303,6 +301,8 @@
 	    Ogr_layer_options = CSLSetNameValue(Ogr_layer_options, "DIM", "2");
 	}
     }
+
+    /* create new OGR layer */
     Ogr_layer = OGR_DS_CreateLayer(ogr_info->ds, ogr_info->layer_name,
 				   Ogr_spatial_ref, Ogr_geom_type, Ogr_layer_options);
     CSLDestroy(Ogr_layer_options);
@@ -325,8 +325,8 @@
 	    G_free(Fi);
 	}
 	else
-	G_warning(_("Database connection not defined. "
-		    "Unable to write attributes."));
+	  G_warning(_("Database connection not defined. "
+		      "Unable to write attributes."));
     }
     
     if (OGR_L_TestCapability(ogr_info->layer, OLCTransactions))

Modified: grass/trunk/lib/vector/Vlib/open_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open_pg.c	2012-03-21 11:05:18 UTC (rev 51125)
+++ grass/trunk/lib/vector/Vlib/open_pg.c	2012-03-21 11:08:56 UTC (rev 51126)
@@ -23,68 +23,10 @@
 #ifdef HAVE_POSTGRES
 #include "pg_local_proto.h"
 
-static char *get_key_column(struct Format_info_pg *pg_info)
-{
-    char *key_column;
-    char stmt[DB_SQL_MAX];
-    
-    PGresult *res;
-    
-    sprintf(stmt,
-	    "SELECT kcu.column_name "
-	    "FROM    INFORMATION_SCHEMA.TABLES t "
-	    "LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc "
-	    "ON tc.table_catalog = t.table_catalog "
-	    "AND tc.table_schema = t.table_schema "
-	    "AND tc.table_name = t.table_name "
-	    "AND tc.constraint_type = 'PRIMARY KEY' "
-	    "LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu "
-	    "ON kcu.table_catalog = tc.table_catalog "
-	    "AND kcu.table_schema = tc.table_schema "
-	    "AND kcu.table_name = tc.table_name "
-	    "AND kcu.constraint_name = tc.constraint_name "
-	    "WHERE t.table_name = '%s'", pg_info->table_name);
-
-    res = PQexec(pg_info->conn, stmt);
-    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
-	PQntuples(res) != 1) {
-	G_warning(_("No key column detected."));
-	if (res)
-	    PQclear(res);
-	return NULL;
-    }
-    key_column = G_store(PQgetvalue(res, 0, 0));
-    
-    PQclear(res);
-
-    return key_column;
-}
-
-static SF_FeatureType ftype_from_string(const char *type)
-{
-    SF_FeatureType sf_type;
-
-    if (G_strcasecmp(type, "POINT") == 0)
-	return SF_POINT;
-    else if (G_strcasecmp(type, "LINESTRING") == 0)
-	return SF_LINESTRING;
-    else if (G_strcasecmp(type, "POLYGON") == 0)
-	return SF_POLYGON;
-    else if (G_strcasecmp(type, "MULTIPOINT") == 0)
-	return SF_MULTIPOINT;
-    else if (G_strcasecmp(type, "MULTILINESTRING") == 0)
-	return SF_MULTILINESTRING;
-    else if (G_strcasecmp(type, "MULTIPOLYGON") == 0)
-	return SF_MULTIPOLYGON;
-    else if (G_strcasecmp(type, "GEOMETRYCOLLECTION") == 0)
-	return SF_GEOMETRYCOLLECTION;
-    
-    return SF_UNKNOWN;
-    
-    G_debug(3, "ftype_from_string(): type='%s' -> %d", type, sf_type);
-    
-    return sf_type;
-}
+static char *get_key_column(struct Format_info_pg *);
+static SF_FeatureType ftype_from_string(const char *);
+static int drop_table(struct Format_info_pg *);
+static int create_table(struct Format_info_pg *, const struct field_info *);
 #endif
 
 /*!
@@ -101,16 +43,14 @@
 int V1_open_old_pg(struct Map_info *Map, int update)
 {
 #ifdef HAVE_POSTGRES
-    int found, ntables, i;
+    int found;
     
-    dbString stmt;
+    char stmt[DB_SQL_MAX];
     
     PGresult *res;
     
     struct Format_info_pg *pg_info;
     
-    db_init_string(&stmt);
-    
     pg_info = &(Map->fInfo.pg);
     if (!pg_info->conninfo) {
 	G_warning(_("Connection string not defined"));
@@ -139,54 +79,44 @@
 	return -1;
     }
     
+    /* if schema not defined, use 'public' */
+    if (!pg_info->schema_name) {
+	pg_info->schema_name = G_store("public");
+    }
+	
     /* get fid and geometry column */
-    db_set_string(&stmt, "SELECT f_table_schema, f_table_name, f_geometry_column,"
-		  "coord_dimension, srid, type "
-		  "FROM geometry_columns");
-    G_debug(2, "SQL: %s", db_get_string(&stmt));
+    sprintf(stmt, "SELECT f_geometry_column, coord_dimension, srid, type "
+	    "FROM geometry_columns WHERE f_table_schema = '%s' AND "
+	    "f_table_name = '%s'",
+	    pg_info->schema_name, pg_info->table_name);
+    G_debug(2, "SQL: %s", stmt);
     
-    res = PQexec(pg_info->conn, db_get_string(&stmt));
+    res = PQexec(pg_info->conn, stmt);
     if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
 	G_fatal_error("%s\n%s", _("No feature tables found in database."),
 		      PQresultErrorMessage(res));
-		      
-    ntables = PQntuples(res);
-    G_debug(3, "\tnrows = %d", ntables);
-    found = FALSE;
-    for (i = 0; i < ntables; i++) {
-	if ((pg_info->schema_name &&   /* schema defined */
-	     strcmp(PQgetvalue(res, i, 0), pg_info->schema_name) == 0 &&
-	     strcmp(PQgetvalue(res, i, 1), pg_info->table_name) == 0) ||
-	    (!pg_info->schema_name && /* schema not defined, get first match */
-	     strcmp(PQgetvalue(res, i, 1), pg_info->table_name) == 0)) {
-	    /* schema name */
-	    if (!pg_info->schema_name) {
-		pg_info->schema_name = G_store(PQgetvalue(res, i, 0));
-	    }
-	    /* geometry column */
-	    pg_info->geom_column = G_store(PQgetvalue(res, i, 2));
-	    G_debug(3, "\t-> table = %s column = %s", pg_info->table_name,
-		    pg_info->geom_column);
-	    /* fid column */
-	    pg_info->fid_column = get_key_column(pg_info);
-	    /* coordinates dimension */
-	    pg_info->coor_dim = atoi(PQgetvalue(res, i, 3));
-	    /* SRS ID */
-	    pg_info->srid = atoi(PQgetvalue(res, i, 4));
-	    /* feature type */
-	    pg_info->feature_type = ftype_from_string(PQgetvalue(res, i, 5));
-	    found = TRUE;
-	    break;
-	}
+	
+    found = PQntuples(res) > 0 ? TRUE : FALSE;
+    if (found) {
+	/* geometry column */
+	pg_info->geom_column = G_store(PQgetvalue(res, 0, 0));
+	G_debug(3, "\t-> table = %s column = %s", pg_info->table_name,
+		pg_info->geom_column);
+	/* fid column */
+	pg_info->fid_column = get_key_column(pg_info);
+	/* coordinates dimension */
+	pg_info->coor_dim = atoi(PQgetvalue(res, 0, 1));
+	/* SRS ID */
+	pg_info->srid = atoi(PQgetvalue(res, 0, 2));
+	/* feature type */
+	pg_info->feature_type = ftype_from_string(PQgetvalue(res, 0, 3));
     }
-
+    
     /* no feature in cache */
     pg_info->cache.fid = -1;
     
     PQclear(res);
     
-    db_free_string(&stmt);
-
     if (!found) {
 	G_warning(_("Feature table <%s> not found in 'geometry_columns'"),
 		  pg_info->table_name);
@@ -243,11 +173,386 @@
 */
 int V1_open_new_pg(struct Map_info *Map, const char *name, int with_z)
 {
-    G_debug(1, "V1_open_new_pg(): name = %s with_z = %d", name, with_z);
 #ifdef HAVE_POSTGRES
+    char stmt[DB_SQL_MAX];
+    
+    struct Format_info_pg *pg_info;
+    
+    PGresult *res;
+    
+    pg_info = &(Map->fInfo.pg);
+    if (!pg_info->conninfo) {
+	G_warning(_("Connection string not defined"));
+	return -1;
+    }
+    
+    if (!pg_info->table_name) {
+	G_warning(_("PostGIS feature table not defined"));
+	return -1;
+    }
+
+    G_debug(1, "V1_open_new_pg(): conninfo='%s' table='%s'", pg_info->conninfo,
+	    pg_info->table_name);
+
+    /* connect database */
+    pg_info->conn = PQconnectdb(pg_info->conninfo);
+    G_debug(2, "   PQconnectdb(): %s", pg_info->conninfo);
+    if (PQstatus(pg_info->conn) == CONNECTION_BAD)
+	G_fatal_error("%s\n%s", _("Connection ton PostgreSQL database failed."), 
+		      PQerrorMessage(pg_info->conn));
+
+    /* get DB name */
+    pg_info->db_name = G_store(PQdb(pg_info->conn));
+    if (!pg_info->db_name) {
+	G_warning(_("Unable to get database name"));
+	return -1;
+    }
+    
+    /* if schema not defined, use 'public' */
+    if (!pg_info->schema_name) {
+	pg_info->schema_name = G_store("public");
+    }
+
+    /* if fid_column not defined, use 'ogc_fid' */
+    if (!pg_info->fid_column) {
+	pg_info->fid_column = G_store("ogc_fid");
+    }
+
+    /* if geom_column not defined, use 'wkb_geometry' */
+    if (!pg_info->geom_column) {
+	pg_info->geom_column = G_store("wkb_geometry");
+    }
+    
+    /* check if feature table already exists */
+    sprintf(stmt, "SELECT * FROM pg_tables "
+	    "WHERE schemaname = '%s' AND tablename = '%s'",
+	    pg_info->schema_name, pg_info->table_name);
+    G_debug(2, "SQL: %s", stmt);
+    
+    res = PQexec(pg_info->conn, stmt);
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
+	G_fatal_error("%s\n%s", _("No feature tables found in database."),
+		      PQresultErrorMessage(res));
+
+    if (PQntuples(res) > 0) {
+	/* table found */
+	if (G_get_overwrite()) {
+	    G_warning(_("PostGIS layer <%s.%s> already exists and will be overwritten"),
+		      pg_info->schema_name, pg_info->table_name);
+	    if (drop_table(pg_info) == -1) {
+		G_warning(_("Unable to delete PostGIS layer <%s>"),
+			  pg_info->table_name);
+		return -1;
+	    }
+	}
+	else {
+	    G_warning(_("PostGIS layer <%s> already exists in database '%s'"),
+		      pg_info->table_name, pg_info->db_name);
+	    return -1;
+	}
+    }
+    
+    /* no feature in cache */
+    pg_info->cache.fid = -1;
+
+    /* unknown feature type */
+    pg_info->feature_type = SF_UNKNOWN;
+    
+    PQclear(res);
+    
     return 0;
 #else
     G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
     return -1;
 #endif
 }
+
+/*!
+   \brief Create new PostGIS layer in given database (level 2)
+
+   V1_open_new_pg() is required to be called before this function.
+
+   List of currently supported types:
+    - GV_POINT     (SF_POINT)
+    - GV_LINE      (SF_LINESTRING)
+    - GV_BOUNDARY  (SF_POLYGON)
+   \param[in,out] Map pointer to Map_info structure
+   \param type feature type (GV_POINT, GV_LINE, ...)
+
+   \return 0 success
+   \return -1 error 
+*/
+int V2_open_new_pg(struct Map_info *Map, int type)
+{
+#ifdef HAVE_POSTGRES
+    int ndblinks;
+    
+    struct Format_info_pg *pg_info;
+    struct field_info *Fi;
+    struct Key_Value *projinfo, *projunits;
+    
+    Fi = NULL;
+    
+    pg_info = &(Map->fInfo.pg);
+    if (!pg_info->conninfo) {
+	G_warning(_("Connection string not defined"));
+	return -1;
+    }
+
+    if (!pg_info->table_name) {
+	G_warning(_("PostGIS feature table not defined"));
+	return -1;
+    }
+
+    G_debug(1, "V2_open_new_pg(): conninfo='%s' table='%s' -> type = %d",
+	    pg_info->conninfo, pg_info->table_name, type);
+    
+    /* get spatial reference */
+    projinfo  = G_get_projinfo();
+    projunits = G_get_projunits();
+    pg_info->srid = 0; /* TODO */
+    // Ogr_spatial_ref = GPJ_grass_to_osr(projinfo, projunits);
+    G_free_key_value(projinfo);
+    G_free_key_value(projunits);
+
+    /* determine geometry type */
+    switch(type) {
+    case GV_POINT:
+	pg_info->feature_type = SF_POINT;
+	break;
+    case GV_LINE:
+	pg_info->feature_type = SF_LINESTRING;
+	break;
+    case GV_BOUNDARY:
+	pg_info->feature_type = SF_POLYGON;
+	break;
+    default:
+	G_warning(_("Unsupported geometry type (%d)"), type);
+	return -1;
+    }
+
+    /* coordinate dimension */
+    pg_info->coor_dim = Vect_is_3d(Map) ? 3 : 2;
+    
+    /* create new PostGIS table */
+    ndblinks = Vect_get_num_dblinks(Map);
+    if (ndblinks > 0) {
+	Fi = Vect_get_dblink(Map, 0);
+	if (Fi) {
+	    if (ndblinks > 1)
+		G_warning(_("More layers defined, using driver <%s> and "
+			    "database <%s>"), Fi->driver, Fi->database);
+	}
+	else {
+	    G_warning(_("Database connection not defined. "
+			"Unable to write attributes."));
+	}
+    }
+    
+    if (create_table(pg_info, Fi) == -1) {
+	G_warning(_("Unable to create new PostGIS table"));
+	return -1;
+    }
+
+    if (Fi) 
+	G_free(Fi);
+    
+    return 0;
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+    return -1;
+#endif
+}
+
+#ifdef HAVE_POSTGRES
+char *get_key_column(struct Format_info_pg *pg_info)
+{
+    char *key_column;
+    char stmt[DB_SQL_MAX];
+    
+    PGresult *res;
+    
+    sprintf(stmt,
+	    "SELECT kcu.column_name "
+	    "FROM INFORMATION_SCHEMA.TABLES t "
+	    "LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc "
+	    "ON tc.table_catalog = t.table_catalog "
+	    "AND tc.table_schema = t.table_schema "
+	    "AND tc.table_name = t.table_name "
+	    "AND tc.constraint_type = 'PRIMARY KEY' "
+	    "LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu "
+	    "ON kcu.table_catalog = tc.table_catalog "
+	    "AND kcu.table_schema = tc.table_schema "
+	    "AND kcu.table_name = tc.table_name "
+	    "AND kcu.constraint_name = tc.constraint_name "
+	    "WHERE t.table_schema = '%s' AND t.table_name = '%s'",
+	    pg_info->schema_name, pg_info->table_name);
+    G_debug(0, "SQL: %s", stmt);
+    
+    res = PQexec(pg_info->conn, stmt);
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
+	PQntuples(res) != 1 || strlen(PQgetvalue(res, 0, 0)) < 1) {
+	G_warning(_("No key column detected."));
+	if (res)
+	    PQclear(res);
+	return NULL;
+    }
+    key_column = G_store(PQgetvalue(res, 0, 0));
+    
+    PQclear(res);
+
+    return key_column;
+}
+
+SF_FeatureType ftype_from_string(const char *type)
+{
+    SF_FeatureType sf_type;
+
+    if (G_strcasecmp(type, "POINT") == 0)
+	return SF_POINT;
+    else if (G_strcasecmp(type, "LINESTRING") == 0)
+	return SF_LINESTRING;
+    else if (G_strcasecmp(type, "POLYGON") == 0)
+	return SF_POLYGON;
+    else if (G_strcasecmp(type, "MULTIPOINT") == 0)
+	return SF_MULTIPOINT;
+    else if (G_strcasecmp(type, "MULTILINESTRING") == 0)
+	return SF_MULTILINESTRING;
+    else if (G_strcasecmp(type, "MULTIPOLYGON") == 0)
+	return SF_MULTIPOLYGON;
+    else if (G_strcasecmp(type, "GEOMETRYCOLLECTION") == 0)
+	return SF_GEOMETRYCOLLECTION;
+    
+    return SF_UNKNOWN;
+    
+    G_debug(3, "ftype_from_string(): type='%s' -> %d", type, sf_type);
+    
+    return sf_type;
+}
+
+int drop_table(struct Format_info_pg *pg_info)
+{
+    char stmt[DB_SQL_MAX];
+
+    sprintf(stmt, "DROP TABLE \"%s\".\"%s\"",
+	    pg_info->schema_name, pg_info->table_name);
+    G_debug(2, "SQL: %s", stmt);
+    
+    if (execute(pg_info->conn, stmt) == -1) {
+	return -1;
+    }    
+    return 0;
+}
+
+int create_table(struct Format_info_pg *pg_info, const struct field_info *Fi)
+{
+    int spatial_index, primary_key;
+    char stmt[DB_SQL_MAX], *geom_type;
+
+    PGresult *result;
+
+    /* by default create spatial index & add primary key */
+    spatial_index = primary_key = TRUE;
+    if (G_find_file2("", "PG", G_mapset())) {
+	FILE *fp;
+	const char *p;
+	
+	struct Key_Value *key_val;
+	
+	fp = G_fopen_old("", "PG", G_mapset());
+	if (!fp) {
+	    G_fatal_error(_("Unable to open PG file"));
+	}
+	key_val = G_fread_key_value(fp);
+	fclose(fp);
+	
+	/* spatial index */
+	p = G_find_key_value("spatial_index", key_val);
+	if (p && G_strcasecmp(p, "off") == 0)
+	    spatial_index = FALSE;
+	/* primary key */
+	p = G_find_key_value("primary_key", key_val);
+	if (p && G_strcasecmp(p, "off") == 0)
+	    primary_key = FALSE;
+    }
+
+    /* begin transaction */
+    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");
+	return -1;
+    }
+    
+    /* add primary key ? */
+    if (primary_key) {
+	sprintf(stmt, "ALTER TABLE \"%s\".\"%s\" ADD PRIMARY KEY (%s)",
+		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");
+	    return -1;
+	}
+    }
+    
+    /* determine geometry type (string) */
+    switch(pg_info->feature_type) {
+    case (SF_POINT):
+	geom_type = "POINT";
+	break;
+    case (SF_LINESTRING):
+	geom_type = "LINESTRING";
+	break;
+    case (SF_POLYGON):
+	geom_type = "POLYGON";
+	break;
+    default:
+	G_warning(_("Unsupported feature type %d"), pg_info->feature_type);
+	execute(pg_info->conn, "ROLLBACK");
+	return -1;
+    }
+
+    /* add geometry column */
+    sprintf(stmt, "SELECT AddGeometryColumn('%s', '%s', "
+	    "'%s', %d, '%s', %d)",
+	    pg_info->schema_name, pg_info->table_name,
+	    pg_info->geom_column, pg_info->srid,
+	    geom_type, pg_info->coor_dim);
+    G_debug(2, "SQL: %s", stmt);
+    result = PQexec(pg_info->conn, stmt);
+    
+    if (!result || PQresultStatus(result) != PGRES_TUPLES_OK) {
+	PQclear(result);
+	execute(pg_info->conn, "ROLLBACK");
+	return -1;
+    }
+    
+    /* create index ? */
+    if (spatial_index) {
+	sprintf(stmt, "CREATE INDEX %s_%s_idx ON %s USING GIST (%s)",
+		pg_info->table_name, pg_info->geom_column, pg_info->table_name,
+		pg_info->geom_column);
+	G_debug(2, "SQL: %s", stmt);
+	
+	if (execute(pg_info->conn, stmt) == -1) {
+	    execute(pg_info->conn, "ROLLBACK");
+	    return -1;
+	}
+    }
+    
+    /* close transaction */
+    if (execute(pg_info->conn, "COMMIT") == -1) {
+	return -1;
+    }
+    
+    return 0;
+}
+#endif

Modified: grass/trunk/lib/vector/Vlib/write.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write.c	2012-03-21 11:05:18 UTC (rev 51125)
+++ grass/trunk/lib/vector/Vlib/write.c	2012-03-21 11:08:56 UTC (rev 51126)
@@ -185,7 +185,7 @@
 	G_fatal_error(_("Unable to write feature, vector map is not opened"));
 
     if (!(Map->plus.update_cidx)) {
-	Map->plus.cidx_up_to_date = 0;
+	Map->plus.cidx_up_to_date = FALSE;
     }
 
     offset = 

Modified: grass/trunk/lib/vector/Vlib/write_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write_pg.c	2012-03-21 11:05:18 UTC (rev 51125)
+++ grass/trunk/lib/vector/Vlib/write_pg.c	2012-03-21 11:08:56 UTC (rev 51126)
@@ -76,13 +76,22 @@
     pg_info = &(Map->fInfo.pg);
     offset_info = &(pg_info->offset);
     
-    if (!pg_info->conn || !pg_info->table_name) {
+    if (!pg_info->conn) {
 	G_warning(_("No connection defined"));
 	return -1;
     }
+
+    if (!pg_info->table_name) {
+	G_warning(_("PostGIS feature table not defined"));
+	return -1;
+    }
+
+    if (pg_info->feature_type == SF_UNKNOWN) {
+	/* create PostGIS table if doesn't exist */
+	if (V2_open_new_pg(Map, type) < 0)
+	    return -1;
+    }
     
-    /* create PostGIS layer if doesn't exist ? */
-    
     cat = -1; /* no attributes to be written */
     if (cats->n_cats > 0 && Vect_get_num_dblinks(Map) > 0) {
 	/* check for attributes */
@@ -633,9 +642,10 @@
 
     /* build INSERT statement */
     stmt = NULL;
-    G_asprintf(&stmt, "INSERT INTO %s (%s, %s) VALUES (%d, '%s'::GEOMETRY)",
-	       pg_info->table_name, pg_info->fid_column, pg_info->geom_column,
-	       fid, text_data);
+    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);
     G_debug(2, "SQL: %s", stmt);
     
     if (execute(pg_info->conn, stmt) == -1) {



More information about the grass-commit mailing list