[GRASS-SVN] r56166 - in grass/trunk: include/vect lib/vector/Vlib

svn_grass at osgeo.org svn_grass at osgeo.org
Wed May 8 12:23:05 PDT 2013


Author: martinl
Date: 2013-05-08 12:23:05 -0700 (Wed, 08 May 2013)
New Revision: 56166

Modified:
   grass/trunk/include/vect/dig_defines.h
   grass/trunk/include/vect/dig_structs.h
   grass/trunk/lib/vector/Vlib/area.c
   grass/trunk/lib/vector/Vlib/build.c
   grass/trunk/lib/vector/Vlib/build_nat.c
   grass/trunk/lib/vector/Vlib/build_pg.c
   grass/trunk/lib/vector/Vlib/build_sfa.c
   grass/trunk/lib/vector/Vlib/close_pg.c
   grass/trunk/lib/vector/Vlib/local_proto.h
   grass/trunk/lib/vector/Vlib/open_pg.c
   grass/trunk/lib/vector/Vlib/pg_local_proto.h
   grass/trunk/lib/vector/Vlib/read_pg.c
   grass/trunk/lib/vector/Vlib/rewind_pg.c
Log:
vlib(pg): implement PG version for Vect_get_area_points()
          improve reading features open/close cursor (work in progress)


Modified: grass/trunk/include/vect/dig_defines.h
===================================================================
--- grass/trunk/include/vect/dig_defines.h	2013-05-08 16:32:08 UTC (rev 56165)
+++ grass/trunk/include/vect/dig_defines.h	2013-05-08 19:23:05 UTC (rev 56166)
@@ -80,13 +80,13 @@
   Don't change GV_FORMAT_* values, this order is hardcoded in lib
 */
 /*! \brief GRASS native format */
-#define GV_FORMAT_NATIVE     0
-/*! \brief OGR format (for layers linked via v.external) */
-#define GV_FORMAT_OGR        1
+#define GV_FORMAT_NATIVE           0
+/*! \brief OGR format */
+#define GV_FORMAT_OGR              1
 /*! \brief OGR format (direct access) */
-#define GV_FORMAT_OGR_DIRECT 2
-/*! \brief PostGIS format (for layers linked via v.external) */
-#define GV_FORMAT_POSTGIS    3
+#define GV_FORMAT_OGR_DIRECT       2
+/*! \brief PostGIS format */
+#define GV_FORMAT_POSTGIS          3
 
 /*! \brief One table linked to vector map */
 #define GV_1TABLE  0

Modified: grass/trunk/include/vect/dig_structs.h
===================================================================
--- grass/trunk/include/vect/dig_structs.h	2013-05-08 16:32:08 UTC (rev 56165)
+++ grass/trunk/include/vect/dig_structs.h	2013-05-08 19:23:05 UTC (rev 56166)
@@ -568,7 +568,7 @@
 struct Format_info_pg
 {
     /*!
-      \brief Connection info string
+      \brief Connection string
     */
     char    *conninfo;
     /*!
@@ -588,19 +588,20 @@
     */
     char    *fid_column;        
     /*!
-      \brief Geometry column
+      \brief Geometry column (simple feature access)
     */
     char    *geom_column;
     /*!
-      \brief Feature type
+      \brief Feature type (simple feature access)
     */
     SF_FeatureType feature_type;
     /*!
-      \brief Coordinates dimension
+      \brief Coordinates dimension (2D or 3D)
     */
     int      coor_dim;
     /*!
-      \brief SRS ID
+      \brief Spatial reference system id (see spatial_ref_sys
+      table)
     */
     int      srid;
 
@@ -626,10 +627,15 @@
     void     *conn;
     void     *res;
 #endif
-  
     /*!
-      \brief Next line to be read for sequential access
+      \brief Open cursor
     */
+    char     *cursor_name;
+    int       cursor_fid;
+    
+    /*!
+      \brief Next line to be read
+    */
     int next_line;
 
     /*!
@@ -637,8 +643,9 @@
     */
     struct Format_info_cache cache;
     
-    /*!
-      \brief Offset list used for building pseudo-topology
+    /*! 
+      \brief Offset list used for building pseudo-topology (simple
+      features acccess)
     */
     struct Format_info_offset offset;
 

Modified: grass/trunk/lib/vector/Vlib/area.c
===================================================================
--- grass/trunk/lib/vector/Vlib/area.c	2013-05-08 16:32:08 UTC (rev 56165)
+++ grass/trunk/lib/vector/Vlib/area.c	2013-05-08 19:23:05 UTC (rev 56166)
@@ -18,6 +18,12 @@
 #include <grass/vector.h>
 #include <grass/glocale.h>
 
+#ifdef HAVE_POSTGRES
+#include "pg_local_proto.h"
+#endif
+
+#include "local_proto.h"
+
 /*!
    \brief Returns polygon array of points (outer ring) of given area
 
@@ -31,11 +37,8 @@
 int Vect_get_area_points(const struct Map_info *Map,
 			 int area, struct line_pnts *BPoints)
 {
-    int i, line, aline, dir;
     const struct Plus_head *Plus;
     struct P_area *Area;
-    static int first_time = 1;
-    static struct line_pnts *Points;
 
     G_debug(3, "Vect_get_area_points(): area = %d", area);
     BPoints->n_points = 0;
@@ -48,35 +51,8 @@
 	return -1;		/* error , because we should not read dead areas */
     }
 
-    if (first_time == 1) {
-	Points = Vect_new_line_struct();
-	first_time = 0;
-    }
-
     G_debug(3, "  n_lines = %d", Area->n_lines);
