[GRASS-SVN] r51902 - in grass/trunk: include/defs include/vect lib/vector/Vlib lib/vector/diglib

svn_grass at osgeo.org svn_grass at osgeo.org
Thu May 31 05:47:12 PDT 2012


Author: martinl
Date: 2012-05-31 05:47:11 -0700 (Thu, 31 May 2012)
New Revision: 51902

Modified:
   grass/trunk/include/defs/vector.h
   grass/trunk/include/vect/dig_structs.h
   grass/trunk/lib/vector/Vlib/build.c
   grass/trunk/lib/vector/Vlib/close_pg.c
   grass/trunk/lib/vector/Vlib/open.c
   grass/trunk/lib/vector/Vlib/open_pg.c
   grass/trunk/lib/vector/Vlib/read.c
   grass/trunk/lib/vector/Vlib/read_pg.c
   grass/trunk/lib/vector/Vlib/read_sfa.c
   grass/trunk/lib/vector/Vlib/rewind.c
   grass/trunk/lib/vector/diglib/frmt.c
   grass/trunk/lib/vector/diglib/spindex_rw.c
Log:
vlib: first steps for full PostGIS topology support
      untabify for given files


Modified: grass/trunk/include/defs/vector.h
===================================================================
--- grass/trunk/include/defs/vector.h	2012-05-31 12:32:19 UTC (rev 51901)
+++ grass/trunk/include/defs/vector.h	2012-05-31 12:47:11 UTC (rev 51902)
@@ -11,44 +11,44 @@
 int Vect_line_insert_point(struct line_pnts *, int, double, double, double);
 int Vect_line_delete_point(struct line_pnts *, int);
 int Vect_line_get_point(const struct line_pnts *, int ,
-			double *, double *, double *);
+                        double *, double *, double *);
 int Vect_get_num_line_points(const struct line_pnts *);
 int Vect_line_prune(struct line_pnts *);
 int Vect_line_prune_thresh(struct line_pnts *, double);
 void Vect_line_reverse(struct line_pnts *);
 int Vect_copy_xyz_to_pnts(struct line_pnts *, const double *, const double *, const double *,
-			  int);
+                          int);
 int Vect_copy_pnts_to_xyz(const struct line_pnts *, double *, double *, double *,
-			  int *);
+                          int *);
 void Vect_reset_line(struct line_pnts *);
 void Vect_destroy_line_struct(struct line_pnts *);
 int Vect_point_on_line(const struct line_pnts *, double, double *, double *,
-		       double *, double *, double *);
+                       double *, double *, double *);
 int Vect_line_segment(const struct line_pnts *, double, double, struct line_pnts *);
 double Vect_line_length(const struct line_pnts *);
 double Vect_area_perimeter(const struct line_pnts *);
 double Vect_line_geodesic_length(const struct line_pnts *);
 int Vect_line_distance(const struct line_pnts *, double, double, double, int,
-		       double *, double *, double *, double *, double *,
-		       double *);
+                       double *, double *, double *, double *, double *,
+                       double *);
 void Vect_line_box(const struct line_pnts *, struct bound_box *);
 void Vect_line_parallel(struct line_pnts *, double, double, int,
-			struct line_pnts *);
+                        struct line_pnts *);
 void Vect_line_parallel2(struct line_pnts *, double, double,
-			 double, int, int, double,
-			 struct line_pnts *);
+                         double, int, int, double,
+                         struct line_pnts *);
 void Vect_line_buffer(const struct line_pnts *, double, double, struct line_pnts *);
 void Vect_line_buffer2(const struct line_pnts *, double, double,
-		       double, int, int, double,
-		       struct line_pnts **,
-		       struct line_pnts ***, int *);
+                       double, int, int, double,
+                       struct line_pnts **,
+                       struct line_pnts ***, int *);
 void Vect_area_buffer2(const struct Map_info *, int, double, double,
-		       double, int, int, double,
-		       struct line_pnts **,
-		       struct line_pnts ***, int *);
+                       double, int, int, double,
+                       struct line_pnts **,
+                       struct line_pnts ***, int *);
 void Vect_point_buffer2(double, double, double, double,
-			double, int, double,
-			struct line_pnts **);
+                        double, int, double,
+                        struct line_pnts **);
 
 
 /* Categories */
@@ -75,28 +75,28 @@
 /* Vector array */
 struct varray *Vect_new_varray(int);
 int Vect_set_varray_from_cat_string(const struct Map_info *, int, const char *, int,
-				    int, struct varray *);
+                                    int, struct varray *);
 int Vect_set_varray_from_cat_list(const struct Map_info *, int, struct cat_list *,
-				  int, int, struct varray *);
+                                  int, int, struct varray *);
 int Vect_set_varray_from_db(const struct Map_info *, int, const char *, int, int,
-			    struct varray *);
+                            struct varray *);
 
 /* DB connection - field info */
 struct dblinks *Vect_new_dblinks_struct(void);
 void Vect_reset_dblinks(struct dblinks *);
 int Vect_add_dblink(struct dblinks *, int, const char *,
-		    const char *, const char *, const char *, const char *);
+                    const char *, const char *, const char *, const char *);
 int Vect_check_dblink(const struct dblinks *, int, const char *);
 int Vect_map_add_dblink(struct Map_info *, int, const char *,
-			const char *, const char *, const char *,
-			const char *);
+                        const char *, const char *, const char *,
+                        const char *);
 int Vect_map_del_dblink(struct Map_info *, int);
 void Vect_copy_map_dblinks(const struct Map_info *, struct Map_info *, int);
 int Vect_map_check_dblink(const struct Map_info *, int, const char *);
 int Vect_read_dblinks(struct Map_info *);
 int Vect_write_dblinks(struct Map_info *);
 struct field_info *Vect_default_field_info(struct Map_info *, int,
-					   const char *, int);
+                                           const char *, int);
 struct field_info *Vect_get_dblink(const struct Map_info *, int);
 struct field_info *Vect_get_field(const struct Map_info *, int);
 struct field_info *Vect_get_field_by_name(const struct Map_info *, const char *);
@@ -143,10 +143,10 @@
 int Vect_cidx_get_num_cats_by_index(const struct Map_info *, int);
 int Vect_cidx_get_num_types_by_index(const struct Map_info *, int);
 int Vect_cidx_get_type_count_by_index(const struct Map_info *, int, int, int *,
-				      int *);
+                                      int *);
 int Vect_cidx_get_type_count(const struct Map_info *, int, int);
 int Vect_cidx_get_cat_by_index(const struct Map_info *, int, int, int *, int *,
-			       int *);
+                               int *);
 int Vect_cidx_find_next(const struct Map_info *, int, int, int, int, int *, int *);
 void Vect_cidx_find_all(const struct Map_info *, int, int, int, struct ilist *);
 int Vect_cidx_dump(const struct Map_info *, FILE *);
@@ -227,7 +227,7 @@
 int Vect_get_built(const struct Map_info *);
 int Vect_build_partial(struct Map_info *, int);
 int Vect_set_constraint_region(struct Map_info *, double, double, double,
-				double, double, double);
+                                double, double, double);
 int Vect_set_constraint_type(struct Map_info *, int);
 int Vect_set_constraint_field(struct Map_info *, int);
 void  Vect_remove_constraints(struct Map_info *);
@@ -239,17 +239,17 @@
 /* Level 1 and 2 */
 int Vect_get_next_line_id(const struct Map_info *);
 int Vect_read_next_line(const struct Map_info *, struct line_pnts *,
-			struct line_cats *);
+                        struct line_cats *);
 off_t Vect_write_line(struct Map_info *, int, const struct line_pnts *,
-		      const struct line_cats *);
+                      const struct line_cats *);
 
 int Vect_get_num_dblinks(const struct Map_info *);
 
 /* Level 2 only */
 int Vect_read_line(const struct Map_info *, struct line_pnts *, struct line_cats *,
-		   int);
+                   int);
 off_t Vect_rewrite_line(struct Map_info *, int, int, const struct line_pnts *,
-		      const struct line_cats *);
+                      const struct line_cats *);
 int Vect_delete_line(struct Map_info *, int);
 int Vect_restore_line(struct Map_info *, int, off_t);
 
@@ -297,34 +297,34 @@
 
 /* Selecting features */
 int Vect_select_lines_by_box(struct Map_info *, const struct bound_box *,
-			 int, struct boxlist *);
+                         int, struct boxlist *);
 int Vect_select_areas_by_box(struct Map_info *, const struct bound_box *, struct boxlist *);
 int Vect_select_isles_by_box(struct Map_info *, const struct bound_box *, struct boxlist *);
 int Vect_select_nodes_by_box(struct Map_info *, const struct bound_box *, struct ilist *);
 int Vect_find_node(struct Map_info *, double, double, double, double, int);
 int Vect_find_line(struct Map_info *, double, double, double, int, double,
-		   int, int);
+                   int, int);
 int Vect_find_line_list(struct Map_info *, double, double, double, int,
-			double, int, const struct ilist *, struct ilist *);
+                        double, int, const struct ilist *, struct ilist *);
 int Vect_find_area(struct Map_info *, double, double);
 int Vect_find_island(struct Map_info *, double, double);
 int Vect_select_lines_by_polygon(struct Map_info *, struct line_pnts *, int,
-				 struct line_pnts **, int, struct ilist *);
+                                 struct line_pnts **, int, struct ilist *);
 int Vect_select_areas_by_polygon(struct Map_info *, struct line_pnts *, int,
-				 struct line_pnts **, struct ilist *);
+                                 struct line_pnts **, struct ilist *);
 
 /* Analysis */
 int Vect_tin_get_z(struct Map_info *, double, double, double *, double *,
-		   double *);
+                   double *);
 
 /* int Vect_point_in_islands (struct Map_info *, int, double, double); */
 int Vect_find_poly_centroid(const struct line_pnts *, double *, double *);
 int Vect__intersect_line_with_poly(const struct line_pnts *, double,
-				   struct line_pnts *);
+                                   struct line_pnts *);
 int Vect_get_point_in_area(const struct Map_info *, int, double *, double *);
 int Vect_get_point_in_poly(const struct line_pnts *, double *, double *);
 int Vect_get_point_in_poly_isl(const struct line_pnts *, const struct line_pnts **, int,
-			       double *, double *);
+                               double *, double *);
 int Vect_point_in_area(double, double, const struct Map_info *, int, struct bound_box);
 int Vect_point_in_area_outer_ring(double, double, const struct Map_info *, int, struct bound_box);
 int Vect_point_in_island(double, double, const struct Map_info *, int, struct bound_box);
@@ -333,36 +333,36 @@
 /* Cleaning */
 void Vect_break_lines(struct Map_info *, int, struct Map_info *);
 int Vect_break_lines_list(struct Map_info *, struct ilist *, struct ilist *,
-			  int, struct Map_info *);
+                          int, struct Map_info *);
 int Vect_check_line_breaks(struct Map_info *, int, struct Map_info *);
 int Vect_check_line_breaks_list(struct Map_info *, struct ilist *, struct ilist *,
-			  int, struct Map_info *);
+                          int, struct Map_info *);
 int Vect_merge_lines(struct Map_info *, int, int *, struct Map_info *);
 void Vect_break_polygons(struct Map_info *, int, struct Map_info *);
 void Vect_remove_duplicates(struct Map_info *, int, struct Map_info *);
 int Vect_line_check_duplicate(const struct line_pnts *,
-			      const struct line_pnts *, int);
+                              const struct line_pnts *, int);
 void Vect_snap_lines(struct Map_info *, int, double, struct Map_info *);
 void Vect_snap_lines_list(struct Map_info *, const struct ilist *, double,
-			  struct Map_info *);
+                          struct Map_info *);
 void Vect_remove_dangles(struct Map_info *, int, double, struct Map_info *);
 void Vect_chtype_dangles(struct Map_info *, double, struct Map_info *);
 void Vect_select_dangles(struct Map_info *, int, double, struct ilist *);
 void Vect_remove_bridges(struct Map_info *, struct Map_info *);
 void Vect_chtype_bridges(struct Map_info *, struct Map_info *);
 int Vect_remove_small_areas(struct Map_info *, double, struct Map_info *,
-			    double *);
+                            double *);
 int Vect_clean_small_angles_at_nodes(struct Map_info *, int,
-				     struct Map_info *);
+                                     struct Map_info *);
 
 /* Overlay */
 int Vect_overlay_str_to_operator(const char *);
 int Vect_overlay(struct Map_info *, int, struct ilist *, struct ilist *,
-		 struct Map_info *, int, struct ilist *, struct ilist *,
-		 int, struct Map_info *);
+                 struct Map_info *, int, struct ilist *, struct ilist *,
+                 int, struct Map_info *);
 int Vect_overlay_and(struct Map_info *, int, struct ilist *,
-		     struct ilist *, struct Map_info *, int,
-		     struct ilist *, struct ilist *, struct Map_info *);
+                     struct ilist *, struct Map_info *, int,
+                     struct ilist *, struct ilist *, struct Map_info *);
 
 /* Graph */
 void Vect_graph_init(dglGraph_s *, int);
@@ -373,50 +373,50 @@
 
 /* Network (graph) */
 int Vect_net_build_graph(struct Map_info *, int, int, int, const char *,
-			 const char *, const char *, int, int);
+                         const char *, const char *, int, int);
 int Vect_net_shortest_path(struct Map_info *, int, int, struct ilist *,
-			   double *);
+                           double *);
 int Vect_net_get_line_cost(const struct Map_info *, int, int, double *);
 int Vect_net_get_node_cost(const struct Map_info *, int, double *);
 int Vect_net_nearest_nodes(struct Map_info *, double, double, double, int,
-			   double, int *, int *, int *, double *, double *,
-			   struct line_pnts *, struct line_pnts *, double *);
+                           double, int *, int *, int *, double *, double *,
+                           struct line_pnts *, struct line_pnts *, double *);
 int Vect_net_shortest_path_coor(struct Map_info *, double, double, double,
-				double, double, double, double, double,
-				double *, struct line_pnts *, struct ilist *,
-				struct line_pnts *, struct line_pnts *,
-				double *, double *);
+                                double, double, double, double, double,
+                                double *, struct line_pnts *, struct ilist *,
+                                struct line_pnts *, struct line_pnts *,
+                                double *, double *);
 int Vect_net_shortest_path_coor2(struct Map_info *, double, double, double,
-				double, double, double, double, double,
-				double *, struct line_pnts *, struct ilist *, struct ilist *,
-				struct line_pnts *, struct line_pnts *,
-				double *, double *);
+                                double, double, double, double, double,
+                                double *, struct line_pnts *, struct ilist *, struct ilist *,
+                                struct line_pnts *, struct line_pnts *,
+                                double *, double *);
 
 /* Miscellaneous */
 int Vect_topo_dump(const struct Map_info *, FILE *);
 double Vect_points_distance(double, double, double, double, double, double,
-			    int);
+                            int);
 int Vect_option_to_types(const struct Option *);
 int Vect_copy_map_lines(struct Map_info *, struct Map_info *);
 int Vect_copy_map_lines_field(struct Map_info *, int, struct Map_info *);
 int Vect_copy(const char *, const char *, const char *);
 int Vect_rename(const char *, const char *);
 int Vect_copy_table(const struct Map_info *, struct Map_info *, int, int,
-		    const char *, int);
+                    const char *, int);
 int Vect_copy_table_by_cats(const struct Map_info *, struct Map_info *, int, int,
-			    const char *, int, int *, int);
+                            const char *, int, int *, int);
 int Vect_copy_tables(const struct Map_info *, struct Map_info *, int);
 int Vect_delete(const char *);
 int Vect_segment_intersection(double, double, double, double, double, double,
-			      double, double, double, double, double, double,
-			      double *, double *, double *, double *,
-			      double *, double *, int);
+                              double, double, double, double, double, double,
+                              double *, double *, double *, double *,
+                              double *, double *, int);
 int Vect_line_intersection(struct line_pnts *, struct line_pnts *,
-			   struct line_pnts ***, struct line_pnts ***, int *,
-			   int *, int);
+                           struct line_pnts ***, struct line_pnts ***, int *,
+                           int *, int);
 int Vect_line_check_intersection(struct line_pnts *, struct line_pnts *, int);
 int Vect_line_get_intersections(struct line_pnts *, struct line_pnts *,
-				struct line_pnts *, int);
+                                struct line_pnts *, int);
 char *Vect_subst_var(const char *, const struct Map_info *);
 
 /* Custom spatial index */
