Browse Source

vlib: first steps for full PostGIS topology support
untabify for given files


git-svn-id: https://svn.osgeo.org/grass/grass/trunk@51902 15284696-431f-4ddb-bdfa-cd5b030d7da7

Martin Landa 13 years ago
parent
commit
7c8d5a94b1

+ 97 - 94
include/defs/vector.h

@@ -11,44 +11,44 @@ int Vect_append_points(struct line_pnts *, const struct line_pnts *, int);
 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 @@ void Vect_destroy_cat_list(struct cat_list *);
 /* 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_unique_cats_by_index(const struct Map_info *, int);
 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_topo_check(struct Map_info *, struct Map_info *);
 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 @@ void Vect_set_error_handler_io(struct Map_info *, struct Map_info *);
 /* 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 @@ char *Vect_hist_read(char *, int, const struct Map_info *);
 
 /* 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 @@ int Vect_point_in_poly(double, double, const struct line_pnts *);
 /* 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 @@ int Vect_graph_shortest_path(dglGraph_s *, int, int, struct ilist *, double *);
 
 /* 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_spatial_index_select(const struct spatial_index *, const struct bound_b
 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 @@ int Vect_coor_info(const struct Map_info *, struct Coor_info *);
 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 @@ int V2_close_pg(struct Map_info *);
 
 /* 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 V2_delete_line_sfa(struct Map_info *, int);
 int V1_restore_line_nat(struct Map_info *, off_t);
 int V2_restore_line_nat(struct Map_info *, int, off_t);
 off_t V1_write_line_nat(struct Map_info *, int, const struct line_pnts *,
-			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);

+ 23 - 4
include/vect/dig_structs.h

@@ -660,6 +660,16 @@ struct Format_info_pg
       \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 @@ struct P_node
       \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 @@ struct P_node
 
       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 @@ struct P_line
     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;
 };
 
 /*!

+ 10 - 3
lib/vector/Vlib/build.c

@@ -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 <grass/glocale.h>
+#include <math.h>
+
 #include <grass/vector.h>
+#include <grass/glocale.h>
 
 #define SEP "-----------------------------------\n"
 
@@ -884,6 +887,7 @@ int Vect_save_topo(struct Map_info *Map)
 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 @@ int Vect_topo_dump(const struct Map_info *Map, FILE *out)
 	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);
 	}
     }
 

+ 6 - 0
lib/vector/Vlib/close_pg.c

@@ -80,6 +80,12 @@ int V1_close_pg(struct Map_info *Map)
     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"));

File diff suppressed because it is too large
+ 483 - 467
lib/vector/Vlib/open.c


+ 681 - 13
lib/vector/Vlib/open_pg.c

@@ -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 @@ int V1_open_old_pg(struct Map_info *Map, int update)
             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 @@ int V1_open_old_pg(struct Map_info *Map, int update)
         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,6 +372,72 @@ int V2_open_new_pg(struct Map_info *Map, int type)
 #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)
 {
@@ -686,4 +759,599 @@ int create_table(struct Format_info_pg *pg_info, const struct field_info *Fi)
 
     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

+ 24 - 17
lib/vector/Vlib/read.c

@@ -34,42 +34,49 @@ static int format()
 }
 #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 @@ int Vect_read_line(const struct Map_info *Map,
 			"(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)

+ 129 - 12
lib/vector/Vlib/read_pg.c

@@ -32,7 +32,7 @@ static unsigned int wkb_data_length;
 
 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 error_corrupted_data(const char *);
 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 @@ int V1_read_line_pg(struct Map_info *Map,
 
         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,6 +283,76 @@ int V1_read_line_pg(struct Map_info *Map,
 #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 @@ int read_next_line_pg(struct Map_info *Map,
         /* 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 @@ int read_next_line_pg(struct Map_info *Map,
 
    \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 @@ SF_FeatureType get_feature(struct Format_info_pg * pg_info, int fid)
         }
     }
     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 @@ SF_FeatureType get_feature(struct Format_info_pg * pg_info, int fid)
         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 @@ SF_FeatureType get_feature(struct Format_info_pg * pg_info, int fid)
 
     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 @@ void add_fpart(struct feat_parts *fparts, SF_FeatureType ftype,
 
     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

+ 51 - 51
lib/vector/Vlib/read_sfa.c

@@ -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 @@ int V2_read_line_sfa(struct Map_info *Map, struct line_pnts *line_p,
     
     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

+ 11 - 10
lib/vector/Vlib/rewind.c

@@ -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 @@ static int format()
 #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 @@ int Vect_rewind(struct Map_info *Map)
     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);
 }

+ 56 - 48
lib/vector/diglib/frmt.c

@@ -39,36 +39,36 @@ int dig_read_frmt_ascii(FILE * dascii, struct Format_info *finfo)
 
     /* 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 @@ int dig_read_frmt_ascii(FILE * dascii, struct Format_info *finfo)
     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 @@ int dig_read_frmt_ascii(FILE * dascii, struct Format_info *finfo)
     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;
 }
 

+ 2 - 0
lib/vector/diglib/spindex_rw.c

@@ -488,6 +488,8 @@ int dig_Rd_spidx_head(struct gvfile * fp, struct Plus_head *ptr)
     /* 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);