-    for (i = 0; i < Area->n_lines; i++) {
-	line = Area->lines[i];
-	aline = abs(line);
-	G_debug(3, "  append line(%d) = %d", i, line);
-
-	if (0 > Vect_read_line(Map, Points, NULL, aline)) {
-	    G_fatal_error(_("Unable to read line %d"), aline);
-	}
-
-	G_debug(3, "  line n_points = %d", Points->n_points);
-
-	if (line > 0)
-	    dir = GV_FORWARD;
-	else
-	    dir = GV_BACKWARD;
-
-	Vect_append_points(BPoints, Points, dir);
-	if (i != (Area->n_lines - 1))	/* all but not last */
-	    BPoints->n_points--;
-	G_debug(3, "  area n_points = %d", BPoints->n_points);
-    }
-
-    return BPoints->n_points;
+    return Vect__get_area_points(Map, Area->lines, Area->n_lines, BPoints);
 }
 
 /*!
@@ -475,3 +451,19 @@
 
     return -1;
 }
+
+int Vect__get_area_points(const struct Map_info *Map, const plus_t *lines, int n_lines,
+                          struct line_pnts *BPoints)
+{
+    if (Map->format == GV_FORMAT_POSTGIS &&
+        Map->fInfo.pg.toposchema_name) {
+#ifdef HAVE_POSTGRES
+        /* PostGIS Topology */
+        return Vect__get_area_points_pg(Map, lines, n_lines, BPoints);
+#else
+        G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+#endif
+    }
+    /* native format */
+    return Vect__get_area_points_nat(Map, lines, n_lines, BPoints);
+}

Modified: grass/trunk/lib/vector/Vlib/build.c
===================================================================
--- grass/trunk/lib/vector/Vlib/build.c	2013-05-08 16:32:08 UTC (rev 56165)
+++ grass/trunk/lib/vector/Vlib/build.c	2013-05-08 19:23:05 UTC (rev 56166)
@@ -5,7 +5,7 @@
 
    Higher level functions for reading/writing/manipulating vectors.
 
-   (C) 2001-2010, 2012 by the GRASS Development Team
+   (C) 2001-2010, 2012-2013 by 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.
@@ -25,8 +25,13 @@
 
 #include "local_proto.h"
 
+#ifdef HAVE_POSTGRES
+#include "pg_local_proto.h"
+#endif
+
 #define SEP "-----------------------------------\n"
 
+
 #if !defined HAVE_OGR || !defined HAVE_POSTGRES
 static int format()
 {
@@ -51,6 +56,16 @@
 #endif
 };
 
+/* for qsort */
+
+typedef struct {
+    int i;
+    double size;
+    struct bound_box box;
+} BOX_SIZE;
+
+static int sort_by_size(const void *, const void *);
+
 /*!
    \brief Build area on given side of line (GV_LEFT or GV_RIGHT)
 
@@ -64,12 +79,11 @@
  */
 int Vect_build_line_area(struct Map_info *Map, int iline, int side)
 {
-    int j, area, isle, n_lines, line, direction;
-    static int first = TRUE;
+    int area, isle, n_lines;
+
     struct Plus_head *plus;
-    struct P_line *BLine;
-    static struct line_pnts *Points, *APoints;
     struct bound_box box;
+    static struct line_pnts *APoints = NULL;
     plus_t *lines;
     double area_size;
 
@@ -77,42 +91,29 @@
 
     G_debug(3, "Vect_build_line_area() line = %d, side = %d", iline, side);
 
-    if (first) {
-	Points = Vect_new_line_struct();
+    if (!APoints)
 	APoints = Vect_new_line_struct();
-	first = FALSE;
-    }
-
+    
+    /* get area */
     area = dig_line_get_area(plus, iline, side);
     if (area != 0) {
+        /* -> areas already exists, skip */
         G_debug(3, "  area/isle = %d -> skip", area);
         return 0;
     }
     
+    /* get lines which forms the area */
     n_lines = dig_build_area_with_line(plus, iline, side, &lines);
     G_debug(3, "  n_lines = %d", n_lines);
     if (n_lines < 1) {
 	return 0;
     }				/* area was not built */
 
-    /* Area or island ? */
-    Vect_reset_line(APoints);
-    for (j = 0; j < n_lines; j++) {
-	line = abs(lines[j]);
-	BLine = plus->Line[line];
-	G_debug(3, "  line[%d] = %d, offset = %lu", j, line,
-		(unsigned long) BLine->offset);
-	Vect_read_line(Map, Points, NULL, line);
-	if (lines[j] > 0)
-	    direction = GV_FORWARD;
-	else
-	    direction = GV_BACKWARD;
-	Vect_append_points(APoints, Points, direction);
-	APoints->n_points--;	/* skip last point, avoids duplicates */
-    }
+    /* get line points which forms a boundary of an area */
+    Vect__get_area_points(Map, lines, n_lines, APoints);
     dig_line_box(APoints, &box);
-    APoints->n_points++;	/* close polygon */
 
+    /* Area or island ? */
     dig_find_area_poly(APoints, &area_size);
 
     /* area_size = dig_find_poly_orientation(APoints); */
@@ -149,27 +150,6 @@
     return 0;
 }
 