@@ -430,9 +430,9 @@
 int Vect_read_ascii(FILE *, struct Map_info *);
 int Vect_read_ascii_head(FILE *, struct Map_info *);
 int Vect_write_ascii(FILE *, FILE *, struct Map_info *, int,
-		     int, int, char *, int, int,
-		     int, const struct cat_list *, const char*,
-		     const char **, int);
+                     int, int, char *, int, int,
+                     int, const struct cat_list *, const char*,
+                     const char **, int);
 void Vect_write_ascii_head(FILE *, struct Map_info *);
 
 /* Simple Features */
@@ -456,6 +456,7 @@
 const char *Vect_maptype_info(const struct Map_info *);
 int Vect_maptype(const struct Map_info *);
 int Vect_open_topo(struct Map_info *, int);
+int Vect_open_topo_pg(struct Map_info *, int);
 int Vect_save_topo(struct Map_info *);
 int Vect_open_sidx(struct Map_info *, int);
 int Vect_save_sidx(struct Map_info *);
@@ -492,27 +493,29 @@
 
 /* Read/write lines (internal use only) */
 int V1_read_line_nat(struct Map_info *, struct line_pnts *,
-		     struct line_cats *, off_t);
+                     struct line_cats *, off_t);
 int V1_read_line_ogr(struct Map_info *, struct line_pnts *,
-		     struct line_cats *, off_t);
+                     struct line_cats *, off_t);
 int V1_read_line_pg(struct Map_info *, struct line_pnts *,
-		    struct line_cats *, off_t);
+                    struct line_cats *, off_t);
 int V2_read_line_nat(struct Map_info *, struct line_pnts *,
-		     struct line_cats *, int);
+                     struct line_cats *, int);
 int V2_read_line_sfa(struct Map_info *, struct line_pnts *,
-		     struct line_cats *, int);
+                     struct line_cats *, int);
+int V3_read_line_pg(struct Map_info *, struct line_pnts *,
+                    struct line_cats *, int);
 int V1_read_next_line_nat(struct Map_info *, struct line_pnts *,
-			  struct line_cats *);
+                          struct line_cats *);
 int V1_read_next_line_ogr(struct Map_info *, struct line_pnts *,
-			  struct line_cats *);
+                          struct line_cats *);
 int V1_read_next_line_pg(struct Map_info *, struct line_pnts *,
-			 struct line_cats *);
+                         struct line_cats *);
 int V2_read_next_line_nat(struct Map_info *, struct line_pnts *,
-			  struct line_cats *);
+                          struct line_cats *);
 int V2_read_next_line_ogr(struct Map_info *, struct line_pnts *,
-			  struct line_cats *);
+                          struct line_cats *);
 int V2_read_next_line_pg(struct Map_info *, struct line_pnts *,
-			 struct line_cats *);
+                         struct line_cats *);
 int V1_delete_line_nat(struct Map_info *, off_t);
 int V1_delete_line_ogr(struct Map_info *, off_t);
 int V1_delete_line_pg(struct Map_info *, off_t);
@@ -521,25 +524,25 @@
 int V1_restore_line_nat(struct Map_info *, off_t);
 int V2_restore_line_nat(struct Map_info *, int, off_t);
 off_t V1_write_line_nat(struct Map_info *, int, const struct line_pnts *,
-			const struct line_cats *);
+                        const struct line_cats *);
 off_t V1_write_line_ogr(struct Map_info *, int, const struct line_pnts *,
-			const struct line_cats *);
+                        const struct line_cats *);
 off_t V1_write_line_pg(struct Map_info *, int, const struct line_pnts *,
-		       const struct line_cats *);
+                       const struct line_cats *);
 off_t V2_write_line_nat(struct Map_info *, int, const struct line_pnts *,
-			const struct line_cats *);
+                        const struct line_cats *);
 off_t V2_write_line_sfa(struct Map_info *, int, const struct line_pnts *,
-			const struct line_cats *);
+                        const struct line_cats *);
 off_t V1_rewrite_line_nat(struct Map_info *, int, int, off_t,
-			  const struct line_pnts *, const struct line_cats *);
+                          const struct line_pnts *, const struct line_cats *);
 off_t V1_rewrite_line_ogr(struct Map_info *, int, int, off_t,
-			  const struct line_pnts *, const struct line_cats *);
+                          const struct line_pnts *, const struct line_cats *);
 off_t V1_rewrite_line_pg(struct Map_info *, int, int, off_t,
-			 const struct line_pnts *, const struct line_cats *);
+                         const struct line_pnts *, const struct line_cats *);
 off_t V2_rewrite_line_nat(struct Map_info *, int, int, off_t,
-			  const struct line_pnts *, const struct line_cats *);
+                          const struct line_pnts *, const struct line_cats *);
 off_t V2_rewrite_line_sfa(struct Map_info *, int, int, off_t,
-			  const struct line_pnts *, const struct line_cats *);
+                          const struct line_pnts *, const struct line_cats *);
 
     /* Build topology */
 int Vect_build_nat(struct Map_info *, int);

Modified: grass/trunk/include/vect/dig_structs.h
===================================================================
--- grass/trunk/include/vect/dig_structs.h	2012-05-31 12:32:19 UTC (rev 51901)
+++ grass/trunk/include/vect/dig_structs.h	2012-05-31 12:47:11 UTC (rev 51902)
@@ -660,6 +660,16 @@
       \brief Offset list used for building pseudo-topology
     */
     struct Format_info_offset offset;
+
+    /* Full-topology support */
+    /*!
+      \brief TopoGeometry column
+    */
+    char    *topogeom_column;
+    /*!
+      \brief Topology schema name
+    */
+    char    *toposchema_name;
 };
 
 /*!
@@ -1434,11 +1444,14 @@
       \brief Number of attached lines (size of
       lines, angle)
 
-      If 0, then is degenerate node, for snappingi ???
+      If 0, then is degenerate node, for snapping ???
     */
     plus_t n_lines;
     /*!
       \brief List of connected lines
+
+      Line id can be positive (for lines which starts at the node) or
+      negative (for lines which ends at the node).
     */
     plus_t *lines;
     /*!
@@ -1446,7 +1459,8 @@
 
       Angles for lines/boundaries are in radians between -PI and
       PI. Value for points or lines with identical points
-      (degenerated) is set to -9.
+      (degenerated) is set to -9. See dig_calc_begin_angle() and
+      dig_calc_end_angle() for details.
     */
     float *angles;
 };
@@ -1551,12 +1565,17 @@
     char type;
     /*!
       \brief Offset in coor file for line
+
+      OGR-links: offset array index
+      PG-links: node/edge id
     */
-    off_t offset;		
+    off_t offset;
     /*!
       \brief Topology info
+
+      NULL for points
     */
-    void *topo;		
+    void *topo;
 };
 
 /*!

Modified: grass/trunk/lib/vector/Vlib/build.c
===================================================================
--- grass/trunk/lib/vector/Vlib/build.c	2012-05-31 12:32:19 UTC (rev 51901)
+++ grass/trunk/lib/vector/Vlib/build.c	2012-05-31 12:47:11 UTC (rev 51902)
@@ -13,12 +13,15 @@
    \author Original author CERL, probably Dave Gerdes or Mike Higgins.
    \author Update to GRASS 5.7 Radim Blazek and David D. Gray.
  */
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <unistd.h>
+#include <math.h>
+
+#include <grass/vector.h>
 #include <grass/glocale.h>
-#include <grass/vector.h>
 
 #define SEP "-----------------------------------\n"
 
@@ -884,6 +887,7 @@
 int Vect_topo_dump(const struct Map_info *Map, FILE *out)
 {
     int i, j, line, isle;
+    float angle_deg;
     struct P_node *Node;
     struct P_line *Line;
     struct P_area *Area;
@@ -914,8 +918,11 @@
 	for (j = 0; j < Node->n_lines; j++) {
 	    line = Node->lines[j];
 	    Line = plus->Line[abs(line)];
-	    fprintf(out, "  line = %3d, type = %d, angle = %f\n", line,
-		    Line->type, Node->angles[j]);
+            angle_deg = (Node->angles[j] * 180) / M_PI;
+            if (angle_deg < 0)
+                angle_deg += 360;
+	    fprintf(out, "  line = %3d, type = %d, angle = %f (%.4f)\n", line,
+		    Line->type, Node->angles[j], angle_deg);
 	}
     }
 

Modified: grass/trunk/lib/vector/Vlib/close_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/close_pg.c	2012-05-31 12:32:19 UTC (rev 51901)
+++ grass/trunk/lib/vector/Vlib/close_pg.c	2012-05-31 12:47:11 UTC (rev 51902)
@@ -80,6 +80,12 @@
     G_free(pg_info->geom_column);
     G_free(pg_info->fid_column);
 
+    if (pg_info->toposchema_name)
+        G_free(pg_info->toposchema_name);
+
+    if (pg_info->topogeom_column)
+        G_free(pg_info->topogeom_column);
+
     return 0;
 #else
     G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));

Modified: grass/trunk/lib/vector/Vlib/open.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open.c	2012-05-31 12:32:19 UTC (rev 51901)
+++ grass/trunk/lib/vector/Vlib/open.c	2012-05-31 12:47:11 UTC (rev 51902)
@@ -97,7 +97,7 @@
 };
 
 static int open_old(struct Map_info *, const char *, const char *,
-		    const char *, int, int);
+                    const char *, int, int);
 
 /*!
   \brief Predetermine level at which a vector map will be opened for
@@ -122,10 +122,10 @@
 {
     Open_level = level;
     if (Open_level < 1 || Open_level > MAX_OPEN_LEVEL) {
-	G_warning(_("Programmer requested unknown access level %d"),
-		  Open_level);
-	Open_level = 0;
-	return 1;
+        G_warning(_("Programmer requested unknown access level %d"),
+                  Open_level);
+        Open_level = 0;
+        return 1;
     }
 
     return 0;
@@ -146,10 +146,10 @@
  \return -1 in error
 */
 int open_old(struct Map_info *Map, const char *name, const char *mapset,
-	     const char *layer, int update, int head_only)
+             const char *layer, int update, int head_only)
 {
     char buf[GNAME_MAX + 10], buf2[GMAPSET_MAX + 10], xname[GNAME_MAX],
-	xmapset[GMAPSET_MAX];
+        xmapset[GMAPSET_MAX];
     FILE *fp;
     int level, level_request;
     int format, ret;
@@ -157,7 +157,7 @@
     const char *fmapset;
 
     G_debug(1, "Vect__open_old(): name='%s' mapset='%s' layer='%s' update=%d",
-	    name, mapset, layer, update);
+            name, mapset, layer, update);
 
     /* zero Map_info structure */
     G_zero(Map, sizeof(struct Map_info));
@@ -178,54 +178,54 @@
     /* check OGR mapset */
     ogr_mapset = FALSE;
     if (G_name_is_fully_qualified(name, xname, xmapset)) {
-	if (strcasecmp(xmapset, "ogr") == 0) {
-	    /* unique OGR mapset detected */
-	    G_debug(1, "OGR mapset detected");
-	    ogr_mapset = TRUE;
-	    Map->fInfo.ogr.dsn = G_store(xname);
-	    if (layer) {
-		Map->fInfo.ogr.layer_name = G_store(layer); /* no layer to be open */
-	    }
-	}
-	else {
-	    sprintf(buf,  "%s/%s", GV_DIRECTORY, xname);
-	    sprintf(buf2, "%s@%s", GV_COOR_ELEMENT, xmapset);
-	}
-	Map->name = G_store(xname);
-	Map->mapset = G_store(xmapset);
+        if (strcasecmp(xmapset, "ogr") == 0) {
+            /* unique OGR mapset detected */
+            G_debug(1, "OGR mapset detected");
+            ogr_mapset = TRUE;
+            Map->fInfo.ogr.dsn = G_store(xname);
+            if (layer) {
+                Map->fInfo.ogr.layer_name = G_store(layer); /* no layer to be open */
+            }
+        }
+        else {
+            sprintf(buf,  "%s/%s", GV_DIRECTORY, xname);
+            sprintf(buf2, "%s@%s", GV_COOR_ELEMENT, xmapset);
+        }
+        Map->name = G_store(xname);
+        Map->mapset = G_store(xmapset);
     }
     else {
-	sprintf(buf, "%s/%s", GV_DIRECTORY, name);
-	sprintf(buf2, "%s",   GV_COOR_ELEMENT);
-	Map->name = G_store(name);
+        sprintf(buf, "%s/%s", GV_DIRECTORY, name);
+        sprintf(buf2, "%s",   GV_COOR_ELEMENT);
+        Map->name = G_store(name);
 
-	if (mapset)
-	    Map->mapset = G_store(mapset);
-	else
-	    Map->mapset = G_store("");
+        if (mapset)
+            Map->mapset = G_store(mapset);
+        else
+            Map->mapset = G_store("");
     }
 
     if (!ogr_mapset) {
-	/* try to find vector map (not for OGR mapset) */
-	fmapset = G_find_vector2(Map->name, Map->mapset);
-	if (fmapset == NULL) {
-	    if (mapset && strcmp(mapset, G_mapset()) == 0)
-		G_fatal_error(_("Vector map <%s> not found in current mapset"),
-			      Vect_get_name(Map));
-	    else
-		G_fatal_error(_("Vector map <%s> not found"),
-			      Vect_get_full_name(Map));
-	    return -1;
-	}
-	Map->mapset = G_store(fmapset);
+        /* try to find vector map (not for OGR mapset) */
+        fmapset = G_find_vector2(Map->name, Map->mapset);
+        if (fmapset == NULL) {
+            if (mapset && strcmp(mapset, G_mapset()) == 0)
+                G_fatal_error(_("Vector map <%s> not found in current mapset"),
+                              Vect_get_name(Map));
+            else
+                G_fatal_error(_("Vector map <%s> not found"),
+                              Vect_get_full_name(Map));
+            return -1;
+        }
+        Map->mapset = G_store(fmapset);
     }
     
     Map->location = G_store(G_location());
     Map->gisdbase = G_store(G_gisdbase());
     
     if (update && !ogr_mapset && (0 != strcmp(Map->mapset, G_mapset()))) {
-	G_warning(_("Vector map which is not in the current mapset cannot be opened for update"));
-	return -1;
+        G_warning(_("Vector map which is not in the current mapset cannot be opened for update"));
+        return -1;
     }
 
     G_debug(1, "Map name: %s", Map->name);
