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

svn_grass at osgeo.org svn_grass at osgeo.org
Sun Nov 24 08:26:40 PST 2013


Author: martinl
Date: 2013-11-24 08:26:40 -0800 (Sun, 24 Nov 2013)
New Revision: 58290

Modified:
   grass/trunk/include/vect/dig_structs.h
   grass/trunk/lib/vector/Vlib/area.c
   grass/trunk/lib/vector/Vlib/build_pg.c
   grass/trunk/lib/vector/Vlib/close.c
   grass/trunk/lib/vector/Vlib/close_ogr.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: speed up PostGIS Topology by caching lines (experimental, work in progress)


Modified: grass/trunk/include/vect/dig_structs.h
===================================================================
--- grass/trunk/include/vect/dig_structs.h	2013-11-24 15:46:40 UTC (rev 58289)
+++ grass/trunk/include/vect/dig_structs.h	2013-11-24 16:26:40 UTC (rev 58290)
@@ -465,8 +465,13 @@
     /*!
       \brief Lines array
       
-      Some features requires more allocated lines (eg. polygon
+      Some simple features require more allocated lines (eg. polygon
       with more rings, multipoint, or geometrycollection)
+
+      Line cache is also used for PostGIS Topology to store single
+      topological element (ctype == CACHE_FEATURE) or all elements
+      from the map (ctype == CACHE_MAP) to avoid random access which
+      is very costly.
     */
     struct line_pnts **lines;
     /*!
@@ -497,6 +502,12 @@
       \brief Simple feature type (currently used only by PG format)
     */
     SF_FeatureType sf_type;
+    /*! 
+      \brief Cache type
+
+      Currenly used only by PostGIS Topology which allows to cache the
+      whole map (CACHE_MAP) */
+    int ctype;
 };
 
 /*!

Modified: grass/trunk/lib/vector/Vlib/area.c
===================================================================
--- grass/trunk/lib/vector/Vlib/area.c	2013-11-24 15:46:40 UTC (rev 58289)
+++ grass/trunk/lib/vector/Vlib/area.c	2013-11-24 16:26:40 UTC (rev 58290)
@@ -85,7 +85,8 @@
     G_debug(3, "  n_lines = %d", Isle->n_lines);
 
     if (Map->format == GV_FORMAT_POSTGIS &&
-        Map->fInfo.pg.toposchema_name) {
+        Map->fInfo.pg.toposchema_name &&
+        Map->fInfo.pg.cache.ctype != CACHE_MAP) {
 #ifdef HAVE_POSTGRES
         /* PostGIS Topology */
         return Vect__get_area_points_pg(Map, Isle->lines, Isle->n_lines, BPoints);
@@ -456,7 +457,8 @@
                           struct line_pnts *BPoints)
 {
     if (Map->format == GV_FORMAT_POSTGIS &&
-        Map->fInfo.pg.toposchema_name) {
+        Map->fInfo.pg.toposchema_name &&
+        Map->fInfo.pg.cache.ctype != CACHE_MAP) {
 #ifdef HAVE_POSTGRES
         /* PostGIS Topology */
         return Vect__get_area_points_pg(Map, lines, n_lines, BPoints);

Modified: grass/trunk/lib/vector/Vlib/build_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/build_pg.c	2013-11-24 15:46:40 UTC (rev 58289)
+++ grass/trunk/lib/vector/Vlib/build_pg.c	2013-11-24 16:26:40 UTC (rev 58290)
@@ -547,8 +547,10 @@
     const struct Format_info_offset *offset;
 
     offset = &(pg_info->offset);
-    if (plus->n_nodes != offset->array_num)
+    if (plus->n_nodes != offset->array_num) {
+        G_warning(_("Unable to write nodes, offset array mismatch"));
         return -1;
+    }
     
     stmt_size = 2 * DB_SQL_MAX + 512;
     stmt = (char *) G_malloc(stmt_size);
@@ -575,6 +577,7 @@
                 "%d, '{%s}', '{%s}')", pg_info->toposchema_name, TOPO_TABLE_NODE,
                 node_id, stmt_lines, stmt_angles);
         if (Vect__execute_pg(pg_info->conn, stmt) == -1) {
+            G_warning(_("Unable to write nodes"));
             return -1;
         }
     }