-
-/* for qsort */
-
-typedef struct {
-    int i;
-    double size;
-    struct bound_box box;
-} BOX_SIZE;
-
-static int sort_by_size(const void *a, const void *b)
-{
-    BOX_SIZE *as = (BOX_SIZE *)a;
-    BOX_SIZE *bs = (BOX_SIZE *)b;
-    
-    if (as->size < bs->size)
-	return -1;
-
-    return (as->size > bs->size);
-}
-
-
 /*!
    \brief Find area outside island
 
@@ -415,18 +395,15 @@
 int Vect_attach_isles(struct Map_info *Map, const struct bound_box *box)
 {
     int i, isle;
-    static int first = TRUE;
-    static struct boxlist *List;
+    static struct boxlist *List = NULL;
     struct Plus_head *plus;
 
     G_debug(3, "Vect_attach_isles()");
       
     plus = &(Map->plus);
 
-    if (first) {
+    if (!List)
 	List = Vect_new_boxlist(FALSE);
-	first = FALSE;
-    }
 
     Vect_select_isles_by_box(Map, box, List);
     G_debug(3, "  number of isles to attach = %d", List->n_values);
@@ -1300,3 +1277,15 @@
 
     return 1;
 }
+
+int sort_by_size(const void *a, const void *b)
+{
+    BOX_SIZE *as = (BOX_SIZE *)a;
+    BOX_SIZE *bs = (BOX_SIZE *)b;
+    
+    if (as->size < bs->size)
+	return -1;
+
+    return (as->size > bs->size);
+}
+

Modified: grass/trunk/lib/vector/Vlib/build_nat.c
===================================================================
--- grass/trunk/lib/vector/Vlib/build_nat.c	2013-05-08 16:32:08 UTC (rev 56165)
+++ grass/trunk/lib/vector/Vlib/build_nat.c	2013-05-08 19:23:05 UTC (rev 56166)
@@ -3,7 +3,7 @@
 
    \brief Vector library - Building topology for native format
 
-   (C) 2001-2012 by the GRASS Development Team
+   (C) 2001-2013 by 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.
@@ -19,6 +19,8 @@
 #include <grass/glocale.h>
 #include <grass/vector.h>
 
+static struct line_pnts *Points;
+
 /*!
    \brief Build topology 
 
@@ -34,7 +36,6 @@
     int i, s, type, line;
     off_t offset;
     int side, area;
-    struct line_pnts *Points;
     struct line_cats *Cats;
     struct P_line *Line;
     struct P_area *Area;
@@ -55,7 +56,8 @@
     }
 
     /* -> upgrade */
-    Points = Vect_new_line_struct();
+    if (!Points)
+        Points = Vect_new_line_struct();
     Cats = Vect_new_cats_struct();
     
     if (plus->built < GV_BUILD_BASE) {
@@ -227,5 +229,51 @@
 	    dig_cidx_add_cat(plus, 0, 0, i, GV_AREA);
     }
 
+    Vect_destroy_cats_struct(Cats);
+    
     return 1;
 }
+
+/*!
+  \brief Get area boundary points (native format)
+  
+  Used by Vect_build_line_area().
+  
+  \param Map pointer to Map_info struct
+  \param lines array of boundary lines
+  \param n_lines number of lines in array
+  \param[out] APoints pointer to output line_pnts struct
+
+  \return number of points
+  \return -1 on error
+*/
+int Vect__get_area_points_nat(struct Map_info *Map, plus_t *lines, int n_lines,
+                              struct line_pnts *APoints)
+{
+    int j, line, direction;
+    struct Plus_head *plus;
+    struct P_line *BLine;
+
+    plus = &(Map->plus);
+    
+    if (!Points)
+        Points = Vect_new_line_struct();
+    
+    Vect_reset_line(APoints);
+    for (j = 0; j < n_lines; j++) {
+	line = abs(lines[j]);
+	BLine = plus->Line[line];
+	G_debug(5, "  line[%d] = %d, offset = %lu", j, line,
+		(unsigned long) BLine->offset);
+	if (0 > Vect_read_line(Map, Points, NULL, line))
+            return -1;
+        
+        direction = lines[j] > 0 ? GV_FORWARD : GV_BACKWARD;
+	Vect_append_points(APoints, Points, direction);
+	APoints->n_points--;	/* skip last point, avoids duplicates */
+    }
+    APoints->n_points++;	/* close polygon */
+
+    return APoints->n_points;
+}
+

Modified: grass/trunk/lib/vector/Vlib/build_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/build_pg.c	2013-05-08 16:32:08 UTC (rev 56165)
+++ grass/trunk/lib/vector/Vlib/build_pg.c	2013-05-08 19:23:05 UTC (rev 56166)
@@ -194,8 +194,10 @@
         
         /* 4) insert faces & update nodes (containing_face) based on
          * GRASS topology */
