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

svn_grass at osgeo.org svn_grass at osgeo.org
Mon Apr 1 08:18:49 PDT 2013


Author: martinl
Date: 2013-04-01 08:18:49 -0700 (Mon, 01 Apr 2013)
New Revision: 55583

Modified:
   grass/trunk/include/defs/vector.h
   grass/trunk/lib/vector/Vlib/open_pg.c
   grass/trunk/lib/vector/Vlib/read_pg.c
   grass/trunk/lib/vector/Vlib/write_pg.c
Log:
vlib/pg: implement V2_delete_line_pg() and V2_rewrite_line_pg() (work in progress)
         various minor issues


Modified: grass/trunk/include/defs/vector.h
===================================================================
--- grass/trunk/include/defs/vector.h	2013-04-01 15:15:14 UTC (rev 55582)
+++ grass/trunk/include/defs/vector.h	2013-04-01 15:18:49 UTC (rev 55583)
@@ -535,6 +535,7 @@
 int V1_delete_line_pg(struct Map_info *, off_t);
 int V2_delete_line_nat(struct Map_info *, int);
 int V2_delete_line_sfa(struct Map_info *, int);
+int V2_delete_line_pg(struct Map_info *, int);
 int V1_restore_line_nat(struct Map_info *, off_t);
 int V2_restore_line_nat(struct Map_info *, int, off_t);
 off_t V1_write_line_nat(struct Map_info *, int, const struct line_pnts *,
@@ -559,6 +560,8 @@
                           const struct line_pnts *, const struct line_cats *);
 off_t V2_rewrite_line_sfa(struct Map_info *, int, int, off_t,
                           const struct line_pnts *, const struct line_cats *);
+off_t V2_rewrite_line_pg(struct Map_info *, int, int, off_t,
+                          const struct line_pnts *, const struct line_cats *);
 
     /* Build topology */
 int Vect_build_nat(struct Map_info *, int);

Modified: grass/trunk/lib/vector/Vlib/open_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open_pg.c	2013-04-01 15:15:14 UTC (rev 55582)
+++ grass/trunk/lib/vector/Vlib/open_pg.c	2013-04-01 15:18:49 UTC (rev 55583)
@@ -386,7 +386,14 @@
     }
     
     /* create new topology schema (if PostGIS topology support is enabled) */