@@ -233,41 +233,41 @@
 
     /* Read vector format information */
     if (ogr_mapset) {
-	format = GV_FORMAT_OGR_DIRECT;
+        format = GV_FORMAT_OGR_DIRECT;
     }
     else {
-	format = 0;
-	sprintf(buf, "%s/%s", GV_DIRECTORY, Map->name);
-	G_debug(1, "open format file: '%s/%s/%s'", Map->mapset, buf,
-		GV_FRMT_ELEMENT);
-	fp = G_fopen_old(buf, GV_FRMT_ELEMENT, Map->mapset);
-	if (fp == NULL) {
-	    G_debug(1, "Vector format: %d (native)", format);
-	    format = GV_FORMAT_NATIVE;
-	}
-	else {
-	    format = dig_read_frmt_ascii(fp, &(Map->fInfo));
-	    fclose(fp);
-	    
-	    G_debug(1, "Vector format: %d (non-native)", format);
-	    if (format < 0) {
-		G_fatal_error(_("Unable to open vector map <%s>"),
-			      Vect_get_full_name(Map));
-		return -1;
-	    }
-	}
+        format = 0;
+        sprintf(buf, "%s/%s", GV_DIRECTORY, Map->name);
+        G_debug(1, "open format file: '%s/%s/%s'", Map->mapset, buf,
+                GV_FRMT_ELEMENT);
+        fp = G_fopen_old(buf, GV_FRMT_ELEMENT, Map->mapset);
+        if (fp == NULL) {
+            G_debug(1, "Vector format: %d (native)", format);
+            format = GV_FORMAT_NATIVE;
+        }
+        else {
+            format = dig_read_frmt_ascii(fp, &(Map->fInfo));
+            fclose(fp);
+            
+            G_debug(1, "Vector format: %d (non-native)", format);
+            if (format < 0) {
+                G_fatal_error(_("Unable to open vector map <%s>"),
+                              Vect_get_full_name(Map));
+                return -1;
+            }
+        }
     }
     Map->format = format;
 
     /* read vector head (ignored for OGR mapset) */
     if (!ogr_mapset && Vect__read_head(Map) != 0) {
-	G_fatal_error(_("Unable to read header file of vector map <%s>"),
-		      Vect_get_full_name(Map));
+        G_fatal_error(_("Unable to read header file of vector map <%s>"),
+                      Vect_get_full_name(Map));
     }
 
     /* projection is not written to head but zone ??? */
     if (Vect_get_zone(Map) == -1)
-	Vect_set_zone(Map, G_zone());
+        Vect_set_zone(Map, G_zone());
     Vect_set_proj(Map, G_projection());
     
     G_debug(1, "Level request = %d", level_request);