+        G_message(_("Updating faces..."));
         nareas = Vect_get_num_areas(Map);
         for (area = 1; area <= nareas; area++) {
+            G_percent(area, nareas, 5);
             if (0 == Vect__insert_face_pg(Map, area)) {
                 Vect__execute_pg(pg_info->conn, "ROLLBACK");
                 return 0;
@@ -224,7 +226,9 @@
         }
 
         /* 5) update edges (left and right face) */ 
+        G_message(_("Updating edges..."));
         for (line = 1; line <= plus->n_lines; line++) {
+            G_percent(line, plus->n_lines, 5);
             type = Vect_read_line(Map, NULL, NULL, line); 
             if (type != GV_BOUNDARY)
                 continue;
@@ -274,8 +278,8 @@
         int centroid;
         
         G_message(_("Updating TopoGeometry data..."));
-
         for (area = 1; area <= plus->n_areas; area++) {
+            G_percent(area, plus->n_areas, 5);
             centroid = Vect_get_area_centroid(Map, area);
             if (centroid < 1)
                 continue;
@@ -473,4 +477,81 @@
     return has_topo;
 }
 
+/*!
+  \brief Get area boundary points (PostGIS Topology)
+  
+  Used by Vect_build_line_area().
+
+  \param Map pointer to Map_info struct
+  \param lines array of boundary lines
+  \param n_lines number of lines in array
+  \param[out] APoints pointer to output line_pnts struct
+
+  \return number of points
+  \return -1 on error
+*/
+int Vect__get_area_points_pg(const struct Map_info *Map, const plus_t *lines, int n_lines,
+                             struct line_pnts *APoints)
+{
+
+    int i, line, direction;
+    size_t stmt_id_size;
+    char *stmt, *stmt_id, buf_id[128];
+    
+    const struct Plus_head *plus;
+    struct Format_info_pg *pg_info;
+    struct P_line *BLine;
+    
+    PGresult *res;
+    
+    plus = &(Map->plus);
+    pg_info = (struct Format_info_pg *)&(Map->fInfo.pg);
+    
+    stmt = NULL;
+    stmt_id_size = DB_SQL_MAX;
+    stmt_id = (char *) G_malloc(stmt_id_size);
+    stmt_id[0] = '\0';
+    
+    Vect_reset_line(APoints);
+
+    for (i = 0; i < n_lines; i++) {
+        if (strlen(stmt_id) + 100 > stmt_id_size) {
+            stmt_id_size = strlen(stmt_id) + DB_SQL_MAX;
+            stmt_id = (char *) G_realloc(stmt_id, stmt_id_size);
+        }
+	line = abs(lines[i]);
+        BLine = plus->Line[line];
+        if (i > 0)
+            strcat(stmt_id, ",");
+        sprintf(buf_id, "%d", (int) BLine->offset);
+        strcat(stmt_id, buf_id);
+    }
+    G_asprintf(&stmt, "SELECT geom FROM \"%s\".edge_data WHERE edge_id IN (%s) "
+               "ORDER BY POSITION(edge_id::text in '%s')", pg_info->toposchema_name,
+               stmt_id, stmt_id);
+    G_free(stmt_id);
+    
+    G_debug(2, "SQL: %s", stmt);
+    res = PQexec(pg_info->conn, stmt);
+    G_free(stmt);
+
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
+        PQntuples(res) != n_lines) {
+        if (res)
+            PQclear(res);
+        
+        return -1;
+    }
+    
+    for (i = 0; i < n_lines; i++) {
+        Vect__cache_feature_pg(PQgetvalue(res, i, 0), FALSE, FALSE,
+                               &(pg_info->cache), NULL); /* do caching in readable way */
+	direction = lines[i] > 0 ? GV_FORWARD : GV_BACKWARD;
+	Vect_append_points(APoints, pg_info->cache.lines[0], direction);
+	APoints->n_points--;	/* skip last point, avoids duplicates */
+    }
+    APoints->n_points++;	/* close polygon */
+
+    return APoints->n_points;
+}
 #endif

Modified: grass/trunk/lib/vector/Vlib/build_sfa.c
===================================================================
--- grass/trunk/lib/vector/Vlib/build_sfa.c	2013-05-08 16:32:08 UTC (rev 56165)
+++ grass/trunk/lib/vector/Vlib/build_sfa.c	2013-05-08 19:23:05 UTC (rev 56166)
@@ -329,7 +329,7 @@
     G_zero(&fparts, sizeof(struct feat_parts));
     
     /* get all features */
-    if (Vect__set_initial_query_pg(pg_info, TRUE) != 0)
+    if (Vect__open_cursor_next_line_pg(pg_info, TRUE) != 0)
         return;
     
     /* scan records */
@@ -340,6 +340,10 @@
     for (iFeature = 0; iFeature < nrecords; iFeature++) {
 	/* get feature id */
 	fid  = atoi(PQgetvalue(pg_info->res, iFeature, 1));
+        if (fid < 1)
+            continue; /* PostGIS Topology: skip features with negative
+                       * fid (isles, universal face, ...) */
+
 	wkb_data = PQgetvalue(pg_info->res, iFeature, 0);
 	
 	G_progress(iFeature + 1, 1e4);

Modified: grass/trunk/lib/vector/Vlib/close_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/close_pg.c	2013-05-08 16:32:08 UTC (rev 56165)
+++ grass/trunk/lib/vector/Vlib/close_pg.c	2013-05-08 19:23:05 UTC (rev 56166)
@@ -50,20 +50,24 @@
         Vect_save_frmt(Map);
     }
 
-    /* close connection */
+    /* clear result */
     if (pg_info->res) {
-        char stmt[DB_SQL_MAX];
-
         PQclear(pg_info->res);
         pg_info->res = NULL;
+    }
 
-        sprintf(stmt, "CLOSE %s_%s%p",
-                pg_info->schema_name, pg_info->table_name, pg_info->conn);
+    /* close open cursor */
+    if (pg_info->cursor_name) {
+        char stmt[DB_SQL_MAX];
+        
+        sprintf(stmt, "CLOSE %s", pg_info->cursor_name);
         if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
-            G_warning(_("Unable to close cursor"));
+            G_warning(_("Unable to close cursor %s"), pg_info->cursor_name);
             return -1;
         }
         Vect__execute_pg(pg_info->conn, "COMMIT");
+        G_free(pg_info->cursor_name);
+        pg_info->cursor_name = NULL;
     }
 
     PQfinish(pg_info->conn);

Modified: grass/trunk/lib/vector/Vlib/local_proto.h
===================================================================
--- grass/trunk/lib/vector/Vlib/local_proto.h	2013-05-08 16:32:08 UTC (rev 56165)
+++ grass/trunk/lib/vector/Vlib/local_proto.h	2013-05-08 19:23:05 UTC (rev 56166)
@@ -6,6 +6,12 @@
 /* Internal vector library subroutines which are not part of public
    API*/
 
+/* area.c */
+int Vect__get_area_points(const struct Map_info *, const plus_t *, int, struct line_pnts *);
+
+/* build_nat.c */
+int Vect__get_area_points_nat(const struct Map_info *, const plus_t *, int, struct line_pnts *);
+
 /* map.c */
 int Vect__delete(const char *, int);
 