Modified: grass/trunk/lib/vector/Vlib/close.c
===================================================================
--- grass/trunk/lib/vector/Vlib/close.c	2013-11-24 15:46:40 UTC (rev 58289)
+++ grass/trunk/lib/vector/Vlib/close.c	2013-11-24 16:26:40 UTC (rev 58290)
@@ -292,6 +292,21 @@
     return 1;
 }
 
+/*! Free memory of line cache
+
+  \param cache pointer to lines cache to be freed
+*/
+void Vect__free_cache(struct Format_info_cache *cache) {
+    int i;
+    /* destroy lines in cache */
+    for (i = 0; i < cache->lines_alloc; i++) {
+	Vect_destroy_line_struct(cache->lines[i]);
+    }
+    G_free(cache->lines);
+    G_free(cache->lines_types);
+    G_free(cache->lines_cats);
+}
+
 void unlink_file(const struct Map_info *Map, const char *name)
 {
     char *path;

Modified: grass/trunk/lib/vector/Vlib/close_ogr.c
===================================================================
--- grass/trunk/lib/vector/Vlib/close_ogr.c	2013-11-24 15:46:40 UTC (rev 58289)
+++ grass/trunk/lib/vector/Vlib/close_ogr.c	2013-11-24 16:26:40 UTC (rev 58290)
@@ -22,6 +22,8 @@
 #include <ogr_api.h>
 #endif
 
+#include "local_proto.h"
+
 /*!
   \brief Close vector map (OGR dsn & layer) on level 1
 
@@ -33,8 +35,6 @@
 int V1_close_ogr(struct Map_info *Map)
 {
 #ifdef HAVE_OGR
-    int i;
-
     struct Format_info_ogr *ogr_info;
     
     G_debug(3, "V1_close_ogr() name = %s mapset = %s", Map->name, Map->mapset);
@@ -58,14 +58,9 @@
 
     /* destroy OGR datasource */
     OGR_DS_Destroy(ogr_info->ds);
+
+    Vect__free_cache(&(ogr_info->cache));
     
-    /* destroy lines in cache */
-    for (i = 0; i < ogr_info->cache.lines_alloc; i++) {
-	Vect_destroy_line_struct(ogr_info->cache.lines[i]);
-    }
-    G_free(ogr_info->cache.lines);
-    G_free(ogr_info->cache.lines_types);
-    
     /* close DB connection (for atgtributes) */
     if (ogr_info->dbdriver) {
 	db_close_database_shutdown_driver(ogr_info->dbdriver);

Modified: grass/trunk/lib/vector/Vlib/close_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/close_pg.c	2013-11-24 15:46:40 UTC (rev 58289)
+++ grass/trunk/lib/vector/Vlib/close_pg.c	2013-11-24 16:26:40 UTC (rev 58290)
@@ -19,6 +19,8 @@
 #include <grass/dbmi.h>
 #include <grass/glocale.h>
 
+#include "local_proto.h"
+
 #ifdef HAVE_POSTGRES
 #include "pg_local_proto.h"
 #endif
@@ -34,7 +36,6 @@
 int V1_close_pg(struct Map_info *Map)
 {
 #ifdef HAVE_POSTGRES
-    int i;
     struct Format_info_pg *pg_info;
 
     G_debug(3, "V2_close_pg() name = %s mapset = %s", Map->name, Map->mapset);
@@ -77,13 +78,8 @@
         db_close_database_shutdown_driver(pg_info->dbdriver);
     }
 
-    /* free allocated space */
-    for (i = 0; i < pg_info->cache.lines_alloc; i++) {
-        Vect_destroy_line_struct(pg_info->cache.lines[i]);
-    }
-    if (pg_info->cache.lines)
-        G_free(pg_info->cache.lines);
-
+    Vect__free_cache(&(pg_info->cache));
+    
     G_free(pg_info->db_name);
     G_free(pg_info->schema_name);
     G_free(pg_info->geom_column);

Modified: grass/trunk/lib/vector/Vlib/local_proto.h
===================================================================
--- grass/trunk/lib/vector/Vlib/local_proto.h	2013-11-24 15:46:40 UTC (rev 58289)
+++ grass/trunk/lib/vector/Vlib/local_proto.h	2013-11-24 16:26:40 UTC (rev 58290)
@@ -10,6 +10,9 @@
 int Vect__get_area_points(const struct Map_info *, const plus_t *, int, struct line_pnts *);
 int Vect__get_area_points_nat(const struct Map_info *, const plus_t *, int, struct line_pnts *);
 
+/* close.c */
+void Vect__free_cache(struct Format_info_cache *);
+
 /* 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-11-24 15:46:40 UTC (rev 58289)
+++ grass/trunk/lib/vector/Vlib/open_pg.c	2013-11-24 16:26:40 UTC (rev 58290)
@@ -20,11 +20,14 @@
 #include <grass/dbmi.h>
 #include <grass/glocale.h>
 
+#include "local_proto.h"
+
 #ifdef HAVE_POSTGRES
 #include "pg_local_proto.h"
 
-struct edge_data {
+struct line_data {
     int id;
+    int fid;
     int start_node;
     int end_node;
     int left_face;
@@ -42,7 +45,7 @@
                                   const char *, const char *, const char *,
                                   struct Format_info_pg *);
 static struct P_line *read_p_line(struct Plus_head *, int,
-                                  const struct edge_data *,
+                                  const struct line_data *,
                                   struct Format_info_cache *);
 static struct P_area *read_p_area(struct Plus_head *, int,
                                   const char *, int, const char *);
@@ -52,7 +55,8 @@
 static void notice_processor(void *, const char *);
 static char **scan_array(const char *);
 static int remap_node(const struct Format_info_offset *, int);
-static int remap_line(const struct Plus_head*, int, int);
+static int remap_line(const struct Plus_head*, off_t, int);
+static void reset_cache(struct Format_info_cache *);
 #endif
 
 /*!
@@ -137,7 +141,7 @@
     if (!found) {
         G_warning(_("Feature table <%s> not found in 'geometry_columns'"),
                   pg_info->table_name);
-        return -1;
+        return 0; /* avoid calling G_fatal_error() */
     }
 
     /* check for topo schema */
@@ -805,10 +809,10 @@
   \return NULL on error
 */
 struct P_line *read_p_line(struct Plus_head *plus, int n,
-                           const struct edge_data *data,
+                           const struct line_data *data,
                            struct Format_info_cache *cache)
 {
-    int tp, itype;
+    int tp;
     struct P_line *line;
     
     struct line_pnts *points;
@@ -875,14 +879,10 @@
         }
     }
 