@@ -282,124 +282,140 @@
     /* Try to open support files if level was not requested or
      * requested level is 2 (format independent) */
     if (level_request == 0 || level_request == 2) {
-	level = 2;		/* we expect success */
-	/* open topo */
-	ret = Vect_open_topo(Map, head_only);
-	if (ret == 1) {		/* topo file is not available */
-	    G_debug(1, "topo file for vector '%s' not available.",
-		    Vect_get_full_name(Map));
-	    level = 1;
-	}
-	else if (ret == -1) {
-	    G_fatal_error(_("Unable to open topology file for vector map <%s>"),
-			  Vect_get_full_name(Map));
-	}
-	/* open spatial index */
-	if (level == 2) {
-	    ret = Vect_open_sidx(Map, (update != 0));
-	    if (ret == 1) {	/* sidx file is not available */
-		G_debug(1, "sidx file for vector '%s' not available.",
-			Vect_get_full_name(Map));
-		level = 1;
-	    }
-	    else if (ret == -1) {
-		G_fatal_error(_("Unable to open spatial index file for vector map <%s>"),
-			      Vect_get_full_name(Map));
-	    }
-	    /* check with_z consistency */
-	    if ((Map->plus.with_z != 0 && Map->plus.spidx_with_z == 0) ||
-	        (Map->plus.with_z == 0 && Map->plus.spidx_with_z != 0)) {
-		    G_warning("Vector map <%s>: topology is %s, but spatial index is %s",
-		    Vect_get_full_name(Map), (Map->plus.with_z != 0 ? "3D" : "2D"),
-		    (Map->plus.spidx_with_z != 0 ? "3D" : "2D"));
-		    level = 1;
-		}
-	}
-	/* open category index */
-	if (level == 2) {
-	    ret = Vect_cidx_open(Map, head_only);
-	    if (ret == 1) {	/* category index is not available */
-		G_debug(1,
-			"cidx file for vector '%s' not available.",
-			Vect_get_full_name(Map));
-		dig_free_plus(&(Map->plus));	/* free topology */
-		dig_spidx_free(&(Map->plus));	/* free spatial index */
-		level = 1;
-	    }
-	    else if (ret == -1) {	/* file exists, but cannot be opened */
-		G_fatal_error(_("Unable to open category index file for vector map <%s>"),
-			      Vect_get_full_name(Map));
-	    }
-	}
+        level = 2;              /* we expect success */
+        /* open topo */
+        ret = -1;
+        
+        if (Map->format == GV_FORMAT_POSTGIS)
+            /* try to read full-topology for PostGIS links */
+            ret = Vect_open_topo_pg(Map, head_only);
+        
+        if (ret != 0) {
+            /* read topology for native format
+               read pseudo-topology for OGR/PostGIS links */
+            ret = Vect_open_topo(Map, head_only);    
+            
+            if (ret == 1) { /* topo file is not available */
+                G_debug(1, "topo file for vector '%s' not available.",
+                        Vect_get_full_name(Map));
+                level = 1;
+            }
+            else if (ret == -1) {
+                G_fatal_error(_("Unable to open topology file for vector map <%s>"),
+                              Vect_get_full_name(Map));
+            }
+        }
+        else {
+            level = 3; /* PostGIS topology available */
+        }
+
+        /* open spatial index */
+        if (level >= 2) {
+            ret = Vect_open_sidx(Map, (update != 0));
+            if (ret == 1) {     /* sidx file is not available */
+                G_debug(1, "sidx file for vector '%s' not available.",
+                        Vect_get_full_name(Map));
+                level = 1;
+            }
+            else if (ret == -1) {
+                G_fatal_error(_("Unable to open spatial index file for vector map <%s>"),
+                              Vect_get_full_name(Map));
+            }
+            /* check with_z consistency */
+            if ((Map->plus.with_z != 0 && Map->plus.spidx_with_z == 0) ||
+                (Map->plus.with_z == 0 && Map->plus.spidx_with_z != 0)) {
+                    G_warning("Vector map <%s>: topology is %s, but spatial index is %s",
+                    Vect_get_full_name(Map), (Map->plus.with_z != 0 ? "3D" : "2D"),
+                    (Map->plus.spidx_with_z != 0 ? "3D" : "2D"));
+                    level = 1;
+                }
+        }
+        /* open category index */
+        if (level >= 2) {
+            ret = Vect_cidx_open(Map, head_only);
+            if (ret == 1) {     /* category index is not available */
+                G_debug(1,
+                        "cidx file for vector '%s' not available.",
+                        Vect_get_full_name(Map));
+                dig_free_plus(&(Map->plus));    /* free topology */
+                dig_spidx_free(&(Map->plus));   /* free spatial index */
+                level = 1;
+            }
+            else if (ret == -1) {       /* file exists, but cannot be opened */
+                G_fatal_error(_("Unable to open category index file for vector map <%s>"),
+                              Vect_get_full_name(Map));
+            }
+        }
 #ifdef HAVE_OGR
-	/* open OGR specific support files */
-	if (level == 2 && Map->format == GV_FORMAT_OGR) {
-	    if (V2_open_old_ogr(Map) < 0) {
-		dig_free_plus(&(Map->plus));
-		dig_spidx_free(&(Map->plus));
-		dig_cidx_free(&(Map->plus));
-		level = 1;
-	    }
-	}
+        /* open OGR specific support files */
+        if (level == 2 && Map->format == GV_FORMAT_OGR) {
+            if (V2_open_old_ogr(Map) < 0) {
+                dig_free_plus(&(Map->plus));
+                dig_spidx_free(&(Map->plus));
+                dig_cidx_free(&(Map->plus));
+                level = 1;
+            }
+        }
 #endif
 #ifdef HAVE_POSTGRES
-	/* open OGR specific support files */
-	if (level == 2 && Map->format == GV_FORMAT_POSTGIS) {
-	    if (V2_open_old_pg(Map) < 0) {
-		dig_free_plus(&(Map->plus));
-		dig_spidx_free(&(Map->plus));
-		dig_cidx_free(&(Map->plus));
-		level = 1;
-	    }
-	}
+        /* open OGR (pseudo-topology access only) specific support
+         * files */
+        if (level == 2 && Map->format == GV_FORMAT_POSTGIS) {
+            if (V2_open_old_pg(Map) < 0) {
+                dig_free_plus(&(Map->plus));
+                dig_spidx_free(&(Map->plus));
+                dig_cidx_free(&(Map->plus));
+                level = 1;
+            }
+        }
 #endif
-	if (level_request == 2 && level < 2) {
-	    if (!ogr_mapset) {
-		/* for direct OGR read access is built pseudo-topology on the fly */
-		G_warning(_("Unable to open vector map <%s> on level %d. "
-			    "Try to rebuild vector topology by v.build."),
-			  Vect_get_full_name(Map), level_request);
-		return -1;
-	    }
-	}
+        if (level_request == 2 && level < 2) {
+            if (!ogr_mapset) {
+                /* for direct OGR read access is built pseudo-topology on the fly */
+                G_warning(_("Unable to open vector map <%s> on level %d. "
+                            "Try to rebuild vector topology by v.build."),
+                          Vect_get_full_name(Map), level_request);
+                return -1;
+            }
+        }
     }
     else {
-	level = 1;		/* i.e. requested level is 1 */
+        level = 1;              /* i.e. requested level is 1 */
     }
 
     /* open level 1 files / sources (format specific) */
     if (!head_only || ogr_mapset || format == GV_FORMAT_POSTGIS) {
-	/* no need to open coordinates */
-	if (0 != (*Open_old_array[format][1]) (Map, update)) {	/* cannot open */
-	    if (level == 2) {	/* support files opened */
-		dig_free_plus(&(Map->plus));
-		dig_spidx_free(&(Map->plus));
-		dig_cidx_free(&(Map->plus));
-	    }
-	    if (level_request == 0)
-		G_fatal_error(_("Unable to open vector map <%s>"),
-			      Vect_get_full_name(Map));
-	    else
-		G_fatal_error(_("Unable to open vector map <%s> on level %d. "
-				"Try to rebuild vector topology by v.build."),
-			      Vect_get_full_name(Map), level_request);
-	    return -1;
-	}
-	if (ogr_mapset && !head_only && level_request != 1) {
-	    /* build pseudo-topology on the fly */
-	    int verbose;
-	    verbose = G_verbose();
-	    G_message(_("Building topology for OGR layer <%s> from datasource '%s'..."),
-		      Map->fInfo.ogr.layer_name, Map->fInfo.ogr.dsn);
-	    G_set_verbose(0);
-	    if (Vect_build(Map)) {
-		level = 2;
-	    }
-	    G_set_verbose(verbose);
-	    if (level < level_request)
-	      G_fatal_error(_("Unable to open vector map <%s> on level %d"),
-			    Map->fInfo.ogr.layer_name, level_request);
-	}
+        /* no need to open coordinates */
+        if (0 != (*Open_old_array[format][1]) (Map, update)) {  /* cannot open */
+            if (level >= 2) {   /* support files opened */
+                dig_free_plus(&(Map->plus));
+                dig_spidx_free(&(Map->plus));
+                dig_cidx_free(&(Map->plus));
+            }
+            if (level_request == 0)
+                G_fatal_error(_("Unable to open vector map <%s>"),
+                              Vect_get_full_name(Map));
+            else
+                G_fatal_error(_("Unable to open vector map <%s> on level %d. "
+                                "Try to rebuild vector topology by v.build."),
+                              Vect_get_full_name(Map), level_request);
+            return -1;
+        }
+        if (ogr_mapset && !head_only && level_request != 1) {
+            /* build pseudo-topology on the fly */
+            int verbose;
+            verbose = G_verbose();
+            G_message(_("Building topology for OGR layer <%s> from datasource '%s'..."),
+                      Map->fInfo.ogr.layer_name, Map->fInfo.ogr.dsn);
+            G_set_verbose(0);
+            if (Vect_build(Map)) {
+                level = 2;
+            }
+            G_set_verbose(verbose);
+            if (level < level_request)
+              G_fatal_error(_("Unable to open vector map <%s> on level %d"),
+                            Map->fInfo.ogr.layer_name, level_request);
+        }
 	if (level < 2 && Map->head.with_z) {
 	    /* topo has been initialized as 2D, update to 3D */
 	    dig_free_plus(&(Map->plus));
@@ -421,27 +437,27 @@
     Map->head_only = head_only;
     Map->support_updated = FALSE;
     if (update) {
-	Map->mode = GV_MODE_RW;
-	Map->plus.mode = GV_MODE_RW;
+        Map->mode = GV_MODE_RW;
+        Map->plus.mode = GV_MODE_RW;
     }
     else {
-	Map->mode = GV_MODE_READ;
-	Map->plus.mode = GV_MODE_READ;
+        Map->mode = GV_MODE_READ;
+        Map->plus.mode = GV_MODE_READ;
     }
     if (head_only) {
-	Map->head_only = TRUE;
+        Map->head_only = TRUE;
     }
     else {
-	Map->head_only = FALSE;
+        Map->head_only = FALSE;
     }
 
     G_debug(1, "Vect_open_old(): vector opened on level %d", level);
 
-    if (level == 1) {		/* without topology */
-	Map->plus.built = GV_BUILD_NONE;
+    if (level == 1) {           /* without topology */
+        Map->plus.built = GV_BUILD_NONE;
     }
-    else {			/* level 2, with topology */
-	Map->plus.built = GV_BUILD_ALL;	/* highest level of topology for level 2 */
+    else {                      /* level 2, with topology */
+        Map->plus.built = GV_BUILD_ALL; /* highest level of topology for level 2 */
     }
 
     Map->plus.uplist.do_uplist = FALSE;
@@ -452,56 +468,56 @@
 
     /* open history file */
     sprintf(buf, "%s/%s", GV_DIRECTORY, Map->name);
-    if (update && !ogr_mapset) {		/* native only */
-	Map->hist_fp = G_fopen_modify(buf, GV_HIST_ELEMENT);
-	if (Map->hist_fp == NULL) {
-	    G_warning(_("Unable to open history file for vector map <%s>"),
-		      Vect_get_full_name(Map));
-	    return -1;
-	}
-	G_fseek(Map->hist_fp, (off_t) 0, SEEK_END);
-	Vect_hist_write(Map,
-			"---------------------------------------------------------------------------------\n");
+    if (update && !ogr_mapset) {                /* native only */
+        Map->hist_fp = G_fopen_modify(buf, GV_HIST_ELEMENT);
+        if (Map->hist_fp == NULL) {
+            G_warning(_("Unable to open history file for vector map <%s>"),
+                      Vect_get_full_name(Map));
+            return -1;
+        }
+        G_fseek(Map->hist_fp, (off_t) 0, SEEK_END);
+        Vect_hist_write(Map,
+                        "---------------------------------------------------------------------------------\n");
 
     }
     else {
-	if (Map->format == GV_FORMAT_NATIVE || Map->format == GV_FORMAT_OGR ||
-	    Map->format == GV_FORMAT_POSTGIS) {
-	    Map->hist_fp = G_fopen_old(buf, GV_HIST_ELEMENT, Map->mapset);
-	    /* If NULL (does not exist) then Vect_hist_read() handle that */
-	}
-	else {
-	    Map->hist_fp = NULL;
-	}
+        if (Map->format == GV_FORMAT_NATIVE || Map->format == GV_FORMAT_OGR ||
+            Map->format == GV_FORMAT_POSTGIS) {
+            Map->hist_fp = G_fopen_old(buf, GV_HIST_ELEMENT, Map->mapset);
+            /* If NULL (does not exist) then Vect_hist_read() handle that */
+        }
+        else {
+            Map->hist_fp = NULL;
+        }
     }
 
-    if (!head_only) {		/* cannot rewind if not fully opened */
-	Vect_rewind(Map);
+    if (!head_only) {           /* cannot rewind if not fully opened */
+        Vect_rewind(Map);
     }
     
     /* delete support files if native format was opened for update (not head_only) */
     if (update && !head_only) {
-	char file_path[GPATH_MAX];
+        char file_path[GPATH_MAX];
 
-	sprintf(buf, "%s/%s", GV_DIRECTORY, name);
+        sprintf(buf, "%s/%s", GV_DIRECTORY, name);
 
-	G_file_name(file_path, buf, GV_TOPO_ELEMENT, G_mapset());
-	if (access(file_path, F_OK) == 0)	/* topo file exists? */
-	    unlink(file_path);
+        G_file_name(file_path, buf, GV_TOPO_ELEMENT, G_mapset());
+        if (access(file_path, F_OK) == 0)       /* topo file exists? */
+            unlink(file_path);
 
-	G_file_name(file_path, buf, GV_SIDX_ELEMENT, G_mapset());
-	if (access(file_path, F_OK) == 0)	/* sidx file exists? */
-	    unlink(file_path);
+        G_file_name(file_path, buf, GV_SIDX_ELEMENT, G_mapset());
+        if (access(file_path, F_OK) == 0)       /* sidx file exists? */
+            unlink(file_path);
 
-	G_file_name(file_path, buf, GV_CIDX_ELEMENT, G_mapset());
-	if (access(file_path, F_OK) == 0)	/* cidx file exists? */
-	    unlink(file_path);
+        G_file_name(file_path, buf, GV_CIDX_ELEMENT, G_mapset());
+        if (access(file_path, F_OK) == 0)       /* cidx file exists? */
+            unlink(file_path);
 
-	if (format == GV_FORMAT_OGR || format == GV_FORMAT_POSTGIS) {
-	    G_file_name(file_path, buf, GV_FIDX_ELEMENT, G_mapset());
-	    if (access(file_path, F_OK) == 0)	/* fidx file exists? */
-		unlink(file_path);
-	}
+        if (format == GV_FORMAT_OGR || format == GV_FORMAT_POSTGIS) {
+            G_file_name(file_path, buf, GV_FIDX_ELEMENT, G_mapset());
+            if (access(file_path, F_OK) == 0)   /* fidx file exists? */
+                unlink(file_path);
+        }
     }
 
     return level;
@@ -543,7 +559,7 @@
   \return -1 on error
 */
 int Vect_open_old2(struct Map_info *Map, const char *name, const char *mapset,
-		   const char *layer)
+                   const char *layer)
 {
     return open_old(Map, name, mapset, layer, 0, 0);
 }
@@ -639,7 +655,7 @@
   \return -1 on error 
 */
 int Vect_open_old_head2(struct Map_info *Map, const char *name, const char *mapset,
-			const char *layer)
+                        const char *layer)
 {
     return open_old(Map, name, mapset, layer, 0, 1);
 }
@@ -656,7 +672,7 @@
   \return -1 on error 
 */
 int Vect_open_update_head(struct Map_info *Map, const char *name,
-			  const char *mapset)
+                          const char *mapset)
 {
     return open_old(Map, name, mapset, NULL, 1, 1);
 }
@@ -688,129 +704,129 @@
     Vect__init_head(Map);
 
     if (G_name_is_fully_qualified(name, xname, xmapset)) {
-	if (strcmp(xmapset, G_mapset()) != 0) {
-	    G_fatal_error(_("<%s> is not the current mapset (%s)"), name,
-			  G_mapset());
-	    return -1;
-	}
-	name = xname;
+        if (strcmp(xmapset, G_mapset()) != 0) {
+            G_fatal_error(_("<%s> is not the current mapset (%s)"), name,
+                          G_mapset());
+            return -1;
+        }
+        name = xname;
     }
 
     /* check for [A-Za-z][A-Za-z0-9_]* in name */
     if (Vect_legal_filename(name) < 0) {
-	G_fatal_error(_("Vector map name is not SQL compliant"));
-	return -1;
+        G_fatal_error(_("Vector map name is not SQL compliant"));
+        return -1;
     }
 
     /* determine output format native or ogr */
     Map->format = GV_FORMAT_NATIVE;
     if (strcmp(G_program_name(), "v.external") != 0) {
-	if (G_find_file2("", "OGR", G_mapset())) {
-	    /* OGR */
-	    FILE *fp;
-	    const char *p;
-	    
-	    struct Key_Value *key_val;
-	    struct Format_info_ogr *ogr_info;
-	    
-	    G_debug(2, " using OGR format");
-	    Map->format = GV_FORMAT_OGR_DIRECT;
-	    fp = G_fopen_old("", "OGR", G_mapset());
-	    if (!fp) {
-		G_fatal_error(_("Unable to open OGR file"));
-	    }
-	    key_val = G_fread_key_value(fp);
-	    fclose(fp);
-	    
-	    ogr_info = &(Map->fInfo.ogr);
-	    /* format */
-	    p = G_find_key_value("format", key_val);
-	    if (p)
-		ogr_info->driver_name = G_store(p);
-	    /* dsn */
-	    p = G_find_key_value("dsn", key_val);
-	    if (p)
-		ogr_info->dsn = G_store(p);
-	    /* options */
-	    p = G_find_key_value("options", key_val);
-	    if (p)
-		ogr_info->layer_options = G_tokenize(p, ",");
-	    
-	    ogr_info->layer_name = G_store(name);
-	}
-	if (G_find_file2("", "PG", G_mapset())) {
-	    /* PostGIS */
-	    if (Map->fInfo.ogr.driver_name) {
-		G_warning(_("OGR output also detected, using OGR"));
-	    }
-	    else {
-		FILE *fp;
-		const char *p;
-		
-		struct Key_Value *key_val;
-		struct Format_info_pg *pg_info;
-		
-		G_debug(2, " using PostGIS format");
-		Map->format = GV_FORMAT_POSTGIS;
-		fp = G_fopen_old("", "PG", G_mapset());
-		if (!fp) {
-		    G_fatal_error(_("Unable to open PG file"));
-		}
-		key_val = G_fread_key_value(fp);
-		fclose(fp);
-		
-		pg_info = &(Map->fInfo.pg);
-		/* conninfo */
-		p = G_find_key_value("conninfo", key_val);
-		if (p) {
-		    pg_info->conninfo = G_store(p);
-		    G_debug(1, "PG: conninfo = '%s'", pg_info->conninfo);
-		}
-		
-		/* schema (default: public) */
-		p = G_find_key_value("schema", key_val);
-		if (p)
-		    pg_info->schema_name = G_store(p);
-		else
-		    pg_info->schema_name = G_store("public");
-		G_debug(1, "PG: schema_name = '%s'", pg_info->schema_name);
-		
-		/* fid column (default: ogc_fid) */
-		p = G_find_key_value("fid", key_val);
-		if (p)
-		    pg_info->fid_column = G_store(p);
-		else
-		    pg_info->fid_column = G_store("ogc_fid");
-		G_debug(1, "PG: fid_column = '%s'", pg_info->fid_column);
-		
-		/* geometry column (default: wkb_geometry) */
-		p = G_find_key_value("geometry_name", key_val);
-		if (p)
-		    pg_info->geom_column = G_store(p);
-		else
-		    pg_info->geom_column = G_store("wkb_geometry");
-		G_debug(1, "PG: geom_column = '%s'", pg_info->geom_column);
-		
+        if (G_find_file2("", "OGR", G_mapset())) {
+            /* OGR */
+            FILE *fp;
+            const char *p;
+            
+            struct Key_Value *key_val;
+            struct Format_info_ogr *ogr_info;
+            
+            G_debug(2, " using OGR format");
+            Map->format = GV_FORMAT_OGR_DIRECT;
+            fp = G_fopen_old("", "OGR", G_mapset());
+            if (!fp) {
+                G_fatal_error(_("Unable to open OGR file"));
+            }
+            key_val = G_fread_key_value(fp);
+            fclose(fp);
+            
+            ogr_info = &(Map->fInfo.ogr);
+            /* format */
+            p = G_find_key_value("format", key_val);
+            if (p)
+                ogr_info->driver_name = G_store(p);
+            /* dsn */
+            p = G_find_key_value("dsn", key_val);
+            if (p)
+                ogr_info->dsn = G_store(p);
+            /* options */
+            p = G_find_key_value("options", key_val);
+            if (p)
+                ogr_info->layer_options = G_tokenize(p, ",");
+            
+            ogr_info->layer_name = G_store(name);
+        }
+        if (G_find_file2("", "PG", G_mapset())) {
+            /* PostGIS */
+            if (Map->fInfo.ogr.driver_name) {
+                G_warning(_("OGR output also detected, using OGR"));
+            }
+            else {
+                FILE *fp;
+                const char *p;
+                
+                struct Key_Value *key_val;
+                struct Format_info_pg *pg_info;
+                
+                G_debug(2, " using PostGIS format");
+                Map->format = GV_FORMAT_POSTGIS;
+                fp = G_fopen_old("", "PG", G_mapset());
+                if (!fp) {
+                    G_fatal_error(_("Unable to open PG file"));
+                }
+                key_val = G_fread_key_value(fp);
+                fclose(fp);
+                
+                pg_info = &(Map->fInfo.pg);
+                /* conninfo */
+                p = G_find_key_value("conninfo", key_val);
+                if (p) {
+                    pg_info->conninfo = G_store(p);
+                    G_debug(1, "PG: conninfo = '%s'", pg_info->conninfo);
+                }
+                
+                /* schema (default: public) */
+                p = G_find_key_value("schema", key_val);
+                if (p)
+                    pg_info->schema_name = G_store(p);
+                else
+                    pg_info->schema_name = G_store("public");
+                G_debug(1, "PG: schema_name = '%s'", pg_info->schema_name);
+                
+                /* fid column (default: ogc_fid) */
+                p = G_find_key_value("fid", key_val);
+                if (p)
+                    pg_info->fid_column = G_store(p);
+                else
+                    pg_info->fid_column = G_store("ogc_fid");
+                G_debug(1, "PG: fid_column = '%s'", pg_info->fid_column);
+                
+                /* geometry column (default: wkb_geometry) */
+                p = G_find_key_value("geometry_name", key_val);
+                if (p)
+                    pg_info->geom_column = G_store(p);
+                else
+                    pg_info->geom_column = G_store("wkb_geometry");
+                G_debug(1, "PG: geom_column = '%s'", pg_info->geom_column);
+                
                 /* table name */
-		Map->fInfo.pg.table_name = G_store(name);
-	    }
-	}
+                Map->fInfo.pg.table_name = G_store(name);
+            }
+        }
     }
     if (Map->format == GV_FORMAT_NATIVE) {
-	/* native */
-	G_debug(2, " using native format");
+        /* native */
+        G_debug(2, " using native format");
 
-	/* check if map already exists */
-	if (G_find_vector2(name, G_mapset()) != NULL) {
-	    G_warning(_("Vector map <%s> already exists and will be overwritten"),
-		      name);
-	    
-	    ret = Vect_delete(name);
-	    if (ret == -1) {
-		G_warning(_("Unable to delete vector map <%s>"), name);
-		return -1;
-	    }
-	}
+        /* check if map already exists */
+        if (G_find_vector2(name, G_mapset()) != NULL) {
+            G_warning(_("Vector map <%s> already exists and will be overwritten"),
+                      name);
+            
+            ret = Vect_delete(name);
+            if (ret == -1) {
+                G_warning(_("Unable to delete vector map <%s>"), name);
+                return -1;
+            }
+        }
     }
 
     Map->name     = G_store(name);
@@ -822,20 +838,20 @@
     Map->plus.spidx_with_z = Map->plus.with_z = Map->head.with_z = (with_z != 0);
 
     if ((*Open_new_array[Map->format][1]) (Map, name, with_z) < 0) {
-	G_fatal_error(_("Unable to create vector map <%s>"),
-		      name);
-	return -1;
+        G_fatal_error(_("Unable to create vector map <%s>"),
+                      name);
+        return -1;
     }
 
     if (Map->format == GV_FORMAT_NATIVE) {
         /* Open history file */
-	sprintf(buf, "%s/%s", GV_DIRECTORY, Map->name);
-	Map->hist_fp = G_fopen_new(buf, GV_HIST_ELEMENT);
-	if (Map->hist_fp == NULL) {
-	    G_warning(_("Unable to open history file of vector map <%s>"),
-		      name);
-	    return -1;
-	}
+        sprintf(buf, "%s/%s", GV_DIRECTORY, Map->name);
+        Map->hist_fp = G_fopen_new(buf, GV_HIST_ELEMENT);
+        if (Map->hist_fp == NULL) {
+            G_warning(_("Unable to open history file of vector map <%s>"),
+                      name);
+            return -1;
+        }
     }
     
     Open_level = 0;
@@ -879,38 +895,38 @@
     
     switch (Map->format) {
     case GV_FORMAT_NATIVE:
-	sprintf(buf, "%s/%s", GV_DIRECTORY, Map->name);
-	G_file_name(path, buf, GV_COOR_ELEMENT, Map->mapset);
-	G_debug(1, "get coor info: %s", path);
-	if (0 != stat(path, &stat_buf)) {
-	    G_warning(_("Unable to stat file <%s>"), path);
-	    Info->size = -1L;
-	    Info->mtime = -1L;
-	}
-	else {
-	    Info->size = (off_t)stat_buf.st_size;      /* file size */
-	    Info->mtime = (long)stat_buf.st_mtime;     /* last modified time */
-	}
-	
+        sprintf(buf, "%s/%s", GV_DIRECTORY, Map->name);
+        G_file_name(path, buf, GV_COOR_ELEMENT, Map->mapset);
+        G_debug(1, "get coor info: %s", path);
+        if (0 != stat(path, &stat_buf)) {
+            G_warning(_("Unable to stat file <%s>"), path);
+            Info->size = -1L;
+            Info->mtime = -1L;
+        }
+        else {
+            Info->size = (off_t)stat_buf.st_size;      /* file size */
+            Info->mtime = (long)stat_buf.st_mtime;     /* last modified time */
+        }
+        
         /* stat does not give correct size on MINGW
          * if the file is opened */
 #ifdef __MINGW32__
-	if (Map->open == VECT_OPEN_CODE) {
-	    dig_fseek(&(Map->dig_fp), 0L, SEEK_END);
-	    G_debug(2, "dig_ftell = %d", dig_ftell(&(Map->dig_fp)));
-	    Info->size = dig_ftell(&(Map->dig_fp));
-	}
+        if (Map->open == VECT_OPEN_CODE) {
+            dig_fseek(&(Map->dig_fp), 0L, SEEK_END);
+            G_debug(2, "dig_ftell = %d", dig_ftell(&(Map->dig_fp)));
+            Info->size = dig_ftell(&(Map->dig_fp));
+        }
 #endif
-	break;
+        break;
     case GV_FORMAT_OGR:
     case GV_FORMAT_OGR_DIRECT:
     case GV_FORMAT_POSTGIS:
-	Info->size = 0L;
-	Info->mtime = 0L;
-	break;
+        Info->size = 0L;
+        Info->mtime = 0L;
+        break;
     }
     G_debug(1, "Info->size = %lu, Info->mtime = %ld",
-	    (unsigned long)Info->size, Info->mtime);
+            (unsigned long)Info->size, Info->mtime);
 
     return 1;
 }
@@ -937,18 +953,18 @@
 
     switch (Map->format) {
     case GV_FORMAT_NATIVE:
-	sprintf(maptype, "native");
-	break;
+        sprintf(maptype, "native");
+        break;
     case GV_FORMAT_OGR:
     case GV_FORMAT_OGR_DIRECT:
-	sprintf(maptype, "OGR");
-	break;
+        sprintf(maptype, "OGR");
+        break;
     case GV_FORMAT_POSTGIS:
-	sprintf(maptype, "PostGIS");
-	break;
+        sprintf(maptype, "PostGIS");
+        break;
     default:
-	sprintf(maptype, _("unknown %d (update Vect_maptype_info)"),
-		Map->format);
+        sprintf(maptype, _("unknown %d (update Vect_maptype_info)"),
+                Map->format);
     }
 
     return G_store(maptype);
@@ -991,23 +1007,23 @@
     struct Plus_head *Plus;
 
     G_debug(1, "Vect_open_topo(): name = %s mapset= %s", Map->name,
-	    Map->mapset);
+            Map->mapset);
 
     Plus = &(Map->plus);
 
     sprintf(buf, "%s/%s", GV_DIRECTORY, Map->name);
     G_file_name(file_path, buf, GV_TOPO_ELEMENT, Map->mapset);
 
