[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