Modified: grass/trunk/lib/vector/Vlib/open_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open_pg.c	2013-05-08 16:32:08 UTC (rev 56165)
+++ grass/trunk/lib/vector/Vlib/open_pg.c	2013-05-08 19:23:05 UTC (rev 56166)
@@ -1027,6 +1027,7 @@
     G_debug(3, "load_plus(): n_nodes = %d", plus->n_nodes);
     dig_alloc_nodes(plus, plus->n_nodes);
     for (i = 0; i < plus->n_nodes; i++) {
+        G_debug(5, "node: %d", i);
         id = atoi(PQgetvalue(res, i, 0));
         read_p_node(plus, i + 1, /* node index starts at 1 */
                     id, (const char *) PQgetvalue(res, i, 1), pg_info);

Modified: grass/trunk/lib/vector/Vlib/pg_local_proto.h
===================================================================
--- grass/trunk/lib/vector/Vlib/pg_local_proto.h	2013-05-08 16:32:08 UTC (rev 56165)
+++ grass/trunk/lib/vector/Vlib/pg_local_proto.h	2013-05-08 19:23:05 UTC (rev 56166)
@@ -53,21 +53,30 @@
     int            *idx;     /* index in cache where to start */
 };
 
-/* functions used in *_pg.c files */
-int Vect__execute_pg(PGconn *, const char *);
-int Vect__execute_get_value_pg(PGconn *, const char *);
+/* build_pg.c */
+int Vect__get_area_points_pg(const struct Map_info *, const plus_t *, int, struct line_pnts *);
+
+/* read_pg.c */
 SF_FeatureType Vect__cache_feature_pg(const char *, int, int,
                                       struct Format_info_cache *,
                                       struct feat_parts *);
-int Vect__set_initial_query_pg(struct Format_info_pg *, int);
-int Vect__load_plus_pg(struct Map_info *, int);
+int Vect__open_cursor_next_line_pg(struct Format_info_pg *, int);
+int Vect__open_cursor_line_pg(struct Format_info_pg *, int, int);
+int Vect__close_cursor_pg(struct Format_info_pg *);
+int Vect__select_line_pg(struct Format_info_pg *, int, int);
+int Vect__execute_pg(PGconn *, const char *);
+int Vect__execute_get_value_pg(PGconn *, const char *);
 
+/* write_pg.c */
 off_t V2__write_node_pg(struct Map_info *, const struct line_pnts *);
 off_t V2__write_area_pg(struct Map_info *, const struct line_pnts **, int,
                         const struct line_cats *);
-
 int Vect__insert_face_pg(struct Map_info *, int);
 
+/* open_pg.c */
+int Vect__load_plus_pg(struct Map_info *, int);
+int Vect__open_new_pg(struct Map_info *, int);
+
 #endif /* HAVE_POSTGRES */
 
 #endif /* __PG_LOCAL_PROTO_H__ */

Modified: grass/trunk/lib/vector/Vlib/read_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_pg.c	2013-05-08 16:32:08 UTC (rev 56165)
+++ grass/trunk/lib/vector/Vlib/read_pg.c	2013-05-08 19:23:05 UTC (rev 56166)
@@ -32,6 +32,8 @@
 #ifdef HAVE_POSTGRES
 #include "pg_local_proto.h"
 
+/* #define USE_CURSOR_RND */
+
 static unsigned char *wkb_data;
 static unsigned int wkb_data_length;
 
@@ -52,6 +54,7 @@
 static void reallocate_cache(struct Format_info_cache *, int);
 static void add_fpart(struct feat_parts *, SF_FeatureType, int, int);
 static int get_centroid(struct Map_info *, int, struct line_pnts *);
+static void error_tuples(struct Format_info_pg *);
 #endif
 
 /*!
@@ -492,78 +495,42 @@
     int seq_type;
     int force_type; /* force type (GV_BOUNDARY or GV_CENTROID) for topo access only */
     char *data;
-    char stmt[DB_SQL_MAX];
     
     if (!pg_info->geom_column && !pg_info->topogeom_column) {
         G_warning(_("No geometry or topo geometry column defined"));
         return -1;
     }