-    if (access(file_path, F_OK) != 0)	/* does not exist */
-	return 1;
+    if (access(file_path, F_OK) != 0)   /* does not exist */
+        return 1;
 
     dig_file_init(&fp);
     fp.file = G_fopen_old(buf, GV_TOPO_ELEMENT, Map->mapset);
 
-    if (fp.file == NULL) {	/* topo file is not available */
-	G_debug(1, "Cannot open topo file for vector '%s@%s'.",
-		Map->name, Map->mapset);
-	return -1;
+    if (fp.file == NULL) {      /* topo file is not available */
+        G_debug(1, "Cannot open topo file for vector '%s@%s'.",
+                Map->name, Map->mapset);
+        return -1;
     }
 
     /* get coor info */
@@ -1016,16 +1032,16 @@
 
     /* load head */
     if (dig_Rd_Plus_head(&fp, Plus) == -1)
-	return -1;
+        return -1;
 
     G_debug(1, "Topo head: coor size = %lu, coor mtime = %ld",
-	    (unsigned long)Plus->coor_size, Plus->coor_mtime);
+            (unsigned long)Plus->coor_size, Plus->coor_mtime);
 
     /* do checks */
     err = 0;
     if (CInfo.size != Plus->coor_size) {
-	G_warning(_("Size of 'coor' file differs from value saved in topology file"));
-	err = 1;
+        G_warning(_("Size of 'coor' file differs from value saved in topology file"));
+        err = 1;
     }
     /* Do not check mtime because mtime is changed by copy */
     /*
@@ -1035,9 +1051,9 @@
        }
      */
     if (err) {
-	G_warning(_("Please rebuild topology for vector map <%s@%s>"),
-		  Map->name, Map->mapset);
-	return -1;
+        G_warning(_("Please rebuild topology for vector map <%s@%s>"),
+                  Map->name, Map->mapset);
+        return -1;
     }
 
     /* load file to the memory */
@@ -1050,7 +1066,7 @@
     /* dig_file_free ( &fp); */
 
     if (ret == 0)
-	return -1;
+        return -1;
 
     return 0;
 }
@@ -1072,11 +1088,11 @@
     struct Plus_head *Plus;
 
     G_debug(1, "Vect_open_sidx(): name = %s mapset= %s mode = %s", Map->name,
-	    Map->mapset, mode == 0 ? "old" : (mode == 1 ? "update" : "new"));
+            Map->mapset, mode == 0 ? "old" : (mode == 1 ? "update" : "new"));
 
     if (Map->plus.Spidx_built == TRUE) {
-	G_warning("Spatial index already opened");
-	return 0;
+        G_warning("Spatial index already opened");
+        return 0;
     }
 
     Plus = &(Map->plus);
@@ -1084,80 +1100,80 @@
     dig_file_init(&(Map->plus.spidx_fp));
 
     if (mode < 2) {
-	sprintf(buf, "%s/%s", GV_DIRECTORY, Map->name);
-	G_file_name(file_path, buf, GV_SIDX_ELEMENT, Map->mapset);
+        sprintf(buf, "%s/%s", GV_DIRECTORY, Map->name);
+        G_file_name(file_path, buf, GV_SIDX_ELEMENT, Map->mapset);
 
-	if (access(file_path, F_OK) != 0)	/* does not exist */
-	    return 1;
+        if (access(file_path, F_OK) != 0)       /* does not exist */
+            return 1;
 
-	Map->plus.spidx_fp.file =
-	    G_fopen_old(buf, GV_SIDX_ELEMENT, Map->mapset);
+        Map->plus.spidx_fp.file =
+            G_fopen_old(buf, GV_SIDX_ELEMENT, Map->mapset);
 
-	if (Map->plus.spidx_fp.file == NULL) {	/* sidx file is not available */
-	    G_debug(1, "Cannot open spatial index file for vector '%s@%s'.",
-		    Map->name, Map->mapset);
-	    return -1;
-	}
+        if (Map->plus.spidx_fp.file == NULL) {  /* sidx file is not available */
+            G_debug(1, "Cannot open spatial index file for vector '%s@%s'.",
+                    Map->name, Map->mapset);
+            return -1;
+        }
 
-	/* get coor info */
-	/* NOTE: coor file not yet opened */
-	Vect_coor_info(Map, &CInfo);
+        /* get coor info */
+        /* NOTE: coor file not yet opened */
+        Vect_coor_info(Map, &CInfo);
 
-	/* initialize spatial index */
-	Map->plus.Spidx_new = FALSE;
+        /* initialize spatial index */
+        Map->plus.Spidx_new = FALSE;
 
-	/* load head */
-	if (dig_Rd_spidx_head(&(Map->plus.spidx_fp), Plus) == -1) {
-	    fclose(Map->plus.spidx_fp.file);
-	    return -1;
-	}
+        /* load head */
+        if (dig_Rd_spidx_head(&(Map->plus.spidx_fp), Plus) == -1) {
+            fclose(Map->plus.spidx_fp.file);
+            return -1;
+        }
 
-	G_debug(1, "Sidx head: coor size = %lu, coor mtime = %ld",
-		(unsigned long)Plus->coor_size, Plus->coor_mtime);
+        G_debug(1, "Sidx head: coor size = %lu, coor mtime = %ld",
+                (unsigned long)Plus->coor_size, Plus->coor_mtime);
 
-	/* do checks */
-	err = 0;
-	if (CInfo.size != Plus->coor_size) {
-	    G_warning(_("Size of 'coor' file differs from value saved in sidx file"));
-	    err = 1;
-	}
-	/* Do not check mtime because mtime is changed by copy */
-	/*
-	   if ( CInfo.mtime != Plus->coor_mtime ) {
-	   G_warning ( "Time of last modification for 'coor' file differs from value saved in topo file.\n");
-	   err = 1;
-	   }
-	 */
-	if (err) {
-	    G_warning(_("Please rebuild topology for vector map <%s@%s>"),
-		      Map->name, Map->mapset);
-	    fclose(Map->plus.spidx_fp.file);
-	    return -1;
-	}
+        /* do checks */
+        err = 0;
+        if (CInfo.size != Plus->coor_size) {
+            G_warning(_("Size of 'coor' file differs from value saved in sidx file"));
+            err = 1;
+        }
+        /* Do not check mtime because mtime is changed by copy */
+        /*
+           if ( CInfo.mtime != Plus->coor_mtime ) {
+           G_warning ( "Time of last modification for 'coor' file differs from value saved in topo file.\n");
+           err = 1;
+           }
+         */
+        if (err) {
+            G_warning(_("Please rebuild topology for vector map <%s@%s>"),
+                      Map->name, Map->mapset);
+            fclose(Map->plus.spidx_fp.file);
+            return -1;
+        }
     }
 
     if (mode) {
-	/* open new spatial index */
-	Map->plus.Spidx_new = TRUE;
-	
-	/* file based or memory based */
-	if (getenv("GRASS_VECTOR_LOWMEM")) {
-	    /* free old indices */
-	    dig_spidx_free(Plus);
-	    /* initialize file based indices */
-	    Map->plus.Spidx_file = 1;
-	    dig_spidx_init(Plus);
-	}
-	G_debug(1, "%s based spatial index",
-	           Map->plus.Spidx_file == 0 ? "Memory" : "File");
+        /* open new spatial index */
+        Map->plus.Spidx_new = TRUE;
+        
+        /* file based or memory based */
+        if (getenv("GRASS_VECTOR_LOWMEM")) {
+            /* free old indices */
+            dig_spidx_free(Plus);
+            /* initialize file based indices */
+            Map->plus.Spidx_file = 1;
+            dig_spidx_init(Plus);
+        }
+        G_debug(1, "%s based spatial index",
+                   Map->plus.Spidx_file == 0 ? "Memory" : "File");
 
-	if (mode == 1) {
-	    /* load spatial index for update */
-	    if (dig_Rd_spidx(&(Map->plus.spidx_fp), Plus) == -1) {
-		fclose(Map->plus.spidx_fp.file);
-		return -1;
-	    }
-	}
+        if (mode == 1) {
+            /* load spatial index for update */
+            if (dig_Rd_spidx(&(Map->plus.spidx_fp), Plus) == -1) {
+                fclose(Map->plus.spidx_fp.file);
+                return -1;
+            }
+        }
     }
 
     Map->plus.Spidx_built = TRUE;

Modified: grass/trunk/lib/vector/Vlib/open_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open_pg.c	2012-05-31 12:32:19 UTC (rev 51901)
+++ grass/trunk/lib/vector/Vlib/open_pg.c	2012-05-31 12:47:11 UTC (rev 51902)
@@ -11,7 +11,7 @@
    (>=v2). Read the file COPYING that comes with GRASS for details.
 
    \author Martin Landa <landa.martin gmail.com>
- */
+*/
 
 #include <string.h>
 #include <stdlib.h>
@@ -23,11 +23,27 @@
 #ifdef HAVE_POSTGRES
 #include "pg_local_proto.h"
 
+static struct edge_data {
+    int id;
+    int start_node;
+    int end_node;
+    int left_face;
+    int right_face;
+};
+
 static char *get_key_column(struct Format_info_pg *);
 static SF_FeatureType ftype_from_string(const char *);
 static int drop_table(struct Format_info_pg *);
 static int check_schema(const struct Format_info_pg *);
 static int create_table(struct Format_info_pg *, const struct field_info *);
+static void connect_db(struct Format_info_pg *);
+static int parse_bbox(const char *, struct bound_box *, int);
+static int num_of_records(const struct Format_info_pg *, const char *);
+static int read_p_node(struct Plus_head *, int, int, struct Format_info_pg *);
+static int read_p_line(struct Plus_head *, int, const struct edge_data *, struct Format_info_pg *);
+static int read_p_area(struct Plus_head *, int, int, struct Format_info_pg *);
+static int load_plus_head(struct Format_info_pg *, PGresult *, struct Plus_head *);
+static int load_plus(struct Format_info_pg *, PGresult *, struct Plus_head *);
 #endif
 
 /*!
@@ -67,13 +83,9 @@
             pg_info->conninfo, pg_info->table_name);
 
     /* connect database */
-    pg_info->conn = PQconnectdb(pg_info->conninfo);
-    G_debug(2, "   PQconnectdb(): %s", pg_info->conninfo);
-    if (PQstatus(pg_info->conn) == CONNECTION_BAD)
-        G_fatal_error("%s\n%s",
-                      _("Connection ton PostgreSQL database failed."),
-                      PQerrorMessage(pg_info->conn));
-
+    if (!pg_info->conn)
+        connect_db(pg_info);
+    
     /* get DB name */
     pg_info->db_name = G_store(PQdb(pg_info->conn));
     if (!pg_info->db_name) {
@@ -81,11 +93,6 @@
         return -1;
     }
 
-    /* if schema not defined, use 'public' */
-    if (!pg_info->schema_name) {
-        pg_info->schema_name = G_store("public");
-    }
-
     /* get fid and geometry column */
     sprintf(stmt, "SELECT f_geometry_column, coord_dimension, srid, type "
             "FROM geometry_columns WHERE f_table_schema = '%s' AND "
@@ -365,7 +372,73 @@
 #endif
 }
 