-    /* update spatial index */
-    Vect__cache_feature_pg(data->wkb_geom, FALSE, FALSE, cache, NULL);
-    itype = cache->lines_types[0];
-    if ((line->type & GV_POINTS && itype != GV_POINT) ||
-        (line->type & GV_LINES  && itype != GV_LINE))
-        G_warning(_("Inconsistency in topology: line %d - unexpected feature type"), n);
-    
-    points = cache->lines[0];
+    Vect__cache_feature_pg(data->wkb_geom, FALSE, tp, cache, NULL);
+    cache->lines_cats[cache->lines_num-1] = data->fid > 0 ? data->fid : -1;
+
+    points = cache->lines[cache->lines_num-1];
     dig_line_box(points, &box);
     dig_spidx_add_line(plus, n, &box);
 
@@ -949,7 +949,7 @@
 
     /* set centroid */
     area->centroid = remap_line(plus, centroid, GV_CENTROID);
-    
+
     G_free_tokens(lines);
     G_free_tokens(isles);
 
@@ -1194,7 +1194,7 @@
 {
     int i, side, line, id, ntuples;
     char stmt[DB_SQL_MAX];
-    struct edge_data line_data;
+    struct line_data line_data;
     
     struct Format_info_pg *pg_info;
     struct Format_info_offset *offset;
@@ -1217,7 +1217,7 @@
     
     Points = Vect_new_line_struct();
     List = Vect_new_list();
-        
+    
     /* read nodes (GRASS Topo)
        note: standalone nodes (ie. points/centroids) are ignored
     */
@@ -1276,18 +1276,25 @@
     */
     if (pg_info->topo_geo_only)
         sprintf(stmt,
-                "SELECT node_id,geom FROM \"%s\".node WHERE containing_face "
+                "SELECT tt.node_id,tt.geom,ft.%s FROM \"%s\".node AS tt "
+                "LEFT JOIN \"%s\" AS ft ON "
+                "(%s).type = 1 AND (%s).id = node_id WHERE containing_face "
                 "IS NULL AND node_id NOT IN "
                 "(SELECT node FROM (SELECT start_node AS node FROM \"%s\".edge "
                 "GROUP BY start_node UNION ALL SELECT end_node AS node FROM "
                 "\"%s\".edge GROUP BY end_node) AS foo) ORDER BY node_id",
-                pg_info->toposchema_name, pg_info->toposchema_name,
+                "fid", pg_info->toposchema_name, pg_info->table_name,
+                pg_info->topogeom_column, pg_info->topogeom_column, pg_info->toposchema_name,
                 pg_info->toposchema_name);
     else
         sprintf(stmt,
-                "SELECT node.node_id,geom FROM \"%s\".node AS node WHERE node_id NOT IN "
+                "SELECT tt.node_id,tt.geom,ft.%s "
+                "FROM \"%s\".node AS tt LEFT JOIN \"%s\" AS ft ON "
+                "(%s).type = 1 AND (%s).id = node_id WHERE node_id NOT IN "
                 "(SELECT node_id FROM \"%s\".%s) AND containing_face IS NULL ORDER BY node_id",
-                pg_info->toposchema_name, pg_info->toposchema_name, TOPO_TABLE_NODE);
+                "fid", pg_info->toposchema_name,  pg_info->table_name,
+                pg_info->topogeom_column, pg_info->topogeom_column,
+                pg_info->toposchema_name, TOPO_TABLE_NODE);
     G_debug(2, "SQL: %s", stmt);
     res = PQexec(pg_info->conn, stmt);
     if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