-    if (fid < 1) {
-        /* next (read n features) */
-        if (!pg_info->res) {
-            if (Vect__set_initial_query_pg(pg_info, FALSE) == -1)
-                return -1;
-        }
+    if (fid < 1) { /* sequantial access */
+        if (pg_info->cursor_name == NULL &&
+            Vect__open_cursor_next_line_pg(pg_info, FALSE) != 0)
+        return -1;
     }
-    else {
-        /* random access */
+    else {         /* random access */
         if (!pg_info->fid_column && !pg_info->toposchema_name) {
             G_warning(_("Random access not supported. "
                         "Primary key not defined."));
             return -1;
         }
 
-        if (Vect__execute_pg(pg_info->conn, "BEGIN") == -1)
+#ifdef USE_CURSOR_RND
+        if (pg_info->cursor_fid > 0)
+            pg_info->next_line = fid - pg_info->cursor_fid;
+        else
+            pg_info->next_line = 0;
+        
+        if (pg_info->next_line < 0 || pg_info->next_line > CURSOR_PAGE)
+            Vect__close_cursor_pg(pg_info);
+        
+        if (pg_info->cursor_name == NULL &&
+            Vect__open_cursor_line_pg(pg_info, fid, type) != 0)
             return -1;
-
-        if (!pg_info->toposchema_name) {
-            /* simple feature access */
-            sprintf(stmt,
-                    "DECLARE %s_%s%p CURSOR FOR SELECT %s FROM \"%s\".\"%s\" "
-                    "WHERE %s = %d", pg_info->schema_name, pg_info->table_name,
-                    pg_info->conn, pg_info->geom_column,
-                    pg_info->schema_name, pg_info->table_name,
-                    pg_info->fid_column, fid);
-        }
-        else {
-            if (!(type & (GV_POINTS | GV_LINES))) {
-                G_warning(_("Unsupported feature type %d"), type);
-                Vect__execute_pg(pg_info->conn, "ROLLBACK");
-                return -1;
-            }
-            
-            if (type & GV_POINTS) {
-                sprintf(stmt,
-                        "DECLARE %s_%s%p CURSOR FOR SELECT geom,containing_face "
-                        " FROM \"%s\".node WHERE node_id = %d",
-                        pg_info->schema_name, pg_info->table_name, pg_info->conn,
-                        pg_info->toposchema_name, fid);
-            }
-            else {
-                sprintf(stmt,
-                        "DECLARE %s_%s%p CURSOR FOR SELECT geom,left_face,right_face "
-                        " FROM \"%s\".edge WHERE edge_id = %d",
-                        pg_info->schema_name, pg_info->table_name, pg_info->conn,
-                        pg_info->toposchema_name, fid);
-            }
-        }
-        G_debug(3, "SQL: %s", stmt);
-        if (Vect__execute_pg(pg_info->conn, stmt) == -1)
+#else
+        pg_info->next_line = 0;
+        if (Vect__select_line_pg(pg_info, fid, type) != 0)
             return -1;
-
-        sprintf(stmt, "FETCH ALL in %s_%s%p",
-                pg_info->schema_name, pg_info->table_name, pg_info->conn);
-        pg_info->res = PQexec(pg_info->conn, stmt);
-        pg_info->next_line = 0;
+#endif
     }
 
-    if (!pg_info->res || PQresultStatus(pg_info->res) != PGRES_TUPLES_OK) {
-        PQclear(pg_info->res);
-        G_warning(_("Reading failed: %s"), PQerrorMessage(pg_info->conn));
-        pg_info->res = NULL;
-        return -1;              /* reading failed */
-    }
-
     /* do we need to fetch more records ? */
     if (PQntuples(pg_info->res) == CURSOR_PAGE &&
         PQntuples(pg_info->res) == pg_info->next_line) {
@@ -571,32 +538,24 @@
 
         PQclear(pg_info->res);
 
-        sprintf(stmt, "FETCH %d in %s_%s%p", CURSOR_PAGE,
-                pg_info->schema_name, pg_info->table_name, pg_info->conn);
+        sprintf(stmt, "FETCH %d in %s", CURSOR_PAGE, pg_info->cursor_name);
+        G_debug(3, "SQL: %s", stmt);
         pg_info->res = PQexec(pg_info->conn, stmt);
-        if (!pg_info->res) {
-            Vect__execute_pg(pg_info->conn, "ROLLBACK");
+        if (!pg_info->res || PQresultStatus(pg_info->res) != PGRES_TUPLES_OK) {
+            error_tuples(pg_info);
             return -1;
         }
         pg_info->next_line = 0;
     }
 
+    G_debug(3, "get_feature(): next_line = %d", pg_info->next_line);
+    
     /* out of results ? */
     if (PQntuples(pg_info->res) == pg_info->next_line) {
-        if (pg_info->res) {
-            PQclear(pg_info->res);
-            pg_info->res = NULL;
-
-            sprintf(stmt, "CLOSE %s_%s%p",
-                    pg_info->schema_name, pg_info->table_name, pg_info->conn);
-            if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
-                Vect__execute_pg(pg_info->conn, "ROLLBACK");
-                G_warning(_("Unable to close cursor"));
-                return -1;
-            }
-            Vect__execute_pg(pg_info->conn, "COMMIT");
-        }
-        return -2;
+        if (Vect__close_cursor_pg(pg_info) != 0)
+            return -1; /* failure */
+        else 
+            return -2; /* nothing to read */
     }
 
     force_type = -1;
@@ -646,19 +605,6 @@
     }
     else {
         pg_info->cache.fid = fid;
-
-        PQclear(pg_info->res);
-        pg_info->res = NULL;
-
-        sprintf(stmt, "CLOSE %s_%s%p",
-                pg_info->schema_name, pg_info->table_name, pg_info->conn);
-        if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
-            G_warning(_("Unable to close cursor"));
-            return -1;
-        }
-
-        if (Vect__execute_pg(pg_info->conn, "COMMIT") == -1)
-            return -1;
     }
     
     return pg_info->cache.sf_type;