+/*!
+  \brief Read full-topology for PostGIS links
+  
+  Note: Only 2D topological primitives are currently supported
+  
+  \param[in,out] Map pointer to Map_info structure
+  \param head_only TRUE to read only header
+  
+  \return 0 on success
+  \return 1 topology layer does not exist
+  \return -1 on error
+*/
+int Vect_open_topo_pg(struct Map_info *Map, int head_only)
+{
 #ifdef HAVE_POSTGRES
+    char stmt[DB_SQL_MAX];
+
+    struct Plus_head *plus;
+    struct Format_info_pg *pg_info;
+    
+    PGresult *res;
+
+    plus = &(Map->plus);
+    pg_info = &(Map->fInfo.pg);
+    
+    /* connect database */
+    if (!pg_info->conn)
+        connect_db(pg_info);
+    
+    /* check if topology layer/schema exists */
+    sprintf(stmt,
+            "SELECT t.name,t.hasz,l.feature_column FROM topology.layer "
+            "AS l JOIN topology.topology AS t ON l.topology_id = t.id "
+            "WHERE schema_name = '%s' AND table_name = '%s'",
+            pg_info->schema_name, pg_info->table_name);
+    G_debug(2, "SQL: %s", stmt);
+    
+    res = PQexec(pg_info->conn, stmt);
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
+        PQntuples(res) != 1) {
+        G_debug(1, "Topology layers for '%s.%s' not found (%s)",
+                pg_info->schema_name, pg_info->table_name,
+                PQerrorMessage(pg_info->conn));
+        if (res)
+            PQclear(res);
+        return 1;
+    }
+
+    pg_info->toposchema_name = G_store(PQgetvalue(res, 0, 0));
+    pg_info->topogeom_column = G_store(PQgetvalue(res, 0, 2));
+
+    /* free and init plus structure */
+    dig_init_plus(plus);
+    if (load_plus_head(pg_info, res, plus) != 0)
+        return -1;
+    
+    if (head_only)
+        return 0;
+    
+    return load_plus(pg_info, res, plus);
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+    return -1;
+#endif
+}
+
+#ifdef HAVE_POSTGRES
 char *get_key_column(struct Format_info_pg *pg_info)
 {
     char *key_column;
@@ -686,4 +759,599 @@
 
     return 0;
 }
+
+void connect_db(struct Format_info_pg *pg_info)
+{
+    pg_info->conn = PQconnectdb(pg_info->conninfo);
+    G_debug(2, "   PQconnectdb(): %s", pg_info->conninfo);
+    if (PQstatus(pg_info->conn) == CONNECTION_BAD)
+        G_fatal_error("%s\n%s",
+                      _("Connection ton PostgreSQL database failed."),
+                      PQerrorMessage(pg_info->conn));
+}
+
+/*!
+  \brief Parse BBOX string
+  
+  \param value string buffer
+  \param[out] bbox pointer to output bound_box struct
+
+  \return 0 on success
+  \return -1 on error
+*/
+int parse_bbox(const char *value, struct bound_box *bbox, int with_z)
+{
+    unsigned int i;
+    size_t length, prefix_length;
+    char **tokens, **tokens_coord, *coord;
+    
+    prefix_length = strlen("box3d(");
+    if (G_strncasecmp(value, "box3d(", prefix_length) != 0)
+        return -1;
+    
+    /* strip off "bbox3d(...)" */
+    length = strlen(value);
+    coord = G_malloc(length - prefix_length);
+    for (i = prefix_length; i < length; i++)
+        coord[i-prefix_length] = value[i];
+    coord[length-prefix_length-1] = '\0';
+    
+    tokens = G_tokenize(coord, ",");
+    G_free(coord);
+    
+    if (G_number_of_tokens(tokens) != 2) {
+        G_free_tokens(tokens);
+        return -1;
+    }
+    
+    /* parse bbox LL corner */
+    tokens_coord = G_tokenize(tokens[0], " ");
+    if (G_number_of_tokens(tokens_coord) != 3) {
+        G_free_tokens(tokens);
+        G_free_tokens(tokens_coord);
+    }
+    bbox->W = atof(tokens_coord[0]);
+    bbox->S = atof(tokens_coord[1]);
+    bbox->B = atof(tokens_coord[2]);
+    
+    G_free_tokens(tokens_coord);
+    
+    /* parse bbox UR corner */
+    tokens_coord = G_tokenize(tokens[1], " ");
+    if (G_number_of_tokens(tokens_coord) != 3) {
+        G_free_tokens(tokens);
+        G_free_tokens(tokens_coord);
+    }
+    bbox->E = atof(tokens_coord[0]);
+    bbox->N = atof(tokens_coord[1]);
+    bbox->T = atof(tokens_coord[2]);
+    
+    G_free_tokens(tokens_coord);
+    G_free_tokens(tokens);
+    
+    return 0;
+}
+
+/*!
+  \brief Get number of records for given SQL statement
+
+  \param stmt string buffer with SQL statement
+  
+  \return number of returned records
+  \return -1 on error
+*/
+int num_of_records(const struct Format_info_pg *pg_info,
+                   const char *stmt)
+{
+    int result;
+    PGresult *res;
+
+    G_debug(2, "SQL: %s", stmt);
+    res = PQexec(pg_info->conn, stmt);
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
+        PQntuples(res) != 1) {
+        G_warning(_("Unable to get number of records for:\n%s"), stmt);
+        if (res)
+            PQclear(res);
+        return -1;
+    }
+    result = atoi(PQgetvalue(res, 0, 0));
+    PQclear(res);
+    
+    return result;
+}
+
+/*!
+  \brief Read P_node structure
+  
+  See dig_Rd_P_node() for reference.
+  
+  \param plus pointer to Plus_head structure
+  \param n index (starts at 1)
+  \param id node id (table "node")
+  \param pg_info pointer to Format_info_pg sttucture
+
+  \return 0 on success
+  \return -1 on failure
+*/
+int read_p_node(struct Plus_head *plus, int n, int id,
+                struct Format_info_pg *pg_info)
+{
+    int i, cnt;
+    char stmt[DB_SQL_MAX];
+    
+    struct P_node *node;
+    
+    PGresult *res;
+    
+    /* get lines connected to the node */
+    sprintf(stmt,
+            "SELECT edge_id,'s' as node,"
+            "ST_Azimuth(ST_StartPoint(geom), ST_PointN(geom, 2)) AS angle"
+            " FROM \"%s\".edge WHERE start_node = %d UNION ALL "
+            "SELECT edge_id,'e' as node,"
+            "ST_Azimuth(ST_EndPoint(geom), ST_PointN(geom, ST_NumPoints(geom) - 1)) AS angle"
+            " FROM \"%s\".edge WHERE end_node = %d"
+            " ORDER BY angle DESC",
+            pg_info->toposchema_name, id,
+            pg_info->toposchema_name, id);
+    G_debug(2, "SQL: %s", stmt);
+    res = PQexec(pg_info->conn, stmt);
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) {
+        G_warning(_("Unable to read node %d"), id);
+        if (res)
+            PQclear(res);
+        return -1;
+    }
+    cnt = PQntuples(res);
+    
+    if (cnt == 0) { /* dead ??? */
+        plus->Node[n] = NULL;
+        return 0;
+    }
+
+    node = dig_alloc_node();
+    node->n_lines = cnt;
+    G_debug(4, "read_p_node(): id = %d, n_lines = %d", id, cnt);
+    
+    if (dig_node_alloc_line(node, node->n_lines) == -1)
+        return -1;
+
+    /* lines / angles */
+    for (i = 0; i < node->n_lines; i++) {
+        node->lines[i] = atoi(PQgetvalue(res, i, 0));
+        if (strcmp(PQgetvalue(res, i, 1), "s") != 0) {
+            /* end node */
+            node->lines[i] *= -1;
+        }
+        node->angles[i] = M_PI / 2 - atof(PQgetvalue(res, i, 2));
+        /* angles range <-PI; PI> */
+        if (node->angles[i] > M_PI)
+            node->angles[i] = node->angles[i] - 2 * M_PI;
+        if (node->angles[i] < -1.0 * M_PI)
+            node->angles[i] = node->angles[i] + 2 * M_PI;
+        G_debug(5, "\tline = %d angle = %f", node->lines[i],
+                node->angles[i]);
+    }
+    PQclear(res);
+    
+    /* ???
+    if (plus->with_z)
+    if (0 >= dig__fread_port_P(&n_edges, 1, fp))
+    */
+    
+    /* get node coordinates */
+    sprintf(stmt,
+            "SELECT ST_X(geom),ST_Y(geom),ST_Z(geom) FROM \"%s\".node "
+            "WHERE node_id = %d",
+            pg_info->toposchema_name, id);
+    G_debug(2, "SQL: %s", stmt);
+    res = PQexec(pg_info->conn, stmt);
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
+        PQntuples(res) != 1) {
+        G_warning(_("Unable to read node %d"), id);
+        if (res)
+            PQclear(res);
+        return -1;
+    }
+    node->x = atof(PQgetvalue(res, 0, 0));
+    node->y = atof(PQgetvalue(res, 0, 1));
+    if (plus->with_z)
+        node->z = atof(PQgetvalue(res, 0, 2));
+    else
+        node->z = 0;
+    PQclear(res);
+
+    plus->Node[n] = node;
+    
+    return 0;
+}
+
+/*!
+  \brief Read P_line structure
+  
+  See dig_Rd_P_line() for reference.
+  
+  Supported feature types:
+   - GV_POINT
+   - GV_LINE
+   - GV_BOUNDARY
+  
+  \param plus pointer to Plus_head structure
+  \param n index (starts at 1)
+  \param data edge data (id, start/end node, left/right face, ...)
+  \param pg_info pointer to Format_info_pg sttucture
+
+  \return 0 on success
+  \return -1 on failure
+*/
+int read_p_line(struct Plus_head *plus, int n,
+                const struct edge_data *data,
+                struct Format_info_pg *pg_info)
+{
+    int tp;
+    struct P_line *line;
+    
+    if (data->start_node == 0 && data->end_node == 0) {
+        if (data->left_face == 0)
+            tp = GV_POINT;
+        else
+            tp = GV_CENTROID;
+    }
+    else if (data->left_face == 0 && data->right_face == 0) {
+        tp = GV_LINE;
+    }
+    else {
+        tp = GV_BOUNDARY;
+    }
+    
+    if (tp == 0) { /* dead ??? */
+        plus->Line[n] = NULL;
+        return 0;
+    }
+
+    line = dig_alloc_line();
+    
+    /* type & offset ( = id) */
+    line->type = tp;
+    line->offset = data->id;
+    G_debug(4, "read_p_line(): id/offset = %d type = %d", data->id, line->type);
+    
+    /* topo */
+    if (line->type == GV_POINT) {
+        line->topo = NULL;
+    }
+    else {
+        line->topo = dig_alloc_topo(line->type);
+
+        /* lines */
+        if (line->type == GV_LINE) {
+            struct P_topo_l *topo = (struct P_topo_l *)line->topo;
+            
+            topo->N1 = data->start_node;
+            topo->N2 = data->end_node;
+        }
+        /* boundaries */
+        else if (line->type == GV_BOUNDARY) {
+            struct P_topo_b *topo = (struct P_topo_b *)line->topo;
+            
+            topo->N1    = data->start_node;
+            topo->N2    = data->end_node;
+            topo->left  = data->left_face == 0 ? -1 : data->left_face;
+            topo->right = data->right_face == 0 ? -1 : data->right_face;
+        }
+        /* centroids */
+        else if (line->type == GV_CENTROID) {
+            struct P_topo_c *topo = (struct P_topo_c *)line->topo;
+            
+            topo->area  = data->left_face;
+        }
+        /* TODO: faces | kernels */
+    }
+
+    plus->Line[n] = line;
+    
+    return 0;
+}
+
+/*!
+  \brief Read P_area structure
+  
+  See dig_Rd_P_area() for reference.
+  
+  \param plus pointer to Plus_head structure
+  \param n index (starts at 1)
+  \param face_id face id (see 'face' table)
+  \param pg_info pointer to Format_info_pg sttucture
+
+  \return 0 on success
+  \return -1 on failure
+*/
+int read_p_area(struct Plus_head *plus, int n, int face_id, struct Format_info_pg *pg_info)
+{
+    int i, cnt;
+    char stmt[DB_SQL_MAX];
+
+    PGresult *res;
+    struct P_area *area;
+
+    sprintf(stmt,
+            "SELECT edge from ST_GetFaceEdges('%s', %d)",
+            pg_info->toposchema_name, face_id);
+    G_debug(2, "SQL: %s", stmt);
+    res = PQexec(pg_info->conn, stmt);
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) {
+        G_warning(_("Unable to read face %d"), face_id);
+        if (res)
+            PQclear(res);
+        return -1;
+    }
+    
+    cnt = PQntuples(res);
+    if (cnt == 0) { /* dead */
+        plus->Area[n] = NULL;
+        return 0;
+    }
+    
+    area = dig_alloc_area();
+
+    /* boundaries */
+    area->n_lines = cnt;
+    if (dig_area_alloc_line(area, area->n_lines) == -1)
+        return -1;
+    area->lines = (plus_t *)G_realloc(area->lines, sizeof(plus_t) * area->n_lines);
+    for (i = 0; i < area->n_lines; i++) {
+        /* GRASS   Topo model: lines in clockwise order
+           PosTGIS Topo model: lines in counter clockwise order */
+        area->lines[i] = -1 * atoi(PQgetvalue(res, i, 0));
+    }
+
+    /* isles */
+    /* TODO */
+
+    /* centroid */
+    area->centroid = plus->n_lines - plus->n_clines + i;
+    
+    plus->Area[n] = area;
+    
+    PQclear(res);
+    
+    return 0;
+}
+
+/*!
+  \brief Read topo header info only
+
+  \param[in,out] plus pointer to Plus_head struct
+
+  \return 0 on success
+  \return -1 on error
+*/
+int load_plus_head(struct Format_info_pg *pg_info, PGresult *res, struct Plus_head *plus)
+{
+    char stmt[DB_SQL_MAX];
+    
+    plus->off_t_size = -1;
+    
+    /* check for 3D */
+    if (strcmp(PQgetvalue(res, 0, 1), "t") == 0)
+        plus->with_z = WITH_Z;
+    PQclear(res);
+    
+    /* get map bounding box */
+    sprintf(stmt,
+            "SELECT ST_3DExtent(%s) FROM \"%s\".\"%s\"",
+            pg_info->topogeom_column, pg_info->schema_name, pg_info->table_name);
+    G_debug(2, "SQL: %s", stmt);
+    res = PQexec(pg_info->conn, stmt);
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
+        PQntuples(res) != 1) {
+        G_warning(_("Unable to get map bounding box from topology"));
+        if (res)
+            PQclear(res);
+        return -1;
+    }
+    if (parse_bbox(PQgetvalue(res, 0, 0), &(plus->box), plus->with_z) != 0) {
+        G_warning(_("Unable to parse map bounding box:\n%s"),
+                  PQgetvalue(res, 0, 0));
+        return -1;
+    }
+    PQclear(res);
+    
+    /* number of topological primitives */
+    /* nodes
+       note: isolated nodes are registered in GRASS Topology model */
+    sprintf(stmt,
+            "SELECT COUNT(DISTINCT 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",
+            pg_info->toposchema_name, pg_info->toposchema_name);
+    plus->n_nodes = num_of_records(pg_info, stmt);
+    G_debug(3, "Vect_open_topo_pg(): n_nodes=%d", plus->n_nodes);
+    /* lines (edges in PostGIS Topology model) */
+    sprintf(stmt,
+            "SELECT COUNT(*) FROM \"%s\".edge",
+            pg_info->toposchema_name);
+    /* + isolated nodes as points
+       + centroids */
+    plus->n_lines = num_of_records(pg_info, stmt); 
+    /* areas (faces in PostGIS Topology model) */
+    sprintf(stmt,
+            "SELECT COUNT(*) FROM \"%s\".face WHERE mbr IS NOT NULL",
+            pg_info->toposchema_name);
+    plus->n_areas = num_of_records(pg_info, stmt);
+    G_debug(3, "Vect_open_topo_pg(): n_areas=%d", plus->n_areas);
+    /* TODO: n_isles | n_volumes | n_holes */
+    
+    /* number of features group by type */
+    /* points */
+    sprintf(stmt,
+            "SELECT COUNT(*) FROM \"%s\".node WHERE 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)",
+            pg_info->toposchema_name, pg_info->toposchema_name,
+            pg_info->toposchema_name);
+    plus->n_plines = num_of_records(pg_info, stmt);
+    G_debug(3, "Vect_open_topo_pg(): n_plines=%d", plus->n_plines);
+    /* lines */
+    sprintf(stmt,
+            "SELECT COUNT(*) FROM \"%s\".edge WHERE "
+            "left_face = 0 AND right_face = 0",
+            pg_info->toposchema_name);
+    plus->n_llines = num_of_records(pg_info, stmt);
+    G_debug(3, "Vect_open_topo_pg(): n_llines=%d", plus->n_llines);
+    /* boundaries */
+    sprintf(stmt,
+            "SELECT COUNT(*) FROM \"%s\".edge WHERE "
+            "left_face != 0 OR right_face != 0",
+            pg_info->toposchema_name);
+    plus->n_blines = num_of_records(pg_info, stmt);
+    G_debug(3, "Vect_open_topo_pg(): n_blines=%d", plus->n_blines);
+    /* centroids */
+    sprintf(stmt,
+            "SELECT COUNT(*) FROM \"%s\".face WHERE mbr IS NOT NULL",
+            pg_info->toposchema_name);
+    plus->n_clines = num_of_records(pg_info, stmt);
+    plus->n_lines += plus->n_plines; /* register isolated nodes as points */
+    G_debug(3, "Vect_open_topo_pg(): n_clines=%d", plus->n_clines);
+    /* TODO: nflines | n_klines */
+
+    /* lines - register isolated nodes as points and centroids */
+    plus->n_lines += plus->n_plines + plus->n_clines;
+    G_debug(3, "Vect_open_topo_pg(): n_lines=%d", plus->n_lines);
+
+    return 0;
+}
+
+/*!
+  \brief Read topo info
+
+  \param[in,out] plus pointer to Plus_head struct
+
+  \return 0 on success
+  \return -1 on error
+*/
+int load_plus(struct Format_info_pg *pg_info, PGresult *res, struct Plus_head *plus)
+{
+    int i, id, ntuples;
+    char stmt[DB_SQL_MAX];
+    struct edge_data line_data;
+    
+    /* read nodes (GRASS Topo)
+       note: standalone nodes are ignored
+    */
+    sprintf(stmt,
+            "SELECT node_id FROM \"%s\".node WHERE node_id 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)",
+            pg_info->toposchema_name, pg_info->toposchema_name,
+            pg_info->toposchema_name);
+    G_debug(2, "SQL: %s", stmt);
+    res = PQexec(pg_info->conn, stmt);
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
+        PQntuples(res) != plus->n_nodes) {
+        G_warning(_("Unable to read nodes"));
+        if (res)
+            PQclear(res);
+        return -1;
+    }
+
+    dig_alloc_nodes(plus, plus->n_nodes);
+    for (i = 1; i <= plus->n_nodes; i++) {
+        id = atoi(PQgetvalue(res, i - 1, 0));
+        read_p_node(plus, i, id, pg_info);
+    }
+    PQclear(res);
+
+    /* read lines (GRASS Topo)
+       - standalone nodes -> points
+       - edges -> lines/bouindaries
+    */
+    dig_alloc_lines(plus, plus->n_lines); 
+    
+    /* read PostGIS Topo standalone nodes */
+    sprintf(stmt,
+            "SELECT node_id FROM \"%s\".node WHERE 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)",
+            pg_info->toposchema_name, pg_info->toposchema_name,
+            pg_info->toposchema_name);
+    G_debug(2, "SQL: %s", stmt);
+    res = PQexec(pg_info->conn, stmt);
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
+        PQntuples(res) > plus->n_lines) {
+        G_warning(_("Unable to read lines"));
+        if (res)
+            PQclear(res);
+        return -1;
+    }
+    
+    ntuples = PQntuples(res); /* plus->n_plines */
+    G_zero(&line_data, sizeof(struct edge_data));
+    for (i = 0; i < ntuples; i++) {
+        /* process standalone nodes (PostGIS Topo) */
+        line_data.id = atoi(PQgetvalue(res, i, 0));
+        read_p_line(plus, i + 1, &line_data, pg_info);
+    }
+    PQclear(res);
+    
+    /* read PostGIS Topo edges */
+    sprintf(stmt,
+            "SELECT edge_id,start_node,end_node,left_face,right_face "
+            "FROM \"%s\".edge",
+            pg_info->toposchema_name);
+    G_debug(2, "SQL: %s", stmt);
+    res = PQexec(pg_info->conn, stmt);
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
+        PQntuples(res) > plus->n_lines) {
+        G_warning(_("Unable to read lines"));
+        if (res)
+            PQclear(res);
+        return -1;
+    }
+
+    ntuples = PQntuples(res);
+    for (i = 0; i < ntuples; i++) {
+        /* process edges (PostGIS Topo) */
+        line_data.id         = atoi(PQgetvalue(res, i, 0));
+        line_data.start_node = atoi(PQgetvalue(res, i, 1));
+        line_data.end_node   = atoi(PQgetvalue(res, i, 2));
+        line_data.left_face  = atoi(PQgetvalue(res, i, 3));
+        line_data.right_face = atoi(PQgetvalue(res, i, 4));
+        read_p_line(plus, plus->n_plines + i + 1, &line_data, pg_info);
+    }
+    PQclear(res);
+    
+    /* read areas (GRASS Topo) */
+    sprintf(stmt,
+            "SELECT face_id from \"%s\".face WHERE mbr IS NOT NULL",
+            pg_info->toposchema_name);
+    G_debug(2, "SQL: %s", stmt);
+    res = PQexec(pg_info->conn, stmt);
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
+        PQntuples(res) != plus->n_areas) {
+        G_warning(_("Unable to read areas"));
+        if (res)
+            PQclear(res);
+        return -1;
+    }
+    
+    dig_alloc_areas(plus, plus->n_areas);
+    G_zero(&line_data, sizeof(struct edge_data));
+    for (i = 1; i <= plus->n_areas; i++) {
+        line_data.id = line_data.left_face = atoi(PQgetvalue(res, i - 1, 0));
+        read_p_area(plus, i, line_data.id, pg_info);
+        /* add centroids */
+        read_p_line(plus, plus->n_lines - plus->n_clines + i,
+                    &line_data, pg_info);
+    }
+    PQclear(res);
+    
+    /* read isle (GRASS Topo) */
+
+    return 0;
+}
 #endif