@@ -1300,12 +1307,17 @@
         return -1;
     }
     
+    reset_cache(&(pg_info->cache));
+    pg_info->cache.ctype = CACHE_MAP; /* experimental - cache all features */
+    
     ntuples = PQntuples(res); /* plus->n_plines */
-    G_zero(&line_data, sizeof(struct edge_data));
+    G_zero(&line_data, sizeof(struct line_data));
     for (i = 0; i < ntuples; i++) {
         /* process standalone nodes (PostGIS Topo) */
         line_data.id = atoi(PQgetvalue(res, i, 0));
         line_data.wkb_geom = (char *) PQgetvalue(res, i, 1);
+        line_data.fid = atoi(PQgetvalue(res, i, 2)); /* feature id */
+
         read_p_line(plus, i + 1, &line_data, &(pg_info->cache));
     }
     PQclear(res);
@@ -1314,10 +1326,12 @@
        -> lines
        -> boundaries
     */
-    sprintf(stmt,
-            "SELECT edge_id,start_node,end_node,left_face,right_face,geom "
-            "FROM \"%s\".edge ORDER BY edge_id",
-            pg_info->toposchema_name);
+    sprintf(stmt, /* fix fid column */
+            "SELECT edge_id,start_node,end_node,left_face,right_face,tt.geom,ft.%s "
+            "FROM \"%s\".edge AS tt LEFT JOIN \"%s\" AS ft ON (%s).type = 2 AND "
+            "(%s).id = edge_id ORDER BY edge_id",
+            "fid", pg_info->toposchema_name, pg_info->table_name,
+            pg_info->topogeom_column, pg_info->topogeom_column);
     G_debug(2, "SQL: %s", stmt);
     res = PQexec(pg_info->conn, stmt);
     if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