-    if(pg_info->toposchema_name) {
+    if (pg_info->toposchema_name) {
+        /* force topological level */
+        Map->level = LEVEL_2;
+        Map->plus.built = GV_BUILD_BASE;
+
+        /* track updated features, used in V2__add_line_to_topo_nat() */
+        Vect_set_updated(Map, TRUE);
+        
         if (create_topo_schema(pg_info, Vect_is_3d(Map)) == -1) {
             G_warning(_("Unable to create new PostGIS topology schema"));
             return -1;
@@ -692,7 +699,11 @@
     /* prepare CREATE TABLE statement */
     sprintf(stmt, "CREATE TABLE \"%s\".\"%s\" (%s SERIAL",
             pg_info->schema_name, pg_info->table_name, pg_info->fid_column);
-
+    
+    /* add primary key ? */
+    if (primary_key)
+        strcat(stmt, " PRIMARY KEY");
+    
     if (Fi) {
         /* append attributes */
         int col, ncols, sqltype, length;
@@ -785,18 +796,6 @@
         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 (Vect__execute_pg(pg_info->conn, stmt) == -1) {
-            Vect__execute_pg(pg_info->conn, "ROLLBACK");
-            return -1;
-        }
-    }
-
     /* determine geometry type (string) */
     switch (pg_info->feature_type) {
     case (SF_POINT):

Modified: grass/trunk/lib/vector/Vlib/read_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_pg.c	2013-04-01 15:15:14 UTC (rev 55582)
+++ grass/trunk/lib/vector/Vlib/read_pg.c	2013-04-01 15:18:49 UTC (rev 55583)
@@ -286,6 +286,22 @@
 #endif
 }
 
+/*!
+   \brief Read feature from PostGIS layer on topological level
+
+   This function implements random access on level 2.
+
+   Note: Topology must be built at level >= GV_BUILD_BASE
+    
+   \param Map pointer to Map_info structure 
+   \param[out] line_p container used to store line points within (pointer line_pnts struct)
+   \param[out] line_c container used to store line categories within (pointer line_cats struct)
+   \param line feature id to read
+
+   \return feature type
+   \return 0 dead feature
+   \return -1 on error
+ */
 int V2_read_line_pg(struct Map_info *Map, struct line_pnts *line_p,
                     struct line_cats *line_c, int line)
 {
@@ -296,10 +312,16 @@
     struct P_line *Line;
 
     pg_info = &(Map->fInfo.pg);
+    
+    if (line < 1 || line > Map->plus.n_lines) {
+        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+        return -1;
+    }
+    
     Line = Map->plus.Line[line];
     if (Line == NULL) {
-        G_warning(_("Attempt to read dead feature %d"), line);
-        return -1;
+        G_warning(_("Attempt to access dead feature %d"), line);
+        return 0;
     }
     
     G_debug(4, "V2_read_line_pg() line = %d type = %d offset = %lu",
@@ -330,7 +352,7 @@
     get_feature(pg_info, fid, Line->type);
     
     if (pg_info->cache.sf_type == SF_NONE) {
-        G_warning(_("Feature %d without geometry skipped"), Line->offset);
+        G_warning(_("Feature %d without geometry skipped"), line);
         return -1;
     }
     
@@ -339,7 +361,7 @@
         return type;
     
     if (Line->type == GV_BOUNDARY && type == GV_LINE)
-        type = GV_BOUNDARY;
+        type = GV_BOUNDARY; /* feature is read as GV_LINE (linestring), force GV_BOUNDARY */
     
     if (line_p)
         Vect_append_points(line_p, pg_info->cache.lines[0], GV_FORWARD);

Modified: grass/trunk/lib/vector/Vlib/write_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write_pg.c	2013-04-01 15:15:14 UTC (rev 55582)
+++ grass/trunk/lib/vector/Vlib/write_pg.c	2013-04-01 15:18:49 UTC (rev 55583)
@@ -13,7 +13,7 @@
    \todo OGR version of V2__add_area_cats_to_cidx_nat
    \todo OGR version of V2__add_line_to_topo_nat
 
-   (C) 2012 by Martin Landa, and the GRASS Development Team
+   (C) 2012-2013 by Martin Landa, and the GRASS Development Team
 
    This program is free software under the GNU General Public License
    (>=v2). Read the file COPYING that comes with GRASS for details.
@@ -50,9 +50,10 @@
                                         int, int *);
 static unsigned char *polygon_to_wkb(int, const struct line_pnts **, int,
                                      int, int *);
+static char *line_to_wkb(struct Format_info_pg *, const struct line_pnts **,
+                         int, int, int);
 static int write_feature(struct Map_info *, int, int,
-                         const struct line_pnts **, int, int,
-                         int, const struct field_info *);
+                         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 *);
 static int insert_topo_element(struct Map_info *, int, int, const char *);
@@ -62,15 +63,21 @@
 static int update_topo_face(struct Map_info *, int);
 #endif
 
+static struct line_pnts *Points;
+
 /*!
    \brief Writes feature on level 1 (PostGIS interface)
 
-   Note:
+   Notes for simple feature access:
    - centroids are not supported in PostGIS, pseudotopo holds virtual
    centroids
    - boundaries are not supported in PostGIS, pseudotopo treats polygons
    as boundaries
 
+   Notes for PostGIS Topology access:
+   - centroids are stored as isolated nodes
+   - boundaries are stored as edges
+
    \param Map pointer to Map_info structure
    \param type feature type (GV_POINT, GV_LINE, ...)
    \param points pointer to line_pnts structure (feature geometry) 
@@ -94,9 +101,11 @@
             return -1;
     }
 
-    if (!pg_info->toposchema_name) { /* simple features */
+    if (!pg_info->toposchema_name) { /* simple features access */
         return write_line_sf(Map, type, &points, 1, cats);
     }
+
+    /* PostGIS Topology access */
     return write_line_tp(Map, type, FALSE, points, cats);
 #else
     G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
@@ -105,8 +114,10 @@
 }
 
 /*!
-   \brief Writes feature on level 2 (PostGIS interface)
+   \brief Writes feature on topological level (PostGIS interface)
 
+   Calls V2_write_line_sfa() for simple features access.
+   
    \param Map pointer to Map_info structure
    \param type feature type (GV_POINT, GV_LINE, ...)
    \param points pointer to line_pnts structure (feature geometry) 
@@ -127,11 +138,9 @@
     if (!pg_info->toposchema_name) { /* pseudo-topology */
         return V2_write_line_sfa(Map, type, points, cats);
     }
-    else {                          /* PostGIS topology */
-        if (Map->plus.built < GV_BUILD_BASE)
-            Map->plus.built = GV_BUILD_BASE; /* update build level */
-        return write_line_tp(Map, type, FALSE, points, cats);
-    }
+
+    /* PostGIS Topology */
+    return write_line_tp(Map, type, FALSE, points, cats);
 #else
     G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
     return -1;
@@ -139,8 +148,12 @@
 }
 
 /*!
-   \brief Rewrites feature at the given offset (level 1) (PostGIS interface)
+   \brief Rewrites feature at the given offset (level 1) (PostGIS interface, internal use only)
 
+   Only for simple feature access. PostGIS Topology requires level 2.
+   
+   \todo Use UPDATE statement ?
+   
    \param Map pointer to Map_info structure
    \param offset feature offset
    \param type feature type (GV_POINT, GV_LINE, ...)
@@ -174,8 +187,86 @@
 }
 
 /*!
+  \brief Rewrites feature at topological level (PostGIS interface, internal use only)
+
+  Note: Topology must be built at level >= GV_BUILD_BASE
+   
+  \todo Handle also categories
+  \todo Store original geometry in tmp table for restore
+  
+  \param Map pointer to Map_info structure
+  \param type feature type  (GV_POINT, GV_LINE, ...)
+  \param line feature id
+  \param points feature geometry
+  \param cats feature categories
+  
+  \return offset where feature was rewritten
+  \return -1 on error
+*/
+off_t V2_rewrite_line_pg(struct Map_info *Map, int line, int type, off_t old_offset,
+			  const struct line_pnts *points, const struct line_cats *cats)
+{
+    G_debug(3, "V2_rewrite_line_pg(): line=%d type=%d offset=%lu",
+            line, type, old_offset);
+#ifdef HAVE_POSTGRES
+    const char *schema_name, *table_name, *keycolumn;
+    char *stmt, *geom_data;
+    
+    struct Format_info_pg *pg_info;
+    
+    geom_data = NULL;
+    stmt = NULL;
+    pg_info = &(Map->fInfo.pg);
+  
+    if (line < 1 || line > Map->plus.n_lines) {
+        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+        return -1;
+    }
+  
+    if (type != V2_read_line_pg(Map, NULL, NULL, line)) {
+	G_warning(_("Unable to rewrite feature (incompatible feature types)"));
+	return -1;
+    }
+
+    if (pg_info->toposchema_name) { /* PostGIS Topology */
+        schema_name = pg_info->toposchema_name;
+        if (type & GV_POINTS) {
+            table_name = keycolumn = "node";
+        }
+        else {
+            table_name = "edge_data";
+            keycolumn = "edge";
+        }
+    }
+    else { /* simple features access */
+        schema_name = pg_info->schema_name;
+        table_name  = pg_info->table_name;
+        keycolumn   = pg_info->fid_column;
+    }
+    
+    geom_data = line_to_wkb(pg_info, &points, 1, type, Map->head.with_z);
+    G_asprintf(&stmt, "UPDATE \"%s\".\"%s\" SET geom = '%s'::GEOMETRY WHERE %s_id = %d",
+               schema_name, table_name, geom_data, keycolumn, line);
+    G_free(geom_data);
+
+    if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
+        G_warning(_("Unable to rewrite feature %d"), line);
+        Vect__execute_pg(pg_info->conn, "ROLLBACK");
+        return -1;
+    }
+
+    return old_offset; /* offset not changed */
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+    return -1;
+#endif
+}
+
+/*!
    \brief Deletes feature at the given offset (level 1)
 
+   Only for simple feature access. PostGIS Topology requires level 2.
+
    \param Map pointer Map_info structure
    \param offset feature offset
 
@@ -204,7 +295,7 @@
 
     fid = pg_info->offset.array[offset];
 
-    G_debug(3, "V1_delete_line_pg(), offset = %lu -> fid = %ld",
+    G_debug(3, "V1_delete_line_pg(): offset = %lu -> fid = %ld",
             (unsigned long)offset, fid);
 
     if (!pg_info->inTransaction) {
@@ -232,8 +323,136 @@
 }
 
 /*!
-   \brief Writes node on level 2 (PostGIS Topology interface) - internal use only
+  \brief Deletes feature on topological level (PostGIS interface)
 
+  Note: Topology must be built at level >= GV_BUILD_BASE
+  
+  Calls V2_delete_line_sfa() for simple feature access.
+  
+  \param Map pointer to Map_info structure
+  \param line feature id to be deleted
+  
+  \return 0 on success
+  \return -1 on error
+*/
+int V2_delete_line_pg(struct Map_info *Map, int line)
+{
+#ifdef HAVE_POSTGRES
+    struct Format_info_pg *pg_info;
+
+    pg_info = &(Map->fInfo.pg);
+
+    if (line < 1 || line > Map->plus.n_lines) {
+        G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+        return -1;
+    }
+    
+    if (!pg_info->toposchema_name) { /* pseudo-topology */
+        return V2_delete_line_sfa(Map, line);
+    }
+    else {                          /* PostGIS topology */
+        int type, n_nodes;
+        char stmt[DB_SQL_MAX];
+        const char *table_name, *keycolumn;
+        
+        struct P_line *Line;
+        
+        if (line < 1 || line > Map->plus.n_lines) {
+            G_warning(_("Attempt to access feature with invalid id (%d)"), line);
+            return -1;
+        }
+        
+        Line = Map->plus.Line[line];
+        if (!Line) {
+            G_warning(_("Attempt to access dead feature %d"), line);
+            return -1;
+        }
+            
+        if (Line->type & GV_POINTS) {
+            table_name = keycolumn = "node";
+        }
+        else {
+            table_name = "edge_data";
+            keycolumn = "edge";
+
+            /* first remove references to this edge */
+            /* (1) left next edge */
+            sprintf(stmt, "UPDATE \"%s\".\"%s\" SET abs_next_left_edge = edge_id, "
+                    "next_left_edge = -edge_id WHERE abs_next_left_edge = %ld",
+                    pg_info->toposchema_name, table_name, Line->offset);
+            if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
+                Vect__execute_pg(pg_info->conn, "ROLLBACK");
+                return -1;
+            }
+
+            /* (2) right next edge */
+            sprintf(stmt, "UPDATE \"%s\".\"%s\" SET abs_next_right_edge = edge_id, "
+                    "next_right_edge = edge_id WHERE abs_next_right_edge = %ld",
+                    pg_info->toposchema_name, table_name, Line->offset);
+            if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
+                Vect__execute_pg(pg_info->conn, "ROLLBACK");
+                return -1;
+            }
+
+        }
+       
+        /* read the line */    
+        if (!Points) {
+            Points = Vect_new_line_struct();
+        }
+        type = V2_read_line_pg(Map, Points, NULL, line);
+        if (type < 0)
+            return -1;
+
+        /* delete record from topology table */
+        sprintf(stmt, "DELETE FROM \"%s\".\"%s\" WHERE %s_id = %ld",
+                pg_info->toposchema_name, table_name, keycolumn, Line->offset);
+        if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
+            G_warning(_("Unable to delete feature (%s) %d"), keycolumn,
+                      line);
+            Vect__execute_pg(pg_info->conn, "ROLLBACK");
+            return -1;
+        }
+        
+        /* update topology */
+        Vect_reset_updated(Map);
+        if (0 != V2__delete_line_from_topo_nat(Map, line, type, Points, NULL))
+            return -1;
+     
+        /* delete nodes from 'nodes' table */
+        n_nodes = Vect_get_num_updated_nodes(Map);
+        if (n_nodes > 0) {
+            int i, node;
+            
+            for (i = 0; i < n_nodes; i++) {
+                node = Vect_get_updated_node(Map, i);
+                if (node > 0)
+                    continue; /* node was updated, not deleted */
+                
+                node = abs(node);
+                G_debug(3, "delete node %d from 'node' table", node);
+                
+                sprintf(stmt, "DELETE FROM \"%s\".\"node\" WHERE node_id = %d",
+                        pg_info->toposchema_name, node);
+                if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
+                    G_warning(_("Unable to delete node %d"), node);
+                    Vect__execute_pg(pg_info->conn, "ROLLBACK");
+                    return -1;
+                }
+            }
+        }
+        
+        return 0;
+    }
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+    return -1;
+#endif
+}
+
+/*!
+   \brief Writes node on topological level (PostGIS Topology interface, internal use only)
+
    \param Map pointer to Map_info structure
    \param points pointer to line_pnts structure
    
@@ -258,7 +477,7 @@
 }
 
 /*!
-   \brief Writes area on level 2 (PostGIS Simple Features interface) - internal use only
+   \brief Writes area on topological level (PostGIS Simple Features interface, internal use only)
 
    \param Map pointer to Map_info structure
    \param type feature type (GV_POINT, GV_LINE, ...)
@@ -408,8 +627,7 @@
     }
 
     /* write feature's geometry and fid */