Modified: grass/trunk/lib/vector/Vlib/read.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read.c	2012-05-31 12:32:19 UTC (rev 51901)
+++ grass/trunk/lib/vector/Vlib/read.c	2012-05-31 12:47:11 UTC (rev 51902)
@@ -34,42 +34,49 @@
 }
 #endif
 
-static int (*Read_next_line_array[][3]) () = {
+static int (*Read_next_line_array[][4]) () = {
     {
-	read_dummy, V1_read_next_line_nat, V2_read_next_line_nat}
+	read_dummy, V1_read_next_line_nat, V2_read_next_line_nat, read_dummy}
 #ifdef HAVE_OGR
     , {
-	read_dummy, V1_read_next_line_ogr, V2_read_next_line_ogr}
+	read_dummy, V1_read_next_line_ogr, V2_read_next_line_ogr, read_dummy}
     , {
-	read_dummy, V1_read_next_line_ogr, V2_read_next_line_ogr}
+	read_dummy, V1_read_next_line_ogr, V2_read_next_line_ogr, read_dummy}
 #else
     , {
-	read_dummy, format, format}
+	read_dummy, format, format, format}
     , {
-	read_dummy, format, format}
+	read_dummy, format, format, format}
 #endif
 #ifdef HAVE_POSTGRES
     , {
-	read_dummy, V1_read_next_line_pg, V2_read_next_line_pg}
+	read_dummy, V1_read_next_line_pg, V2_read_next_line_pg, V2_read_next_line_pg}
 #else
     , {
-	read_dummy, format, format}
+	read_dummy, format, format, format}
 #endif
 };
 
-static int (*Read_line_array[]) () = {
-    V2_read_line_nat
+static int (*Read_line_array[][2]) () = {
+    {
+        V2_read_line_nat, read_dummy}
 #ifdef HAVE_OGR
-    , V2_read_line_sfa
-    , V2_read_line_sfa
+    , {
+        V2_read_line_sfa, read_dummy}
+    , {
+        V2_read_line_sfa, read_dummy}
 #else
-    , format
-    , format
+    , {
+        format, format}
+    , {
+        format, format}
 #endif
 #ifdef HAVE_POSTGRES
-    , V2_read_line_sfa
+    , {
+        V2_read_line_sfa, V3_read_line_pg}
 #else
-    , format
+    , {
+        format, format}
 #endif
 };
 
@@ -169,7 +176,7 @@
 			"(max features in vector map <%s>: %d)"),
 		      line, Vect_get_full_name(Map), Map->plus.n_lines);
 