@@ -1339,7 +1353,8 @@
         line_data.left_face  = atoi(PQgetvalue(res, i, 3));
         line_data.right_face = atoi(PQgetvalue(res, i, 4));
         line_data.wkb_geom   = (char *) PQgetvalue(res, i, 5);
-        
+        line_data.fid        = atoi(PQgetvalue(res, i, 6)); /* feature id */
+
         id = plus->n_plines + i + 1; /* points already registered */
         read_p_line(plus, id, &line_data, &(pg_info->cache));
         /* TODO: update category index */
@@ -1351,19 +1366,27 @@
     */
     if (pg_info->topo_geo_only)
         sprintf(stmt,
-                "SELECT node_id,geom,containing_face FROM \"%s\".node WHERE containing_face "
+                "SELECT node_id,tt.geom,containing_face,ft.%s FROM "
+                "\"%s\".node AS tt LEFT JOIN \"%s\" AS ft ON "
+                "(%s).type = 3 AND (%s).id = containing_face WHERE containing_face"
                 "IS NOT NULL AND node_id NOT IN "
                 "(SELECT node FROM (SELECT start_node AS node FROM \"%s\".edge "
                 "GROUP BY start_node UNION ALL SELECT end_node AS node FROM "
                 "\"%s\".edge GROUP BY end_node) AS foo) ORDER BY node_id",
-                pg_info->toposchema_name, pg_info->toposchema_name,
+                "fid", pg_info->toposchema_name, pg_info->table_name,
+                pg_info->topogeom_column, pg_info->topogeom_column,
+                pg_info->toposchema_name,
                 pg_info->toposchema_name);
     else
         sprintf(stmt,
-                "SELECT node.node_id,geom,containing_face FROM \"%s\".node AS node WHERE "
+                "SELECT tt.node_id,tt.geom,containing_face,ft.%s FROM "
+                "\"%s\".node AS tt LEFT JOIN \"%s\" AS ft ON "
+                "(%s).type = 3 AND (%s).id = containing_face WHERE "
                 "node_id NOT IN (SELECT node_id FROM \"%s\".%s) AND containing_face "
                 "IS NOT NULL ORDER BY node_id",
-                pg_info->toposchema_name, pg_info->toposchema_name, TOPO_TABLE_NODE);
+                "fid", pg_info->toposchema_name, pg_info->table_name,
+                pg_info->topogeom_column, pg_info->topogeom_column,
+                pg_info->toposchema_name, TOPO_TABLE_NODE);
     G_debug(2, "SQL: %s", stmt);
     res = PQexec(pg_info->conn, stmt);
     if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
@@ -1376,12 +1399,13 @@
         return -1;
     }
     
-    G_zero(&line_data, sizeof(struct edge_data));
+    G_zero(&line_data, sizeof(struct line_data));
     id = plus->n_plines + plus->n_llines + plus->n_blines + 1;
     for (i = 0; i < plus->n_clines; i++) {
         line_data.id = atoi(PQgetvalue(res, i, 0)); 
         line_data.wkb_geom = (char *)PQgetvalue(res, i, 1);
         line_data.left_face = atoi(PQgetvalue(res, i, 2)); /* face id */
+        line_data.fid = atoi(PQgetvalue(res, i, 3)); /* feature id */
         /* area id and face id can be different */
         
         read_p_line(plus, id + i, &line_data, &(pg_info->cache));
@@ -1431,6 +1455,12 @@
         for (i = 0; i < plus->n_areas; i++) {
             read_p_area(plus, i + 1, (char *)PQgetvalue(res, i, 1),
                         atoi(PQgetvalue(res, i, 2)), (char *)PQgetvalue(res, i, 3));
+            
+            /* update spatial index -- needed ?
+            Vect_get_area_points(Map, i+1, Points);
+            dig_line_box(Points, &box);
+            dig_spidx_add_area(&(Map->plus), i+1, &box);
+            */
         }
         PQclear(res);
     }