@@ -1173,33 +1119,41 @@
 }
 
 /*!
-   \brief Set initial SQL query for sequential access
-
-   \param pg_info pointer to Format_info_pg struct
-
-   \return 0 on success
-   \return -1 on error
- */
-int Vect__set_initial_query_pg(struct Format_info_pg *pg_info, int fetch_all)
+  \brief Create select cursor for sequential access (internal use only)
+  
+  Allocated cursor name should be freed by G_free().
+  
+  \param pg_info pointer to Format_info_pg struct
+  \param fetch_all TRUE to fetch all records
+  \param[out] cursor name
+  
+  \return 0 on success
+  \return -1 on failure
+*/
+int Vect__open_cursor_next_line_pg(struct Format_info_pg *pg_info, int fetch_all)
 {
     char stmt[DB_SQL_MAX];
-
+    
     if (Vect__execute_pg(pg_info->conn, "BEGIN") == -1)
         return -1;
-
+    
+    /* set cursor name */
+    G_asprintf(&(pg_info->cursor_name),
+               "%s_%s_%p",  pg_info->schema_name, pg_info->table_name, pg_info->conn);
+    
     if (!pg_info->toposchema_name) {
-        /* simple feature access */
+        /* simple feature access (geom, fid) */
+        /* TODO: start_fid */
         sprintf(stmt,
-                "DECLARE %s_%s%p CURSOR FOR SELECT %s,%s FROM \"%s\".\"%s\" ORDER BY %s",
-                pg_info->schema_name, pg_info->table_name, pg_info->conn,
-                pg_info->geom_column, pg_info->fid_column, pg_info->schema_name,
+                "DECLARE %s CURSOR FOR SELECT %s,%s FROM \"%s\".\"%s\" ORDER BY %s",
+                pg_info->cursor_name, pg_info->geom_column, pg_info->fid_column, pg_info->schema_name,
                 pg_info->table_name, pg_info->fid_column);
     }
     else {
-        /* topology access */
+        /* topology access (geom,fid,type) */
         /* TODO: optimize SQL statement (for points/centroids) */
         sprintf(stmt,
-                "DECLARE %s_%s%p CURSOR FOR "
+                "DECLARE %s CURSOR FOR "
                 "SELECT geom,fid,type FROM ("
                 "SELECT node_id AS fid,geom, %d AS type FROM \"%s\".node WHERE "
                 "containing_face IS NULL AND node_id NOT IN "
@@ -1214,12 +1168,11 @@
                 "UNION ALL SELECT edge_id AS fid, geom, %d AS type FROM \"%s\".edge WHERE "
                 "left_face = 0 AND right_face = 0 UNION ALL SELECT edge_id AS fid, geom, %d AS type FROM "
                 "\"%s\".edge WHERE left_face != 0 OR right_face != 0 ) AS foo ORDER BY type,fid",
-                pg_info->schema_name, pg_info->table_name, pg_info->conn, GV_POINT,
+                pg_info->cursor_name, GV_POINT,
                 pg_info->toposchema_name, pg_info->toposchema_name, pg_info->toposchema_name,
                 GV_CENTROID, pg_info->toposchema_name, pg_info->toposchema_name, pg_info->toposchema_name,
-                GV_LINE, pg_info->toposchema_name, GV_BOUNDARY, pg_info->toposchema_name); 
+                GV_LINE, pg_info->toposchema_name, GV_BOUNDARY, pg_info->toposchema_name);
     }
-    G_debug(2, "SQL: %s", stmt);
     
     if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
         Vect__execute_pg(pg_info->conn, "ROLLBACK");
@@ -1227,23 +1180,182 @@
     }
 
     if (fetch_all)
-        sprintf(stmt, "FETCH ALL in %s_%s%p",
-                pg_info->schema_name, pg_info->table_name, pg_info->conn);
+        sprintf(stmt, "FETCH ALL in %s", pg_info->cursor_name);
     else
-        sprintf(stmt, "FETCH %d in %s_%s%p", CURSOR_PAGE,
-                pg_info->schema_name, pg_info->table_name, pg_info->conn);
-    pg_info->res = PQexec(pg_info->conn, stmt);
-    if (!pg_info->res) {
+        sprintf(stmt, "FETCH %d in %s", CURSOR_PAGE, pg_info->cursor_name);
+    G_debug(3, "SQL: %s", stmt);
+    pg_info->res = PQexec(pg_info->conn, stmt); /* fetch records from select cursor */
+    if (!pg_info->res || PQresultStatus(pg_info->res) != PGRES_TUPLES_OK) {
+        error_tuples(pg_info);
+        return -1;
+    }
+    pg_info->next_line = 0;
+
+    return 0;
+}
+
+/*!
+  \brief Open select cursor for random access (internal use only)
+
+  Fetch number of feature (given by CURSOR_PAGE) starting with
+  <em>fid</em>.
+
+  Allocated cursor name should be freed by G_free().
+
+  \param pg_info pointer to Format_info_pg struct
+  \param fid feature id to get
+  \param type feature type
+
+  \return 0 on success
+  \return -1 on failure
+*/
+int Vect__open_cursor_line_pg(struct Format_info_pg *pg_info, int fid, int type)
+{
+    char stmt[DB_SQL_MAX];
+    
+    G_debug(3, "Vect__open_cursor_line_pg(): fid range = %d-%d, type = %d",
+            fid, fid + CURSOR_PAGE, type);
+
+    if (Vect__execute_pg(pg_info->conn, "BEGIN") == -1)
+        return -1;
+
+    pg_info->cursor_fid = fid;
+    G_asprintf(&(pg_info->cursor_name),
+               "%s_%s_%d_%p",  pg_info->schema_name, pg_info->table_name, fid, pg_info->conn);
+    
+    if (!pg_info->toposchema_name) {
+        /* simple feature access (geom) */
+        sprintf(stmt,
+                "DECLARE %s CURSOR FOR SELECT %s FROM \"%s\".\"%s\" "
+                "WHERE %s BETWEEN %d AND %d ORDER BY %s", pg_info->cursor_name,
+                pg_info->geom_column, pg_info->schema_name, pg_info->table_name,
+                pg_info->fid_column, fid, fid + CURSOR_PAGE, pg_info->fid_column);
+    }
+    else {
+        /* topological access */
+        if (!(type & (GV_POINTS | GV_LINES))) {
+            G_warning(_("Unsupported feature type %d"), type);
+            Vect__execute_pg(pg_info->conn, "ROLLBACK");
+            return -1;
+        }
+        
+        if (type & GV_POINTS) {
+            /* points (geom,containing_face) */
+            sprintf(stmt,
+                    "DECLARE %s CURSOR FOR SELECT geom,containing_face "
+                    " FROM \"%s\".node WHERE node_id BETWEEN %d AND %d ORDER BY node_id",
+                    pg_info->cursor_name,
+                    pg_info->toposchema_name, fid, fid + CURSOR_PAGE);
+        }
+        else {
+            /* edges (geom,left_face,right_face) */
+            sprintf(stmt,
+                    "DECLARE %s CURSOR FOR SELECT geom,left_face,right_face "
+                    " FROM \"%s\".edge WHERE edge_id BETWEEN %d AND %d ORDER BY edge_id",
+                    pg_info->cursor_name,
+                    pg_info->toposchema_name, fid, fid + CURSOR_PAGE);
+        }
+    }
+    if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
         Vect__execute_pg(pg_info->conn, "ROLLBACK");
-        G_warning(_("Unable to get features"));
         return -1;
     }
     pg_info->next_line = 0;
 