-    ret = (*Read_line_array[Map->format]) (Map, line_p, line_c, line);
+    ret = (*Read_line_array[Map->format][Map->level == 3 ? 1 : 0]) (Map, line_p, line_c, line);
 
     /*
     if (ret == -1)

Modified: grass/trunk/lib/vector/Vlib/read_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_pg.c	2012-05-31 12:32:19 UTC (rev 51901)
+++ grass/trunk/lib/vector/Vlib/read_pg.c	2012-05-31 12:47:11 UTC (rev 51902)
@@ -32,7 +32,7 @@
 
 static int read_next_line_pg(struct Map_info *,
                              struct line_pnts *, struct line_cats *, int);
-SF_FeatureType get_feature(struct Format_info_pg *, int);
+SF_FeatureType get_feature(struct Format_info_pg *, int, const char *);
 static unsigned char *hex_to_wkb(const char *, int *);
 static int point_from_wkb(const unsigned char *, int, int, int,
                           struct line_pnts *);
@@ -47,6 +47,7 @@
 static int set_initial_query();
 static void reallocate_cache(struct Format_info_cache *, int);
 static void add_fpart(struct feat_parts *, SF_FeatureType, int, int);
+static int read_centroid_pg(struct Format_info_pg *, int, struct line_pnts *);
 #endif
 
 /*!
@@ -248,7 +249,7 @@
 
         G_debug(3, "read (%s) feature (fid = %ld) to cache",
                 pg_info->table_name, fid);
-        get_feature(pg_info, fid);
+        get_feature(pg_info, fid, NULL);
 
         if (pg_info->cache.sf_type == SF_NONE) {
             G_warning(_("Feature %d without geometry skipped"), fid);
@@ -282,7 +283,77 @@
 #endif
 }
 
+int V3_read_line_pg(struct Map_info *Map, struct line_pnts *line_p,
+                    struct line_cats *line_c, int line)
+{
 #ifdef HAVE_POSTGRES
+    int type;
+    char *topotable_name;
+    
+    struct Format_info_pg *pg_info;
+    struct P_line *Line;
+
+    pg_info = &(Map->fInfo.pg);
+    Line = Map->plus.Line[line];
+    if (Line == NULL) {
+        G_warning(_("Attempt to read dead feature %d"), line);
+        return -1;
+    }
+    
+    G_debug(4, "V3_read_line_pg() line = %d type = %d offset = %llu",
+            line, Line->type, Line->offset);
+    
+    if (!line_p && !line_c)
+        return Line->type;
+
+    if (line_p != NULL)
+        Vect_reset_line(line_p);
+    if (line_c != NULL)
+        Vect_reset_cats(line_c);
+
+    if (line_c)
+        Vect_cat_set(line_c, 1, (int) Line->offset);
+    
+    if (Line->type == GV_POINT)
+        topotable_name = "node";
+    else if (Line->type & GV_LINES)
+        topotable_name = "edge";
+    else if (Line->type == GV_CENTROID) {
+        return read_centroid_pg(pg_info, (int) Line->offset, line_p);
+    }
+    else {
+        G_warning(_("Unsupported feature type %d"), Line->type);
+        return -1;
+    }
+    
+    get_feature(pg_info, Line->offset, topotable_name);
+    
+    if (pg_info->cache.sf_type == SF_NONE) {
+        G_warning(_("Feature %d without geometry skipped"), Line->offset);
+        return -1;
+    }
+    
+    type = (int)pg_info->cache.sf_type;
+    if (type < 0)           /* -1 || - 2 */
+        return type;
+    
+    if (Line->type == GV_BOUNDARY && type == GV_LINE)
+        type = GV_BOUNDARY;
+    
+    if (line_p)
+        Vect_append_points(line_p, pg_info->cache.lines[0], GV_FORWARD);
+    
+    return type;
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+    return -1;
+#endif
+
+
+
+}
+
+#ifdef HAVE_POSTGRES
 /*!
    \brief Read next feature from PostGIS layer. 
 
@@ -325,7 +396,7 @@
         /* read feature to cache if necessary */
         while (pg_info->cache.lines_next == pg_info->cache.lines_num) {
             /* cache feature -> line_p & line_c */
-            sf_type = get_feature(pg_info, -1);
+            sf_type = get_feature(pg_info, -1, NULL);
 
             if (sf_type == SF_NONE) {
                 G_warning(_("Feature %d without geometry skipped"), line);
@@ -389,17 +460,18 @@
 
    \param[in,out] pg_info pointer to Format_info_pg struct
    \param fid feature id to be read (-1 for next)
-   \param[out] line_c pointer to line_cats structure (or NULL)
+   \param topotable_name table name for topological access (NULL for pseudo-topological access) - "node" or "edge"
 
    \return simple feature type (SF_POINT, SF_LINESTRING, ...)
    \return -1 on error
  */
-SF_FeatureType get_feature(struct Format_info_pg * pg_info, int fid)
+SF_FeatureType get_feature(struct Format_info_pg *pg_info, int fid,
+                           const char *topotable_name)
 {
     char *data;
     char stmt[DB_SQL_MAX];
 
-    if (!pg_info->geom_column) {
+    if (!topotable_name && !pg_info->geom_column) {
         G_warning(_("No geometry column defined"));
         return -1;
     }
@@ -411,7 +483,7 @@
         }
     }
     else {
-        if (!pg_info->fid_column) {
+        if (!topotable_name && !pg_info->fid_column) {
             G_warning(_("Random access not supported. "
                         "Primary key not defined."));
             return -1;
@@ -420,11 +492,22 @@
         if (execute(pg_info->conn, "BEGIN") == -1)
             return -1;
 
-        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);
+        if (!topotable_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 {
+            /* topological access */
+            sprintf(stmt,
+                    "DECLARE %s_%s%p CURSOR FOR SELECT geom FROM \"%s\".\"%s\" "
+                    "WHERE %s_id = %d", pg_info->schema_name, pg_info->table_name,
+                    pg_info->conn, pg_info->toposchema_name,
+                    topotable_name, topotable_name, fid);
+        }
 
         if (execute(pg_info->conn, stmt) == -1)
             return -1;
@@ -437,6 +520,7 @@
 
     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 */
     }
@@ -1142,4 +1226,37 @@
 
     fparts->n_parts++;
 }
+
+int read_centroid_pg(struct Format_info_pg *pg_info,
+                     int centroid, struct line_pnts *line_p)
+{
+    char stmt[DB_SQL_MAX];
+    char *data;
+
+    PGresult *res;
+    
+    sprintf(stmt,
+            "SELECT ST_PointOnSurface(geom) AS geom FROM "
+            "ST_GetFaceGeometry('%s', %d) as geom",
+            pg_info->toposchema_name, centroid);
+    res = PQexec(pg_info->conn, stmt);
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
+        PQntuples(res) != 1) {
+        G_warning(_("Unable to read centroid %d: %s"),
+                  centroid, PQerrorMessage(pg_info->conn));
+        if (res)
+            PQclear(res);
+        return -1;
+    }
+    
+    data = (char *)PQgetvalue(res, 0, 0);
+    PQclear(res);
+    
+    if (GV_POINT != cache_feature(data, FALSE, &(pg_info->cache), NULL))
+        return -1;
+    
+    Vect_append_points(line_p, pg_info->cache.lines[0], GV_FORWARD);
+    
+    return GV_CENTROID;
+}
 #endif

Modified: grass/trunk/lib/vector/Vlib/read_sfa.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_sfa.c	2012-05-31 12:32:19 UTC (rev 51901)
+++ grass/trunk/lib/vector/Vlib/read_sfa.c	2012-05-31 12:47:11 UTC (rev 51902)
@@ -36,7 +36,7 @@
   \return -1 on failure 
 */
 int V2_read_line_sfa(struct Map_info *Map, struct line_pnts *line_p,
-		     struct line_cats *line_c, int line)
+                     struct line_cats *line_c, int line)
 {
 #if defined HAVE_OGR || defined HAVE_POSTGRES
     int type;
@@ -46,69 +46,69 @@
     
     Line = Map->plus.Line[line];
     if (Line == NULL) {
-	G_warning(_("Attempt to read dead feature %d"), line);
-	return -1;
+        G_warning(_("Attempt to read dead feature %d"), line);
+        return -1;
     }
     
     if (Line->type == GV_CENTROID) {
-	/* read centroid for topo */
-	if (line_p != NULL) {
-	    int i, found;
-	    struct bound_box box;
-	    struct boxlist list;
-	    struct P_topo_c *topo = (struct P_topo_c *)Line->topo;
+        /* read centroid for topo */
+        if (line_p != NULL) {
+            int i, found;
+            struct bound_box box;
+            struct boxlist list;
+            struct P_topo_c *topo = (struct P_topo_c *)Line->topo;
 
-	    G_debug(4, "Centroid: area = %d", topo->area);
-	    Vect_reset_line(line_p);
-	    
-	    if (topo->area > 0 && topo->area <= Map->plus.n_areas) {
-		/* get area bbox */
-		Vect_get_area_box(Map, topo->area, &box);
-		/* search in spatial index for centroid with area bbox */
-		dig_init_boxlist(&list, TRUE);
-		Vect_select_lines_by_box(Map, &box, Line->type, &list);
-		
-		found = -1;
-		for (i = 0; i < list.n_values; i++) {
-		    if (list.id[i] == line) {
-			found = i;
-			break;
-		    }
-		}
-		
-		if (found > -1) {
-		    Vect_append_point(line_p, list.box[found].E, list.box[found].N, 0.0);
-		}
-		else {
-		    G_warning(_("Unable to construct centroid for area %d. Skipped."),
-			      topo->area);
-		}
-	    }
-	    else {
-		G_warning(_("Centroid %d: invalid area %d"), line, topo->area);
-	    }
-	}
+            G_debug(4, "Centroid: area = %d", topo->area);
+            Vect_reset_line(line_p);
+            
+            if (topo->area > 0 && topo->area <= Map->plus.n_areas) {
+                /* get area bbox */
+                Vect_get_area_box(Map, topo->area, &box);
+                /* search in spatial index for centroid with area bbox */
+                dig_init_boxlist(&list, TRUE);
+                Vect_select_lines_by_box(Map, &box, Line->type, &list);
+                
+                found = -1;
+                for (i = 0; i < list.n_values; i++) {
+                    if (list.id[i] == line) {
+                        found = i;
+                        break;
+                    }
+                }
+                
+                if (found > -1) {
+                    Vect_append_point(line_p, list.box[found].E, list.box[found].N, 0.0);
+                }
+                else {
+                    G_warning(_("Unable to construct centroid for area %d. Skipped."),
+                              topo->area);
+                }
+            }
+            else {
+                G_warning(_("Centroid %d: invalid area %d"), line, topo->area);
+            }
+        }
 
-	if (line_c != NULL) {
-	  /* cat = fid and offset = fid for centroid */
-	  Vect_reset_cats(line_c);
-	  Vect_cat_set(line_c, 1, (int) Line->offset);
-	}
-	
-	return GV_CENTROID;
+        if (line_c != NULL) {
+          /* cat = fid and offset = fid for centroid */
+          Vect_reset_cats(line_c);
+          Vect_cat_set(line_c, 1, (int) Line->offset);
+        }
+        
+        return GV_CENTROID;
     }
     
     if (!line_p && !line_c)
-	return Line->type;
+        return Line->type;
     
     if (Map->format == GV_FORMAT_POSTGIS)
-	type = V1_read_line_pg(Map, line_p, line_c, Line->offset);
+        type = V1_read_line_pg(Map, line_p, line_c, Line->offset);
     else
-	type = V1_read_line_ogr(Map, line_p, line_c, Line->offset);
+        type = V1_read_line_ogr(Map, line_p, line_c, Line->offset);
 
     if (type != Line->type)
-	G_fatal_error(_("Unexpected feature type (%s) - should be (%d)"),
-		      type, Line->type);
+        G_fatal_error(_("Unexpected feature type (%s) - should be (%d)"),
+                      type, Line->type);
 
     return type;
 #else

Modified: grass/trunk/lib/vector/Vlib/rewind.c
===================================================================
--- grass/trunk/lib/vector/Vlib/rewind.c	2012-05-31 12:32:19 UTC (rev 51901)
+++ grass/trunk/lib/vector/Vlib/rewind.c	2012-05-31 12:47:11 UTC (rev 51902)
@@ -5,13 +5,14 @@
 
    Higher level functions for reading/writing/manipulating vectors.
 
-   (C) 2001-2009, 2011 by the GRASS Development Team
+   (C) 2001-2009, 2011-2012 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.
 
    \author Original author CERL, probably Dave Gerdes or Mike Higgins.
    \author Update to GRASS 5.7 Radim Blazek and David D. Gray.
+   \author Level 3 by Martin Landa <landa.martin gmail.com>
 */
 
 #include <grass/vector.h>
@@ -31,26 +32,26 @@
 #endif
 
 
-static int (*Rewind_array[][3]) () = {
+static int (*Rewind_array[][4]) () = {
     {
-	rew_dummy, V1_rewind_nat, V2_rewind_nat}
+        rew_dummy, V1_rewind_nat, V2_rewind_nat, rew_dummy}
 #ifdef HAVE_OGR
     , {
-	rew_dummy, V1_rewind_ogr, V2_rewind_ogr}
+	rew_dummy, V1_rewind_ogr, V2_rewind_ogr, rew_dummy}
     , {
-	rew_dummy, V1_rewind_ogr, V2_rewind_ogr}
+	rew_dummy, V1_rewind_ogr, V2_rewind_ogr, rew_dummy}
 #else
     , {
-	rew_dummy, format, format}
+	rew_dummy, format, format, rew_dummy}
     , {
-	rew_dummy, format, format}
+	rew_dummy, format, format, rew_dummy}
 #endif
 #ifdef HAVE_POSTGRES
     , {
-	rew_dummy, V1_rewind_pg, V2_rewind_pg}
+	rew_dummy, V1_rewind_pg, V2_rewind_pg, V2_rewind_pg}
 #else
     , {
-	rew_dummy, format, format}
+	rew_dummy, format, format, rew_dummy}
 #endif
 };
 
@@ -67,7 +68,7 @@
     if (!VECT_OPEN(Map))
 	return -1;
 
-    G_debug(1, "Vect_Rewind(): name = %s", Map->name);
+    G_debug(1, "Vect_Rewind(): name = %s level = %d", Map->name, Map->level);
 
     return (*Rewind_array[Map->format][Map->level]) (Map);
 }

Modified: grass/trunk/lib/vector/diglib/frmt.c
===================================================================
--- grass/trunk/lib/vector/diglib/frmt.c	2012-05-31 12:32:19 UTC (rev 51901)
+++ grass/trunk/lib/vector/diglib/frmt.c	2012-05-31 12:47:11 UTC (rev 51902)
@@ -39,36 +39,36 @@
 
     /* read first line which must be FORMAT: */
     if (G_getl2(buff, 2000, dascii)) {
-	G_chop(buff);
+        G_chop(buff);
 
-	if (!(ptr = strchr(buff, ':'))) {
-	    G_warning("Vector format not recognized: %s", buff);
-	    return (-1);
-	}
+        if (!(ptr = strchr(buff, ':'))) {
+            G_warning(_("Vector format not recognized: %s"), buff);
+            return -1;
+        }
 
-	strcpy(buf1, buff);
-	buf1[ptr - buff] = '\0';
+        strcpy(buf1, buff);
+        buf1[ptr - buff] = '\0';
 
-	ptr++;			/* Search for the start of text */
-	while (*ptr == ' ')
-	    ptr++;
+        ptr++;                  /* Search for the start of text */
+        while (*ptr == ' ')
+            ptr++;
 
-	if (strcmp(buf1, "FORMAT") == 0) {
+        if (strcmp(buf1, "FORMAT") == 0) {
 #ifdef HAVE_OGR
-	    if (G_strcasecmp(ptr, "ogr") == 0) {
-		frmt = GV_FORMAT_OGR;
-	    }
+            if (G_strcasecmp(ptr, "ogr") == 0) {
+                frmt = GV_FORMAT_OGR;
+            }
 #endif
 #ifdef HAVE_POSTGRES
-	    if (G_strcasecmp(ptr, "postgis") == 0) {
-		frmt = GV_FORMAT_POSTGIS;
-	    }
+            if (G_strcasecmp(ptr, "postgis") == 0) {
+                frmt = GV_FORMAT_POSTGIS;
+            }
 #endif
-	}
+        }
     }
     if (frmt == -1) {
-	G_warning("Vector format not recognized: %s", buff);
-	return -1;
+        G_warning(_("Vector format not recognized: %s"), buff);
+        return -1;
     }
 
     /* init format info values */
@@ -76,8 +76,8 @@
     G_zero(&(finfo->ogr), sizeof(struct Format_info_ogr));
 #else
     if (frmt == GV_FORMAT_OGR) {
-	G_warning(_("Vector format '%s' not supported"), ptr);
-	return -1;
+        G_warning(_("Vector format '%s' not supported"), ptr);
+        return -1;
     }
 #endif
 
@@ -85,46 +85,54 @@
     G_zero(&(finfo->pg), sizeof(struct Format_info_pg));
 #else
     if (frmt == GV_FORMAT_POSTGIS) {
-	G_warning(_("Vector format '%s' not supported"), ptr);
-	return -1;
+        G_warning(_("Vector format '%s' not supported"), ptr);
+        return -1;
     }
 #endif
 
     while (G_getl2(buff, 2000, dascii)) {
-	G_chop(buff);
+        G_chop(buff);
 
-	if (!(ptr = strchr(buff, ':'))) {
-	    G_warning("Format definition is not correct: %s", buff);
-	    continue;
-	}
+        if (!(ptr = strchr(buff, ':'))) {
+            G_warning(_("Format definition is not correct: %s"), buff);
+            continue;
+        }
 
-	strcpy(buf1, buff);
-	buf1[ptr - buff] = '\0';
+        strcpy(buf1, buff);
+        buf1[ptr - buff] = '\0';
 
-	ptr++;			/* Search for the start of text */
-	while (*ptr == ' ')
-	    ptr++;
+        ptr++;                  /* Search for the start of text */
+        while (*ptr == ' ')
+            ptr++;
 
 #ifdef HAVE_OGR
-	if (frmt == GV_FORMAT_OGR) {
-	    if (strcmp(buf1, "DSN") == 0)
-		finfo->ogr.dsn = G_store(ptr);
-	    if (strcmp(buf1, "LAYER") == 0)
-		finfo->ogr.layer_name = G_store(ptr);
-	}
+        if (frmt == GV_FORMAT_OGR) {
+            if (strcmp(buf1, "DSN") == 0)
+                finfo->ogr.dsn = G_store(ptr);
+            if (strcmp(buf1, "LAYER") == 0)
+                finfo->ogr.layer_name = G_store(ptr);
+        }
 #endif
 #ifdef HAVE_POSTGRES
-	if (frmt == GV_FORMAT_POSTGIS) {
-	    if (strcmp(buf1, "CONNINFO") == 0)
-		finfo->pg.conninfo = G_store(ptr);
-	    if (strcmp(buf1, "SCHEMA") == 0)
-		finfo->pg.schema_name = G_store(ptr);
-	    if (strcmp(buf1, "TABLE") == 0)
-		finfo->pg.table_name = G_store(ptr);
-	}
+        if (frmt == GV_FORMAT_POSTGIS) {
+            if (strcmp(buf1, "CONNINFO") == 0)
+                finfo->pg.conninfo = G_store(ptr);
+            if (strcmp(buf1, "SCHEMA") == 0)
+                finfo->pg.schema_name = G_store(ptr);
+            if (strcmp(buf1, "TABLE") == 0)
+                finfo->pg.table_name = G_store(ptr);
+        }
 #endif
     }
 
+#ifdef HAVE_POSTGRES
+    /* if schema not defined, use 'public' */
+    if (frmt == GV_FORMAT_POSTGIS &&
+        !finfo->pg.schema_name) {
+        finfo->pg.schema_name = G_store("public");
+    }
+#endif
+
     return frmt;
 }
 

Modified: grass/trunk/lib/vector/diglib/spindex_rw.c
===================================================================
--- grass/trunk/lib/vector/diglib/spindex_rw.c	2012-05-31 12:32:19 UTC (rev 51901)
+++ grass/trunk/lib/vector/diglib/spindex_rw.c	2012-05-31 12:47:11 UTC (rev 51902)
@@ -488,6 +488,8 @@
     /* ptr->Hole_spidx->rootpos = ptr->Hole_spidx_offset; */
 
     /* coor file size : bytes 110 - 113 (117) (LFS: 138 - 145) */
+    if (ptr->off_t_size == -1)
+        ptr->off_t_size = ptr->spidx_port.off_t_size;
     if (0 >= dig__fread_port_O(&(ptr->coor_size), 1, fp, ptr->off_t_size))
 	return (-1);
     G_debug(2, "  coor size %lu", (long unsigned)ptr->coor_size);



More information about the grass-commit mailing list