@@ -1463,6 +1493,12 @@
         for (i = 0; i < plus->n_isles; i++) {
             read_p_isle(plus, i + 1, (char *)PQgetvalue(res, i, 1),
                         atoi(PQgetvalue(res, i, 2)));
+
+            /* update spatial index -- needed ?
+            Vect_get_isle_points(Map, i+1, Points);
+            dig_line_box(Points, &box);
+            dig_spidx_add_isle(&(Map->plus), i+1, &box);
+            */
         }
         PQclear(res);
     }
@@ -1544,8 +1580,6 @@
 /*!
   \brief Get node id from offset
 
-  \todo speed up
-
   \param offset pointer to Format_info_offset struct
   \param node node to find
 
@@ -1554,44 +1588,53 @@
 */
 int remap_node(const struct Format_info_offset *offset, int node)
 {
+    /* probably not needed
     int i;
-    
-    for (i = 0; i < offset->array_num; i++) {
+    for (i = node-1; i < offset->array_num; i++) {
         if (offset->array[i] == node)
-            return i + 1; /* node id starts at 1 */
+            return i + 1; 
     }
+    
+    return -1;
+    */
 
-    return -1;
+    return offset->array[node-1];
 }
 
 /*!
   \brief Get line id from offset
 
-  \todo Do it better, speed up
-
   \param plus pointer to Plus_head struct
-  \param line line to find
+  \param offset line offset
   \param type line type
 
   \return line id
   \return -1 not found
 */
-int remap_line(const struct Plus_head* plus, int line, int type)
+int remap_line(const struct Plus_head* plus, off_t offset, int type)
 {
     int i;
     
     struct P_line *Line;
     
-    for (i = 1; i <= plus->n_lines; i++) {
+    for (i = (int) offset; i <= plus->n_lines; i++) {
         Line = plus->Line[i];
         
         if (!Line || Line->type != type)
             continue;
         
-        if ((int) Line->offset == line)
+        if ((int) Line->offset == offset)
             return i;
     }
 
     return -1;
 }
+
+/*! Reset lines cache */
+void reset_cache(struct Format_info_cache *cache)
+{
+    Vect__free_cache(cache);
+    G_zero(cache, sizeof(struct Format_info_cache));
+    cache->fid = -1;
+}
 #endif

Modified: grass/trunk/lib/vector/Vlib/pg_local_proto.h
===================================================================
--- grass/trunk/lib/vector/Vlib/pg_local_proto.h	2013-11-24 15:46:40 UTC (rev 58289)
+++ grass/trunk/lib/vector/Vlib/pg_local_proto.h	2013-11-24 16:26:40 UTC (rev 58290)
@@ -8,6 +8,9 @@
 
 #define CURSOR_PAGE 500
 
+#define CACHE_FEATURE 0
+#define CACHE_MAP     1
+
 /*! Topological access */
 #define TOPO_SCHEMA "topology"
 #define TOPO_ID     "topology_id"

Modified: grass/trunk/lib/vector/Vlib/read_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_pg.c	2013-11-24 15:46:40 UTC (rev 58289)
+++ grass/trunk/lib/vector/Vlib/read_pg.c	2013-11-24 16:26:40 UTC (rev 58290)
@@ -51,7 +51,7 @@
                                         struct Format_info_cache *,
                                         struct feat_parts *);
 static int error_corrupted_data(const char *);