-    if (-1 == write_feature(Map, -1, type, points, nparts,
-                            Vect_is_3d(Map) ? WITH_Z : WITHOUT_Z, cat, Fi)) {
+    if (-1 == write_feature(Map, -1, type, points, nparts, cat, Fi)) {
         Vect__execute_pg(pg_info->conn, "ROLLBACK");
         return -1;
     }
@@ -461,7 +679,7 @@
     
     /* check type for nodes */
     if (is_node && type != GV_POINT) {
-        G_warning(_("Invalid type (%d) for nodes"), type);
+        G_warning(_("Invalid feature type (%d) for nodes"), type);
         return -1;
     }
 
@@ -510,15 +728,14 @@
         Vect_cat_get(cats, 1, &cat);
     }
 
-    /* update GRASS-like topology before writing feature */
+    /* update GRASS topology before writing PostGIS feature */
     if (is_node) {
         dig_add_node(plus, points->x[0], points->y[0], points->z[0]);
     }
     else {
+        int n_nodes;
         off_t offset;
-        struct bound_box box;
         
-        dig_line_box(points, &box);
         /* better is probably to check nextval directly */
         if (type & GV_POINTS) {
             offset = Vect_get_num_primitives(Map, GV_POINTS) + 1; /* next */
@@ -527,26 +744,49 @@
         else { /* LINES */
             offset = Vect_get_num_primitives(Map, GV_LINES) + 1; /* next */
         }
-        line = dig_add_line(plus, type, points, &box, offset);
-        G_debug(3, "  line added to topo with id = %d", line);
         
-        if (line == 1)
-            Vect_box_copy(&(plus->box), &box);
-        else
-            Vect_box_extend(&(plus->box), &box);
+        Vect_reset_updated(Map);
+        line = V2__add_line_to_topo_nat(Map, offset, type, points, NULL, /* TODO: handle categories */
+                                        -1, NULL);
+        
+        /* insert new nodes into 'nodes' table */
+        n_nodes = Vect_get_num_updated_nodes(Map);
+        if (n_nodes > 0) {
+            int i, node;
+            double x, y, z;
+            
+            if (!Points)
+                Points = Vect_new_line_struct();
+            
+            for (i = 0; i < n_nodes; i++) {
+                node = Vect_get_updated_node(Map, i);
+                G_debug(3, "  new node: %d", node);
+
+                Vect_get_node_coor(Map, node, &x, &y, &z);
+                Vect_reset_line(Points);
+                Vect_append_point(Points, x, y, z);
+                
+                write_feature(Map, -1, GV_POINT, (const struct line_pnts **) &Points, 1,
+                              -1, NULL);
+            }
+        }
     }
     
     /* write new feature to PostGIS
        - feature table for simple features
        - feature table and topo schema for topological access 
     */
-    if (-1 == write_feature(Map, line, type, &points, 1,
-                            Vect_is_3d(Map) ? WITH_Z : WITHOUT_Z,
-                            cat, Fi)) {
+    if (-1 == write_feature(Map, line, type, &points, 1, cat, Fi)) {
         Vect__execute_pg(pg_info->conn, "ROLLBACK");
         return -1;
     }
 
+    /* update PostGIS-line topo */
+    if (plus->built >= GV_BUILD_BASE && (type & GV_LINES))
+        update_topo_edge(Map, line);
+    if (plus->built >= GV_BUILD_AREAS && type == GV_BOUNDARY)
+        update_topo_face(Map, line);
+    
     return 0;
 }
 
@@ -581,7 +821,7 @@
 }
 
 /*!
-   \bried Write point into WKB buffer
+   \brief Write point into WKB buffer
 
    See OGRPoint::exportToWkb from GDAL/OGR library
 
@@ -823,50 +1063,34 @@
 }
 
 /*!
-   \brief Insert feature into table
+  \brief Write feature to WKB buffer
 
-   \param Map pointer to Map_info structure
-   \param line feature id (topo access only)
-   \param type feature type (GV_POINT, GV_LINE, ...)
-   \param points pointer to line_pnts struct
-   \param nparts number of parts (rings for polygon)
-   \param with_z WITH_Z for 3D data
-   \param cat category number (-1 for no category)
-   \param Fi pointer to field_info (attributes to copy, NULL for no attributes)
+  Allocated string buffer should be freed by G_free().
 
-   \return -1 on error
-   \retirn 0 on success
- */
-int write_feature(struct Map_info *Map, int line, int type,
-                  const struct line_pnts **points, int nparts, int with_z,
-                  int cat, const struct field_info *Fi)
+  \param pg_info pointer to Format_info_pg struct
+  \param points array of geometries which form feature
+  \param nparts number of geometries in array
+  \param type feature type (GV_POINT, GV_LINE, ...)
+  \param with_z WITH_Z for 3D data
+
+  \return allocated string buffer
+  \return NULL on error
+*/
+char *line_to_wkb(struct Format_info_pg *pg_info,
+                  const struct line_pnts **points, int nparts, int type, int with_z)
 {
     int byte_order, nbytes, nsize;
     unsigned int sf_type;
+    
     unsigned char *wkb_data;
-    char *stmt, *text_data, *text_data_p, *hex_data;
-
-    struct Format_info_pg *pg_info;
+    char *text_data, *text_data_p, *hex_data;
     
-    pg_info = &(Map->fInfo.pg);
-    
-    if (with_z && pg_info->coor_dim != 3) {
-        G_warning(_("Trying to insert 3D data into feature table "
-                    "which store 2D data only"));
-        return -1;
-    }
-    if (!with_z && pg_info->coor_dim != 2) {
-        G_warning(_("Trying to insert 2D data into feature table "
-                    "which store 3D data only"));
-        return -1;
-    }
-
     byte_order = dig__byte_order_out();
 
     /* get wkb data */
     nbytes = -1;
     wkb_data = NULL;
-    if (type == GV_POINT || type == GV_CENTROID)
+    if (type & GV_POINTS) /* point or centroid */
         wkb_data = point_to_wkb(byte_order, points[0], with_z, &nbytes);
     else if (type == GV_LINE)
         wkb_data = linestring_to_wkb(byte_order, points[0], with_z, &nbytes);
@@ -884,7 +1108,7 @@
     
     if (!wkb_data || nbytes < 1) {
         G_warning(_("Unsupported feature type %d"), type);
-        return -1;
+        return NULL;
     }
 
     /* When converting to hex, each byte takes 2 hex characters. In
@@ -936,24 +1160,74 @@
     strcpy(text_data_p, hex_data);
     G_free(hex_data);
 
+    return text_data;
+}
+
+/*!
+   \brief Insert feature into table
+
+   \param Map pointer to Map_info structure
+   \param line feature id (topo access only)
+   \param type feature type (GV_POINT, GV_LINE, ...)
+   \param points pointer to line_pnts struct
+   \param nparts number of parts (rings for polygon)
+   \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(struct Map_info *Map, int line, int type,
+                  const struct line_pnts **points, int nparts,
+                  int cat, const struct field_info *Fi)
+{
+    int with_z;
+    char *stmt, *geom_data;
+
+    struct Format_info_pg *pg_info;
+    
+    pg_info = &(Map->fInfo.pg);
+    with_z  = Map->head.with_z;
+    
+    if (with_z && pg_info->coor_dim != 3) {
+        G_warning(_("Trying to insert 3D data into feature table "
+                    "which store 2D data only"));
+        return -1;
+    }
+    if (!with_z && pg_info->coor_dim != 2) {
+        G_warning(_("Trying to insert 2D data into feature table "
+                    "which store 3D data only"));
+        return -1;
+    }
+
+    /* build WKB geometry from line_pnts structures */
+    geom_data = line_to_wkb(pg_info, points, nparts, type, with_z);
+    if (!geom_data)
+        return -1;
+    
     /* build INSERT statement
        simple feature geometry + attributes
     */
-    stmt = build_insert_stmt(pg_info, text_data, cat, Fi);
+    stmt = build_insert_stmt(pg_info, geom_data, cat, Fi);
     G_debug(2, "SQL: %s", stmt);
 
     if (!pg_info->inTransaction) {
         /* start transaction */
         pg_info->inTransaction = TRUE;
-        if (Vect__execute_pg(pg_info->conn, "BEGIN") == -1)
+        if (Vect__execute_pg(pg_info->conn, "BEGIN") == -1) {
+            G_free(geom_data);
+            
             return -1;
+        }
     }
 
     /* stmt can NULL when writing PostGIS topology with no attributes
      * attached */
     if (stmt && Vect__execute_pg(pg_info->conn, stmt) == -1) {
         /* rollback transaction */
-        Vect__execute_pg(pg_info->conn, "ROLLBACK");
+        Vect__execute_pg(pg_info->conn, "ROLLBACK"); 
+        G_free(geom_data);
+        
         return -1;
     }
     G_free(stmt);
@@ -961,25 +1235,14 @@
     /* write feature in PostGIS topology schema if enabled */
     if (pg_info->toposchema_name) {
         /* insert feature into topology schema (node or edge) */
-        if (insert_topo_element(Map, line, type, text_data) != 0) {
+        if (insert_topo_element(Map, line, type, geom_data) != 0) {
             G_warning(_("Unable to insert topological element into PostGIS Topology schema"));
+            G_free(geom_data);
+            
             return -1;
         }
-        
-        /* update GRASS-like topo */
-        if (line > 0) /* skip nodes */
-            V2__add_line_to_topo_nat(Map, line, points[0], NULL, /* TODO: cats */
-                                     delete_face);
-        
-        /* update PostGIS-line topo */
-        if (type & GV_LINES)
-            update_topo_edge(Map, line);
-        if (type == GV_BOUNDARY)
-            update_topo_face(Map, line);
     }
-
-    G_free(wkb_data);
-    G_free(text_data);
+    G_free(geom_data);
     
     return 0;
 }
@@ -1499,13 +1762,13 @@
 
     pg_info = &(Map->fInfo.pg);
     
-    if (line < 1 || line > Vect_get_num_lines(Map)) {
-        G_warning(_("Inconsistency in topology: invalid feature id"));
+    if (line < 1 || line > Map->plus.n_lines) {
+        G_warning(_("Attempt to access non-existing feature %d"), line);
         return -1;
     }
     Line = Map->plus.Line[line];
     if (!Line) {
-        G_warning(_("Inconsistency in topology: dead line found"));
+        G_warning(_("Attempt to access dead feature %d"), line);
         return -1;
     }
     
@@ -1531,8 +1794,7 @@
                 nle = next_edge; /* update next left edge for end node */
         }
         else {
-            G_warning(_("Inconsistency in topology detected: "
-                        "unable to determine next left/right edge."));
+            G_warning(_("Unable to determine next left/right edge"));
             return -1;
         }
     }
@@ -1597,13 +1859,13 @@
     
     pg_info = &(Map->fInfo.pg);
     
-    if (line < 1 || line > Vect_get_num_lines(Map)) {
-        G_warning(_("Inconsistency in topology detected: invalid feature id"));
+    if (line < 1 || line > Map->plus.n_lines) {
+        G_warning(_("Attempt to access non-existing feature %d"), line);
         return -1;
     }
     Line = Map->plus.Line[line];
     if (!Line) {
-        G_warning(_("Inconsistency in topology detected: dead line found"));
+        G_warning(_("Attempt to access dead feature %d"), line);
         return -1;
     }
     
@@ -1666,5 +1928,4 @@
     
     return 0;
 }
-
 #endif



More information about the grass-commit mailing list