+    sprintf(stmt, "FETCH ALL in %s", pg_info->cursor_name);
+    pg_info->res = PQexec(pg_info->conn, stmt);
+    if (!pg_info->res || PQresultStatus(pg_info->res) != PGRES_TUPLES_OK) {
+        error_tuples(pg_info);
+        return -1;
+    }
+    
     return 0;
 }
 
 /*!
+  \brief Close select cursor
+
+  \param pg_info pointer to Format_info_pg struct
+
+  \return 0 on success
+  \return -1 on failure
+*/ 
+int Vect__close_cursor_pg(struct Format_info_pg *pg_info)
+{
+    if (pg_info->res) {
+        PQclear(pg_info->res);
+        pg_info->res = NULL;
+    }
+    
+    if (pg_info->cursor_name) {
+        char stmt[DB_SQL_MAX];
+        
+        sprintf(stmt, "CLOSE %s", pg_info->cursor_name);
+        if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
+            G_warning(_("Unable to close cursor %s"), pg_info->cursor_name);
+            return -1;
+        }
+        Vect__execute_pg(pg_info->conn, "COMMIT");
+        G_free(pg_info->cursor_name);
+        pg_info->cursor_name = NULL;
+    }
+    
+    return 0;
+}
+
+/*!
+  \brief Select feature (internal use only)
+
+  \param pg_info pointer to Format_info_pg struct
+  \param fid feature id to get
+  \param type feature type
+
+  \return 0 on success
+  \return -1 on failure
+*/
+int Vect__select_line_pg(struct Format_info_pg *pg_info, int fid, int type)
+{
+    char stmt[DB_SQL_MAX];
+    
+    if (!pg_info->toposchema_name) {
+        /* simple feature access */
+        sprintf(stmt,
+                "SELECT %s FROM \"%s\".\"%s\" WHERE %s = %d",
+                pg_info->geom_column, pg_info->schema_name, pg_info->table_name,
+                pg_info->fid_column, fid);
+    }
+    else {
+        /* topological access */
+        if (!(type & (GV_POINTS | GV_LINES))) {
+            G_warning(_("Unsupported feature type %d"), type);
+            return -1;
+        }
+        
+        if (type & GV_POINTS) {
+            sprintf(stmt,
+                    "SELECT geom,containing_face FROM \"%s\".node WHERE node_id = %d",
+                    pg_info->toposchema_name, fid);
+        }
+        else {
+            sprintf(stmt,
+                    "SELECT geom,left_face,right_face FROM \"%s\".edge WHERE edge_id = %d",
+                    pg_info->toposchema_name, fid);
+        }
+    }
+    G_debug(3, "SQL: %s", stmt);
+    
+    pg_info->next_line = 0;
+    
+    pg_info->res = PQexec(pg_info->conn, stmt);
+    if (!pg_info->res || PQresultStatus(pg_info->res) != PGRES_TUPLES_OK) {
+        error_tuples(pg_info);
+        return -1;
+    }
+    
+    return 0;
+}
+
+/*!
    \brief Execute SQL statement
 
    See pg_local_proto.h
@@ -1264,7 +1376,7 @@
     result = PQexec(conn, stmt);
     if (!result || PQresultStatus(result) != PGRES_COMMAND_OK) {
         PQclear(result);
-
+        
         G_warning(_("Execution failed: %s"), PQerrorMessage(conn));
         return -1;
     }
@@ -1415,4 +1527,16 @@
     
     return GV_CENTROID;
 }
+
+void error_tuples(struct Format_info_pg *pg_info)
+{
+    if (pg_info->res) {
+        PQclear(pg_info->res);
+        pg_info->res = NULL;
+    }
+    
+    Vect__execute_pg(pg_info->conn, "ROLLBACK");
+    G_warning(_("Unable to read PostGIS features\n%s"),
+              PQresultErrorMessage(pg_info->res));
+}
 #endif

Modified: grass/trunk/lib/vector/Vlib/rewind_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/rewind_pg.c	2013-05-08 16:32:08 UTC (rev 56165)
+++ grass/trunk/lib/vector/Vlib/rewind_pg.c	2013-05-08 19:23:05 UTC (rev 56166)
@@ -46,22 +46,7 @@
     pg_info->cache.fid = -1;
 
     /* close DB cursor if necessary */
-    if (pg_info->res) {
-        char stmt[DB_SQL_MAX];
-
-        PQclear(pg_info->res);
-        pg_info->res = NULL;
-
-        sprintf(stmt, "CLOSE %s_%s%p",
-                pg_info->schema_name, pg_info->table_name, pg_info->conn);
-        if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
-            G_warning(_("Unable to close cursor"));
-            return -1;
-        }
-        Vect__execute_pg(pg_info->conn, "COMMIT");
-    }
-
-    return 0;
+    return Vect__close_cursor_pg(pg_info);
 #else
     G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
     return -1;



More information about the grass-commit mailing list