-static void reallocate_cache(struct Format_info_cache *, int);
+static void reallocate_cache(struct Format_info_cache *, int, 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 *);
@@ -319,7 +319,7 @@
                     struct line_cats *line_c, int line)
 {
 #ifdef HAVE_POSTGRES
-    int fid;
+    int fid, cache_idx;
     
     struct Format_info_pg *pg_info;
     struct P_line *Line;
@@ -357,8 +357,18 @@
         fid = pg_info->offset.array[Line->offset];
 
     /* read feature */
-    get_feature(pg_info, fid, Line->type);
-    
+    if (pg_info->cache.ctype == CACHE_MAP) {
+        cache_idx = line - 1;
+        
+        if (pg_info->cache.lines_types[cache_idx] != Line->type)
+            G_warning(_("Feature %d: unexpected type (%d) - should be %d"), 
+                      line, pg_info->cache.lines_types[cache_idx], Line->type);
+    }
+    else {
+        get_feature(pg_info, fid, Line->type);
+        cache_idx = 0;
+    }
+
     /* check sf type */
     if (pg_info->cache.sf_type == SF_NONE) {
         G_warning(_("Feature %d without geometry skipped"), line);
@@ -371,16 +381,31 @@
         int cat;
 
         Vect_reset_cats(line_c);
-        if (!pg_info->toposchema_name) /* simple features access */
+        if (!pg_info->toposchema_name) { /* simple features access */
             cat = (int) Line->offset;
-        else                           /* PostGIS Topology (cats are cached) */
-            cat = pg_info->cache.lines_cats[0];
-        if (cat != -1)
+        }
+        else {                           /* PostGIS Topology (cats are cached) */
+            cat = pg_info->cache.lines_cats[cache_idx];
+            if (cat == 0) { /* not cached yet */
+                int col_idx;
+
+                Vect__select_line_pg(pg_info, fid, Line->type);
+             
+                col_idx = Line->type & GV_POINTS ? 2 : 3;
+                
+                if (!PQgetisnull(pg_info->res, 0, col_idx))
+                    cat = pg_info->cache.lines_cats[cache_idx] =
+                        atoi(PQgetvalue(pg_info->res, 0, col_idx)); 
+                else
+                    pg_info->cache.lines_cats[cache_idx] = -1; /* no cat */   
+            }
+        }
+        if (cat > 0)
             Vect_cat_set(line_c, 1, cat);
     }
 
     if (line_p)
-        Vect_append_points(line_p, pg_info->cache.lines[0], GV_FORWARD);
+        Vect_append_points(line_p, pg_info->cache.lines[cache_idx], GV_FORWARD);
     
     return Line->type;
 #else
@@ -428,7 +453,8 @@
             Vect_reset_cats(line_c);
 
         /* read feature to cache if necessary */
-        while (pg_info->cache.lines_next == pg_info->cache.lines_num) {
+        while (pg_info->cache.ctype != CACHE_MAP &&
+               pg_info->cache.lines_next == pg_info->cache.lines_num) {
             /* cache feature -> line_p & line_c */
             sf_type = get_feature(pg_info, -1, -1);
             
@@ -480,11 +506,24 @@
 
         if (line_c) {
             int cat;
-            if (!pg_info->toposchema_name) /* simple features access */
+            if (!pg_info->toposchema_name) { /* simple features access */
                 cat = (int)pg_info->cache.fid;
-            else                           /* PostGIS Topology (cats are cached) */
+            }
+            else {                           /* PostGIS Topology (cats are cached) */
                 cat = pg_info->cache.lines_cats[pg_info->cache.lines_next];
-            if (cat != -1)
+                if (cat == 0) { /* not cached yet */
+                    int col_idx;
+                    
+                    col_idx = itype & GV_POINTS ? 2 : 3;
+                
+                    if (!PQgetisnull(pg_info->res, pg_info->cache.lines_next, col_idx))
+                        cat = pg_info->cache.lines_cats[Map->next_line-1] =
+                        atoi(PQgetvalue(pg_info->res, pg_info->cache.lines_next, col_idx)); 
+                    else
+                        pg_info->cache.lines_cats[Map->next_line-1] = -1; /* no cat */ 
+                }
+            }
+            if (cat > 0)
                 Vect_cat_set(line_c, 1, cat);
         }
 
@@ -663,8 +702,7 @@
     *nbytes = length - 1;
     for (i = 0; i < (*nbytes); i++) {
         wkb_data[i] =
-            (unsigned
-             char)((hex_data[2 * i] >
+            (unsigned char)((hex_data[2 * i] >
                     'F' ? hex_data[2 * i] - 0x57 : hex_data[2 * i] >
                     '9' ? hex_data[2 * i] - 0x37 : hex_data[2 * i] -
                     0x30) << 4);
@@ -707,7 +745,10 @@
     SF_FeatureType ftype;
 
     /* reset cache */
-    cache->lines_num = 0;
+    if (cache->ctype == CACHE_MAP)
+        cache->lines_num++;
+    else
+        cache->lines_num = 1;
     cache->fid = -1;
     /* next to be read from cache */
     cache->lines_next = 0;
@@ -782,28 +823,32 @@
        more lines require eg. polygon with more rings, multi-features
        or geometry collections
      */
-    if (!cache->lines) {
-        reallocate_cache(cache, 1);
+    if (cache->ctype == CACHE_MAP) {
+        reallocate_cache(cache, 1, TRUE);
     }
-
+    else {
+        if (!cache->lines) {
+            reallocate_cache(cache, 1, FALSE);
+        }
+    }
+    
     ret = -1;
     if (ftype == SF_POINT) {
-        cache->lines_num = 1;
-        cache->lines_types[0] = force_type == GV_CENTROID ? force_type : GV_POINT;
+        cache->lines_types[cache->lines_num-1] = force_type == GV_CENTROID ? force_type : GV_POINT;
         ret = point_from_wkb(wkb_data, nbytes, byte_order,
-                             is3D, cache->lines[0]);
+                             is3D, cache->lines[cache->lines_num-1]);
         add_fpart(fparts, ftype, 0, 1);
     }
     else if (ftype == SF_LINESTRING) {
-        cache->lines_num = 1;
-        cache->lines_types[0] = force_type == GV_BOUNDARY ? force_type : GV_LINE;
+        cache->lines_types[cache->lines_num-1] = force_type == GV_BOUNDARY ? force_type : GV_LINE;
         ret = linestring_from_wkb(wkb_data, nbytes, byte_order,
-                                  is3D, cache->lines[0], FALSE);
+                                  is3D, cache->lines[cache->lines_num-1], FALSE);
         add_fpart(fparts, ftype, 0, 1);
     }
     else if (ftype == SF_POLYGON && !skip_polygon) {
         int nrings;
 
+        cache->lines_num = 0; /* reset before reading rings */
         ret = polygon_from_wkb(wkb_data, nbytes, byte_order,
                                is3D, cache, &nrings);
         add_fpart(fparts, ftype, 0, nrings);
@@ -988,7 +1033,7 @@
     }
 
     /* reallocate space for islands if needed */
-    reallocate_cache(cache, *nrings);
+    reallocate_cache(cache, *nrings, FALSE);
     cache->lines_num += *nrings;
 
     /* each ring has a minimum of 4 bytes (point count) */
@@ -1072,7 +1117,7 @@
         nbytes -= data_offset;
 
     /* reallocate space for parts if needed */
-    reallocate_cache(cache, nparts);
+    reallocate_cache(cache, nparts, FALSE);
 
     /* get parts */
     for (ipart = 0; ipart < nparts; ipart++) {
@@ -1476,14 +1521,14 @@
 /*!
    \brief Reallocate lines cache
  */
-void reallocate_cache(struct Format_info_cache *cache, int num)
+void reallocate_cache(struct Format_info_cache *cache, int num, int incr)
 {
     int i;
 
-    if (cache->lines_alloc >= num)
+    if (!incr && cache->lines_alloc >= num)
         return;
 
-    if (!cache->lines) {
+    if (!incr && !cache->lines) {
         /* most of features requires only one line cache */
         cache->lines_alloc = 1;
     }

Modified: grass/trunk/lib/vector/Vlib/rewind_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/rewind_pg.c	2013-11-24 15:46:40 UTC (rev 58289)
+++ grass/trunk/lib/vector/Vlib/rewind_pg.c	2013-11-24 16:26:40 UTC (rev 58290)
@@ -42,7 +42,9 @@
     pg_info->next_line = 0;
 
     /* reset cache */
-    pg_info->cache.lines_num = pg_info->cache.lines_next = 0;
+    if (pg_info->cache.ctype != CACHE_MAP)
+        pg_info->cache.lines_num = 0;
+    pg_info->cache.lines_next = 0;
     pg_info->cache.fid = -1;
 
     /* close DB cursor if necessary */



More information about the grass-commit mailing list