[GRASS-SVN] r50670 - in grass/trunk: gui/wxpython/vdigit include include/Make include/defs include/vect lib/vector/Vlib lib/vector/diglib vector/v.external vector/v.info

svn_grass at osgeo.org svn_grass at osgeo.org
Sun Feb 5 12:19:13 EST 2012


Author: martinl
Date: 2012-02-05 09:19:12 -0800 (Sun, 05 Feb 2012)
New Revision: 50670

Added:
   grass/trunk/lib/vector/Vlib/build_pg.c
   grass/trunk/lib/vector/Vlib/build_sfa.c
   grass/trunk/lib/vector/Vlib/close_pg.c
   grass/trunk/lib/vector/Vlib/open_pg.c
   grass/trunk/lib/vector/Vlib/pg_local_proto.h
   grass/trunk/lib/vector/Vlib/read_pg.c
   grass/trunk/lib/vector/Vlib/rewind_pg.c
Modified:
   grass/trunk/gui/wxpython/vdigit/wxdigit.py
   grass/trunk/include/Make/Grass.make
   grass/trunk/include/defs/vector.h
   grass/trunk/include/gis.h
   grass/trunk/include/vect/dig_defines.h
   grass/trunk/include/vect/dig_structs.h
   grass/trunk/lib/vector/Vlib/build.c
   grass/trunk/lib/vector/Vlib/build_ogr.c
   grass/trunk/lib/vector/Vlib/close.c
   grass/trunk/lib/vector/Vlib/close_ogr.c
   grass/trunk/lib/vector/Vlib/constraint.c
   grass/trunk/lib/vector/Vlib/dgraph.h
   grass/trunk/lib/vector/Vlib/e_intersect.h
   grass/trunk/lib/vector/Vlib/field.c
   grass/trunk/lib/vector/Vlib/header.c
   grass/trunk/lib/vector/Vlib/line.c
   grass/trunk/lib/vector/Vlib/map.c
   grass/trunk/lib/vector/Vlib/open.c
   grass/trunk/lib/vector/Vlib/open_ogr.c
   grass/trunk/lib/vector/Vlib/read.c
   grass/trunk/lib/vector/Vlib/read_nat.c
   grass/trunk/lib/vector/Vlib/read_ogr.c
   grass/trunk/lib/vector/Vlib/rewind.c
   grass/trunk/lib/vector/Vlib/rewind_nat.c
   grass/trunk/lib/vector/Vlib/rewind_ogr.c
   grass/trunk/lib/vector/Vlib/simple_features.c
   grass/trunk/lib/vector/Vlib/write_ogr.c
   grass/trunk/lib/vector/diglib/frmt.c
   grass/trunk/lib/vector/diglib/plus_struct.c
   grass/trunk/lib/vector/diglib/update.c
   grass/trunk/vector/v.external/Makefile
   grass/trunk/vector/v.external/args.c
   grass/trunk/vector/v.external/list.c
   grass/trunk/vector/v.external/local_proto.h
   grass/trunk/vector/v.external/main.c
   grass/trunk/vector/v.info/print.c
Log:
vlib: *initial* support for native reading PostGIS data (without OGR library)
      read-only access is implemented for points, linestrings and polygons
      OGR-like pseudo-topology is built on level 2
      todo: implemenent read access to other feature types (multipoints, geometry collections...)
      	    implemenent write access
	    implemenent support for PostGIS Topology
v.external: update for native PostGIS support

      more coming soon


Modified: grass/trunk/gui/wxpython/vdigit/wxdigit.py
===================================================================
--- grass/trunk/gui/wxpython/vdigit/wxdigit.py	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/gui/wxpython/vdigit/wxdigit.py	2012-02-05 17:19:12 UTC (rev 50670)
@@ -1635,5 +1635,5 @@
         @return feature type as string (Point, Line String, Polygon)
         @return None for native format
         """
-        return Vect_get_ogr_geometry_type(self.poMapInfo)
+        return Vect_get_finfo_geometry_type(self.poMapInfo)
         

Modified: grass/trunk/include/Make/Grass.make
===================================================================
--- grass/trunk/include/Make/Grass.make	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/include/Make/Grass.make	2012-02-05 17:19:12 UTC (rev 50670)
@@ -31,7 +31,7 @@
 ARCH_INCDIR     = $(ARCH_DISTDIR)/include/grass
 
 INC		= -I$(ARCH_DISTDIR)/include -I$(GISBASE)/include
-VECT_INC        = 
+VECT_INC        = $(PQINCPATH)
 
 # libraries
 ARCH_LIBDIR     = $(ARCH_DISTDIR)/lib
@@ -78,7 +78,7 @@
 LFS_CFLAGS = -D_FILE_OFFSET_BITS=64
 endif
 
-LDFLAGS     =  $(LIBPATH) $(LINK_FLAGS) $(LD_SEARCH_FLAGS) $(PQLIBPATH)
+LDFLAGS     =  $(LIBPATH) $(LINK_FLAGS) $(LD_SEARCH_FLAGS) $(PQLIBPATH) $(PQLIB)
 VECT_CFLAGS =  $(GDALCFLAGS) $(GEOSCFLAGS)
 
 # Object with _fmode which must be linked to each executable on Windows

Modified: grass/trunk/include/defs/vector.h
===================================================================
--- grass/trunk/include/defs/vector.h	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/include/defs/vector.h	2012-02-05 17:19:12 UTC (rev 50670)
@@ -160,10 +160,10 @@
 const char *Vect_get_name(const struct Map_info *);
 const char *Vect_get_mapset(const struct Map_info *);
 const char *Vect_get_full_name(const struct Map_info *);
-const char *Vect_get_ogr_dsn_name(const struct Map_info *);
-const char *Vect_get_ogr_layer_name(const struct Map_info *);
-const char *Vect_get_ogr_format_info(const struct Map_info *);
-const char *Vect_get_ogr_geometry_type(const struct Map_info *);
+const char *Vect_get_finfo_dsn_name(const struct Map_info *);
+const char *Vect_get_finfo_layer_name(const struct Map_info *);
+const char *Vect_get_finfo_format_info(const struct Map_info *);
+const char *Vect_get_finfo_geometry_type(const struct Map_info *);
 int Vect_is_3d(const struct Map_info *);
 int Vect_set_organization(struct Map_info *, const char *);
 const char *Vect_get_organization(const struct Map_info *);
@@ -436,8 +436,9 @@
 void Vect_write_ascii_head(FILE *, struct Map_info *);
 
 /* Simple Features */
-int Vect_sfa_get_line_type(const struct line_pnts *, int, int);
-int Vect_sfa_check_line_type(const struct line_pnts *, int, int, int);
+SF_FeatureType Vect_sfa_get_line_type(const struct line_pnts *, int, int);
+int Vect_sfa_get_type(SF_FeatureType);
+int Vect_sfa_check_line_type(const struct line_pnts *, int, SF_FeatureType, int);
 int Vect_sfa_line_dimension(int);
 char *Vect_sfa_line_geometry_type(const struct line_pnts *, int);
 int Vect_sfa_line_astext(const struct line_pnts *, int, int, int, FILE *);
@@ -461,22 +462,31 @@
 int Vect_sidx_dump(struct Map_info *, FILE *);
 int Vect_build_sidx_from_topo(struct Map_info *);
 int Vect_build_sidx(struct Map_info *);
+int Vect_open_fidx(struct Map_info *, struct Format_info_offset *);
+int Vect_save_fidx(struct Map_info *, struct Format_info_offset *);
 
 int Vect__write_head(const struct Map_info *);
 int Vect__read_head(struct Map_info *);
 int V1_open_old_nat(struct Map_info *, int);
 int V1_open_old_ogr(struct Map_info *, int);
+int V1_open_old_pg(struct Map_info *, int);
 int V2_open_old_ogr(struct Map_info *);
+int V2_open_old_pg(struct Map_info *);
 int V1_open_new_nat(struct Map_info *, const char *, int);
 int V1_open_new_ogr(struct Map_info *, const char *, int);
+int V1_open_new_pg(struct Map_info *, const char *, int);
 int V2_open_new_ogr(struct Map_info *, int);
 int V1_rewind_nat(struct Map_info *);
 int V1_rewind_ogr(struct Map_info *);
+int V1_rewind_pg(struct Map_info *);
 int V2_rewind_nat(struct Map_info *);
 int V2_rewind_ogr(struct Map_info *);
+int V2_rewind_pg(struct Map_info *);
 int V1_close_nat(struct Map_info *);
 int V1_close_ogr(struct Map_info *);
+int V1_close_pg(struct Map_info *);
 int V2_close_ogr(struct Map_info *);
+int V2_close_pg(struct Map_info *);
 
 /* Read/write lines */
 int V1_read_line_nat(struct Map_info *, struct line_pnts *,
@@ -487,14 +497,20 @@
 			  struct line_cats *);
 int V1_read_next_line_ogr(struct Map_info *, struct line_pnts *,
 			  struct line_cats *);
+int V1_read_next_line_pg(struct Map_info *, struct line_pnts *,
+			 struct line_cats *);
 int V2_read_line_nat(struct Map_info *, struct line_pnts *,
 		     struct line_cats *, int);
 int V2_read_line_ogr(struct Map_info *, struct line_pnts *,
 		     struct line_cats *, int);
+int V2_read_line_pg(struct Map_info *, struct line_pnts *,
+		    struct line_cats *, int);
 int V2_read_next_line_nat(struct Map_info *, struct line_pnts *,
 			  struct line_cats *);
 int V2_read_next_line_ogr(struct Map_info *, struct line_pnts *,
 			  struct line_cats *);
+int V2_read_next_line_pg(struct Map_info *, struct line_pnts *,
+			 struct line_cats *);
 int V1_delete_line_nat(struct Map_info *, off_t);
 int V2_delete_line_nat(struct Map_info *, int);
 int V1_delete_line_ogr(struct Map_info *, off_t);
@@ -520,7 +536,9 @@
 
     /* Build topology */
 int Vect_build_nat(struct Map_info *, int);
+int Vect__build_sfa(struct Map_info *, int);
 int Vect_build_ogr(struct Map_info *, int);
+int Vect_build_pg(struct Map_info *, int);
 int Vect_build_line_area(struct Map_info *, int, int);
 int Vect_isle_find_area(struct Map_info *, int);
 int Vect_attach_isle(struct Map_info *, int);

Modified: grass/trunk/include/gis.h
===================================================================
--- grass/trunk/include/gis.h	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/include/gis.h	2012-02-05 17:19:12 UTC (rev 50670)
@@ -251,6 +251,11 @@
 #define G_FATAL_PRINT   1
 #define G_FATAL_RETURN  2
 
+/*! \brief Endian check */
+#define ENDIAN_LITTLE 0
+#define ENDIAN_BIG    1
+#define ENDIAN_OTHER  2
+
 /* for vector maps */
 /*!
   \brief Name of default key column

Modified: grass/trunk/include/vect/dig_defines.h
===================================================================
--- grass/trunk/include/vect/dig_defines.h	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/include/vect/dig_defines.h	2012-02-05 17:19:12 UTC (rev 50670)
@@ -31,14 +31,6 @@
 /*! \brief Name of the timestamp file */
 #define GV_TIMESTAMP_ELEMENT "timestamp"
 
-/*! \brief Endian check
-
-  \todo To be moved to gislib?
-*/
-#define ENDIAN_LITTLE 0
-#define ENDIAN_BIG    1
-#define ENDIAN_OTHER  2
-
 /*! \brief Sizes of types used in portable format (different names used in
   Vlib/ and diglib/ for the same thing)
 
@@ -93,6 +85,8 @@
 #define GV_FORMAT_OGR        1
 /*! \brief OGR format (direct access) */
 #define GV_FORMAT_OGR_DIRECT 2
+/*! \brief PostGIS format (for layers linked via v.external) */
+#define GV_FORMAT_POSTGIS    3
 
 /*! \brief One table linked to vector map */
 #define GV_1TABLE  0
@@ -224,11 +218,33 @@
 #define GV_ASCII_FORMAT_STD   1
 #define GV_ASCII_FORMAT_WKT   2
 
-/*! \brief Simple feature types */
-#define SF_POINT      0x01
-#define SF_LINE	      0x02
-#define SF_LINESTRING 0x04
-#define SF_LINEARRING 0x08
-#define SF_POLYGON    0x10
+/*! \brief Simple feature types
+  
+  Taken from GDAL/OGR library (ogr/ogr_core.h)
+*/
+typedef enum
+{
+    SF_UNKNOWN = 0,                       /* unknown type, non-standard */
+    SF_POINT = 1,                         /* 0-dimensional geometric object */
+    SF_LINESTRING = 2,                    /* 1-dimensional geometric object with linear
+					     interpolation between Points */
+    SF_POLYGON = 3,                       /* planar 2-dimensional geometric object defined
+					     by 1 exterior boundary and 0 or more interior
+					     boundaries */
+    SF_MULTIPOINT = 4,                    /* GeometryCollection of Points */
+    SF_MULTILINESTRING = 5,               /* GeometryCollection of LineStrings */
+    SF_MULTIPOLYGON = 6,                  /* GeometryCollection of Polygons */
+    SF_GEOMETRYCOLLECTION = 7,            /* geometric object that is a collection of 1
+					     or more geometric objects  */
+    SF_NONE = 100,                        /* non-standard, for pure attribute records */
+    SF_LINEARRING = 101,                  /* non-standard */
+    SF_POINT25D = 0x80000001,             /* 2.5D extension as per 99-402 */
+    SF_LINESTRING25D = 0x80000002,        /* 2.5D extension as per 99-402 */
+    SF_POLYGON25D = 0x80000003,           /* 2.5D extension as per 99-402 */
+    SF_MULTIPOINT25D = 0x80000004,        /* 2.5D extension as per 99-402 */
+    SF_MULTILINESTRING25D = 0x80000005,   /* 2.5D extension as per 99-402 */
+    SF_MULTIPOLYGON25D = 0x80000006,      /* 2.5D extension as per 99-402 */
+    SF_GEOMETRYCOLLECTION25D = 0x80000007 /* 2.5D extension as per 99-402 */
+} SF_FeatureType;
 
 #define HEADSTR	50

Modified: grass/trunk/include/vect/dig_structs.h
===================================================================
--- grass/trunk/include/vect/dig_structs.h	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/include/vect/dig_structs.h	2012-02-05 17:19:12 UTC (rev 50670)
@@ -30,6 +30,10 @@
 #include <ogr_api.h>
 #endif
 
+#ifdef HAVE_POSTGRES
+#include <libpq-fe.h>
+#endif
+
 /*!
   \brief plus_t size
 
@@ -391,10 +395,43 @@
 };
 
 /*!
+  \brief Data structure used for building pseudo-topology
+
+  See Vect__build_sfa() (Format_info_ogr and Format_info_pg) for
+  implementation issues.
+*/
+struct Format_info_offset
+{
+    /*!
+      \brief Offset list
+
+      Array where feature/part info is stored for each feature in
+      GRASS. This is not used for GV_CENTROID. Because one feature may
+      contain more elements (geometry collection also recursively),
+      offset for one line may be stored in more records. First record
+      is FID, next records are part indexes if necessary. Example:
+      5. ring in 3. polygon in 7. feature (multipolygon) of geometry
+      collection which has FID = 123 123 (feature 123: geometry
+      colletion) 6 (7. feature in geometry collection: multiPolygon) 2
+      (3. polygon) 4 (5. ring in the polygon)
+    */
+    int *array;
+    /*!
+      \brief Number of items in offset list
+    */
+    int array_num;
+    /*!
+      \brief Space allocated for offset list
+    */
+    int array_alloc;
+
+};
+
+/*!
   \brief Non-native format info (OGR)
 
   \todo Structure size should not change depending on compilation I
-        think, do it better
+  think, do it better
 */
 struct Format_info_ogr
 {
@@ -446,31 +483,36 @@
     */
     char **layer_options;
     
-    /* Level 1 (used by V*_read_next_line_ogr) */
-    
     /*!
-      \brief Points cache (level 1)
+      \brief Lines cache (per feature)
     */
-    struct line_pnts **lines;	
+    struct {
+	/*!
+	  \brief Lines array
+	  
+	  Some features requires more allocated lines (eg. polygon
+	  with more rings, multipoint, or geometrycollection)
+	*/
+	struct line_pnts **lines;	
+	/*!
+	  \brief List of line types
+	*/
+	int *lines_types;
+	/*!
+	  \brief Number of allocated lines in cache
+	*/
+	int lines_alloc;
+	/*!
+	  \brief Number of lines which forms current feature
+	*/
+	int lines_num;
+	/*!
+	  \brief Next line to be read from cache
+	*/
+	int lines_next;
+    } cache;
+    
     /*!
-      \brief List of line types (level 1)
-    */
-    int *lines_types;
-    /*!
-      \brief Number of allocated lines (level 1)
-    */
-    int lines_alloc;
-    /*!
-      \brief Number of lines in cache (level 1)
-    */
-    int lines_num;
-    /*!
-      \brief Next line to be read from cache (level 1)
-    */
-    int lines_next;
-
-    /* Level 2 */
-    /*!
       \brief Cache to avoid repeated reading (level 2)
 
       NULL if no feature is in cache
@@ -486,34 +528,97 @@
     int feature_cache_id;
 
     /*!
-      \brief Offset list
+      \brief Offset list used for building pseudo-topology
+    */
+    struct Format_info_offset offset;
+    
+    /*!					      
+      \brief Next line to be read
 
-      Array where OGR feature/part info is stored for each line in
-      GRASS. This is not used for GV_CENTROID. Because one feature
-      may contain more elements (geometry collection also
-      recursively), offset for one line may be stored in more
-      records. First record is FID, next records are part indexes if
-      necessary. Example: 5. ring in 3. polygon in 7. feature
-      (multipolygon) of geometry collection which has FID = 123 123
-      (feature 123: geometry colletion) 6 (7. feature in geometry
-      collection: multiPolygon) 2 (3. polygon) 4 (5. ring in the
-      polygon)
+      Used by V2_read_next_line_ogr()
     */
-    int *offset;
+    int next_line;
+};
+
+/*!
+  \brief Non-native format info (PostGIS)
+*/
+struct Format_info_pg
+{
     /*!
-      \brief Number of items in offset
+      \brief Connection info string
     */
-    int offset_num;
+    char    *conninfo;
     /*!
-      \brief Space allocated for offset
+      \brief Database name (derived from conninfo)
     */
-    int offset_alloc;
-    /*!					      
-      \brief Next line to be read
-
-      Used by V2_read_next_line_ogr()
+    char    *db_name;
+    /*!
+      \brief Table name
     */
+    char    *table_name;
+    /*!
+      \brief FID column
+    */
+    char    *fid_column;        
+    /*!
+      \brief Geometry column
+    */
+    char    *geom_column;       
+#ifdef HAVE_POSTGRES
+    /*!
+      \brief PGconn object (generated by PQconnectdb)
+    */
+    PGconn   *conn;
+    PGresult *res;
+    // dbDriver *dbdriver;
+#else
+    void     *conn;
+    void     *res;
+#endif
+  
+    /*!
+      \brief Next line to be read for sequential access
+    */
     int next_line;
+    
+    /*!
+      \brief Lines cache (per feature)
+    */
+    struct {
+	/*!
+	  \brief Lines array
+	  
+	  Some features requires more allocated lines (eg. polygon
+	  with more rings, multipoint, or geometrycollection)
+	*/
+	struct line_pnts **lines;
+      	/*!
+	  \brief List of line types
+	*/
+	int *lines_types;
+	/*!
+	  \brief Number of allocated lines in cache
+	*/
+	int lines_alloc;
+	/*!
+	  \brief Number of lines which forms current feature
+	*/
+	int lines_num;
+	/*!
+	  \brief Next line to be read from cache
+	*/
+	int lines_next;
+	/*!
+	  \brief Feature id
+	*/
+	long fid;
+    } cache;
+    
+    /*!
+      \brief Offset list used for building pseudo-topology
+    */
+    struct Format_info_offset offset;
 };
 
 /*!
@@ -529,6 +634,10 @@
       \brief OGR info
     */
     struct Format_info_ogr ogr;
+    /*!
+      \brief PostGIS info
+    */
+    struct Format_info_pg  pg;
 };
 
 /*!

Modified: grass/trunk/lib/vector/Vlib/build.c
===================================================================
--- grass/trunk/lib/vector/Vlib/build.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/build.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -5,10 +5,10 @@
 
    Higher level functions for reading/writing/manipulating vectors.
 
-   (C) 2001-2010 by the GRASS Development Team
+   (C) 2001-2010, 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.
+   (>=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.
@@ -22,7 +22,13 @@
 
 #define SEP "-----------------------------------\n"
 
-#ifndef HAVE_OGR
+static int build_dummy()
+{
+    G_warning(_("Not implemented"));
+    return -1;
+}
+
+#if !defined HAVE_OGR || !defined HAVE_POSTGRES
 static int format()
 {
     G_fatal_error(_("Requested format is not compiled in this version"));
@@ -33,12 +39,17 @@
 static int (*Build_array[]) () = {
     Vect_build_nat
 #ifdef HAVE_OGR
-	, Vect_build_ogr
-	, Vect_build_ogr
+    , Vect_build_ogr
+    , Vect_build_ogr
 #else
-	, format
-        , format
+    , format
+    , format
 #endif
+#ifdef HAVE_POSTGRES
+    , Vect_build_pg
+#else
+    , format
+#endif
 };
 
 /*!
@@ -699,7 +710,7 @@
     if (Map->format != GV_FORMAT_OGR_DIRECT)
 	Map->support_updated = 1;
 
-    if (Map->plus.Spidx_built == 0)
+    if (Map->plus.Spidx_built == FALSE)
 	Vect_open_sidx(Map, 2);
 
     plus = &(Map->plus);

Modified: grass/trunk/lib/vector/Vlib/build_ogr.c
===================================================================
--- grass/trunk/lib/vector/Vlib/build_ogr.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/build_ogr.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -4,15 +4,11 @@
    \brief Vector library - Building topology for OGR
 
    Higher level functions for reading/writing/manipulating vectors.
-
-   Line offset is
-    - centroids   : FID
-    - other types : index of the first record (which is FID) in offset array.
- 
+   
    Category: FID, not all layer have FID, OGRNullFID is defined
    (5/2004) as -1, so FID should be only >= 0
 
-   (C) 2001-2010 by the GRASS Development Team
+   (C) 2001-2010, 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.
@@ -29,312 +25,10 @@
 
 #ifdef HAVE_OGR
 #include <ogr_api.h>
-
-/*! 
-  \brief This structure keeps info about geometry parts above
-  current geometry, path to curent geometry in the * feature. First
-  'part' number however is feature Id
-*/
-typedef struct
-{
-    int *part;
-    int a_parts;
-    int n_parts;
-} GEOM_PARTS;
-
-/*!
-  \brief Init parts
-*/
-static void init_parts(GEOM_PARTS * parts)
-{
-    parts->part = NULL;
-    parts->a_parts = parts->n_parts = 0;
-}
-
-/*!
-  \brief Reset parts
-*/
-static void reset_parts(GEOM_PARTS * parts)
-{
-    parts->n_parts = 0;
-}
-
-/*!
-  \brief Free parts
-*/
-static void free_parts(GEOM_PARTS * parts)
-{
-    G_free(parts->part);
-    parts->a_parts = parts->n_parts = 0;
-}
-
-/*!
-  \brief Add new part number to parts
-*/
-static void add_part(GEOM_PARTS * parts, int part)
-{
-    if (parts->a_parts == parts->n_parts) {
-	parts->a_parts += 10;
-	parts->part =
-	    (int *)G_realloc((void *)parts->part,
-			     parts->a_parts * sizeof(int));
-    }
-    parts->part[parts->n_parts] = part;
-    parts->n_parts++;
-}
-
-/*!
-  \brief Remove last part
-*/
-static void del_part(GEOM_PARTS * parts)
-{
-    parts->n_parts--;
-}
-
-/*!
-  \brief Add parts to offset
-*/
-static void add_parts_to_offset(struct Map_info *Map, GEOM_PARTS * parts)
-{
-    int i, j;
-
-    if (Map->fInfo.ogr.offset_num + parts->n_parts >=
-	Map->fInfo.ogr.offset_alloc) {
-	Map->fInfo.ogr.offset_alloc += parts->n_parts + 1000;
-	Map->fInfo.ogr.offset = (int *)G_realloc(Map->fInfo.ogr.offset,
-						 Map->fInfo.ogr.offset_alloc *
-						 sizeof(int));
-    }
-    j = Map->fInfo.ogr.offset_num;
-    for (i = 0; i < parts->n_parts; i++) {
-	G_debug(4, "add offset %d", parts->part[i]);
-	Map->fInfo.ogr.offset[j] = parts->part[i];
-	j++;
-    }
-    Map->fInfo.ogr.offset_num += parts->n_parts;
-}
-
-/*!
-  \brief Add line to support structures
-*/
-static int add_line(struct Map_info *Map, int type, struct line_pnts *Points,
-		    int FID, GEOM_PARTS * parts)
-{
-    int line;
-    struct Plus_head *plus;
-    long offset;
-    struct bound_box box;
-
-    plus = &(Map->plus);
-
-    if (type != GV_CENTROID) {
-	/* beginning in the offset array */
-	offset = Map->fInfo.ogr.offset_num;
-    }
-    else {
-	/* TODO : could be used to statore category ? */
-	/* because centroids are read from topology, not from layer */
-	offset = FID; 
-    }
-    G_debug(4, "Register line: FID = %d offset = %ld", FID, offset);
-    dig_line_box(Points, &box);
-    line = dig_add_line(plus, type, Points, &box, offset);
-    G_debug(4, "Line registered with line = %d", line);
-
-    /* Set box */
-    if (line == 1)
-	Vect_box_copy(&(plus->box), &box);
-    else
-	Vect_box_extend(&(plus->box), &box);
-
-    if (type != GV_BOUNDARY) {
-	dig_cidx_add_cat(plus, 1, (int)FID, line, type);
-    }
-    else {
-	dig_cidx_add_cat(plus, 0, 0, line, type);
-    }
-
-    if (type != GV_CENTROID)	/* because centroids are read from topology, not from layer */
-	add_parts_to_offset(Map, parts);
-
-    return line;
-}
-
-/*!
-  \brief Recursively add geometry to topology
-*/
-static int add_geometry(struct Map_info *Map, OGRGeometryH hGeom, int FID, int build,
-			GEOM_PARTS * parts)
-{
-    struct Plus_head *plus;
-    int i, ret;
-    int line;
-    int area, isle, outer_area = 0;
-    int lines[1];
-    static struct line_pnts **Points = NULL;
-    static int alloc_points = 0;
-    struct bound_box box;
-    struct P_line *Line;
-    double area_size, x, y;
-    int eType, nRings, iPart, nParts, nPoints;
-    OGRGeometryH hGeom2, hRing;
-
-    G_debug(4, "add_geometry() FID = %d", FID);
-    plus = &(Map->plus);
-
-    if (!Points) {
-	alloc_points = 1;
-	Points = (struct line_pnts **)G_malloc(sizeof(struct line_pnts *));
-	Points[0] = Vect_new_line_struct();
-    }
-    Vect_reset_line(Points[0]);
-
-    eType = wkbFlatten(OGR_G_GetGeometryType(hGeom));
-    G_debug(4, "OGR type = %d", eType);
-
-    switch (eType) {
-    case wkbPoint:
-	G_debug(4, "Point");
-	Vect_append_point(Points[0], OGR_G_GetX(hGeom, 0),
-			  OGR_G_GetY(hGeom, 0), OGR_G_GetZ(hGeom, 0));
-	add_line(Map, GV_POINT, Points[0], FID, parts);
-	break;
-
-    case wkbLineString:
-	G_debug(4, "LineString");
-	nPoints = OGR_G_GetPointCount(hGeom);
-	for (i = 0; i < nPoints; i++) {
-	    Vect_append_point(Points[0],
-			      OGR_G_GetX(hGeom, i), OGR_G_GetY(hGeom, i),
-			      OGR_G_GetZ(hGeom, i));
-	}
-	add_line(Map, GV_LINE, Points[0], FID, parts);
-	break;
-
-    case wkbPolygon:
-	G_debug(4, "Polygon");
-
-	nRings = OGR_G_GetGeometryCount(hGeom);
-	G_debug(4, "Number of rings: %d", nRings);
-
-	/* Alloc space for islands */
-	if (nRings >= alloc_points) {
-	    Points = (struct line_pnts **)G_realloc((void *)Points,
-						    nRings *
-						    sizeof(struct line_pnts
-							   *));
-	    for (i = alloc_points; i < nRings; i++) {
-		Points[i] = Vect_new_line_struct();
-	    }
-	}
-
-	for (iPart = 0; iPart < nRings; iPart++) {
-	    hRing = OGR_G_GetGeometryRef(hGeom, iPart);
-	    nPoints = OGR_G_GetPointCount(hRing);
-	    G_debug(4, "  ring %d : nPoints = %d", iPart, nPoints);
-
-
-	    Vect_reset_line(Points[iPart]);
-	    for (i = 0; i < nPoints; i++) {
-		Vect_append_point(Points[iPart],
-				  OGR_G_GetX(hRing, i), OGR_G_GetY(hRing, i),
-				  OGR_G_GetZ(hRing, i));
-	    }
-
-	    /* register boundary */
-	    add_part(parts, iPart);
-	    line = add_line(Map, GV_BOUNDARY, Points[iPart], FID, parts);
-	    del_part(parts);
-
-	    if (build < GV_BUILD_AREAS)
-		continue;
-	    
-	    /* add area (each inner ring is also area) */
-	    dig_line_box(Points[iPart], &box);
-	    dig_find_area_poly(Points[iPart], &area_size);
-
-	    if (area_size > 0)	        /* area clockwise */
-		lines[0] = line;
-	    else
-		lines[0] = -line;
-
-	    area = dig_add_area(plus, 1, lines, &box);
-
-	    /* Each area is also isle */
-	    lines[0] = -lines[0];	/* island is counter clockwise */
-
-	    isle = dig_add_isle(plus, 1, lines, &box);
-
-	    if (build < GV_BUILD_ATTACH_ISLES)
-		continue;
-	    
-	    if (iPart == 0) {	/* outer ring */
-		outer_area = area;
-	    }
-	    else {		/* inner ring */
-		struct P_isle *Isle;
-
-		Isle = plus->Isle[isle];
-		Isle->area = outer_area;
-
-		dig_area_add_isle(plus, outer_area, isle);
-	    }
-	}
-	
-	if (build >= GV_BUILD_CENTROIDS) {
-	    /* create virtual centroid */
-	    ret = Vect_get_point_in_poly_isl((const struct line_pnts *) Points[0],
-					     (const struct line_pnts **) Points + 1,
-					     nRings - 1, &x, &y);
-	    if (ret < -1) {
-		G_warning(_("Unable to calculate centroid for area %d"),
-			  outer_area);
-	    }
-	    else {
-		struct P_area *Area;
-		struct P_topo_c *topo;
-		
-		G_debug(4, "  Centroid: %f, %f", x, y);
-		Vect_reset_line(Points[0]);
-		Vect_append_point(Points[0], x, y, 0.0);
-		line = add_line(Map, GV_CENTROID, Points[0], FID, parts);
-		
-		Line = plus->Line[line];
-		topo = (struct P_topo_c *)Line->topo;
-		topo->area = outer_area;
-		
-		/* register centroid to area */
-		Area = plus->Area[outer_area];
-		Area->centroid = line;
-	    }
-	}
-	break;
-
-    case wkbMultiPoint:
-    case wkbMultiLineString:
-    case wkbMultiPolygon:
-    case wkbGeometryCollection:
-	nParts = OGR_G_GetGeometryCount(hGeom);
-	G_debug(4, "%d geoms -> next level", nParts);
-	for (i = 0; i < nParts; i++) {
-	    add_part(parts, i);
-	    hGeom2 = OGR_G_GetGeometryRef(hGeom, i);
-	    add_geometry(Map, hGeom2, FID, build, parts);
-	    del_part(parts);
-	}
-	break;
-
-    default:
-	G_warning(_("OGR feature type %d not supported"), eType);
-	break;
-    }
-
-    return 0;
-}
 #endif
 
 /*!
-   \brief Build pseudo-topology for OGR layer
+   \brief Build pseudo-topology (simple features) for OGR layer
 
    Build levels:
     - GV_BUILD_NONE
@@ -352,137 +46,120 @@
 int Vect_build_ogr(struct Map_info *Map, int build)
 {
 #ifdef HAVE_OGR
-    int iFeature, FID, line;
     struct Plus_head *plus;
-    struct P_line *Line;
-    
-    GEOM_PARTS parts;
-    OGRFeatureH hFeature;
-    OGRGeometryH hGeom;
+    struct Format_info_ogr *ogr_info;
 
-    G_debug(1, "Vect_build_ogr(): dsn=%s layer=%s, build=%d",
-	    Map->fInfo.ogr.dsn, Map->fInfo.ogr.layer_name, build);
+    plus     = &(Map->plus);
+    ogr_info = &(Map->fInfo.ogr);
     
-    plus = &(Map->plus);
+    G_debug(1, "Vect_build_ogr(): dsn='%s' layer='%s', build=%d",
+	    ogr_info->dsn, ogr_info->layer_name, build);
+    
     if (build == plus->built)
 	return 1;		/* do nothing */
     
-    /* TODO move this init to better place (Vect_open_ ?), because in theory build may be reused on level2 */
+    /* TODO move this init to better place (Vect_open_ ?), because in
+       theory build may be reused on level2 */
     if (build >= plus->built && build > GV_BUILD_BASE) {
-	G_free((void *) Map->fInfo.ogr.offset);
-	Map->fInfo.ogr.offset = NULL;
-	Map->fInfo.ogr.offset_num = 0;
-	Map->fInfo.ogr.offset_alloc = 0;
+	G_free((void *) ogr_info->offset.array);
+	G_zero(&(ogr_info->offset), sizeof(struct Format_info_offset));
     }
-    if (!Map->fInfo.ogr.layer) {
+
+    if (!ogr_info->layer) {
 	G_warning(_("Empty OGR layer, nothing to build"));
 	return 0;
     }
     
-    if (OGR_L_TestCapability(Map->fInfo.ogr.layer, OLCTransactions))
-	OGR_L_CommitTransaction(Map->fInfo.ogr.layer);
+    if (OGR_L_TestCapability(ogr_info->layer, OLCTransactions))
+	OGR_L_CommitTransaction(ogr_info->layer);
 
     /* test layer capabilities */
-    if (!OGR_L_TestCapability(Map->fInfo.ogr.layer, OLCRandomRead)) {
+    if (!OGR_L_TestCapability(ogr_info->layer, OLCRandomRead)) {
 	G_warning(_("Random read is not supported by OGR for this layer, "
 		    "unable to build topology"));
 	return 0;
     }
 
     G_message(_("Using external data format '%s' (feature type '%s')"),
-	      Vect_get_ogr_format_info(Map),
-	      Vect_get_ogr_geometry_type(Map));
+	      Vect_get_finfo_format_info(Map),
+	      Vect_get_finfo_geometry_type(Map));
     
-    /* initialize data structures */
-    init_parts(&parts);
+    return Vect__build_sfa(Map, build);
+#else
+    G_fatal_error(_("GRASS is not compiled with OGR support"));
+    return 0;
+#endif
+}
 
-    /* Check if upgrade or downgrade */
-    if (build < plus->built) {	/* lower level request, currently only GV_BUILD_NONE */
-	if (plus->built >= GV_BUILD_CENTROIDS && build < GV_BUILD_CENTROIDS) {
-	    /* reset info about areas stored for centroids */
-	    int nlines = Vect_get_num_lines(Map);
-	    
-	    for (line = 1; line <= nlines; line++) {
-		Line = plus->Line[line];
-		if (Line && Line->type == GV_CENTROID) {
-		    struct P_topo_c *topo = (struct P_topo_c *)Line->topo;
-		    topo->area = 0;
-		}
-	    }
-	    dig_free_plus_areas(plus);
-	    dig_spidx_free_areas(plus);
-	    dig_free_plus_isles(plus);
-	    dig_spidx_free_isles(plus);
-	}
-	
-	if (plus->built >= GV_BUILD_AREAS && build < GV_BUILD_AREAS) {
-	    /* reset info about areas stored for lines */
-	    int nlines = Vect_get_num_lines(Map);
+/*!
+   \brief Save feature index file for vector map
 
-	    for (line = 1; line <= nlines; line++) {
-		Line = plus->Line[line];
-		if (Line && Line->type == GV_BOUNDARY) {
-		    struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
-		    topo->left = 0;
-		    topo->right = 0;
-		}
-	    }
-	    dig_free_plus_areas(plus);
-	    dig_spidx_free_areas(plus);
-	    dig_free_plus_isles(plus);
-	    dig_spidx_free_isles(plus);
-	}
+   \param Map pointer to Map_info structure
+   \param offset pointer to Format_info_offset struct
+   (see Format_info_ogr and Format_info_pg struct for implementation issues)
 
-	if (plus->built >= GV_BUILD_BASE && build < GV_BUILD_BASE) {
-	    dig_free_plus_nodes(plus);
-	    dig_spidx_free_nodes(plus);
-	    dig_free_plus_lines(plus);
-	    dig_spidx_free_lines(plus);
-	}
-    }
-    else {
-	if (plus->built < GV_BUILD_BASE) {
-	    /* Note: Do not use OGR_L_GetFeatureCount (it may scan all features) */
-	    OGR_L_ResetReading(Map->fInfo.ogr.layer);
-	    iFeature = 0;
-	    while ((hFeature = OGR_L_GetNextFeature(Map->fInfo.ogr.layer)) != NULL) {
-		iFeature++;
-		
-		G_debug(3, "   Feature %d", iFeature);
-		
-		hGeom = OGR_F_GetGeometryRef(hFeature);
-		if (hGeom == NULL) {
-		    G_warning(_("Feature %d without geometry ignored"), iFeature);
-		    OGR_F_Destroy(hFeature);
-		    continue;
-		}
-		
-		FID = (int)OGR_F_GetFID(hFeature);
-		if (FID == OGRNullFID) {
-		    G_warning(_("OGR feature %d without ID ignored"), iFeature);
-		    OGR_F_Destroy(hFeature);
-		    continue;
-		}
-		G_debug(4, "    FID = %d", FID);
-		
-		reset_parts(&parts);
-		add_part(&parts, FID);
-		add_geometry(Map, hGeom, FID, build, &parts);
-		
-		OGR_F_Destroy(hFeature);
-	    } /* while */
-	    
-	    plus->built = GV_BUILD_BASE;
-	}
-    }
+   \return 1 on success
+   \return 0 on error
+ */
+int Vect_save_fidx(struct Map_info *Map,
+		   struct Format_info_offset *offset)
+{
+#ifdef HAVE_OGR
+    char fname[GPATH_MAX], elem[GPATH_MAX];
+    char buf[5];
+    long length;
+    struct gvfile fp;
+    struct Port_info port;
 
-    free_parts(&parts);
+    if (strcmp(Map->mapset, G_mapset()) != 0 ||
+	Map->support_updated == FALSE ||
+	Map->plus.built != GV_BUILD_ALL)
+	return 1;
     
-    plus->built = build;
+    length = 9;
+
+    sprintf(elem, "%s/%s", GV_DIRECTORY, Map->name);
+    G_file_name(fname, elem, GV_FIDX_ELEMENT, Map->mapset);
+    G_debug(4, "Open fidx: %s", fname);
+    dig_file_init(&fp);
+    fp.file = fopen(fname, "w");
+    if (fp.file == NULL) {
+	G_warning(_("Unable to open fidx file for write <%s>"), fname);
+	return 0;
+    }
     
+    dig_init_portable(&port, dig__byte_order_out());
+    dig_set_cur_port(&port);
+    
+    /* Header */
+    /* bytes 1 - 5 */
+    buf[0] = 5;
+    buf[1] = 0;
+    buf[2] = 5;
+    buf[3] = 0;
+    buf[4] = (char)dig__byte_order_out();
+    if (0 >= dig__fwrite_port_C(buf, 5, &fp))
+	return 0;
+    
+    /* bytes 6 - 9 : header size */
+    if (0 >= dig__fwrite_port_L(&length, 1, &fp))
+	return 0;
+    
+    /* Body */
+    /* number of records  */
+    if (0 >= dig__fwrite_port_I(&(offset->array_num), 1, &fp))
+	return 0;
+    
+    /* offsets */
+    if (0 >= dig__fwrite_port_I(offset->array,
+				offset->array_num, &fp))
+	return 0;
+    
+    fclose(fp.file);
+
     return 1;
 #else
     G_fatal_error(_("GRASS is not compiled with OGR support"));
-    return -1;
+    return 0;
 #endif
 }

Added: grass/trunk/lib/vector/Vlib/build_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/build_pg.c	                        (rev 0)
+++ grass/trunk/lib/vector/Vlib/build_pg.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -0,0 +1,91 @@
+/*!
+   \file lib/vector/Vlib/build_pg.c
+
+   \brief Vector library - Building topology for PostGIS layers
+
+   Higher level functions for reading/writing/manipulating vectors.
+
+   \todo Implement build_topo()
+   
+   Line offset is
+    - centroids   : FID
+    - other types : index of the first record (which is FID) in offset array.
+ 
+   (C) 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 Martin Landa <landa.martin gmail.com>
+*/
+
+#include <grass/vector.h>
+#include <grass/glocale.h>
+
+#ifdef HAVE_POSTGRES
+#include <libpq-fe.h>
+
+static int build_topo(struct Map_info *, int);
+#endif
+
+/*!
+   \brief Build topology for PostGIS layer
+
+   Build levels:
+    - GV_BUILD_NONE
+    - GV_BUILD_BASE
+    - GV_BUILD_ATTACH_ISLES
+    - GV_BUILD_CENTROIDS
+    - GV_BUILD_ALL
+   
+   \param Map pointer to Map_info structure
+   \param build build level
+
+   \return 1 on success
+   \return 0 on error
+ */
+int Vect_build_pg(struct Map_info *Map, int build)
+{
+#ifdef HAVE_POSTGRES
+    struct Plus_head *plus;
+    struct Format_info_pg *pg_info;
+
+    plus     = &(Map->plus);
+    pg_info  = &(Map->fInfo.pg);
+    
+    G_debug(1, "Vect_build_pg(): db='%s' table='%s', build=%d",
+	    pg_info->db_name, pg_info->table_name, build);
+    
+    if (build == plus->built)
+	return 1;		/* do nothing */
+    
+    /* TODO move this init to better place (Vect_open_ ?), because in
+       theory build may be reused on level2 */
+    if (build >= plus->built && build > GV_BUILD_BASE) {
+	G_free((void *) pg_info->offset.array);
+	G_zero(&(pg_info->offset), sizeof(struct Format_info_offset));
+    }
+
+    if (!pg_info->conn) {
+	G_warning(_("No DB connection"));
+	return 0;
+    }
+    
+    G_message(_("Using external data format '%s' (feature type '%s')"),
+	      Vect_get_finfo_format_info(Map),
+	      Vect_get_finfo_geometry_type(Map));
+    
+    return Vect__build_sfa(Map, build);
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+    return 0;
+#endif
+}
+
+#ifdef HAVE_POSTGRES
+int build_topo(struct Map_info *Map, int build)
+{
+    G_fatal_error(_("Not implemented"));
+    return 1;
+}
+#endif


Property changes on: grass/trunk/lib/vector/Vlib/build_pg.c
___________________________________________________________________
Added: svn:mime-type
   + text/x-csrc
Added: svn:eol-style
   + native

Added: grass/trunk/lib/vector/Vlib/build_sfa.c
===================================================================
--- grass/trunk/lib/vector/Vlib/build_sfa.c	                        (rev 0)
+++ grass/trunk/lib/vector/Vlib/build_sfa.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -0,0 +1,718 @@
+/*!
+   \file lib/vector/Vlib/build_sfa.c
+
+   \brief Vector library - Building pseudo-topology for simple feature access
+
+   Higher level functions for reading/writing/manipulating vectors.
+
+   Line offset is
+    - centroids   : FID
+    - other types : index of the first record (which is FID) in offset array.
+ 
+   (C) 2001-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 Radim Blazek
+   \author Piero Cavalieri
+   \author Various updates for GRASS 7 by Martin Landa <landa.martin gmail.com>
+*/
+
+#include <stdlib.h>
+
+#include <grass/gis.h>
+#include <grass/vector.h>
+#include <grass/glocale.h>
+
+/*!  
+  \brief This structure keeps info about geometry parts above current
+  geometry, path to curent geometry in the feature. First 'part' number
+  however is feature id */
+struct geom_parts
+{
+    int *part;
+    int a_parts;
+    int n_parts;
+};
+
+static void init_parts(struct geom_parts *);
+static void reset_parts(struct geom_parts *);
+static void free_parts(struct geom_parts *);
+static void add_part(struct geom_parts *, int);
+static void del_part(struct geom_parts *);
+static void add_parts_to_offset(struct Format_info_offset *,
+				struct geom_parts *);
+static int add_line(struct Plus_head *, struct Format_info_offset *,
+		    int, struct line_pnts *,
+		    int, struct geom_parts *);
+
+#ifdef HAVE_POSTGRES
+#include "pg_local_proto.h"
+
+static int add_geometry_pg(struct Plus_head *,
+			   struct Format_info_pg *,
+			   SF_FeatureType, int, int,
+			   struct geom_parts *);
+static void build_pg(struct Map_info *, int);
+#endif
+
+#ifdef HAVE_OGR
+#include <ogr_api.h>
+
+static int add_geometry_ogr(struct Plus_head *,
+			    struct Format_info_ogr *,
+			    OGRGeometryH, int, int,
+			    struct geom_parts *);
+
+static void build_ogr(struct Map_info *, int);
+#endif
+
+/*!
+  \brief Init parts
+*/
+void init_parts(struct geom_parts * parts)
+{
+    G_zero(parts, sizeof(struct geom_parts));
+}
+
+/*!
+  \brief Reset parts
+*/
+void reset_parts(struct geom_parts * parts)
+{
+    parts->n_parts = 0;
+}
+
+/*!
+  \brief Free parts
+*/
+void free_parts(struct geom_parts * parts)
+{
+    G_free(parts->part);
+    G_zero(parts, sizeof(struct geom_parts));
+}
+
+/*!
+  \brief Add new part number to parts
+*/
+void add_part(struct geom_parts *parts, int part)
+{
+    if (parts->a_parts == parts->n_parts) {
+	parts->a_parts += 10;
+	parts->part = (int *) G_realloc((void *)parts->part,
+					parts->a_parts * sizeof(int));
+    }
+    parts->part[parts->n_parts] = part;
+    parts->n_parts++;
+}
+
+/*!
+  \brief Remove last part
+*/
+void del_part(struct geom_parts *parts)
+{
+    parts->n_parts--;
+}
+
+/*!
+  \brief Add parts to offset
+*/
+void add_parts_to_offset(struct Format_info_offset *offset,
+			 struct geom_parts *parts)
+{
+    int i, j;
+
+    if (offset->array_num + parts->n_parts >= offset->array_alloc) {
+	offset->array_alloc += parts->n_parts + 1000;
+	offset->array = (int *)G_realloc(offset->array,
+					 offset->array_alloc * sizeof(int));
+    }
+    j = offset->array_num;
+    for (i = 0; i < parts->n_parts; i++) {
+	G_debug(4, "add offset %d", parts->part[i]);
+	offset->array[j] = parts->part[i];
+	j++;
+    }
+    offset->array_num += parts->n_parts;
+}
+
+/*!
+  \brief Add line to support structures
+*/
+int add_line(struct Plus_head *plus, struct Format_info_offset *offset,
+	     int type, struct line_pnts *Points,
+	     int FID, struct geom_parts *parts)
+{
+    int line;
+    long offset_value;
+    struct bound_box box;
+
+    if (type != GV_CENTROID) {
+	/* beginning in the offset array */
+	offset_value = offset->array_num;
+    }
+    else {
+	/* TODO : could be used to statore category ? */
+	/* because centroids are read from topology, not from layer */
+	offset_value = FID; 
+    }
+
+    G_debug(4, "Register line: FID = %d offset = %ld", FID, offset_value);
+    dig_line_box(Points, &box);
+    line = dig_add_line(plus, type, Points, &box, offset_value);
+    G_debug(4, "Line registered with line = %d", line);
+
+    /* Set box */
+    if (line == 1)
+	Vect_box_copy(&(plus->box), &box);
+    else
+	Vect_box_extend(&(plus->box), &box);
+
+    if (type != GV_BOUNDARY) {
+	dig_cidx_add_cat(plus, 1, (int)FID, line, type);
+    }
+    else {
+	dig_cidx_add_cat(plus, 0, 0, line, type);
+    }
+
+    if (type != GV_CENTROID)	/* because centroids are read from topology, not from layer */
+	add_parts_to_offset(offset, parts);
+
+    return line;
+}
+
+#ifdef HAVE_POSTGRES
+/*!
+  \brief Recursively add geometry (PostGIS) to topology
+*/
+int add_geometry_pg(struct Plus_head *plus,
+		    struct Format_info_pg *pg_info,
+		    SF_FeatureType ftype, int FID, int build,
+		    struct geom_parts *parts)
+{
+    int line, iPart, area, isle, outer_area, ret;
+    int lines[1];
+    double area_size, x, y;
+    struct bound_box box;
+    struct Format_info_offset *offset;
+
+    G_debug(4, "add_geometry_pg() FID = %d ftype = %d", FID, ftype);
+    
+    offset = &(pg_info->offset);
+    
+    outer_area = 0;
+    
+    switch(ftype) {	
+    case SF_POINT:
+	G_debug(4, "Point");
+	add_line(plus, offset, GV_POINT, pg_info->cache.lines[0], FID, parts);
+	break;
+    case SF_LINESTRING:
+	G_debug(4, "LineString");
+	add_line(plus, offset, GV_LINE, pg_info->cache.lines[0], FID, parts);
+	break;
+    case SF_POLYGON:
+	G_debug(4, "Polygon");
+
+	/* register boundaries */
+	for (iPart = 0; iPart < pg_info->cache.lines_num; iPart++) {
+	    add_part(parts, iPart);
+	    line = add_line(plus, offset, GV_BOUNDARY, pg_info->cache.lines[iPart],
+			    FID, parts);
+	    del_part(parts);
+
+	    if (build < GV_BUILD_AREAS)
+		continue;
+	    
+	    /* add area (each inner ring is also area) */
+	    dig_line_box(pg_info->cache.lines[iPart], &box);
+	    dig_find_area_poly(pg_info->cache.lines[iPart], &area_size);
+
+	    if (area_size > 0)	        /* area clockwise */
+		lines[0] = line;
+	    else
+		lines[0] = -line;
+
+	    area = dig_add_area(plus, 1, lines, &box);
+
+	    /* each area is also isle */
+	    lines[0] = -lines[0];	/* island is counter clockwise */
+
+	    isle = dig_add_isle(plus, 1, lines, &box);
+
+	    if (build < GV_BUILD_ATTACH_ISLES)
+		continue;
+	    
+	    if (iPart == 0) {	/* outer ring */
+		outer_area = area;
+	    }
+	    else {		/* inner ring */
+		struct P_isle *Isle;
+
+		Isle = plus->Isle[isle];
+		Isle->area = outer_area;
+
+		dig_area_add_isle(plus, outer_area, isle);
+	    }
+	}
+
+	if (build >= GV_BUILD_CENTROIDS) {
+	    /* create virtual centroid */
+	    ret = Vect_get_point_in_poly_isl((const struct line_pnts *) pg_info->cache.lines[0],
+					     (const struct line_pnts **) pg_info->cache.lines + 1,
+					     pg_info->cache.lines_num - 1, &x, &y);
+	    if (ret < -1) {
+		G_warning(_("Unable to calculate centroid for area %d"),
+			  outer_area);
+	    }
+	    else {
+		struct P_area *Area;
+		struct P_topo_c *topo;
+		struct P_line *Line;
+		
+		G_debug(4, "  Centroid: %f, %f", x, y);
+		Vect_reset_line(pg_info->cache.lines[0]);
+		Vect_append_point(pg_info->cache.lines[0], x, y, 0.0);
+		line = add_line(plus, offset, GV_CENTROID, pg_info->cache.lines[0], FID, parts);
+		
+		Line = plus->Line[line];
+		topo = (struct P_topo_c *)Line->topo;
+		topo->area = outer_area;
+		
+		/* register centroid to area */
+		Area = plus->Area[outer_area];
+		Area->centroid = line;
+	    }
+	}
+	break;
+    default:
+	G_warning(_("Feature type %d not supported"), ftype);
+	break;
+    }
+    
+    return 0;
+}
+
+/*!
+  \brief Build pseudo-topology for PostGIS layers
+*/
+void build_pg(struct Map_info *Map, int build)
+{
+    int iFeature, FID, nrecords;
+    char stmt[DB_SQL_MAX];
+    SF_FeatureType ftype;
+    
+    struct Format_info_pg *pg_info;
+    
+    struct geom_parts parts;
+
+    pg_info = &(Map->fInfo.pg);
+
+    /* initialize data structures */
+    init_parts(&parts);
+
+    /* get records */
+    sprintf(stmt, "SELECT %s,%s FROM %s",
+	    pg_info->fid_column,
+	    pg_info->geom_column, pg_info->table_name);
+    G_debug(2, "SQL: %s", stmt);
+    pg_info->res = PQexec(pg_info->conn, stmt);
+    if (!pg_info->res || PQresultStatus(pg_info->res) != PGRES_TUPLES_OK) {
+	PQclear(pg_info->res);
+	G_warning(_("Unable to get features:\n%s"),
+		  PQerrorMessage(pg_info->conn));
+	return; /* reading failed */
+    }
+
+    /* scan records */
+    nrecords = PQntuples(pg_info->res);
+    G_debug(4, "build_pg(): nrecords = %d", nrecords);
+    for (iFeature = 0; iFeature < nrecords; iFeature++) {
+	/* get feature id */
+	FID  = atoi(PQgetvalue(pg_info->res, iFeature, 0));
+	/* cache feature (lines) */
+    	ftype = cache_feature(PQgetvalue(pg_info->res, iFeature, 1),
+			      FALSE, pg_info);
+	
+	if (pg_info->cache.lines_num < 1) {
+	    G_warning(_("Feature %d without geometry ignored"), iFeature);
+	    continue;
+	}
+	
+	G_debug(3, "Feature %d: cat=%d", iFeature, FID);
+
+	/* register topo */
+	reset_parts(&parts);
+	add_part(&parts, FID);
+	add_geometry_pg(&(Map->plus), pg_info,
+			ftype, FID, build, &parts);
+    }
+
+    Map->plus.built = GV_BUILD_BASE;
+
+    PQclear(pg_info->res);
+    pg_info->res = NULL;
+    
+    /* free allocated space */
+    free_parts(&parts);
+}
+#endif /* HAVE_POSTGRES */
+
+#ifdef HAVE_OGR
+/*!
+  \brief Recursively add geometry (OGR) to topology
+*/
+int add_geometry_ogr(struct Plus_head *plus,
+		     struct Format_info_ogr *ogr_info,
+		     OGRGeometryH hGeom, int FID, int build,
+		     struct geom_parts *parts)
+{
+    int i, ret;
+    int line;
+    int area, isle, outer_area;
+    int lines[1];
+    double area_size, x, y;
+    int eType, nRings, iPart, nParts, nPoints;
+
+    struct bound_box box;
+    struct P_line *Line;
+    struct Format_info_offset *offset;
+    
+    OGRGeometryH hGeom2, hRing;
+
+    G_debug(4, "add_geometry_ogr() FID = %d", FID);
+
+    offset = &(ogr_info->offset);
+    
+    /* allocate space in cache */
+    if (!ogr_info->cache.lines) {
+	ogr_info->cache.lines_alloc = 1;
+	ogr_info->cache.lines = (struct line_pnts **) G_malloc(sizeof(struct line_pnts *));
+	
+	ogr_info->cache.lines_types = (int *) G_malloc(sizeof(int));
+	ogr_info->cache.lines[0] = Vect_new_line_struct();
+	ogr_info->cache.lines_types[0] = -1;
+    }
+
+    outer_area = 0;
+    eType = wkbFlatten(OGR_G_GetGeometryType(hGeom));
+    G_debug(4, "OGR type = %d", eType);
+
+    switch (eType) {
+    case wkbPoint:
+	G_debug(4, "Point");
+	
+	ogr_info->cache.lines_types[0] = GV_POINT;
+	Vect_reset_line(ogr_info->cache.lines[0]);
+	Vect_append_point(ogr_info->cache.lines[0], OGR_G_GetX(hGeom, 0),
+			  OGR_G_GetY(hGeom, 0), OGR_G_GetZ(hGeom, 0));
+	add_line(plus, offset, GV_POINT, ogr_info->cache.lines[0], FID, parts);
+	break;
+
+    case wkbLineString:
+	G_debug(4, "LineString");
+	
+	ogr_info->cache.lines_types[0] = GV_LINE;
+	nPoints = OGR_G_GetPointCount(hGeom);
+	Vect_reset_line(ogr_info->cache.lines[0]);
+	for (i = 0; i < nPoints; i++) {
+	    Vect_append_point(ogr_info->cache.lines[0],
+			      OGR_G_GetX(hGeom, i), OGR_G_GetY(hGeom, i),
+			      OGR_G_GetZ(hGeom, i));
+	}
+	add_line(plus, offset, GV_LINE, ogr_info->cache.lines[0], FID, parts);
+	break;
+
+    case wkbPolygon:
+	G_debug(4, "Polygon");
+
+	nRings = OGR_G_GetGeometryCount(hGeom);
+	G_debug(4, "Number of rings: %d", nRings);
+
+	/* alloc space for islands if needed */
+	if (nRings > ogr_info->cache.lines_alloc) {
+	    ogr_info->cache.lines_alloc += 20;
+	    ogr_info->cache.lines = (struct line_pnts **) G_realloc(ogr_info->cache.lines,
+								    ogr_info->cache.lines_alloc *
+								    sizeof(struct line_pnts *));
+	    ogr_info->cache.lines_types = (int *) G_realloc(ogr_info->cache.lines_types,
+							    ogr_info->cache.lines_alloc * sizeof(int));
+		
+	    for (i = ogr_info->cache.lines_alloc - 20; i < ogr_info->cache.lines_alloc; i++) {
+		ogr_info->cache.lines[i] = Vect_new_line_struct();
+		ogr_info->cache.lines_types[i] = -1;
+	    }
+	}
+
+	/* go thru rings */
+	for (iPart = 0; iPart < nRings; iPart++) {
+	    ogr_info->cache.lines_types[iPart] = GV_BOUNDARY;
+	    hRing = OGR_G_GetGeometryRef(hGeom, iPart);
+	    nPoints = OGR_G_GetPointCount(hRing);
+	    G_debug(4, "  ring %d : nPoints = %d", iPart, nPoints);
+
+	    Vect_reset_line(ogr_info->cache.lines[iPart]);
+	    for (i = 0; i < nPoints; i++) {
+		Vect_append_point(ogr_info->cache.lines[iPart],
+				  OGR_G_GetX(hRing, i), OGR_G_GetY(hRing, i),
+				  OGR_G_GetZ(hRing, i));
+	    }
+
+	    /* register boundary */
+	    add_part(parts, iPart);
+	    line = add_line(plus, offset, GV_BOUNDARY, ogr_info->cache.lines[iPart], FID, parts);
+	    del_part(parts);
+
+	    if (build < GV_BUILD_AREAS)
+		continue;
+	    
+	    /* add area (each inner ring is also area) */
+	    dig_line_box(ogr_info->cache.lines[iPart], &box);
+	    dig_find_area_poly(ogr_info->cache.lines[iPart], &area_size);
+
+	    if (area_size > 0)	        /* area clockwise */
+		lines[0] = line;
+	    else
+		lines[0] = -line;
+
+	    area = dig_add_area(plus, 1, lines, &box);
+
+	    /* each area is also isle */
+	    lines[0] = -lines[0];	/* island is counter clockwise */
+
+	    isle = dig_add_isle(plus, 1, lines, &box);
+
+	    if (build < GV_BUILD_ATTACH_ISLES)
+		continue;
+	    
+	    if (iPart == 0) {	/* outer ring */
+		outer_area = area;
+	    }
+	    else {		/* inner ring */
+		struct P_isle *Isle;
+
+		Isle = plus->Isle[isle];
+		Isle->area = outer_area;
+
+		dig_area_add_isle(plus, outer_area, isle);
+	    }
+	}
+	
+	if (build >= GV_BUILD_CENTROIDS) {
+	    /* create virtual centroid */
+	    ret = Vect_get_point_in_poly_isl((const struct line_pnts *) ogr_info->cache.lines[0],
+					     (const struct line_pnts **) ogr_info->cache.lines + 1,
+					     nRings - 1, &x, &y);
+	    if (ret < -1) {
+		G_warning(_("Unable to calculate centroid for area %d"),
+			  outer_area);
+	    }
+	    else {
+		struct P_area *Area;
+		struct P_topo_c *topo;
+		
+		G_debug(4, "  Centroid: %f, %f", x, y);
+		Vect_reset_line(ogr_info->cache.lines[0]);
+		Vect_append_point(ogr_info->cache.lines[0], x, y, 0.0);
+		line = add_line(plus, offset, GV_CENTROID, ogr_info->cache.lines[0],
+				FID, parts);
+		
+		Line = plus->Line[line];
+		topo = (struct P_topo_c *)Line->topo;
+		topo->area = outer_area;
+		
+		/* register centroid to area */
+		Area = plus->Area[outer_area];
+		Area->centroid = line;
+	    }
+	}
+	break;
+
+    case wkbMultiPoint:
+    case wkbMultiLineString:
+    case wkbMultiPolygon:
+    case wkbGeometryCollection:
+	nParts = OGR_G_GetGeometryCount(hGeom);
+	G_debug(4, "%d geoms -> next level", nParts);
+
+	/* alloc space for parts if needed */
+	if (nParts > ogr_info->cache.lines_alloc) {
+	    ogr_info->cache.lines_alloc += 20;
+	    ogr_info->cache.lines = (struct line_pnts **) G_realloc(ogr_info->cache.lines,
+								    ogr_info->cache.lines_alloc *
+								    sizeof(struct line_pnts *));
+	    ogr_info->cache.lines_types = (int *) G_realloc(ogr_info->cache.lines_types,
+							    ogr_info->cache.lines_alloc * sizeof(int));
+		
+	    for (i = ogr_info->cache.lines_alloc - 20; i < ogr_info->cache.lines_alloc; i++) {
+		ogr_info->cache.lines[i] = Vect_new_line_struct();
+		ogr_info->cache.lines_types[i] = -1;
+	    }
+	}
+	
+	/* go thru all parts */
+	for (i = 0; i < nParts; i++) {
+	    add_part(parts, i);
+	    hGeom2 = OGR_G_GetGeometryRef(hGeom, i);
+	    add_geometry_ogr(plus, ogr_info, hGeom2, FID, build, parts);
+	    del_part(parts);
+	}
+	break;
+
+    default:
+	G_warning(_("OGR feature type %d not supported"), eType);
+	break;
+    }
+
+    return 0;
+}
+
+void build_ogr(struct Map_info *Map, int build)
+{
+    int iFeature, FID;
+    
+    struct Format_info_ogr *ogr_info;
+    
+    OGRFeatureH hFeature;
+    OGRGeometryH hGeom;
+		
+    struct geom_parts parts;
+    
+    ogr_info = &(Map->fInfo.ogr);
+    
+    /* initialize data structures */
+    init_parts(&parts);
+
+    /* Note: Do not use OGR_L_GetFeatureCount (it may scan all features) */
+    OGR_L_ResetReading(ogr_info->layer);
+    iFeature = 0;
+    while ((hFeature = OGR_L_GetNextFeature(ogr_info->layer)) != NULL) {
+	iFeature++;
+	
+	G_debug(3, "   Feature %d", iFeature);
+	
+	hGeom = OGR_F_GetGeometryRef(hFeature);
+	if (hGeom == NULL) {
+	    G_warning(_("Feature %d without geometry ignored"), iFeature);
+	    OGR_F_Destroy(hFeature);
+	    continue;
+	}
+	
+	FID = (int) OGR_F_GetFID(hFeature);
+	if (FID == OGRNullFID) {
+	    G_warning(_("OGR feature %d without ID ignored"), iFeature);
+	    OGR_F_Destroy(hFeature);
+	    continue;
+	}
+	G_debug(4, "    FID = %d", FID);
+	
+	reset_parts(&parts);
+	add_part(&parts, FID);
+	add_geometry_ogr(&(Map->plus), ogr_info, hGeom,
+			 FID, build, &parts);
+	
+	OGR_F_Destroy(hFeature);
+    } /* while */
+    
+    Map->plus.built = GV_BUILD_BASE;
+    
+    free_parts(&parts);
+}
+#endif /* HAVE_OGR */
+
+/*!
+   \brief Build pseudo-topology (for simple features) - internal use only
+
+   See Vect_build_ogr() and Vect_build_pg() for implemetation issues.
+   
+   Build levels:
+    - GV_BUILD_NONE
+    - GV_BUILD_BASE
+    - GV_BUILD_ATTACH_ISLES
+    - GV_BUILD_CENTROIDS
+    - GV_BUILD_ALL
+   
+   \param Map pointer to Map_info structure
+   \param build build level
+
+   \return 1 on success
+   \return 0 on error
+*/
+int Vect__build_sfa(struct Map_info *Map, int build)
+{
+    int line;
+    struct Plus_head *plus;
+    struct P_line *Line;
+    
+    plus = &(Map->plus);
+    
+    /* check if upgrade or downgrade */
+    if (build < plus->built) { 
+	/* lower level request, currently only GV_BUILD_NONE */
+	if (plus->built >= GV_BUILD_CENTROIDS && build < GV_BUILD_CENTROIDS) {
+	    /* reset info about areas stored for centroids */
+	    for (line = 1; line <= plus->n_lines; line++) {
+		Line = plus->Line[line];
+		if (Line && Line->type == GV_CENTROID) {
+		    struct P_topo_c *topo = (struct P_topo_c *)Line->topo;
+		    topo->area = 0;
+		}
+	    }
+	    dig_free_plus_areas(plus);
+	    dig_spidx_free_areas(plus);
+	    dig_free_plus_isles(plus);
+	    dig_spidx_free_isles(plus);
+	}
+	
+	if (plus->built >= GV_BUILD_AREAS && build < GV_BUILD_AREAS) {
+	    /* reset info about areas stored for lines */
+	    for (line = 1; line <= plus->n_lines; line++) {
+		Line = plus->Line[line];
+		if (Line && Line->type == GV_BOUNDARY) {
+		    struct P_topo_b *topo = (struct P_topo_b *)Line->topo;
+		    topo->left = 0;
+		    topo->right = 0;
+		}
+	    }
+	    dig_free_plus_areas(plus);
+	    dig_spidx_free_areas(plus);
+	    dig_free_plus_isles(plus);
+	    dig_spidx_free_isles(plus);
+	}
+
+	if (plus->built >= GV_BUILD_BASE && build < GV_BUILD_BASE) {
+	    dig_free_plus_nodes(plus);
+	    dig_spidx_free_nodes(plus);
+	    dig_free_plus_lines(plus);
+	    dig_spidx_free_lines(plus);
+	}
+    }
+    else {
+	if (plus->built < GV_BUILD_BASE) {
+	    if (Map->format == GV_FORMAT_OGR ||
+		Map->format == GV_FORMAT_OGR_DIRECT) {
+#ifdef HAVE_OGR
+		build_ogr(Map, build);
+#else
+		G_fatal_error(_("GRASS is not compiled with OGR support"));
+#endif
+	    }
+ 	    else if (Map->format == GV_FORMAT_POSTGIS) {
+#ifdef HAVE_POSTGRES
+		build_pg(Map, build);
+#else
+		G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+#endif
+	    }
+	    else {
+		G_fatal_error(_("%s: Native format unsupported"),
+			      "Vect__build_sfa()");
+	    }
+	}
+    }
+
+    plus->built = build;
+    
+    return 1;
+}


Property changes on: grass/trunk/lib/vector/Vlib/build_sfa.c
___________________________________________________________________
Added: svn:mime-type
   + text/x-csrc
Added: svn:eol-style
   + native

Modified: grass/trunk/lib/vector/Vlib/close.c
===================================================================
--- grass/trunk/lib/vector/Vlib/close.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/close.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -1,17 +1,18 @@
 /*!
    \file lib/vector/Vlib/close.c
 
-   \brief Vector library - Close map
+   \brief Vector library - Close vector map
 
    Higher level functions for reading/writing/manipulating vectors.
 
-   (C) 2001-2009 by the GRASS Development Team
+   (C) 2001-2009, 2011 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.
+   (>=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 Update to GRASS 7 Martin Landa <landa.martin gmail.com>
  */
 
 #include <stdlib.h>
@@ -28,7 +29,7 @@
     return -1;
 }
 
-#ifndef HAVE_OGR
+#if !defined HAVE_OGR || !defined HAVE_POSTGRES
 static int format()
 {
     G_fatal_error(_("Requested format is not compiled in this version"));
@@ -50,13 +51,19 @@
     , {
     clo_dummy, format}
 #endif
+#ifdef HAVE_POSTGRES
+    , {
+    clo_dummy, V1_close_pg}
+#else
+    , {
+    clo_dummy, format}
+#endif
 };
 
-
 /*!
    \brief Close vector map
 
-   \param Map pointer to Map_info (vector map to close)
+   \param Map pointer to Map_info
 
    \return 0 on success
    \return non-zero on error
@@ -69,8 +76,10 @@
 	    "Vect_close(): name = %s, mapset = %s, format = %d, level = %d",
 	    Map->name, Map->mapset, Map->format, Map->level);
 
-    /* Store support files if in write mode on level 2 */
-    if (strcmp(Map->mapset, G_mapset()) == 0 && Map->support_updated &&
+    /* Store support files for vector maps in the current mapsset if
+       in write mode on level 2 */
+    if (strcmp(Map->mapset, G_mapset()) == 0 &&
+	Map->support_updated &&
 	Map->plus.built == GV_BUILD_ALL) {
 	char buf[GPATH_MAX];
 	char file_path[GPATH_MAX];
@@ -90,6 +99,13 @@
 	if (access(file_path, F_OK) == 0)	/* file exists? */
 	    unlink(file_path);
 
+	if (Map->format == GV_FORMAT_OGR ||
+	    Map->format == GV_FORMAT_POSTGIS) {
+	    G_file_name(file_path, buf, GV_FIDX_ELEMENT, G_mapset());
+	    if (access(file_path, F_OK) == 0)	/* file exists? */
+		unlink(file_path);
+	}
+	
 	Vect_coor_info(Map, &CInfo);
 	Map->plus.coor_size = CInfo.size;
 	Map->plus.coor_mtime = CInfo.mtime;
@@ -100,16 +116,18 @@
 
 	Vect_cidx_save(Map);
 
-#ifdef HAVE_OGR
+	/* write out fidx file */
 	if (Map->format == GV_FORMAT_OGR)
 	    V2_close_ogr(Map);
-#endif
+	else if (Map->format == GV_FORMAT_POSTGIS)
+	    V2_close_pg(Map);
     }
     else {
-	/* spatial index must also be closed when opened with topo but not modified */
+	/* spatial index must also be closed when opened with topo but
+	 * not modified */
 	/* NOTE: also close sidx for GV_FORMAT_OGR if not direct OGR access */
 	if (Map->format != GV_FORMAT_OGR_DIRECT &&
-	    Map->plus.Spidx_built == 1 &&
+	    Map->plus.Spidx_built == TRUE &&
 	    Map->plus.built == GV_BUILD_ALL)
 	    fclose(Map->plus.spidx_fp.file);
     }
@@ -141,15 +159,11 @@
 	}
     }
 
-    G_free((void *)Map->name);
-    Map->name = NULL;
-    G_free((void *)Map->mapset);
-    Map->mapset = NULL;
-    G_free((void *)Map->location);
-    Map->location = NULL;
-    G_free((void *)Map->gisdbase);
-    Map->gisdbase = NULL;
-
+    G_free(Map->name);
+    G_free(Map->mapset);
+    G_free(Map->location);
+    G_free(Map->gisdbase);
+    
     Map->open = VECT_CLOSED_CODE;
 
     return 0;

Modified: grass/trunk/lib/vector/Vlib/close_ogr.c
===================================================================
--- grass/trunk/lib/vector/Vlib/close_ogr.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/close_ogr.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -5,7 +5,7 @@
 
    Higher level functions for reading/writing/manipulating vectors.
 
-   (C) 2001-2009 by the GRASS Development Team
+   (C) 2001-2009, 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.
@@ -23,9 +23,9 @@
 #endif
 
 /*!
-  \brief Close vector map (OGR dsn & layer)
+  \brief Close vector map (OGR dsn & layer) on level 1
 
-  \param Map pointer to Map_info
+  \param Map pointer to Map_info structure
 
   \return 0 on success
   \return non-zero on error
@@ -35,36 +35,40 @@
 #ifdef HAVE_OGR
     int i;
 
-    struct Format_info_ogr *fInfo;
+    struct Format_info_ogr *ogr_info;
     
+    G_debug(3, "V1_close_ogr() name = %s mapset = %s", Map->name, Map->mapset);
+    
     if (!VECT_OPEN(Map))
 	return -1;
-
-    fInfo = &(Map->fInfo.ogr);
+    
+    ogr_info = &(Map->fInfo.ogr);
     if (Map->format != GV_FORMAT_OGR_DIRECT &&
 	(Map->mode == GV_MODE_WRITE || Map->mode == GV_MODE_RW))
 	Vect__write_head(Map);
 
-    if (fInfo->feature_cache)
-	OGR_F_Destroy(fInfo->feature_cache);
+    if (ogr_info->feature_cache)
+	OGR_F_Destroy(ogr_info->feature_cache);
 
-    OGR_DS_Destroy(fInfo->ds);
+    /* destroy OGR datasource */
+    OGR_DS_Destroy(ogr_info->ds);
     
-    for (i = 0; i < fInfo->lines_alloc; i++) {
-	Vect_destroy_line_struct(fInfo->lines[i]);
+    /* destroy lines in cache */
+    for (i = 0; i < ogr_info->cache.lines_alloc; i++) {
+	Vect_destroy_line_struct(ogr_info->cache.lines[i]);
     }
-
-    if (fInfo->dbdriver) {
-	db_close_database_shutdown_driver(fInfo->dbdriver);
+    G_free(ogr_info->cache.lines);
+    G_free(ogr_info->cache.lines_types);
+    
+    /* close DB connection (for atgtributes) */
+    if (ogr_info->dbdriver) {
+	db_close_database_shutdown_driver(ogr_info->dbdriver);
     }
+    
+    G_free(ogr_info->driver_name);
+    G_free(ogr_info->dsn);
+    G_free(ogr_info->layer_name);
 
-    G_free(fInfo->lines);
-    G_free(fInfo->lines_types);
-
-    G_free(fInfo->driver_name);
-    G_free(fInfo->dsn);
-    G_free(fInfo->layer_name);
-
     return 0;
 #else
     G_fatal_error(_("GRASS is not compiled with OGR support"));
@@ -73,9 +77,9 @@
 }
 
 /*!
-  \brief Write OGR specific files (fidx)
+  \brief Close vector map on topological level (write out fidx file)
 
-  \param Map vector map
+  \param Map pointer to Map_info structure
   
   \return 0 on success
   \return non-zero on error
@@ -83,62 +87,22 @@
 int V2_close_ogr(struct Map_info *Map)
 {
 #ifdef HAVE_OGR
-    char fname[1000], elem[1000];
-    char buf[5];
-    long length = 9;
-    struct gvfile fp;
-    struct Port_info port;
+    struct Format_info_ogr *ogr_info;
+  
+    G_debug(3, "V2_close_ogr() name = %s mapset = %s", Map->name, Map->mapset);
 
-    G_debug(3, "V2_close_ogr()");
-
     if (!VECT_OPEN(Map))
 	return -1;
 
-    if (strcmp(Map->mapset, G_mapset()) == 0 && Map->support_updated &&
-	Map->plus.built == GV_BUILD_ALL) {
-	sprintf(elem, "%s/%s", GV_DIRECTORY, Map->name);
-	G_file_name(fname, elem, "fidx", Map->mapset);
-	G_debug(4, "Open fidx: %s", fname);
-	dig_file_init(&fp);
-	fp.file = fopen(fname, "w");
-	if (fp.file == NULL) {
-	    G_warning(_("Unable to open fidx file for write <%s>"), fname);
-	    return 1;
-	}
-
-	dig_init_portable(&port, dig__byte_order_out());
-	dig_set_cur_port(&port);
-
-	/* Header */
-	/* bytes 1 - 5 */
-	buf[0] = 5;
-	buf[1] = 0;
-	buf[2] = 5;
-	buf[3] = 0;
-	buf[4] = (char)dig__byte_order_out();
-	if (0 >= dig__fwrite_port_C(buf, 5, &fp))
-	    return (1);
-
-	/* bytes 6 - 9 : header size */
-	if (0 >= dig__fwrite_port_L(&length, 1, &fp))
-	    return (1);
-
-	/* Body */
-	/* number of records  */
-	if (0 >= dig__fwrite_port_I(&(Map->fInfo.ogr.offset_num), 1, &fp))
-	    return (1);
-
-	/* offsets */
-	if (0 >= dig__fwrite_port_I(Map->fInfo.ogr.offset,
-				    Map->fInfo.ogr.offset_num, &fp))
-	    return (1);
-
-	fclose(fp.file);
-
-    }
-
-    G_free(Map->fInfo.ogr.offset);
-
+    ogr_info = &(Map->fInfo.ogr);
+    
+    /* write fidx for maps in the current mapset */
+    if (Vect_save_fidx(Map, &(ogr_info->offset)) != 1)
+	G_warning(_("Unable to save feature index file for vector map <%s>"),
+		  Map->name);
+    
+    G_free(ogr_info->offset.array);
+    
     return 0;
 #else
     G_fatal_error(_("GRASS is not compiled with OGR support"));

Added: grass/trunk/lib/vector/Vlib/close_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/close_pg.c	                        (rev 0)
+++ grass/trunk/lib/vector/Vlib/close_pg.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -0,0 +1,114 @@
+/*!
+   \file lib/vector/Vlib/close_pg.c
+
+   \brief Vector library - Close map (PostGIS)
+
+   Higher level functions for reading/writing/manipulating vectors.
+
+   (C) 2011 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 Martin Landa <landa.martin gmail.com>
+*/
+
+#include <stdlib.h>
+#include <grass/vector.h>
+#include <grass/dbmi.h>
+#include <grass/glocale.h>
+
+#ifdef HAVE_POSTGRES
+#include "pg_local_proto.h"
+#endif
+
+/*!
+  \brief Close vector map (PostGIS layer) on level 1
+
+  \param Map pointer to Map_info structure
+
+  \return 0 on success
+  \return non-zero on error
+*/
+int V1_close_pg(struct Map_info *Map)
+{
+#ifdef HAVE_POSTGRES
+    int i;
+    struct Format_info_pg *pg_info;
+    
+    G_debug(3, "V2_close_pg() name = %s mapset = %s", Map->name, Map->mapset);
+    
+    if (!VECT_OPEN(Map))
+	return -1;
+    
+    pg_info = &(Map->fInfo.pg);
+    if (Map->mode == GV_MODE_WRITE || Map->mode == GV_MODE_RW)
+	Vect__write_head(Map);
+    
+    /* close connection */
+    if (pg_info->res) {
+	char stmt[DB_SQL_MAX];
+	
+	PQclear(pg_info->res);
+	pg_info->res = NULL;
+	
+	sprintf(stmt, "CLOSE %s%p",
+		pg_info->table_name, pg_info->conn);
+	if (execute(pg_info->conn, stmt) == -1) {
+	    G_warning(_("Unable to close cursor"));
+	    return -1;
+	}
+	execute(pg_info->conn, "COMMIT");
+    }
+    
+    PQfinish(pg_info->conn);
+    
+    /* free allocated space */
+    for (i = 0; i < pg_info->cache.lines_alloc; i++) {
+	Vect_destroy_line_struct(pg_info->cache.lines[i]);
+    }
+    if (pg_info->cache.lines)
+	G_free(pg_info->cache.lines);
+    if (pg_info->db_name)
+	G_free(pg_info->db_name);
+    if (pg_info->geom_column)
+	G_free(pg_info->geom_column);
+    if (pg_info->fid_column)
+	G_free(pg_info->fid_column);
+
+    return 0;
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+    return -1;
+#endif
+}
+
+/*!
+  \brief Close vector map (PostGIS layer) on topological level (write out fidx file)
+
+  \param Map pointer to Map_info structure
+  
+  \return 0 on success
+  \return non-zero on error
+*/
+int V2_close_pg(struct Map_info *Map)
+{
+#ifdef HAVE_POSTGRES
+    G_debug(3, "V2_close_pg() name = %s mapset = %s", Map->name, Map->mapset);
+
+    if (!VECT_OPEN(Map))
+	return -1;
+
+    /* write fidx for maps in the current mapset */
+    if (Vect_save_fidx(Map, &(Map->fInfo.pg.offset)) != 1)
+	G_warning(_("Unable to save feature index file for vector map <%s>"),
+		  Map->name);
+    
+    G_free(Map->fInfo.pg.offset.array);
+    
+    return 0;
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+    return -1;
+#endif
+}


Property changes on: grass/trunk/lib/vector/Vlib/close_pg.c
___________________________________________________________________
Added: svn:mime-type
   + text/x-csrc
Added: svn:eol-style
   + native

Modified: grass/trunk/lib/vector/Vlib/constraint.c
===================================================================
--- grass/trunk/lib/vector/Vlib/constraint.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/constraint.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -1,7 +1,7 @@
 /*!
    \file lib/vector/Vlib/constraint.c
 
-   \brief Vector library - constraints
+   \brief Vector library - constraints for reading features
 
    Higher level functions for reading/writing/manipulating vectors.
 
@@ -18,7 +18,7 @@
    By default all DEAD lines are ignored by the Vect_read_next_line()
    functions. This too can be overridden by including their types.
 
-   (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.
@@ -28,15 +28,16 @@
  */
 
 #include <grass/vector.h>
+#include <grass/glocale.h>
 
 /*!
    \brief Set constraint region
 
    Vect_read_next_line() will read only features inside of given
-   region.
+   region. Constraint is ignored for random access - Vect_read_line().
 
-   \param Map vector map
-   \param n,s,e,w,t,b north, south, east, west, top, and bottom coordinates
+   \param Map pointer to Map_info struct
+   \param n,s,e,w,t,b bbox definition (north, south, east, west, top, and bottom coordinates)
    
    \return 0 on success
    \return -1 on error (invalid region)
@@ -91,10 +92,11 @@
 /*!
    \brief Set constraint type
 
-   Vect_read_next_line() will read only features of given type.
+   Vect_read_next_line() will read only features of given
+   type. Constraint is ignored for random access - Vect_read_line().
 
-   \param Map vector map
-   \param type constraint type (GV_POINT, GV_LINE, ...)
+   \param Map pointer to Map_info struct
+   \param type constraint feature type (GV_POINT, GV_LINE, ...)
 
    \return 0 on success
    \return -1 invalid feature type
@@ -111,35 +113,42 @@
 }
 
 /*!
-   \brief Remove constraints
+   \brief Remove all constraints
 
-   \param Map vector map
-
-   \return 0
+   \param Map pointer to Map_info struct
  */
 void Vect_remove_constraints(struct Map_info *Map)
 {
     Map->constraint.region_flag = FALSE;
-    Map->constraint.type_flag = FALSE;
-    Map->constraint.field_flag = FALSE;
+    Map->constraint.type_flag   = FALSE;
+    Map->constraint.field_flag  = FALSE;
 }
 
 /*!
    \brief Set constraint field
 
    Vect_read_next_line() will read only features of given type. Note
-   that categories must be read otherwise this constraint is ignored.
+   that categories must be read otherwise this constraint is
+   ignored. Constraint is ignored for random access -
+   Vect_read_line().
 
+   Ignored for non-native vector formats.
+   
    Note: Field is called layer on user level.
 
-   \param Map vector map
+   \param Map pointer to Map_info struct
    \param field field number (-1 for all fields)
 
    \return 0 on success
-   \return -1 invalid feature type
+   \return -1 invalid field
 */
 int Vect_set_constraint_field(struct Map_info *Map, int field)
 {
+    if (Map->format != GV_FORMAT_NATIVE) {
+	G_warning(_("Layer constraint ignored for non-native vector formats"));
+	return -1;
+    }
+
     if (field == -1) {
 	Map->constraint.field_flag = FALSE;
 	return 0;


Property changes on: grass/trunk/lib/vector/Vlib/dgraph.h
___________________________________________________________________
Added: svn:mime-type
   + text/x-chdr


Property changes on: grass/trunk/lib/vector/Vlib/e_intersect.h
___________________________________________________________________
Added: svn:mime-type
   + text/x-chdr

Modified: grass/trunk/lib/vector/Vlib/field.c
===================================================================
--- grass/trunk/lib/vector/Vlib/field.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/field.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -9,7 +9,7 @@
   OGR_L_GetFIDColumn() is working or solution found if FID not
   available
   
-  (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.
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <grass/gis.h>
 #include <grass/glocale.h>
 #include <grass/dbmi.h>
 #include <grass/vector.h>
@@ -38,6 +39,7 @@
   \brief Create and init new dblinks structure
   
   \return pointer to new dblinks structure
+  \return NULL on failure
  */
 struct dblinks *Vect_new_dblinks_struct(void)
 {
@@ -46,15 +48,15 @@
     p = (struct dblinks *)G_malloc(sizeof(struct dblinks));
 
     if (p) {
-	p->alloc_fields = p->n_fields = 0;
-	p->field = NULL;
+	/* initialize members */
+	G_zero(p, sizeof(struct dblinks));
     }
 
     return p;
 }
 
 /*!
-  \brief Reset dblinks structure
+  \brief Reset dblinks structure (number of fields)
 
   \param p pointer to existing dblinks structure
 */
@@ -549,17 +551,7 @@
     return atoi(field);
 }
 
-/*!
-  \brief Read dblinks to existing structure.
-  
-  Variables are not substituted by values.
-  
-  \param Map pointer to Map_info structure
-
-  \return number of links read
-  \return -1 on error
- */
-int Vect_read_dblinks(struct Map_info *Map)
+static int read_dblinks_nat(struct Map_info *Map)
 {
     FILE *fd;
     char file[1024], buf[2001];
@@ -571,59 +563,142 @@
     char **tokens;
     int ntok, i;
 
-    G_debug(1, "Vect_read_dblinks(): map = %s, mapset = %s", Map->name,
-	    Map->mapset);
-
     dbl = Map->dblnk;
-    Vect_reset_dblinks(dbl);
 
-    G_debug(3, "Searching for FID column in OGR DB");
-    if (Map->format & (GV_FORMAT_OGR | GV_FORMAT_OGR_DIRECT)) {
+    /* Read dblink for native format */
+    sprintf(file, "%s/%s/%s/%s/%s/%s", Map->gisdbase, Map->location,
+	    Map->mapset, GV_DIRECTORY, Map->name,
+	    GV_DBLN_ELEMENT);
+    G_debug(1, "dbln file: %s", file);
 
-#ifndef HAVE_OGR
-	G_warning(_("GRASS is not compiled with OGR support"));
-#else
-#if GDAL_VERSION_NUM > 1320 && HAVE_OGR /* seems to be fixed after 1320 release */
-	int nLayers;
-	char *ogr_fid_col;
+    fd = fopen(file, "r");
+    if (fd == NULL) {		/* This may be correct, no tables defined */
+	G_debug(1, "Cannot open vector database definition file");
+	return (-1);
+    }
 
-	G_debug(3, "GDAL_VERSION_NUM: %d", GDAL_VERSION_NUM);
+    row = 0;
+    rule = 0;
+    while (G_getl2(buf, 2000, fd)) {
+	row++;
+	G_chop(buf);
+	G_debug(1, "dbln: %s", buf);
 
-	if (Map->fInfo.ogr.ds == NULL) {
-	    /* open the connection to fetch the FID column name */
-	    OGRRegisterAll();
+	c = (char *)strchr(buf, '#');
+	if (c != NULL)
+	    *c = '\0';
 
-	    /* data source handle */
-	    Map->fInfo.ogr.ds = OGROpen(Map->fInfo.ogr.dsn, FALSE, NULL);
-	    if (Map->fInfo.ogr.ds == NULL)
-		G_fatal_error(_("Unable to open OGR data source '%s'"),
-			      Map->fInfo.ogr.dsn);
+	if (strlen(buf) == 0)
+	    continue;
+
+#ifdef NOT_ABLE_TO_READ_GRASS_6
+	int ndef;
+	ndef = sscanf(buf, "%s|%s|%s|%s|%s", fldstr, tab, col, db, drv);
+
+        if (ndef < 2 || (ndef < 5 && rule < 1)) {
+            G_warning(_("Error in rule on row %d in <%s>"), row, file);
+            continue;
+        }
+#else
+	tokens = G_tokenize(buf, " |");
+	ntok = G_number_of_tokens(tokens);
+
+	if (ntok < 2 || (ntok < 5 && rule < 1)) {
+	    G_warning(_("Error in rule on row %d in <%s>"), row, file);
+	    continue;
 	}
-	if (Map->fInfo.ogr.layer == NULL) {
-	    /* get layer number */
-	    nLayers = OGR_DS_GetLayerCount(Map->fInfo.ogr.ds);	/* Layers = Maps in OGR DB */
-	    
-	    G_debug(3, "%d layers (maps) found in data source", nLayers);
-	    
-	    G_debug(3, "Trying to open OGR layer: %s", Map->fInfo.ogr.layer_name);
-	    if (Map->fInfo.ogr.layer_name) {
-		Map->fInfo.ogr.layer = OGR_DS_GetLayerByName(Map->fInfo.ogr.ds, Map->fInfo.ogr.layer_name);
-		if (Map->fInfo.ogr.layer == NULL) {
-		    OGR_DS_Destroy(Map->fInfo.ogr.ds);
-		    Map->fInfo.ogr.ds = NULL;
-		    G_fatal_error(_("Unable to open OGR layer <%s>"),
-				  Map->fInfo.ogr.layer_name);
+
+	strcpy(fldstr, tokens[0]);
+	strcpy(tab, tokens[1]);
+	if (ntok > 2) {
+	    strcpy(col, tokens[2]);
+	    if (ntok > 3) {
+		strcpy(db, tokens[3]);
+		/* allow for spaces in path names */
+		for (i=4; i < ntok-1; i++) {
+		    strcat(db, " ");
+		    strcat(db, tokens[i]);
 		}
+
+		strcpy(drv, tokens[ntok-1]);
 	    }
 	}
+	G_free_tokens(tokens);
+#endif
 
-	/* get fid column */
-	ogr_fid_col = G_store(OGR_L_GetFIDColumn(Map->fInfo.ogr.layer));
-	G_debug(3, "Using FID column <%s> in OGR DB", ogr_fid_col);
-	Vect_add_dblink(dbl, 1,  Map->fInfo.ogr.layer_name,
-			Map->fInfo.ogr.layer_name, ogr_fid_col,
-			Map->fInfo.ogr.dsn, "ogr");
+	/* get field and field name */
+	fldname = strchr(fldstr, '/');
+	if (fldname != NULL) {	/* field has name */
+	    fldname[0] = 0;
+	    fldname++;
+	}
+	fld = atoi(fldstr);
+
+	Vect_add_dblink(dbl, fld, fldname, tab, col, db, drv);
+
+	G_debug(1,
+		"field = %d name = %s, table = %s, key = %s, database = %s, driver = %s",
+		fld, fldname, tab, col, db, drv);
+
+	rule++;
+    }
+    fclose(fd);
+
+    G_debug(1, "Dblinks read");
+    
+    return rule;
+}
+
+static int read_dblinks_ogr(struct Map_info *Map)
+{
+    struct dblinks *dbl;
+    
+    dbl = Map->dblnk;
+    G_debug(3, "Searching for FID column in OGR DB");
+#ifndef HAVE_OGR
+    G_warning(_("GRASS is not compiled with OGR support"));
 #else
+#if GDAL_VERSION_NUM > 1320 && HAVE_OGR /* seems to be fixed after 1320 release */
+    int nLayers;
+    char *ogr_fid_col;
+    
+    G_debug(3, "GDAL_VERSION_NUM: %d", GDAL_VERSION_NUM);
+    
+    if (Map->fInfo.ogr.ds == NULL) {
+	/* open the connection to fetch the FID column name */
+	OGRRegisterAll();
+	
+	/* data source handle */
+	Map->fInfo.ogr.ds = OGROpen(Map->fInfo.ogr.dsn, FALSE, NULL);
+	if (Map->fInfo.ogr.ds == NULL)
+	    G_fatal_error(_("Unable to open OGR data source '%s'"),
+			  Map->fInfo.ogr.dsn);
+    }
+    if (Map->fInfo.ogr.layer == NULL) {
+	/* get layer number */
+	nLayers = OGR_DS_GetLayerCount(Map->fInfo.ogr.ds);	/* Layers = Maps in OGR DB */
+	
+	G_debug(3, "%d layers (maps) found in data source", nLayers);
+	
+	G_debug(3, "Trying to open OGR layer: %s", Map->fInfo.ogr.layer_name);
+	if (Map->fInfo.ogr.layer_name) {
+	    Map->fInfo.ogr.layer = OGR_DS_GetLayerByName(Map->fInfo.ogr.ds, Map->fInfo.ogr.layer_name);
+	    if (Map->fInfo.ogr.layer == NULL) {
+		OGR_DS_Destroy(Map->fInfo.ogr.ds);
+		Map->fInfo.ogr.ds = NULL;
+		G_fatal_error(_("Unable to open OGR layer <%s>"),
+			      Map->fInfo.ogr.layer_name);
+	    }
+	}
+    }
+    
+    /* get fid column */
+    ogr_fid_col = G_store(OGR_L_GetFIDColumn(Map->fInfo.ogr.layer));
+    G_debug(3, "Using FID column <%s> in OGR DB", ogr_fid_col);
+    Vect_add_dblink(dbl, 1,  Map->fInfo.ogr.layer_name,
+		    Map->fInfo.ogr.layer_name, ogr_fid_col,
+		    Map->fInfo.ogr.dsn, "ogr");
+#else
 	dbDriver *driver;
 	dbCursor cursor;
 	dbString sql;
@@ -728,94 +803,65 @@
 	    }
 	}
 #endif /* GDAL_VERSION_NUM > 1320 && HAVE_OGR */
-	return (1);
+	return 1;
 #endif	/* HAVE_GDAL */
-    }
-    else if (Map->format != GV_FORMAT_NATIVE) {
-	G_fatal_error(_("Don't know how to read links for format %d"),
-		      Map->format);
-    }
+}
 
-    sprintf(file, "%s/%s/%s/%s/%s/%s", Map->gisdbase, Map->location,
-	    Map->mapset, GV_DIRECTORY, Map->name,
-	    GV_DBLN_ELEMENT);
-    G_debug(1, "dbln file: %s", file);
-
-    fd = fopen(file, "r");
-    if (fd == NULL) {		/* This may be correct, no tables defined */
-	G_debug(1, "Cannot open vector database definition file");
-	return (-1);
+static int read_dblinks_pg(struct Map_info *Map)
+{
+#ifdef HAVE_POSTGRES
+    struct dblinks *dbl;
+    struct Format_info_pg *pg_info;
+    
+    dbl = Map->dblnk;
+    pg_info = &(Map->fInfo.pg);
+    
+    if (!pg_info->fid_column) {
+	G_warning(_("No FID column defined"));
+	return -1;
     }
-
-    row = 0;
-    rule = 0;
-    while (G_getl2(buf, 2000, fd)) {
-	row++;
-	G_chop(buf);
-	G_debug(1, "dbln: %s", buf);
-
-	c = (char *)strchr(buf, '#');
-	if (c != NULL)
-	    *c = '\0';
-
-	if (strlen(buf) == 0)
-	    continue;
-
-#ifdef NOT_ABLE_TO_READ_GRASS_6
-	int ndef;
-	ndef = sscanf(buf, "%s|%s|%s|%s|%s", fldstr, tab, col, db, drv);
-
-        if (ndef < 2 || (ndef < 5 && rule < 1)) {
-            G_warning(_("Error in rule on row %d in <%s>"), row, file);
-            continue;
-        }
+    G_debug(3, "Using FID column <%s>", pg_info->fid_column);
+    Vect_add_dblink(dbl, 1, pg_info->table_name,
+		    pg_info->table_name, pg_info->fid_column,
+		    pg_info->db_name, "pg");
+    return 1;
 #else
-	tokens = G_tokenize(buf, " |");
-	ntok = G_number_of_tokens(tokens);
-
-	if (ntok < 2 || (ntok < 5 && rule < 1)) {
-	    G_warning(_("Error in rule on row %d in <%s>"), row, file);
-	    continue;
-	}
-
-	strcpy(fldstr, tokens[0]);
-	strcpy(tab, tokens[1]);
-	if (ntok > 2) {
-	    strcpy(col, tokens[2]);
-	    if (ntok > 3) {
-		strcpy(db, tokens[3]);
-		/* allow for spaces in path names */
-		for (i=4; i < ntok-1; i++) {
-		    strcat(db, " ");
-		    strcat(db, tokens[i]);
-		}
-
-		strcpy(drv, tokens[ntok-1]);
-	    }
-	}
-	G_free_tokens(tokens);
+    G_warning(_("GRASS not compiled with PostgreSQL support"));
+    return -1;
 #endif
+}
 
-	/* get field and field name */
-	fldname = strchr(fldstr, '/');
-	if (fldname != NULL) {	/* field has name */
-	    fldname[0] = 0;
-	    fldname++;
-	}
-	fld = atoi(fldstr);
+/*!
+  \brief Read dblinks to existing structure.
+  
+  Variables are not substituted by values.
+  
+  \param Map pointer to Map_info structure
 
-	Vect_add_dblink(dbl, fld, fldname, tab, col, db, drv);
+  \return number of links read
+  \return -1 on error
+ */
+int Vect_read_dblinks(struct Map_info *Map)
+{
+    G_debug(1, "Vect_read_dblinks(): map = %s, mapset = %s", Map->name,
+	    Map->mapset);
+    
+    Vect_reset_dblinks(Map->dblnk);
 
-	G_debug(1,
-		"field = %d name = %s, table = %s, key = %s, database = %s, driver = %s",
-		fld, fldname, tab, col, db, drv);
-
-	rule++;
+    if (Map->format == GV_FORMAT_NATIVE) {
+	return read_dblinks_nat(Map);
     }
-    fclose(fd);
+    else if (Map->format == GV_FORMAT_OGR || Map->format == GV_FORMAT_OGR_DIRECT) {
+	return read_dblinks_ogr(Map);
+    }
+    else if (Map->format == GV_FORMAT_POSTGIS) {
+	return read_dblinks_pg(Map);
+    }
+    else {
+	G_fatal_error(_("Unknown vector map format"));
+    }
 
-    G_debug(1, "Dblinks read");
-    return (rule);
+    return -1;
 }
 
 /*!

Modified: grass/trunk/lib/vector/Vlib/header.c
===================================================================
--- grass/trunk/lib/vector/Vlib/header.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/header.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -251,97 +251,132 @@
 }
 
 /*!
-   \brief Get OGR datasource name (relevant only for OGR format)
+   \brief Get datasource name (relevant only for non-native formats)
 
+   Returns:
+    - datasource name for OGR format (GV_FORMAT_OGR and GV_FORMAT_OGR_DIRECT)
+    - database name for PostGIS format (GV_FORMAT_POSTGIS)
+   
    \param Map pointer to Map_info structure
 
-   \return string containing OGR datasource name
+   \return string containing OGR/PostGIS datasource name
+   \return NULL on error (map format is native)
  */
-const char *Vect_get_ogr_dsn_name(const struct Map_info *Map)
+const char *Vect_get_finfo_dsn_name(const struct Map_info *Map)
 {
+    if (Map->format == GV_FORMAT_OGR ||
+	Map->format == GV_FORMAT_OGR_DIRECT) {
 #ifndef HAVE_OGR
-    G_warning(_("GRASS is not compiled with OGR support"));
-#else
-    if (Map->format != GV_FORMAT_OGR &&
-	Map->format != GV_FORMAT_OGR_DIRECT)
-	G_warning(_("Format of vector map <%s> is not OGR"),
-		  Vect_get_full_name(Map));
+	G_warning(_("GRASS is not compiled with OGR support"));
 #endif
+        return Map->fInfo.ogr.dsn;
+    }
+    else if (Map->format == GV_FORMAT_POSTGIS) {
+#ifndef HAVE_POSTGRES
+	G_warning(_("GRASS is not compiled with PostgreSQL support"));
+#endif
+        return Map->fInfo.pg.db_name;
+    }
     
-    return Map->fInfo.ogr.dsn;
+    G_warning(_("Native vector format detected for <%s>"),
+	      Vect_get_full_name(Map));
+    
+    return NULL;
 }
 
 /*!
-   \brief Get OGR layer name (relevant only for OGR format)
+   \brief Get layer name (relevant only for non-native formats)
 
+   Returns:
+    - layer name for OGR format (GV_FORMAT_OGR and GV_FORMAT_OGR_DIRECT)
+    - table name for PostGIS format (GV_FORMAT_POSTGIS)
+
    \param Map pointer to Map_info structure
 
-   \return string containing OGR layer name
+   \return string containing layer name
+   \return NULL on error (map format is native)
  */
-const char *Vect_get_ogr_layer_name(const struct Map_info *Map)
+const char *Vect_get_finfo_layer_name(const struct Map_info *Map)
 {
+    if (Map->format == GV_FORMAT_OGR ||
+	Map->format == GV_FORMAT_OGR_DIRECT) {
 #ifndef HAVE_OGR
-    G_warning(_("GRASS is not compiled with OGR support"));
-#else
-    if (Map->format != GV_FORMAT_OGR &&
-	Map->format != GV_FORMAT_OGR_DIRECT)
-	G_warning(_("Format of vector map <%s> is not OGR"),
-		  Vect_get_full_name(Map));
+	G_warning(_("GRASS is not compiled with OGR support"));
 #endif
+	return Map->fInfo.ogr.layer_name;
+    }
+    else if (Map->format == GV_FORMAT_POSTGIS) {
+#ifndef HAVE_POSTGRES
+	G_warning(_("GRASS is not compiled with PostgreSQL support"));
+#endif
+        return Map->fInfo.pg.table_name;
+    }
+
+    G_warning(_("Native vector format detected for <%s>"),
+	      Vect_get_full_name(Map));
     
-    return Map->fInfo.ogr.layer_name;
+    return NULL;
 }
 
 /*!
-  \brief Get OGR format info (relevant only for OGR format)
+  \brief Get format info (relevant only for non-native formats)
 
   Allocated space should be freed by G_free().
 
+   Returns:
+    - layer name for OGR format (GV_FORMAT_OGR and GV_FORMAT_OGR_DIRECT)
+    
   \param Map pointer to Map_info structure
   
   \return string containing name of OGR format (allocated by G_store())
   \return NULL on error (or on missing OGR support)
 */
-const char *Vect_get_ogr_format_info(const struct Map_info *Map)
+const char *Vect_get_finfo_format_info(const struct Map_info *Map)
 {
+    char format[GPATH_MAX];
+
+    if (Map->format == GV_FORMAT_OGR ||
+	Map->format == GV_FORMAT_OGR_DIRECT) {
 #ifndef HAVE_OGR
-    G_warning(_("GRASS is not compiled with OGR support"));
+	G_warning(_("GRASS is not compiled with OGR support"));
 #else
-    if (Map->format != GV_FORMAT_OGR &&
-	Map->format != GV_FORMAT_OGR_DIRECT)
-	G_warning(_("Format of vector map <%s> is not OGR"),
-		  Vect_get_full_name(Map));
-    
-    if (!Map->fInfo.ogr.ds)
-	return NULL;
-    
-    return G_store(OGR_Dr_GetName(OGR_DS_GetDriver(Map->fInfo.ogr.ds)));
+	if (!Map->fInfo.ogr.ds)
+	    return NULL;
+
+	sprintf(format, "%s/%s", "OGR",
+		OGR_Dr_GetName(OGR_DS_GetDriver(Map->fInfo.ogr.ds)));
+	return G_store(format);
 #endif
+    }
+    else if (Map->format == GV_FORMAT_POSTGIS) {
+#ifndef HAVE_OGR
+	G_warning(_("GRASS is not compiled with PostgreSQL support"));
+#else
+	return G_store("PostGIS");
+#endif
+    }
     
     return NULL;
 }
 
 /*!
-  \brief Get OGR geometry type (relevant only for OGR format)
+  \brief Get geometry type (relevant only for non-native formats)
 
   \param Map pointer to Map_info structure
 
   \return allocated string containing geometry type info
-  \return NULL on error (or on missing OGR support)
+  \return NULL on error (map format is native)
 */
-const char *Vect_get_ogr_geometry_type(const struct Map_info *Map)
+const char *Vect_get_finfo_geometry_type(const struct Map_info *Map)
 {
+    if (Map->format == GV_FORMAT_OGR ||
+	Map->format == GV_FORMAT_OGR_DIRECT) {
 #ifndef HAVE_OGR
     G_warning(_("GRASS is not compiled with OGR support"));
 #else
     OGRwkbGeometryType Ogr_geom_type;
     OGRFeatureDefnH    Ogr_feature_defn;
     
-    if (Map->format != GV_FORMAT_OGR &&
-	Map->format != GV_FORMAT_OGR_DIRECT)
-	G_warning(_("Format of vector map <%s> is not OGR"),
-		  Vect_get_full_name(Map));
-    
     if (!Map->fInfo.ogr.layer)
 	return NULL;
 
@@ -350,6 +385,34 @@
     
     return OGRGeometryTypeToName(Ogr_geom_type);
 #endif
+    }
+    else if (Map->format == GV_FORMAT_POSTGIS) {
+#ifndef HAVE_POSTGRES
+	G_warning(_("GRASS is not compiled with PostgreSQL support"));
+#else
+	char stmt[DB_SQL_MAX], *ftype;
+	
+	const struct Format_info_pg *pg_info;
+	
+	PGresult *res;
+		
+	pg_info = &(Map->fInfo.pg);
+	sprintf(stmt, "SELECT type FROM geometry_columns "
+		"WHERE f_table_name = '%s'", 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("%s\n%s", _("Unable to get feature type."),
+		      PQresultErrorMessage(res));
+	
+	ftype = G_store(PQgetvalue(res, 0, 0));
+	PQclear(res);
+
+	return ftype;
+#endif
+    }
     
     return NULL;
 }

Modified: grass/trunk/lib/vector/Vlib/line.c
===================================================================
--- grass/trunk/lib/vector/Vlib/line.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/line.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -136,6 +136,8 @@
   If you are re-using a line struct, be sure to clear out old data
   first by calling Vect_reset_line().
   
+  Calls G_fatal_error() when out of memory.
+  
   \param Points pointer to line_pnts structure
   \param x,y,z point coordinates to be added
 
@@ -146,9 +148,11 @@
 {
     register int n;
 
-    if (0 > dig_alloc_points(Points, Points->n_points + 1))
-	return (-1);
-
+    if (0 > dig_alloc_points(Points, Points->n_points + 1)) {
+	G_fatal_error(_("Out of memory"));
+	return -1;
+    }
+    
     n = Points->n_points;
     Points->x[n] = x;
     Points->y[n] = y;

Modified: grass/trunk/lib/vector/Vlib/map.c
===================================================================
--- grass/trunk/lib/vector/Vlib/map.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/map.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -524,7 +524,7 @@
 /*!
    \brief Delete vector map including attribute tables
 
-   \param map vector map name
+   \param map pointer to Map_info structure
 
    \return -1 error
    \return 0 success

Modified: grass/trunk/lib/vector/Vlib/open.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/open.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -1,19 +1,19 @@
 /*!
- * \file lib/vector/Vlib/open.c
- *
- * \brief Vector library - Open vector map (native or OGR format)
- *
- * Higher level functions for reading/writing/manipulating vectors.
- *
- * (C) 2001-2009, 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.
- */
+  \file lib/vector/Vlib/open.c
+  
+  \brief Vector library - Open vector map (native or OGR/PostGIS format)
+  
+  Higher level functions for reading/writing/manipulating vectors.
+  
+  (C) 2001-2009, 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 Update to GRASS 7 Martin Landa <landa.martin gmail.com> (better OGR support and native PostGIS access)
+*/
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -40,7 +40,7 @@
     return 0;
 }
 
-#ifndef HAVE_OGR
+#if !defined HAVE_OGR || !defined HAVE_POSTGRES
 static int format()
 {
     G_fatal_error(_("Requested format is not compiled in this version"));
@@ -64,6 +64,13 @@
     , {
     open_old_dummy, format}
 #endif
+#ifdef HAVE_POSTGRES
+    , {
+    open_old_dummy, V1_open_old_pg}
+#else
+    , {
+    open_old_dummy, format}
+#endif
 };
 
 static int (*Open_new_array[][2]) () = {
@@ -80,30 +87,37 @@
     , {
     open_new_dummy, format}
 #endif
+#ifdef HAVE_POSTGRES
+    , {
+    open_old_dummy, V1_open_new_pg}
+#else
+    , {
+    open_old_dummy, format}
+#endif
 };
 
+static int open_old(struct Map_info *, const char *, const char *,
+		    const char *, int, int);
+
 /*!
- * \brief Predetermine level at which a vector map will be opened for
- * reading.
- *
- * If it can't open that level, the open will fail. The specified
- * level must be set before any call to open. The default is to try to
- * open the highest level possible, and keep stepping down until
- * success.
- *
- * NOTE: This should only be used to set when you wish to force a
- * lower level open. If you require a higher level, then just check
- * the return to verify the level instead of forcing it. This is
- * because future releases will have higher levels which will be
- * downward compatible and which your programs should support by
- * default.
- *
- * \param level vector access level
- *
- * \return 0 on success
- * \return 1 on error
- */
-
+  \brief Predetermine level at which a vector map will be opened for
+  reading.
+  
+  If it can't open that level, the open will fail. The specified level
+  must be set before any call to open. The default is to try to open
+  the highest level possible, and keep stepping down until success.
+  
+  NOTE: This should only be used to set when you wish to force a lower
+  level open. If you require a higher level, then just check the
+  return to verify the level instead of forcing it. This is because
+  future releases will have higher levels which will be downward
+  compatible and which your programs should support by default.
+ 
+  \param level vector access level
+  
+  \return 0 on success
+  \return 1 on error (invalid access level)
+*/
 int Vect_set_open_level(int level)
 {
     Open_level = level;
@@ -118,21 +132,21 @@
 }
 
 /*! 
- * \brief Open existing vector map for reading (internal use only)
- *
- * \param[out] Map pointer to Map_info structure
- * \param name name of vector map to open
- * \param mapset mapset name ("" for search path)
- * \param layer layer name (OGR format only)
- * \param update non-zero to open for update otherwise read-only mode
- * \param head_only read only header info from 'head', 'dbln', 'topo',
- * 'cidx' is not opened. The header may be opened on level 2 only.
- *
- * \return level of openness (1, 2)
- * \return -1 in error
- */
-int Vect__open_old(struct Map_info *Map, const char *name, const char *mapset, const char *layer,
-		   int update, int head_only)
+ \brief Open existing vector map for reading (internal use only)
+ 
+ \param[out] Map pointer to Map_info structure
+ \param name name of vector map to open
+ \param mapset mapset name ("" for search path)
+ \param layer layer name (OGR format only)
+ \param update non-zero to open for update otherwise read-only mode
+ \param head_only read only header info from 'head', 'dbln', 'topo',
+ 'cidx' is not opened. The header may be opened on level 2 only.
+ 
+ \return level of openness (1, 2)
+ \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)
 {
     char buf[GNAME_MAX + 10], buf2[GMAPSET_MAX + 10], xname[GNAME_MAX],
 	xmapset[GMAPSET_MAX];
@@ -142,8 +156,8 @@
     int ogr_mapset;
     const char *fmapset;
 
-    G_debug(1, "Vect__open_old(): name = %s mapset = %s layer= %s update = %d", name,
-	    mapset, layer, update);
+    G_debug(1, "Vect__open_old(): name='%s' mapset='%s' layer='%s' update=%d",
+	    name, mapset, layer, update);
 
     /* zero Map_info structure */
     G_zero(Map, sizeof(struct Map_info));
@@ -155,10 +169,10 @@
 
     /* initialize Map->head */
     Vect__init_head(Map);
-    /* initialize support structures for 2D, update to 3D when reading support files */
+    /* initialize support structures for 2D, update to 3D when reading
+       support files */
     Map->plus.spidx_with_z = Map->plus.with_z = Map->head.with_z = WITHOUT_Z;
     /* initialize Map->plus */
-    Map->plus.Spidx_file = 0;
     dig_init_plus(&(Map->plus));
 
     /* check OGR mapset */
@@ -318,7 +332,7 @@
 	    }
 	}
 #ifdef HAVE_OGR
-	/* Open OGR specific support files */
+	/* 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));
@@ -328,6 +342,17 @@
 	    }
 	}
 #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;
+	    }
+	}
+#endif
 	if (level_request == 2 && level < 2) {
 	    if (!ogr_mapset) {
 		/* for direct OGR read access is built pseudo-topology on the fly */
@@ -350,9 +375,13 @@
 		dig_spidx_free(&(Map->plus));
 		dig_cidx_free(&(Map->plus));
 	    }
-	    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);
+	    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) {
@@ -379,7 +408,7 @@
     Map->open = VECT_OPEN_CODE;
     Map->level = level;
     Map->head_only = head_only;
-    Map->support_updated = 0;
+    Map->support_updated = FALSE;
     if (update) {
 	Map->mode = GV_MODE_RW;
 	Map->plus.mode = GV_MODE_RW;
@@ -389,10 +418,10 @@
 	Map->plus.mode = GV_MODE_READ;
     }
     if (head_only) {
-	Map->head_only = 1;
+	Map->head_only = TRUE;
     }
     else {
-	Map->head_only = 0;
+	Map->head_only = FALSE;
     }
 
     G_debug(1, "Vect_open_old(): vector opened on level %d", level);
@@ -425,9 +454,9 @@
 
     }
     else {
-	if (Map->format == GV_FORMAT_NATIVE || Map->format == GV_FORMAT_OGR) {
-	    Map->hist_fp =
-		G_fopen_old(buf, GV_HIST_ELEMENT, Map->mapset);
+	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 {
@@ -462,153 +491,172 @@
 }
 
 /*!
- * \brief Open existing vector map for reading (native or OGR format
- * via v.external)
- *
- * This function is replaced by Vect_open_old2() to handle also direct
- * OGR support.
- * 
- * \param[out] Map pointer to Map_info structure
- * \param name name of vector map to open
- * \param mapset mapset name
- *
- * \return level of openness [1, 2, (3)]
- * \return -1 on error
- */
+  \brief Open existing vector map for reading
+  
+  This function is replaced by Vect_open_old2() to handle also direct
+  OGR support.
+  
+  Calls G_fatal_error() on failure.
+  
+  \param[out] Map pointer to Map_info structure
+  \param name name of vector map to open
+  \param mapset mapset name ("" for search path)
+  
+  \return 1 open on level 1 (without topology)
+  \return 2 open on level 2 (with topology)
+  \return -1 on error
+*/
 int Vect_open_old(struct Map_info *Map, const char *name, const char *mapset)
 {
-    return (Vect__open_old(Map, name, mapset, NULL, 0, 0));
+    return open_old(Map, name, mapset, NULL, 0, 0);
 }
 
 /*!
- * \brief Open existing vector map for reading (native and OGR format)
- *
- * \param[out] Map pointer to Map_info structure
- * \param name name of vector map to open
- * \param mapset mapset name
- * \param layer layer name (OGR format)
- *
- * \return level of openness [1, 2, (3)]
- * \return -1 on error
- */
-int Vect_open_old2(struct Map_info *Map, const char *name, const char *mapset, const char *layer)
+  \brief Open existing vector map for reading
+  
+  Calls G_fatal_error() on failure.
+
+  \param[out] Map pointer to Map_info structure
+  \param name name of vector map to open (datasource for direct OGR access)
+  \param mapset mapset name ("" for search path, "OGR" for direct OGR access)
+  \param layer layer name (OGR layer for direct OGR access)
+  
+  \return 1 open on level 1 (without topology)
+  \return 2 open on level 2 (with topology)
+  \return -1 on error
+*/
+int Vect_open_old2(struct Map_info *Map, const char *name, const char *mapset,
+		   const char *layer)
 {
-    return (Vect__open_old(Map, name, mapset, layer, 0, 0));
+    return open_old(Map, name, mapset, layer, 0, 0);
 }
 
 /*!
- * \brief Open existing vector map for reading/writing (native or OGR
- * format via v.external)
- *
- * This function is replaced by Vect_open_update2() to handle also
- * direct OGR support.
- *
- * By default list of updated features is not maintained, see
- * Vect_set_updated() for details.
- *
- * \param[out] Map pointer to Map_info structure
- * \param name name of vector map to update
- * \param mapset mapset name
- *
- * \return level of openness [1, 2, (3)]
- * \return -1 on error
- */
+  \brief Open existing vector map for reading/writing
+  
+  This function is replaced by Vect_open_update2() to handle also
+  direct OGR support.
+  
+  By default list of updated features is not maintained, see
+  Vect_set_updated() for details.
+  
+  Calls G_fatal_error() on failure.
+
+  \param[out] Map pointer to Map_info structure
+  \param name name of vector map to update
+  \param mapset mapset name
+  
+  \return 1 open on level 1 (without topology)
+  \return 2 open on level 2 (with topology)
+  \return -1 on error
+*/
 int Vect_open_update(struct Map_info *Map, const char *name, const char *mapset)
 {
-    return Vect__open_old(Map, name, mapset, NULL, 1, 0);
+    return open_old(Map, name, mapset, NULL, 1, 0);
 }
 
 /*!
- * \brief Open existing vector map for reading/writing (native or OGR
- * format)
- *
- * By default list of updated features is not maintained, see
- * Vect_set_updated() for details.
- *
- * \param[out] Map pointer to Map_info structure
- * \param name name of vector map to update
- * \param mapset mapset name
- * \param layer layer name (OGR format)
- *
- * \return level of openness [1, 2, (3)]
- * \return -1 on error
- */
+  \brief Open existing vector map for reading/writing
+  
+  By default list of updated features is not maintained, see
+  Vect_set_updated() for details.
+  
+  Calls G_fatal_error() on failure.
+    
+  \param[out] Map pointer to Map_info structure
+  \param name name of vector map to open (datasource for direct OGR access)
+  \param mapset mapset name ("" for search path, "OGR" for direct OGR access)
+  \param layer layer name (OGR layer for direct OGR access)
+  
+  \return 1 open on level 1 (without topology)
+  \return 2 open on level 2 (with topology)
+  \return -1 on error 
+*/
 int Vect_open_update2(struct Map_info *Map, const char *name, const char *mapset, const char *layer)
 {
-    return Vect__open_old(Map, name, mapset, layer, 1, 0);
+    return open_old(Map, name, mapset, layer, 1, 0);
 }
 
 /*! 
- * \brief Reads only info about vector map from headers of 'head',
- * 'dbln', 'topo' and 'cidx' file (native or OGR format via
- * v.external)
- *
- * This function is replaced by Vect_open_old_head2() to handle also
- * direct OGR support.
- *
- * \param[out] Map pointer to Map_info structure
- * \param name name of vector map to read (dsn for OGR)
- * \param mapset mapset name ("" for search path)
- *
- * \return level of openness [1, 2, (3)]
- * \return -1 on error
- */
+  \brief Reads only info about vector map (headers)
+
+  Reads from headers of 'head', 'dbln', 'topo' and 'cidx' file.
+  
+  This function is replaced by Vect_open_old_head2() to handle also
+  direct OGR support.
+  
+  Calls G_fatal_error() on failure.
+   
+  \param[out] Map pointer to Map_info structure
+  \param name name of vector map to read
+  \param mapset mapset name ("" for search path)
+  
+  \return 1 open on level 1 (without topology)
+  \return 2 open on level 2 (with topology)
+  \return -1 on error 
+*/
 int Vect_open_old_head(struct Map_info *Map, const char *name, const char *mapset)
 {
-    return (Vect__open_old(Map, name, mapset, NULL, 0, 1));
+    return open_old(Map, name, mapset, NULL, 0, 1);
 }
 
 /*! 
- * \brief Reads only info about vector map from headers of 'head',
- * 'dbln', 'topo' and 'cidx' file (native or OGR format)
- *
- * \param[out] Map pointer to Map_info structure
- * \param name name of vector map to read (dsn for OGR)
- * \param mapset mapset name ("" for search path)
- * \param layer layer name (OGR format)
- *
- * \return level of openness [1, 2, (3)]
- * \return -1 on error
- */
-int Vect_open_old_head2(struct Map_info *Map, const char *name, const char *mapset, const char *layer)
+  \brief Reads only info about vector map (headers)
+  
+  Reads from headers of 'head', 'dbln', 'topo' and 'cidx' file.
+  
+  Calls G_fatal_error() on failure.
+   
+  \param[out] Map pointer to Map_info structure
+  \param name name of vector map to read (dsn for OGR)
+  \param mapset mapset name ("" for search path)
+  \param layer layer name (OGR format)
+  
+  \param[out] Map pointer to Map_info structure
+  \param name name of vector map to open (datasource for direct OGR access)
+  \param mapset mapset name ("" for search path, "OGR" for direct OGR access)
+  \param layer layer name (OGR layer for direct OGR access)
+  
+  \return 1 open on level 1 (without topology)
+  \return 2 open on level 2 (with topology)
+  \return -1 on error 
+*/
+int Vect_open_old_head2(struct Map_info *Map, const char *name, const char *mapset,
+			const char *layer)
 {
-    return (Vect__open_old(Map, name, mapset, layer, 0, 1));
+    return open_old(Map, name, mapset, layer, 0, 1);
 }
 
-/*!
- * \brief Open header file of existing vector map for updating (mostly
- * for database link updates)
- *
- * \param[out] Map pointer to Map_info structure
- * \param name name of vector map to update
- * \param mapset mapset name
- *
- * \return level of openness [1, 2, (3)]
- * \return -1 on error
- */
+/*!  \brief Open header file of existing vector map for updating
+  (mostly for database link updates)
+  
+  \param[out] Map pointer to Map_info structure
+  \param name name of vector map to update
+  \param mapset mapset name
+  
+  \return 1 open on level 1 (without topology)
+  \return 2 open on level 2 (with topology)
+  \return -1 on error 
+*/
 int Vect_open_update_head(struct Map_info *Map, const char *name,
 			  const char *mapset)
 {
-    int ret;
-
-    ret = Vect__open_old(Map, name, mapset, NULL, 1, 1);
-    
-    return ret;
+    return open_old(Map, name, mapset, NULL, 1, 1);
 }
 
 /*!
- * \brief Create new vector map for reading/writing
- *
- * By default list of updated features is not maintained, see
- * Vect_set_updated() for details.
- *
- * \param[in,out] Map pointer to Map_info structure
- * \param name name of vector map
- * \param with_z non-zero value for 3D vector data
- *
- * \return 1 on success
- * \return -1 on error
- */
+  \brief Create new vector map for reading/writing
+ 
+  By default list of updated features is not maintained, see
+  Vect_set_updated() for details.
+  
+  \param[in,out] Map pointer to Map_info structure
+  \param name name of vector map
+  \param with_z non-zero value for 3D vector data
+  
+  \return 1 on success
+  \return -1 on error
+*/
 int Vect_open_new(struct Map_info *Map, const char *name, int with_z)
 {
     int ret;
@@ -731,17 +779,17 @@
 }
 
 /*!
- * \brief Update Coor_info structure
- *
- * \param Map pointer to Map_info structure
- * \param[out] Info pointer to Coor_info structure
- *
- * \return 1 on success
- * \return 0 on error
- */
+  \brief Update Coor_info structure
+  
+  \param Map pointer to Map_info structure
+  \param[out] Info pointer to Coor_info structure
+  
+  \return 1 on success
+  \return 0 on error
+*/
 int Vect_coor_info(const struct Map_info *Map, struct Coor_info *Info)
 {
-    char buf[2000], path[2000];
+    char buf[GPATH_MAX], path[GPATH_MAX];
     STRUCT_STAT stat_buf;
     
     switch (Map->format) {
@@ -756,7 +804,7 @@
 	}
 	else {
 	    Info->size = (off_t)stat_buf.st_size;      /* file size */
-	    Info->mtime = (long)stat_buf.st_mtime;      /* last modified time */
+	    Info->mtime = (long)stat_buf.st_mtime;     /* last modified time */
 	}
 	
         /* stat does not give correct size on MINGW
@@ -771,6 +819,7 @@
 	break;
     case GV_FORMAT_OGR:
     case GV_FORMAT_OGR_DIRECT:
+    case GV_FORMAT_POSTGIS:
 	Info->size = 0L;
 	Info->mtime = 0L;
 	break;
@@ -782,20 +831,21 @@
 }
 
 /*!
- * \brief Gets vector map format (as string)
- *
- * Note: string is allocated by G_store(). Free allocated memory with
- * G_free().
- *
- * Currently are implemeted:
- *  - Native format (native)
- *  - OGR format    (ogr)
- *
- * \param Map pointer to Map_info structure
- *
- * \return maptype string on success
- * \return error message on error
- */
+  \brief Gets vector map format (as string)
+  
+  Note: string is allocated by G_store(). Free allocated memory with
+  G_free().
+  
+  Currently are implemeted:
+   - Native format  (native)
+   - OGR format     (ogr)
+   - PostGIS format (postgis)
+   
+   \param Map pointer to Map_info structure
+   
+   \return maptype string on success (allocated by G_store())
+   \return error message on error
+*/
 const char *Vect_maptype_info(const struct Map_info *Map)
 {
     char maptype[1000];
@@ -806,8 +856,11 @@
 	break;
     case GV_FORMAT_OGR:
     case GV_FORMAT_OGR_DIRECT:
-	sprintf(maptype, "ogr");
+	sprintf(maptype, "OGR");
 	break;
+    case GV_FORMAT_POSTGIS:
+	sprintf(maptype, "PostGIS");
+	break;
     default:
 	sprintf(maptype, _("unknown %d (update Vect_maptype_info)"),
 		Map->format);
@@ -822,8 +875,9 @@
   Currently are implemeted:
    - Native format                    (GV_FORMAT_NATIVE)
    - OGR format linked via v.external (GV_FORMAT_OGR)
-   - OGR format                       (GV_FORMAT_DIRECT)
-
+   - OGR format                       (GV_FORMAT_OGR_DIRECT)
+   - PostGIS fomat                    (GV_FORMAT_POSTGIS)
+   
   \param Map pointer to Map_info structure
   
   \return maptype code
@@ -834,19 +888,19 @@
 }
 
 /*!
- * \brief Open topology file ('topo')
- *
- * \param[in,out] Map pointer to Map_info structure
- * \param head_only TRUE to read only header
- *
- * \return 0 on success
- * \return 1 file does not exist
- * \return -1 on error
- */
+  \brief Open topology file ('topo')
+  
+  \param[in,out] Map pointer to Map_info structure
+  \param head_only TRUE to read only header
+  
+  \return 0 on success
+  \return 1 file does not exist
+  \return -1 on error
+*/
 int Vect_open_topo(struct Map_info *Map, int head_only)
 {
     int err, ret;
-    char buf[500], file_path[2000];
+    char buf[GPATH_MAX], file_path[GPATH_MAX];
     struct gvfile fp;
     struct Coor_info CInfo;
     struct Plus_head *Plus;
@@ -917,14 +971,14 @@
 }
 
 /*!
- * \brief Open spatial index file ('sidx')
- *
- * \param[in,out] Map pointer to Map_info
- * \param mode 0 old, 1 update, 2 new
- *
- * \return 0 on success
- * \return -1 on error
- */
+  \brief Open spatial index file ('sidx')
+  
+  \param[in,out] Map pointer to Map_info
+  \param mode 0 old, 1 update, 2 new
+  
+  \return 0 on success
+  \return -1 on error
+*/
 int Vect_open_sidx(struct Map_info *Map, int mode)
 {
     char buf[500], file_path[2000];

Modified: grass/trunk/lib/vector/Vlib/open_ogr.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open_ogr.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/open_ogr.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -49,6 +49,9 @@
 {
 #ifdef HAVE_OGR
     int i, layer, nLayers;
+
+    struct Format_info_ogr *ogr_info;
+    
     OGRDataSourceH Ogr_ds;
     OGRLayerH Ogr_layer;
     OGRFeatureDefnH Ogr_featuredefn;
@@ -56,28 +59,29 @@
     
     Ogr_layer = NULL;
     Ogr_geom_type = wkbUnknown;
-    
-    if (!Map->fInfo.ogr.dsn) {
+
+    ogr_info = &(Map->fInfo.ogr);
+    if (!ogr_info->dsn) {
 	G_fatal_error(_("OGR datasource not defined"));
 	return -1;
     }
     
-    if (!Map->fInfo.ogr.layer_name) {
+    if (!ogr_info->layer_name) {
 	G_fatal_error(_("OGR layer not defined"));
 	return -1;
     }
     
-    G_debug(2, "V1_open_old_ogr(): dsn = %s layer = %s", Map->fInfo.ogr.dsn,
-	    Map->fInfo.ogr.layer_name);
+    G_debug(2, "V1_open_old_ogr(): dsn = %s layer = %s", ogr_info->dsn,
+	    ogr_info->layer_name);
 
     OGRRegisterAll();
 
     /* open data source handle */
-    Ogr_ds = OGROpen(Map->fInfo.ogr.dsn, FALSE, NULL);
+    Ogr_ds = OGROpen(ogr_info->dsn, FALSE, NULL);
     if (Ogr_ds == NULL)
 	G_fatal_error(_("Unable to open OGR data source '%s'"),
-		      Map->fInfo.ogr.dsn);
-    Map->fInfo.ogr.ds = Ogr_ds;
+		      ogr_info->dsn);
+    ogr_info->ds = Ogr_ds;
 
     /* get layer number */
     layer = -1;
@@ -87,7 +91,7 @@
     for (i = 0; i < nLayers; i++) {
 	Ogr_layer = OGR_DS_GetLayer(Ogr_ds, i);
 	Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer);
-	if (strcmp(OGR_FD_GetName(Ogr_featuredefn), Map->fInfo.ogr.layer_name) == 0) {
+	if (strcmp(OGR_FD_GetName(Ogr_featuredefn), ogr_info->layer_name) == 0) {
 	    Ogr_geom_type = OGR_FD_GetGeomType(Ogr_featuredefn);
 	    layer = i;
 	    break;
@@ -96,20 +100,14 @@
     if (layer == -1) {
 	OGR_DS_Destroy(Ogr_ds);
 	G_fatal_error(_("OGR layer <%s> not found"),
-		      Map->fInfo.ogr.layer_name);
+		      ogr_info->layer_name);
     }
     G_debug(2, "OGR layer %d opened", layer);
 
-    Map->fInfo.ogr.layer = Ogr_layer;
-    if (update && OGR_L_TestCapability(Map->fInfo.ogr.layer, OLCTransactions))
-	OGR_L_StartTransaction(Map->fInfo.ogr.layer);
+    ogr_info->layer = Ogr_layer;
+    if (update && OGR_L_TestCapability(ogr_info->layer, OLCTransactions))
+	OGR_L_StartTransaction(ogr_info->layer);
     
-    Map->fInfo.ogr.lines = NULL;
-    Map->fInfo.ogr.lines_types = NULL;
-    Map->fInfo.ogr.lines_alloc = 0;
-    Map->fInfo.ogr.lines_num = 0;
-    Map->fInfo.ogr.lines_next = 0;
-    
     switch(Ogr_geom_type) {
     case wkbPoint25D: case wkbLineString25D: case wkbPolygon25D:
     case wkbMultiPoint25D: case wkbMultiLineString25D: case wkbMultiPolygon25D:
@@ -121,8 +119,7 @@
 	break;
     }
     
-    Map->fInfo.ogr.feature_cache = NULL;
-    Map->fInfo.ogr.feature_cache_id = -1;	/* FID >= 0 */
+    ogr_info->feature_cache_id = -1;	/* FID >= 0 */
     
     return 0;
 #else
@@ -142,75 +139,16 @@
 int V2_open_old_ogr(struct Map_info *Map)
 {
 #ifdef HAVE_OGR
-    char elem[GPATH_MAX];
-    char buf[5];		/* used for format version */
-    long length;
-    struct gvfile fp;
-    struct Port_info port;
-    int Version_Major, Version_Minor, Back_Major, Back_Minor, byte_order;
 
-    G_debug(3, "V2_open_old_ogr()");
-    
-    sprintf(elem, "%s/%s", GV_DIRECTORY, Map->name);
-    dig_file_init(&fp);
-    fp.file = G_fopen_old(elem, GV_FIDX_ELEMENT, Map->mapset);
-    if (fp.file == NULL) {
-	G_warning(_("Unable to open fidx file for vector map <%s@%s>"),
-		  Map->name, Map->mapset);
-	return -1;
+    G_debug(3, "V2_open_old_ogr(): name = %s mapset = %s", Map->name,
+	    Map->mapset);
+
+    if (Vect_open_fidx(Map, &(Map->fInfo.ogr.offset)) != 0) {
+	G_warning(_("Unable to open feature index file for vector map <%s>"),
+		  Vect_get_full_name(Map));
+	G_zero(&(Map->fInfo.ogr.offset), sizeof(struct Format_info_offset));
     }
-
-    /* Header */
-    if (0 >= dig__fread_port_C(buf, 5, &fp))
-	return (-1);
-    Version_Major = buf[0];
-    Version_Minor = buf[1];
-    Back_Major = buf[2];
-    Back_Minor = buf[3];
-    byte_order = buf[4];
     
-    /* check version numbers */
-    if (Version_Major > 5 || Version_Minor > 0) {
-	if (Back_Major > 5 || Back_Minor > 0) {
-	    G_fatal_error(_("Feature index format version %d.%d is not supported by this release."
-			   " Try to rebuild topology or upgrade GRASS."),
-			  Version_Major, Version_Minor);
-	    return (-1);
-	}
-	G_warning(_("Your GRASS version does not fully support feature index format %d.%d of the vector."
-		   " Consider to rebuild topology or upgrade GRASS."),
-		  Version_Major, Version_Minor);
-    }
-
-    dig_init_portable(&port, byte_order);
-    dig_set_cur_port(&port);
-
-    /* Body */
-    /* bytes 6 - 9 : header size */
-    if (0 >= dig__fread_port_L(&length, 1, &fp))
-	return (-1);
-    G_debug(3, "  header size %ld", length);
-
-    G_fseek(fp.file, length, SEEK_SET);
-
-    /* number of records  */
-    if (0 >= dig__fread_port_I(&(Map->fInfo.ogr.offset_num), 1, &fp))
-	return (-1);
-
-    /* alloc space */
-    Map->fInfo.ogr.offset =
-	(int *)G_malloc(Map->fInfo.ogr.offset_num * sizeof(int));
-    Map->fInfo.ogr.offset_alloc = Map->fInfo.ogr.offset_num;
-
-    /* offsets */
-    if (0 >= dig__fread_port_I(Map->fInfo.ogr.offset,
-			       Map->fInfo.ogr.offset_num, &fp))
-	return (-1);
-
-    fclose(fp.file);
-
-    G_debug(3, "%d records read from fidx", Map->fInfo.ogr.offset_num);
-
     Map->fInfo.ogr.next_line = 1;
 
     return 0;
@@ -235,31 +173,35 @@
 int V1_open_new_ogr(struct Map_info *Map, const char *name, int with_z)
 {
 #ifdef HAVE_OGR
+    int            i, nlayers;
+
+    struct Format_info_ogr *ogr_info;
+    
     OGRSFDriverH    Ogr_driver;
     OGRDataSourceH  Ogr_ds;
     OGRLayerH       Ogr_layer;
     OGRFeatureDefnH Ogr_featuredefn;
     
-    int            i, nlayers;
-     
     OGRRegisterAll();
     
+    ogr_info = &(Map->fInfo.ogr);
+    
     G_debug(1, "V1_open_new_ogr(): name = %s with_z = %d", name, with_z);
-    Ogr_driver = OGRGetDriverByName(Map->fInfo.ogr.driver_name);
+    Ogr_driver = OGRGetDriverByName(ogr_info->driver_name);
     if (!Ogr_driver) {
-	G_warning(_("Unable to get OGR driver <%s>"), Map->fInfo.ogr.driver_name);
+	G_warning(_("Unable to get OGR driver <%s>"), ogr_info->driver_name);
 	return -1;
     }
-    Map->fInfo.ogr.driver = Ogr_driver;
+    ogr_info->driver = Ogr_driver;
     
     /* TODO: creation options */
-    Ogr_ds = OGR_Dr_CreateDataSource(Ogr_driver, Map->fInfo.ogr.dsn, NULL);
+    Ogr_ds = OGR_Dr_CreateDataSource(Ogr_driver, ogr_info->dsn, NULL);
     if (!Ogr_ds) {
 	G_warning(_("Unable to create OGR data source '%s'"),
-		  Map->fInfo.ogr.dsn);
+		  ogr_info->dsn);
 	return -1;
     }
-    Map->fInfo.ogr.ds = Ogr_ds;
+    ogr_info->ds = Ogr_ds;
 
     nlayers = OGR_DS_GetLayerCount(Ogr_ds);
     for (i = 0; i < nlayers; i++) {
@@ -268,19 +210,19 @@
 	if (strcmp(OGR_FD_GetName(Ogr_featuredefn), name) == 0) {	
 	    if (G_get_overwrite()) {
 		G_warning(_("OGR layer <%s> already exists and will be overwritten"),
-			  Map->fInfo.ogr.layer_name);
+			  ogr_info->layer_name);
 		
 		if (OGR_DS_DeleteLayer(Ogr_ds, i) != OGRERR_NONE) {
 		    G_warning(_("Unable to delete OGR layer <%s>"),
-			      Map->fInfo.ogr.layer_name);
+			      ogr_info->layer_name);
 		    return -1;
 		}
 	    }
 	    else {
 		G_fatal_error(_("OGR layer <%s> already exists in datasource '%s'"),
-			      Map->fInfo.ogr.layer_name, Map->fInfo.ogr.dsn);
+			      ogr_info->layer_name, ogr_info->dsn);
 	    }
-	    Map->fInfo.ogr.layer = NULL;
+	    ogr_info->layer = NULL;
 	    break;
 	}
     }
@@ -316,13 +258,16 @@
     
     struct field_info *Fi;
     struct Key_Value *projinfo, *projunits;
+    struct Format_info_ogr *ogr_info;
     
     OGRwkbGeometryType Ogr_geom_type;
     char             **Ogr_layer_options;
     
-    if (!Map->fInfo.ogr.driver_name ||
-	!Map->fInfo.ogr.layer_name ||
-	!Map->fInfo.ogr.ds)
+    ogr_info = &(Map->fInfo.ogr);
+    
+    if (!ogr_info->driver_name ||
+	!ogr_info->layer_name ||
+	!ogr_info->ds)
 	return -1;
     
     /* get spatial reference */
@@ -347,26 +292,26 @@
 	return -1;
     }
     
-    Ogr_layer_options = Map->fInfo.ogr.layer_options;
+    Ogr_layer_options = ogr_info->layer_options;
     if (Vect_is_3d(Map)) {
-	if (strcmp(Map->fInfo.ogr.driver_name, "PostgreSQL") == 0) {
+	if (strcmp(ogr_info->driver_name, "PostgreSQL") == 0) {
 	    Ogr_layer_options = CSLSetNameValue(Ogr_layer_options, "DIM", "3");
 	}
     }
     else {
-	if (strcmp(Map->fInfo.ogr.driver_name, "PostgreSQL") == 0) {
+	if (strcmp(ogr_info->driver_name, "PostgreSQL") == 0) {
 	    Ogr_layer_options = CSLSetNameValue(Ogr_layer_options, "DIM", "2");
 	}
     }
-    Ogr_layer = OGR_DS_CreateLayer(Map->fInfo.ogr.ds, Map->fInfo.ogr.layer_name,
+    Ogr_layer = OGR_DS_CreateLayer(ogr_info->ds, ogr_info->layer_name,
 				   Ogr_spatial_ref, Ogr_geom_type, Ogr_layer_options);
     CSLDestroy(Ogr_layer_options);
     if (!Ogr_layer) {
 	G_warning(_("Unable to create OGR layer <%s> in '%s'"),
-		  Map->fInfo.ogr.layer_name, Map->fInfo.ogr.dsn);
+		  ogr_info->layer_name, ogr_info->dsn);
 	return -1;
     }
-    Map->fInfo.ogr.layer = Ogr_layer;
+    ogr_info->layer = Ogr_layer;
 
     ndblinks = Vect_get_num_dblinks(Map);
     if (ndblinks > 0) {
@@ -376,7 +321,7 @@
 	    if (ndblinks > 1)
 		G_warning(_("More layers defined, using driver <%s> and "
 			    "database <%s>"), Fi->driver, Fi->database);
-	    Map->fInfo.ogr.dbdriver = create_table(Map->fInfo.ogr.layer, Fi);
+	    ogr_info->dbdriver = create_table(ogr_info->layer, Fi);
 	    G_free(Fi);
 	}
 	else
@@ -384,8 +329,8 @@
 		    "Unable to write attributes."));
     }
     
-    if (OGR_L_TestCapability(Map->fInfo.ogr.layer, OLCTransactions))
-	OGR_L_StartTransaction(Map->fInfo.ogr.layer);
+    if (OGR_L_TestCapability(ogr_info->layer, OLCTransactions))
+	OGR_L_StartTransaction(ogr_info->layer);
 
     return 0;
 #else
@@ -394,6 +339,90 @@
 #endif
 }
 
+/*!
+  \brief Open feature index file for vector map
+  
+  \param[in,out] Map pointer to Map_info struct
+  \param[out] offset pointer to Format_info_offset (OGR or PG)
+  
+  \return 0 on success
+  \return -1 on error
+*/
+int Vect_open_fidx(struct Map_info *Map, struct Format_info_offset *offset)
+{
+    char elem[GPATH_MAX];
+    char buf[5];		/* used for format version */
+    long length;
+    int Version_Major, Version_Minor, Back_Major, Back_Minor, byte_order;
+    
+    struct gvfile fp;
+    struct Port_info port;
+    
+    G_debug(1, "Vect_open_fidx(): name = %s mapset = %s format = %d",
+	    Map->name, Map->mapset, Map->format);
+    
+    sprintf(elem, "%s/%s", GV_DIRECTORY, Map->name);
+    dig_file_init(&fp);
+    fp.file = G_fopen_old(elem, GV_FIDX_ELEMENT, Map->mapset);
+    if (fp.file == NULL) {
+	G_warning(_("Unable to open fidx file for vector map <%s>"),
+		  Vect_get_full_name(Map));
+	return -1;
+    }
+
+    /* Header */
+    if (0 >= dig__fread_port_C(buf, 5, &fp))
+	return -1;
+    Version_Major = buf[0];
+    Version_Minor = buf[1];
+    Back_Major    = buf[2];
+    Back_Minor    = buf[3];
+    byte_order    = buf[4];
+    
+    /* check version numbers */
+    if (Version_Major > 5 || Version_Minor > 0) {
+	if (Back_Major > 5 || Back_Minor > 0) {
+	    G_fatal_error(_("Feature index format version %d.%d is not supported by this release."
+			   " Try to rebuild topology or upgrade GRASS."),
+			  Version_Major, Version_Minor);
+	    return -1;
+	}
+	G_warning(_("Your GRASS version does not fully support feature index format %d.%d of the vector."
+		   " Consider to rebuild topology or upgrade GRASS."),
+		  Version_Major, Version_Minor);
+    }
+
+    dig_init_portable(&port, byte_order);
+    dig_set_cur_port(&port);
+
+    /* Body */
+    /* bytes 6 - 9 : header size */
+    if (0 >= dig__fread_port_L(&length, 1, &fp))
+	return -1;
+    G_debug(4, "  header size %ld", length);
+
+    G_fseek(fp.file, length, SEEK_SET);
+
+    /* number of records  */
+    if (0 >= dig__fread_port_I(&(offset->array_num), 1, &fp))
+	return -1;
+    
+    /* alloc space */
+    offset->array = (int *) G_malloc(offset->array_num * sizeof(int));
+    offset->array_alloc = offset->array_num;
+    
+    /* offsets */
+    if (0 >= dig__fread_port_I(offset->array,
+			       offset->array_num, &fp))
+	return -1;
+
+    fclose(fp.file);
+
+    G_debug(3, "%d records read from fidx", offset->array_num);
+
+    return 0;
+}
+
 #ifdef HAVE_OGR
 dbDriver *create_table(OGRLayerH hLayer, const struct field_info *Fi)
 {

Added: grass/trunk/lib/vector/Vlib/open_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/open_pg.c	                        (rev 0)
+++ grass/trunk/lib/vector/Vlib/open_pg.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -0,0 +1,208 @@
+/*!
+   \file lib/vector/Vlib/open_pg.c
+
+   \brief Vector library - Open PostGIS layer as vector map layer
+
+   Higher level functions for reading/writing/manipulating vectors.
+
+   (C) 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 Martin Landa <landa.martin gmail.com>
+ */
+
+#include <string.h>
+
+#include <grass/vector.h>
+#include <grass/dbmi.h>
+#include <grass/glocale.h>
+
+#ifdef HAVE_POSTGRES
+#include "pg_local_proto.h"
+
+static char *get_key_column(struct Format_info_pg *pg_info)
+{
+    char *key_column;
+    char stmt[DB_SQL_MAX];
+    
+    PGresult *res;
+    
+    sprintf(stmt,
+	    "SELECT kcu.column_name "
+	    "FROM    INFORMATION_SCHEMA.TABLES t "
+	    "LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc "
+	    "ON tc.table_catalog = t.table_catalog "
+	    "AND tc.table_schema = t.table_schema "
+	    "AND tc.table_name = t.table_name "
+	    "AND tc.constraint_type = 'PRIMARY KEY' "
+	    "LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu "
+	    "ON kcu.table_catalog = tc.table_catalog "
+	    "AND kcu.table_schema = tc.table_schema "
+	    "AND kcu.table_name = tc.table_name "
+	    "AND kcu.constraint_name = tc.constraint_name "
+	    "WHERE t.table_name = '%s'", pg_info->table_name);
+
+    res = PQexec(pg_info->conn, stmt);
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK ||
+	PQntuples(res) != 1) {
+	G_warning(_("No key column detected."));
+	if (res)
+	    PQclear(res);
+	return NULL;
+    }
+    key_column = G_store(PQgetvalue(res, 0, 0));
+    
+    PQclear(res);
+
+    return key_column;
+}
+#endif
+
+/*!
+   \brief Open existing PostGIS feature table (level 1 - without topology)
+   
+   \todo Check database instead of geometry_columns
+   
+   \param[in,out] Map pointer to Map_info structure
+   \param update TRUE for write mode, otherwise read-only
+   
+   \return 0 success
+   \return -1 error
+*/
+int V1_open_old_pg(struct Map_info *Map, int update)
+{
+#ifdef HAVE_POSTGRES
+    int found, ntables, i;
+    
+    dbString stmt;
+    
+    PGresult *res;
+    
+    struct Format_info_pg *pg_info;
+    
+    db_init_string(&stmt);
+    
+    pg_info = &(Map->fInfo.pg);
+    if (!pg_info->conninfo) {
+	G_warning(_("Connection string not defined"));
+	return -1;
+    }
+    
+    if (!pg_info->table_name) {
+	G_warning(_("PostGIS feature table not defined"));
+	return -1;
+    }
+
+    G_debug(1, "V1_open_old_pg(): conninfo='%s' table='%s'", 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));
+
+    /* get DB name */
+    pg_info->db_name = G_store(PQdb(pg_info->conn));
+    if (!pg_info->db_name) {
+	G_warning(_("Unable to get database name"));
+	return -1;
+    }
+    
+    /* get fid and geometry column */
+    db_set_string(&stmt, "SELECT f_table_name, f_geometry_column "
+		  "FROM geometry_columns");
+    G_debug(2, "SQL: %s", db_get_string(&stmt));
+    
+    res = PQexec(pg_info->conn, db_get_string(&stmt));
+    if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
+	G_fatal_error("%s\n%s", _("No feature tables found in database."),
+		      PQresultErrorMessage(res));
+		      
+    ntables = PQntuples(res);
+    G_debug(3, "\tnrows = %d", ntables);
+    found = FALSE;
+    for (i = 0; i < ntables; i++) {
+	if (strcmp(PQgetvalue(res, i, 0), pg_info->table_name) == 0) {
+	    pg_info->geom_column = G_store(PQgetvalue(res, i, 1));
+	    G_debug(3, "\t-> table = %s column = %s", pg_info->table_name,
+		    pg_info->geom_column);
+	    pg_info->fid_column = get_key_column(pg_info);
+	    found = TRUE;
+	    break;
+	}
+    }
+
+    /* no feature in cache */
+    pg_info->cache.fid = -1;
+    
+    PQclear(res);
+    
+    db_free_string(&stmt);
+
+    if (!found) {
+	G_warning(_("Feature table <%s> not found in 'geometry_columns'"));
+	return -1;
+    }
+    
+    return 0;
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+    return -1;
+#endif
+}
+
+/*!
+   \brief Open existing PostGIS layer (level 2 - feature index)
+
+   \param[in,out] Map pointer to Map_info structure
+   
+   \return 0 success
+   \return -1 error
+*/
+int V2_open_old_pg(struct Map_info *Map)
+{
+#ifdef HAVE_POSTGRES
+
+    G_debug(3, "V2_open_old_pg(): name = %s mapset = %s", Map->name,
+	    Map->mapset);
+
+    if (Vect_open_fidx(Map, &(Map->fInfo.pg.offset)) != 0) {
+	G_warning(_("Unable to open feature index file for vector map <%s>"),
+		  Vect_get_full_name(Map));
+	G_zero(&(Map->fInfo.pg.offset), sizeof(struct Format_info_offset));
+    }
+    
+    return 0;
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+    return -1;
+#endif
+}
+
+/*!
+   \brief Prepare PostGIS database for creating new feature table
+   (level 1)
+
+   \todo To implement
+   
+   \param[out] Map pointer to Map_info structure
+   \param name name of PostGIS feature table to create
+   \param with_z WITH_Z for 3D vector data otherwise WITHOUT_Z
+
+   \return 0 success
+   \return -1 error 
+*/
+int V1_open_new_pg(struct Map_info *Map, const char *name, int with_z)
+{
+    G_debug(1, "V1_open_new_pg(): name = %s with_z = %d", name, with_z);
+#ifdef HAVE_POSTGRES
+    return 0;
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+    return -1;
+#endif
+}


Property changes on: grass/trunk/lib/vector/Vlib/open_pg.c
___________________________________________________________________
Added: svn:mime-type
   + text/x-csrc
Added: svn:eol-style
   + native

Added: grass/trunk/lib/vector/Vlib/pg_local_proto.h
===================================================================
--- grass/trunk/lib/vector/Vlib/pg_local_proto.h	                        (rev 0)
+++ grass/trunk/lib/vector/Vlib/pg_local_proto.h	2012-02-05 17:19:12 UTC (rev 50670)
@@ -0,0 +1,14 @@
+#ifndef __PG_LOCAL_PROTO_H__
+#define __PG_LOCAL_PROTO_H__
+
+#ifdef HAVE_POSTGRES
+#include <libpq-fe.h>
+
+/* functions used in *_pg.c files */
+int execute(PGconn *, const char *);
+int cache_feature(const char *, int,
+		  struct Format_info_pg *);
+
+#endif /* HAVE_POSTGRES */
+
+#endif /* __PG_LOCAL_PROTO_H__ */


Property changes on: grass/trunk/lib/vector/Vlib/pg_local_proto.h
___________________________________________________________________
Added: svn:mime-type
   + text/x-chdr
Added: svn:eol-style
   + native

Modified: grass/trunk/lib/vector/Vlib/read.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/read.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -1,29 +1,30 @@
 /*!
    \file lib/vector/Vlib/read.c
 
-   \brief Vector library - read vector features
+   \brief Vector library - read features
 
    Higher level functions for reading/writing/manipulating vectors.
 
    (C) 2001-2009, 2011 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.
+   (>=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 Update to GRASS 7 Martin Landa <landa.martin gmail.com>
  */
 
 #include <sys/types.h>
 #include <grass/vector.h>
 #include <grass/glocale.h>
 
-static int read_next_dummy()
+static int read_dummy()
 {
     return -1;
 }
 
-#ifndef HAVE_OGR
+#if !defined HAVE_OGR || !defined HAVE_POSTGRES
 static int format()
 {
     G_fatal_error(_("Requested format is not compiled in this version"));
@@ -33,29 +34,41 @@
 
 static int (*Read_next_line_array[][3]) () = {
     {
-    read_next_dummy, V1_read_next_line_nat, V2_read_next_line_nat}
+	read_dummy, V1_read_next_line_nat, V2_read_next_line_nat}
 #ifdef HAVE_OGR
     , {
-    read_next_dummy, V1_read_next_line_ogr, V2_read_next_line_ogr}
+	read_dummy, V1_read_next_line_ogr, V2_read_next_line_ogr}
     , {
-    read_next_dummy, V1_read_next_line_ogr, V2_read_next_line_ogr}
+	read_dummy, V1_read_next_line_ogr, V2_read_next_line_ogr}
 #else
     , {
-    read_next_dummy, format, format}
+	read_dummy, format, format}
     , {
-    read_next_dummy, format, format}
+	read_dummy, format, format}
 #endif
+#ifdef HAVE_POSTGRES
+    , {
+	read_dummy, V1_read_next_line_pg, V2_read_next_line_pg}
+#else
+    , {
+	read_dummy, format, format}
+#endif
 };
 
-static int (*V2_read_line_array[]) () = {
+static int (*Read_line_array[]) () = {
     V2_read_line_nat
 #ifdef HAVE_OGR
-	, V2_read_line_ogr
-	, V2_read_line_ogr
+    , V2_read_line_ogr
+    , V2_read_line_ogr
 #else
-	, format
-	, format
+    , format
+    , format
 #endif
+#ifdef HAVE_POSTGRES
+    , V2_read_line_pg
+#else
+    , format
+#endif
 };
 
 
@@ -74,76 +87,101 @@
     G_debug(3, "Vect_get_next_line()");
 
     if (!VECT_OPEN(Map))
-	return -1;
+	G_fatal_error(_("Vector map is not open for reading"));
     
     return Map->next_line - 1;
 }
 
 /*!
-   \brief Read next vector feature (level 1 and 2)
+   \brief Read next vector feature
 
-   This function implements sequential access.
+   This function implements sequential access, constraints are
+   reflected, see Vect_set_constraint_region(),
+   Vect_set_constraint_type(), or Vect_set_constraint_field().
      
-   \param Map pointer vector map
+   Use Vect_rewind() to reset reading.
+
+   G_fatal_error() is called on failure.
+   
+   \param Map pointer Map_info struct
    \param[out] line_p feature geometry
+   (pointer to line_pnts struct)
    \param[out] line_c feature categories
+   (pointer to line_cats struct)
 
-   \return feature type,
-   \return -1 out of memory
-   \return -2 EOF   
+   \return feature type (GV_POINT, GV_LINE, ...)
+   \return -1 on error
+   \return -2 nothing to read
  */
 int Vect_read_next_line(const struct Map_info *Map,
 			struct line_pnts *line_p, struct line_cats *line_c)
 {
+    int ret;
+    
+    G_debug(3, "Vect_read_next_line(): next_line = %d", Map->next_line);
 
-    G_debug(3, "Vect_read_next_line()");
-
     if (!VECT_OPEN(Map))
-	return -1;
-
-    return (*Read_next_line_array[Map->format][Map->level]) (Map, line_p,
-							     line_c);
+	G_fatal_error(_("Vector map is not open for reading"));
+    
+    ret = (*Read_next_line_array[Map->format][Map->level]) (Map, line_p,
+							    line_c);
+    if (ret == -1)
+	G_fatal_error(_("Unable to read vector map <%s>"),
+		      Vect_get_full_name(Map));
+    
+    return ret;
 }
 
 /*!
-   \brief Read vector feature  (level 2 only)
+   \brief Read vector feature
 
-   This function implements random access.
+   This function implements random access. Note that constraits are
+   ignored!
 
+   G_fatal_error() is called on failure.
+   
    \param Map pointer to vector map
    \param[out] line_p feature geometry
+   (pointer to line_pnts struct)
    \param[out] line_c feature categories
-   \param line feature id 
+   (pointer to line_cats struct)
+   \param line feature id (starts at 1)
    
    \return feature type
-   \return -1 out of memory,
-   \return -2 EOF   
+   \return -1 on failure
+   \return -2 nothing to read   
  */
 int Vect_read_line(const struct Map_info *Map,
 		   struct line_pnts *line_p, struct line_cats *line_c, int line)
 {
+    int ret;
+    
+    G_debug(3, "Vect_read_line(): line = %d", line);
 
-    G_debug(3, "Vect_read_line() line = %d", line);
-
     if (!VECT_OPEN(Map))
-	G_fatal_error("Vect_read_line(): %s", _("vector map is not opened"));
+	G_fatal_error(_("Vector map is not open for reading"));
 
     if (line < 1 || line > Map->plus.n_lines)
-	G_fatal_error(_("Vect_read_line(): feature id %d is not reasonable "
+	G_fatal_error(_("Requested feature id %d is not reasonable"
 			"(max features in vector map <%s>: %d)"),
 		      line, Vect_get_full_name(Map), Map->plus.n_lines);
 
-    return (*V2_read_line_array[Map->format]) (Map, line_p, line_c, line);
+    ret = (*Read_line_array[Map->format]) (Map, line_p, line_c, line);
+    if (ret == -1)
+	G_fatal_error(_("Unable to read feature %d vector map <%s>"),
+		      line, Vect_get_full_name(Map));
+    
+    return ret;
 }
 
 /*!
-   \brief Check if feature is alive or dead
-
-   \param Map pointer to vector map
-   \param line feature id
-
-   \return 1 if feature alive
-   \return 0 if feature is dead
+  \brief Check if feature is alive or dead (level 2 required)
+  
+  \param Map pointer to Map_info structure
+  \param line feature id
+  
+  \return 1 feature alive
+  \return 0 feature is dead
  */
 int Vect_line_alive(const struct Map_info *Map, int line)
 {
@@ -154,13 +192,13 @@
 }
 
 /*!
-   \brief Check if node is alive or dead
-
-   \param Map pointer to vector map
-   \param node node id
-
-   \return 1 if node alive
-   \return 0 if node is dead
+  \brief Check if node is alive or dead (level 2 required)
+  
+  \param Map pointer to Map_info structure
+  \param node node id
+  
+  \return 1 node alive
+  \return 0 node is dead
  */
 int Vect_node_alive(const struct Map_info *Map, int node)
 {
@@ -171,14 +209,14 @@
 }
 
 /*!
-   \brief Check if area is alive or dead
-
-   \param Map pointer to vector map
-   \param area area id
-
-   \return 1 if area alive
-   \return 0 if area is dead
- */
+  \brief Check if area is alive or dead (level 2 required)
+  
+  \param Map pointer to Map_info structure
+  \param area area id
+  
+  \return 1 area alive
+  \return 0 area is dead
+*/
 int Vect_area_alive(const struct Map_info *Map, int area)
 {
     if (Map->plus.Area[area] != NULL)
@@ -188,14 +226,14 @@
 }
 
 /*!
-   \brief Check if isle is alive or dead
+  \brief Check if isle is alive or dead (level 2 required)
 
-   \param Map pointer to vector map
-   \param isle isle id
-
-   \return 1 if isle alive
-   \return 0 if isle is dead
- */
+  \param Map pointer to Map_info structure
+  \param isle isle id
+  
+  \return 1 isle alive
+  \return 0 isle is dead
+*/
 int Vect_isle_alive(const struct Map_info *Map, int isle)
 {
     if (Map->plus.Isle[isle] != NULL)
@@ -206,10 +244,10 @@
 
 /*!
   \brief Get feature offset
-
-  Can be used for Vect_restore_line().
-
-  \param Map pointer to vector map
+  
+  Used for Vect_restore_line().
+  
+  \param Map pointer to Map_info structure
   \param line feature id
 
   \return feature offset

Modified: grass/trunk/lib/vector/Vlib/read_nat.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_nat.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/read_nat.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -1,22 +1,18 @@
 /*!
    \file lib/vector/Vlib/read_nat.c
 
-   \brief Vector library - reading data (native format)
+   \brief Vector library - reading features (native format)
 
    Higher level functions for reading/writing/manipulating vectors.
 
-   The action of this routine can be modified by:
-   - Vect_read_constraint_region()
-   - Vect_read_constraint_type()
-   - Vect_remove_constraints()
+   (C) 2001-2009, 2011-2012 by the GRASS Development Team
 
-   (C) 2001-2009, 2011 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.
+   (>=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 Update to GRASS 5.7 by Radim Blazek and David D. Gray.
+   \author Update to GRASS 7 by Martin Landa <landa.martin gmail.com>
  */
 
 #include <sys/types.h>
@@ -26,20 +22,23 @@
 static int read_line_nat(struct Map_info *,
 			 struct line_pnts *, struct line_cats *, off_t);
 
-/*!
-  \brief Read line from coor file on given offset (level 1)
+/*! \brief Read vector feature on non-topological level (level 1) -
+  native format - internal use only
+
+  This function implements random access for native format,
+  constraints are ignored!
   
-  This function implements random access on level 1.
-
-  \param Map vector map 
+  \param Map pointer to Map_info struct 
   \param[out] Points container used to store line points within
+  (pointer to line_pnts struct)
   \param[out] Cats container used to store line categories within
+  (pointer to line_cats struct)
   \param offset given offset 
   
-  \return line type
+  \return feature type (GV_POINT, GV_LINE, ...)
   \return 0 dead line
-  \return -2 end of table (last row)
-  \return -1 out of memory
+  \return -2 nothing to read
+  \return -1 on failure
 */
 int V1_read_line_nat(struct Map_info *Map,
 		     struct line_pnts *Points,
@@ -48,19 +47,27 @@
     return read_line_nat(Map, Points, Cats, offset);
 }
 
-/*!
-  \brief Read next line from coor file.
+/*! \brief Read next vector feature on non-topological level (level
+  1) - native format - internal use only.
+
+  This function implements sequential access, constraints are
+  reflected, see Vect_set_constraint_region(),
+  Vect_set_constraint_type(), or Vect_set_constraint_field().
   
-  This function implements sequential access on level 1.
-    
-  \param Map vector map layer
+  Dead features are skipped.
+  
+  Vect_rewind() can be used to reset reading.
+   
+  \param Map pointer to Map_info struct
   \param[out] line_p container used to store line points within
+  (pointer to line_pnts struct)
   \param[out] line_c container used to store line categories within
+  (pointer to line_cats struct)
   
-  \return line type
+  \return feature type (GV_POINT, GV_LINE, ...)
   \return 0 dead line
-  \return -2 end of table (last row)
-  \return -1 out of memory
+  \return -2 nothing to read
+  \return -1 on failure
 */
 int V1_read_next_line_nat(struct Map_info *Map,
 			  struct line_pnts *line_p, struct line_cats *line_c)
@@ -74,50 +81,57 @@
     if (Map->constraint.region_flag)
 	Vect_get_constraint_box(Map, &mbox);
 
-    while (1) {
+    while (TRUE) {
 	offset = dig_ftell(&(Map->dig_fp));
 	itype = read_line_nat(Map, line_p, line_c, offset);
 	if (itype < 0)
-	    return (itype);
+	    return itype; /* nothing to read or failure */
 
-	if (itype == 0)		/* is it DEAD? */
+	if (itype == 0)	  /* skip dead line */
 	    continue;
 
-	/* Constraint on Type of line 
-	 * Default is all of  Point, Line, Area and whatever else comes along
-	 */
 	if (Map->constraint.type_flag) {
+	    /* skip feature by type */
 	    if (!(itype & Map->constraint.type))
 		continue;
 	}
 
-	/* Constraint on specified region */
-	if (Map->constraint.region_flag) {
+	if (line_p && Map->constraint.region_flag) {
+	    /* skip feature by region */
 	    Vect_line_box(line_p, &lbox);
-
+	    
 	    if (!Vect_box_overlap(&lbox, &mbox))
 		continue;
 	}
+	
+	if (line_c && Map->constraint.field_flag) {
+	    /* skip feature by field */
+	    if (Vect_cat_get(line_c, Map->constraint.field, NULL) == 0)
+		continue;
+	}
 
-	return (itype);
+	return itype;
     }
-    /* NOTREACHED */
+
+    return -1; /* NOTREACHED */
 }
 
-/*!
-  \brief Reads any specified line, this is NOT affected by constraints
- 
-  This function implements random access on level 2.
- 
-  \param Map vector map layer
-  \param[out] line_p container used to store line points within
-  \param[out] line_c container used to store line categories within
-  \param line line id
+/*! \brief Read vector feature on topological level (level 2) -
+  native format - internal use only
+
+  This function implements random access for native format,
+  constraints are ignored!
   
-  \return line type ( > 0 )
-  \return 0 dead line
-  \return -1 out of memory
-  \return -2 end of file
+  \param Map pointer to Map_info struct 
+  \param[out] Points container used to store line points within
+  (pointer to line_pnts struct)
+  \param[out] Cats container used to store line categories within
+  (pointer to line_cats struct)
+  \param line feature id to read (starts at 1)
+  
+  \return feature type (GV_POINT, GV_LINE, ...)
+  \return -2 nothing to read
+  \return -1 on failure
 */
 int V2_read_line_nat(struct Map_info *Map,
 		     struct line_pnts *line_p, struct line_cats *line_c, int line)
@@ -129,31 +143,39 @@
 
     Line = Map->plus.Line[line];
 
-    if (Line == NULL)
-	G_fatal_error("V2_read_line_nat(): %s %d",
-		      _("Attempt to read dead line"), line);
+    if (Line == NULL) {
+	G_warning(_("Attempt to read dead feature %d"), line);
+	return -1;
+    }
 
     return read_line_nat(Map, line_p, line_c, Line->offset);
 }
 
-/*!
-  \brief Reads next unread line each time called.  Use Vect_rewind to reset.
+/*! \brief Read next vector feature on topological level (level 2) -
+  native format - internal use only.
+
+  This function implements sequential access, constraints are
+  reflected, see Vect_set_constraint_region(),
+  Vect_set_constraint_type(), or Vect_set_constraint_field().
   
-  This function implements sequential access on level 2.
+  Use Vect_rewind() to reset reading.
 
-  \param Map vector map layer
+  Dead feature are skipped.
+   
+  \param Map pointer to Map_info struct
   \param[out] line_p container used to store line points within
+  (pointer to line_pnts struct)
   \param[out] line_c container used to store line categories within
+  (pointer to line_cats struct)
   
-  \return line type ( > 0 )
-  \return 0 dead line
-  \return -1 out of memory
-  \return -2 end of file
+  \return feature type (GV_POINT, GV_LINE, ...)
+  \return -2 nothing to read
+  \return -1 on error
 */
 int V2_read_next_line_nat(struct Map_info *Map,
 			  struct line_pnts *line_p, struct line_cats *line_c)
 {
-    int line, ret, i;
+    int line, ret;
     struct P_line *Line;
     struct bound_box lbox, mbox;
 
@@ -166,44 +188,48 @@
 	line = Map->next_line;
 
 	if (line > Map->plus.n_lines)
-	    return -2;
+	    return -2; /* nothing to read */
 
 	Line = Map->plus.Line[line];
-	if (Line == NULL) {	/* Dead line */
+	if (Line == NULL) {
+	    /* skip dead line */
 	    Map->next_line++;
 	    continue;
 	}
 
-	if ((Map->constraint.type_flag &&
-	     !(Line->type & Map->constraint.type))) {
-	    Map->next_line++;
-	    continue;
+	if (Map->constraint.type_flag) {
+	    /* skip feature by type */
+	    if (!(Line->type & Map->constraint.type)) {
+		Map->next_line++;
+		continue;
+	    }
 	}
 
-	ret = V2_read_line_nat(Map, line_p, line_c, Map->next_line++);
-
-	if (Map->constraint.region_flag) {
+	Map->next_line++;
+	ret = read_line_nat(Map, line_p, line_c, Line->offset);
+	if (ret < 0)
+	    return ret;
+	
+	if (line_p && Map->constraint.region_flag) {
+	    /* skip feature by bbox */
 	    Vect_line_box(line_p, &lbox);
-	    if (!Vect_box_overlap(&lbox, &mbox)) {
+	    
+	    if (!Vect_box_overlap(&lbox, &mbox))
 		continue;
-	    }
 	}
 
 	if (line_c && Map->constraint.field_flag) {
-	    for (i = 0; i < line_c->n_cats; i++) {
-		if (line_c->field[i] == Map->constraint.field)
-		    break;
-	    }
-	    if (i == line_c->n_cats)
+	    /* skip feature by field */
+	    if (Vect_cat_get(line_c, Map->constraint.field, NULL) == 0)
 		continue;
 	}
+	
 	return ret;
     }
     
-    /* NOTREACHED */
+    return -1; /* NOTREACHED */
 }
 
-
 /*!  
   \brief Read line from coor file 
   

Modified: grass/trunk/lib/vector/Vlib/read_ogr.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_ogr.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/read_ogr.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -26,8 +26,301 @@
 static int get_line_type(const struct Map_info *, long);
 static int read_next_line_ogr(struct Map_info *, struct line_pnts *,
 			      struct line_cats *, int);
+#endif
 
 /*!
+  \brief Read next feature from OGR layer.
+  Skip empty features (level 1 without topology).
+  
+  This function implements sequential access.
+  
+  The action of this routine can be modified by:
+   - Vect_read_constraint_region()
+   - Vect_read_constraint_type()
+   - Vect_remove_constraints()
+  
+  \param Map pointer to Map_info structure
+  \param[out] line_p container used to store line points within
+  \param[out] line_c container used to store line categories within
+  
+  \return feature type
+  \return -2 no more features (EOF)
+  \return -1 out of memory
+*/
+int V1_read_next_line_ogr(struct Map_info *Map, struct line_pnts *line_p,
+			  struct line_cats *line_c)
+{
+#ifdef HAVE_OGR
+    return read_next_line_ogr(Map, line_p, line_c, FALSE);
+#else
+    G_fatal_error(_("GRASS is not compiled with OGR support"));
+    return -1;
+#endif
+}
+
+/*!
+  \brief Read next feature from OGR layer on topological level.
+
+  This function implements sequential access.
+
+  \param Map pointer to Map_info structure
+  \param[out] line_p container used to store line points within
+  (pointer to line_pnts struct)
+  \param[out] line_c container used to store line categories within
+  (pointer to line_cats struct)
+  
+  \return feature type
+  \return -2 no more features (EOF)
+  \return -1 on failure
+*/
+int V2_read_next_line_ogr(struct Map_info *Map, struct line_pnts *line_p,
+			  struct line_cats *line_c)
+{
+#ifdef HAVE_OGR
+    int line, ret;
+    struct P_line *Line;
+    struct bound_box lbox, mbox;
+
+    G_debug(3, "V2_read_next_line_ogr()");
+    
+    if (Map->constraint.region_flag)
+	Vect_get_constraint_box(Map, &mbox);
+    
+    while(TRUE) {
+	line = Map->next_line;
+	
+	if (Map->next_line > Map->plus.n_lines)
+	    return -2; /* nothing to read */
+	
+	Map->next_line++;
+	Line = Map->plus.Line[line];
+	if (Line == NULL) {	/* skip dead features */
+	    continue;
+	}
+
+	if (Map->constraint.type_flag) {
+	    /* skip feature by type */
+	    if (!(Line->type & Map->constraint.type))
+		continue;
+	}
+
+	if (Line->type == GV_CENTROID) {
+	    G_debug(4, "Centroid");
+	    
+	    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;
+		
+		/* 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 = 0;
+		for (i = 0; i < list.n_values; i++) {
+		    if (list.id[i] == line) {
+			found = i;
+			break;
+		    }
+		}
+		
+		Vect_reset_line(line_p);
+		Vect_append_point(line_p, list.box[found].E, list.box[found].N, 0.0);
+	    }
+	    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);
+	    }
+
+	    ret = GV_CENTROID;
+	}
+	else {
+	    ret = read_next_line_ogr(Map, line_p, line_c, TRUE);
+	}
+
+	if (line_p && Map->constraint.region_flag) {
+	    /* skip feature by region */
+	    Vect_line_box(line_p, &lbox);
+	    if (!Vect_box_overlap(&lbox, &mbox))
+		continue;
+	}
+	
+	/* skip feature by field ignored */
+		
+	return ret;
+    }
+#else
+    G_fatal_error(_("GRASS is not compiled with OGR support"));
+    return -1;
+#endif
+}
+
+/*!
+  \brief Read feature from OGR layer at given offset (level 1 without topology)
+  
+  This function implements random access on level 1.
+
+  \param Map pointer to Map_info structure 
+  \param[out] line_p container used to store line points within
+  (pointer line_pnts struct)
+  \param[out] line_c container used to store line categories within
+  (pointer line_cats struct)
+  \param offset given offset 
+  
+  \return line type
+  \return 0 dead line
+  \return -2 no more features
+  \return -1 on failure
+*/
+int V1_read_line_ogr(struct Map_info *Map,
+		     struct line_pnts *line_p, struct line_cats *line_c, off_t offset)
+{
+#ifdef HAVE_OGR
+    long FID;
+    int type;
+    OGRGeometryH hGeom;
+
+    struct Format_info_ogr *ogr_info;
+    
+    ogr_info = &(Map->fInfo.ogr);
+    G_debug(4, "V1_read_line_ogr(): offset = %lu offset_num = %lu",
+	    (long) offset, (long) ogr_info->offset.array_num);
+
+    if (offset >= ogr_info->offset.array_num)
+	return -2;
+    
+    if (line_p != NULL)
+	Vect_reset_line(line_p);
+    if (line_c != NULL)
+	Vect_reset_cats(line_c);
+
+    FID = ogr_info->offset.array[offset];
+    G_debug(4, "  FID = %ld", FID);
+    
+    /* coordinates */
+    if (line_p != NULL) {
+	/* Read feature to cache if necessary */
+	if (ogr_info->feature_cache_id != FID) {
+	    G_debug(4, "Read feature (FID = %ld) to cache", FID);
+	    if (ogr_info->feature_cache) {
+		OGR_F_Destroy(ogr_info->feature_cache);
+	    }
+	    ogr_info->feature_cache =
+		OGR_L_GetFeature(ogr_info->layer, FID);
+	    if (ogr_info->feature_cache == NULL) {
+		G_warning(_("Unable to get feature geometry, FID %ld"),
+			  FID);
+		return -1;
+	    }
+	    ogr_info->feature_cache_id = FID;
+	}
+	
+	hGeom = OGR_F_GetGeometryRef(ogr_info->feature_cache);
+	if (hGeom == NULL) {
+	    G_warning(_("Unable to get feature geometry, FID %ld"),
+		      FID);
+	    return -1;
+	}
+	
+	type = read_line(Map, hGeom, offset + 1, line_p);
+    }
+    else {
+	type = get_line_type(Map, FID);
+    }
+
+    /* category */
+    if (line_c != NULL) {
+	Vect_cat_set(line_c, 1, (int) FID);
+    }
+
+    return type;
+#else
+    G_fatal_error(_("GRASS is not compiled with OGR support"));
+    return -1;
+#endif
+}
+
+/*!
+  \brief Reads feature from OGR layer on topological level.
+ 
+  This function implements random access on level 2.
+  
+  \param Map pointer to Map_info structure
+  \param[out] line_p container used to store line points within
+  (pointer to line_pnts struct)
+  \param[out] line_c container used to store line categories within
+  (pointer to line_cats struct)
+  \param line feature id (starts at 1)
+  
+  \return feature type
+  \return -2 no more features
+  \return -1 on failure 
+*/
+int V2_read_line_ogr(struct Map_info *Map, struct line_pnts *line_p,
+		     struct line_cats *line_c, int line)
+{
+#ifdef HAVE_OGR
+    struct P_line *Line;
+    
+    G_debug(4, "V2_read_line_ogr() line = %d", line);
+    
+    Line = Map->plus.Line[line];
+    if (Line == NULL) {
+	G_warning(_("Attempt to read dead feature %d"), line);
+	return -1;
+    }
+    
+    if (Line->type == GV_CENTROID) {
+	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, 1);
+		Vect_select_lines_by_box(Map, &box, Line->type, &list);
+		
+		found = 0;
+		for (i = 0; i < list.n_values; i++) {
+		    if (list.id[i] == line) {
+			found = i;
+			break;
+		    }
+		}
+		
+		Vect_append_point(line_p, list.box[found].E, list.box[found].N, 0.0);
+	    }
+	}
+
+	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;
+    }
+    
+    return V1_read_line_ogr(Map, line_p, line_c, Line->offset);
+#else
+    G_fatal_error(_("GRASS is not compiled with OGR support"));
+    return -1;
+#endif
+}
+
+#ifdef HAVE_OGR
+/*!
   \brief Recursively read feature and add all elements to points_cache and types_cache.
   
   ftype: if > 0 use this type (because parts of Polygon are read as wkbLineString)
@@ -42,40 +335,44 @@
 int cache_feature(struct Map_info *Map, OGRGeometryH hGeom, int ftype)
 {
     int line, i, np, ng, tp;
+
+    struct Format_info_ogr *ogr_info;
+
     OGRwkbGeometryType type;
     OGRGeometryH hGeom2;
 
     G_debug(4, "cache_feature() ftype = %d", ftype);
 
-    /* Alloc space */
-    line = Map->fInfo.ogr.lines_num;
-    if (line == Map->fInfo.ogr.lines_alloc) {
-	Map->fInfo.ogr.lines_alloc += 20;
-	Map->fInfo.ogr.lines =
-	    (struct line_pnts **)G_realloc((void *)Map->fInfo.ogr.lines,
-					   Map->fInfo.ogr.lines_alloc *
+    ogr_info = &(Map->fInfo.ogr);
+    
+    /* alloc space in lines cache */
+    line = ogr_info->cache.lines_num;
+    if (line == ogr_info->cache.lines_alloc) {
+	ogr_info->cache.lines_alloc += 1;
+	ogr_info->cache.lines =
+	    (struct line_pnts **)G_realloc((void *)ogr_info->cache.lines,
+					   ogr_info->cache.lines_alloc *
 					   sizeof(struct line_pnts *));
 
-	Map->fInfo.ogr.lines_types =
-	    (int *)G_realloc(Map->fInfo.ogr.lines_types,
-			     Map->fInfo.ogr.lines_alloc * sizeof(int));
+	ogr_info->cache.lines_types =
+	    (int *)G_realloc(ogr_info->cache.lines_types,
+			     ogr_info->cache.lines_alloc * sizeof(int));
 
-	for (i = Map->fInfo.ogr.lines_num; i < Map->fInfo.ogr.lines_alloc; i++)
-	    Map->fInfo.ogr.lines[i] = Vect_new_line_struct();
-
+	for (i = ogr_info->cache.lines_num; i < ogr_info->cache.lines_alloc; i++)
+	    ogr_info->cache.lines[i] = Vect_new_line_struct();
     }
-    Vect_reset_line(Map->fInfo.ogr.lines[line]);
+    Vect_reset_line(ogr_info->cache.lines[line]);
 
     type = wkbFlatten(OGR_G_GetGeometryType(hGeom));
 
     switch (type) {
     case wkbPoint:
 	G_debug(4, "Point");
-	Vect_append_point(Map->fInfo.ogr.lines[line],
+	Vect_append_point(ogr_info->cache.lines[line],
 			  OGR_G_GetX(hGeom, 0), OGR_G_GetY(hGeom, 0),
 			  OGR_G_GetZ(hGeom, 0));
-	Map->fInfo.ogr.lines_types[line] = GV_POINT;
-	Map->fInfo.ogr.lines_num++;
+	ogr_info->cache.lines_types[line] = GV_POINT;
+	ogr_info->cache.lines_num++;
 	return 0;
 	break;
 
@@ -83,18 +380,18 @@
 	G_debug(4, "LineString");
 	np = OGR_G_GetPointCount(hGeom);
 	for (i = 0; i < np; i++) {
-	    Vect_append_point(Map->fInfo.ogr.lines[line],
+	    Vect_append_point(ogr_info->cache.lines[line],
 			      OGR_G_GetX(hGeom, i), OGR_G_GetY(hGeom, i),
 			      OGR_G_GetZ(hGeom, i));
 	}
 
 	if (ftype > 0) {	/* Polygon rings */
-	    Map->fInfo.ogr.lines_types[line] = ftype;
+	    ogr_info->cache.lines_types[line] = ftype;
 	}
 	else {
-	    Map->fInfo.ogr.lines_types[line] = GV_LINE;
+	    ogr_info->cache.lines_types[line] = GV_LINE;
 	}
-	Map->fInfo.ogr.lines_num++;
+	ogr_info->cache.lines_num++;
 	return 0;
 	break;
 
@@ -133,216 +430,93 @@
     OGRFeatureH hFeature;
     OGRGeometryH hGeom;
 
-    struct Format_info_ogr *fInfo;
+    struct Format_info_ogr *ogr_info;
 
     G_debug(3, "V1_read_next_line_ogr()");
 
-    if (line_p != NULL)
-	Vect_reset_line(line_p);
-    if (line_c != NULL)
-	Vect_reset_cats(line_c);
-
     if (Map->constraint.region_flag && !ignore_constraint)
 	Vect_get_constraint_box(Map, &mbox);
 
-    fInfo = &(Map->fInfo.ogr);
+    ogr_info = &(Map->fInfo.ogr);
     while (TRUE) {
-	/* Read feature to cache if necessary */
-	while (fInfo->lines_next == fInfo->lines_num) {
-	    hFeature = OGR_L_GetNextFeature(fInfo->layer);
+	/* reset data structures */
+	if (line_p != NULL)
+	    Vect_reset_line(line_p);
+	if (line_c != NULL)
+	    Vect_reset_cats(line_c);
+    
+	/* read feature to cache if necessary */
+	while (ogr_info->cache.lines_next == ogr_info->cache.lines_num) {
+	    hFeature = OGR_L_GetNextFeature(ogr_info->layer);
 	    if (hFeature == NULL) {
-		return -2;
-	    }			/* no more features */
+		return -2;              /* nothing to read */
+	    }			
 
 	    hGeom = OGR_F_GetGeometryRef(hFeature);
-	    if (hGeom == NULL) {	/* feature without geometry */
+	    if (hGeom == NULL) {	/* skip feature without geometry */
+		G_warning(_("Feature without geometry. Skipped."));
 		OGR_F_Destroy(hFeature);
 		continue;
 	    }
 
-	    fInfo->feature_cache_id = (int)OGR_F_GetFID(hFeature);
-	    if (fInfo->feature_cache_id == OGRNullFID) {
+	    /* cache OGR feature */
+	    ogr_info->feature_cache_id = (int)OGR_F_GetFID(hFeature);
+	    if (ogr_info->feature_cache_id == OGRNullFID) {
 		G_warning(_("OGR feature without ID"));
 	    }
 
-	    /* Cache the feature */
-	    fInfo->lines_num = 0;
+	    /* cache feature */
+	    ogr_info->cache.lines_num = 0;
 	    cache_feature(Map, hGeom, -1);
-	    G_debug(4, "%d lines read to cache", fInfo->lines_num);
+	    G_debug(4, "%d lines read to cache", ogr_info->cache.lines_num);
 	    OGR_F_Destroy(hFeature);
 
-	    fInfo->lines_next = 0;	/* next to be read from cache */
+	    /* next to be read from cache */
+	    ogr_info->cache.lines_next = 0;	
 	}
 
-	/* Read next part of the feature */
-	G_debug(4, "read next cached line %d", fInfo->lines_next);
-	itype = fInfo->lines_types[fInfo->lines_next];
+	/* read next part of the feature */
+	G_debug(4, "read next cached line %d", ogr_info->cache.lines_next);
+	itype = ogr_info->cache.lines_types[ogr_info->cache.lines_next];
 
-	/* Constraint on Type of line 
-	 * Default is all of  Point, Line, Area and whatever else comes along
-	 */
 	if (Map->constraint.type_flag && !ignore_constraint) {
+	    /* skip feature by type */
 	    if (!(itype & Map->constraint.type)) {
-		fInfo->lines_next++;
+		ogr_info->cache.lines_next++;
 		continue;
 	    }
 	}
 
-	/* Constraint on specified region */
 	if (Map->constraint.region_flag && !ignore_constraint) {
-	    Vect_line_box(fInfo->lines[fInfo->lines_next],
+	    /* skip feature by region */
+	    Vect_line_box(ogr_info->cache.lines[ogr_info->cache.lines_next],
 			  &lbox);
-
+	    
 	    if (!Vect_box_overlap(&lbox, &mbox)) {
-		fInfo->lines_next++;
+		ogr_info->cache.lines_next++;
 		continue;
 	    }
 	}
-
+	
+	/* skip feature by field - ignored */
+	
 	if (line_p != NULL)
 	    Vect_append_points(line_p,
-			       fInfo->lines[fInfo->lines_next], GV_FORWARD);
+			       ogr_info->cache.lines[ogr_info->cache.lines_next], GV_FORWARD);
 
-	if (line_c != NULL && fInfo->feature_cache_id != OGRNullFID)
-	    Vect_cat_set(line_c, 1, fInfo->feature_cache_id);
+	if (line_c != NULL && ogr_info->feature_cache_id != OGRNullFID)
+	    Vect_cat_set(line_c, 1, ogr_info->feature_cache_id);
 
-	fInfo->lines_next++;
+	ogr_info->cache.lines_next++;
 	G_debug(4, "next line read, type = %d", itype);
 	
 	return itype;
     }
-    return -2;			/* not reached */
-}
-#endif
 
-/*!
-  \brief Read next feature from OGR layer. Skip empty features (level 1)
-  
-  This function implements sequential access.
-  
-  The action of this routine can be modified by:
-   - Vect_read_constraint_region()
-   - Vect_read_constraint_type()
-   - Vect_remove_constraints()
-  
-  \param Map pointer to Map_info structure
-  \param[out] line_p container used to store line points within
-  \param[out] line_c container used to store line categories within
-  
-  \return feature type
-  \return -2 no more features (EOF)
-  \return -1 out of memory
-*/
-int V1_read_next_line_ogr(struct Map_info *Map, struct line_pnts *line_p,
-			  struct line_cats *line_c)
-{
-#ifdef HAVE_OGR
-    return read_next_line_ogr(Map, line_p, line_c, FALSE);
-#else
-    G_fatal_error(_("GRASS is not compiled with OGR support"));
-    return -1;
-#endif
+    return -1;			/* not reached */
 }
 
 /*!
-  \brief Read next feature from OGR layer (topology level).
-
-  This function implements sequential access.
-
-  \param Map pointer to Map_info structure
-  \param[out] line_p container used to store line points within
-  \param[out] line_c container used to store line categories within
-  
-  \return feature type
-  \return -2 no more features (EOF)
-  \return -1 out of memory
-*/
-int V2_read_next_line_ogr(struct Map_info *Map, struct line_pnts *line_p,
-			  struct line_cats *line_c)
-{
-#ifdef HAVE_OGR
-    int line, ret;
-    struct P_line *Line;
-    struct bound_box lbox, mbox;
-
-    G_debug(3, "V2_read_next_line_ogr()");
-    
-    if (Map->constraint.region_flag)
-	Vect_get_constraint_box(Map, &mbox);
-    
-    while(TRUE) {
-	line = Map->next_line;
-	
-	if (Map->next_line > Map->plus.n_lines)
-	    return -2;
-	
-	Map->next_line++;
-	
-	Line = Map->plus.Line[line];
-	if (Line == NULL) {	/* Dead line */
-	    continue;
-	}
-
-	if ((Map->constraint.type_flag &&
-	     !(Line->type & Map->constraint.type))) {
-	    continue;
-	}
-
-	if (Line->type == GV_CENTROID) {
-	    G_debug(4, "Centroid");
-	    
-	    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;
-		
-		/* 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 = 0;
-		for (i = 0; i < list.n_values; i++) {
-		    if (list.id[i] == line) {
-			found = i;
-			break;
-		    }
-		}
-		
-		Vect_reset_line(line_p);
-		Vect_append_point(line_p, list.box[found].E, list.box[found].N, 0.0);
-	    }
-	    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);
-	    }
-	    
-	    ret = GV_CENTROID;
-	}
-	else {
-	    ret = read_next_line_ogr(Map, line_p, line_c, TRUE);
-	}
-	
-	if (Map->constraint.region_flag) {
-	    Vect_line_box(line_p, &lbox);
-	    if (!Vect_box_overlap(&lbox, &mbox)) {
-		continue;
-	    }
-	}
-	
-	return ret;
-    }
-#else
-    G_fatal_error(_("GRASS is not compiled with OGR support"));
-    return -1;
-#endif
-}
-
-#ifdef HAVE_OGR
-/*!
   \brief Recursively descend to feature and read the part
   
   \param Map pointer to Map_info structure
@@ -358,12 +532,17 @@
 {
     int i, nPoints;
     int eType, line;
+    
+    const struct Format_info_ogr *ogr_info;
+    
     OGRGeometryH hGeom2;
 
     /* Read coors if hGeom is a simple element (wkbPoint,
      * wkbLineString) otherwise descend to geometry specified by
      * offset[offset] */
 
+    ogr_info = &(Map->fInfo.ogr);
+    
     eType = wkbFlatten(OGR_G_GetGeometryType(hGeom));
     G_debug(4, "OGR geometry type: %d", eType);
     
@@ -394,8 +573,8 @@
     case wkbMultiLineString:
     case wkbMultiPolygon:
     case wkbGeometryCollection:
-	G_debug(4, "\t->more geoms -> part %d", Map->fInfo.ogr.offset[offset]);
-	hGeom2 = OGR_G_GetGeometryRef(hGeom, Map->fInfo.ogr.offset[offset]);
+	G_debug(4, "\t->more geoms -> part %d", ogr_info->offset.array[offset]);
+	hGeom2 = OGR_G_GetGeometryRef(hGeom, ogr_info->offset.array[offset]);
 	line = read_line(Map, hGeom2, offset + 1, Points);
 	if (eType == wkbPolygon || wkbMultiPolygon)
 	    return GV_BOUNDARY;
@@ -429,12 +608,17 @@
 int get_line_type(const struct Map_info *Map, long FID)
 {
     int eType;
+
+    const struct Format_info_ogr *ogr_info;
+    
     OGRFeatureH hFeat;
     OGRGeometryH hGeom;
 
     G_debug(4, "get_line_type() fid = %ld", FID);
 
-    hFeat = OGR_L_GetFeature(Map->fInfo.ogr.layer, FID);
+    ogr_info = &(Map->fInfo.ogr);
+    
+    hFeat = OGR_L_GetFeature(ogr_info->layer, FID);
     if (hFeat == NULL)
 	return -1;
 
@@ -473,155 +657,3 @@
     return -1;
 }
 #endif
-
-/*!
-  \brief Read feature from OGR layer at given offset (level 1)
-  
-  This function implements random access on level 1.
-
-  \param Map pointer to Map_info structure 
-  \param[out] line_p container used to store line points within
-  \param[out] line_c container used to store line categories within
-  \param offset given offset 
-  
-  \return line type
-  \return 0 dead line
-  \return -2 no more features
-  \return -1 out of memory
-*/
-int V1_read_line_ogr(struct Map_info *Map,
-		     struct line_pnts *line_p, struct line_cats *line_c, off_t offset)
-{
-#ifdef HAVE_OGR
-    long FID;
-    int type;
-    OGRGeometryH hGeom;
-
-    struct Format_info_ogr *fInfo;
-    
-    fInfo = &(Map->fInfo.ogr);
-    G_debug(4, "V1_read_line_ogr() offset = %lu offset_num = %lu",
-	    (long) offset, (long) fInfo->offset_num);
-
-    if (offset >= fInfo->offset_num)
-	return -2;
-    
-    if (line_p != NULL)
-	Vect_reset_line(line_p);
-    if (line_c != NULL)
-	Vect_reset_cats(line_c);
-
-    FID = fInfo->offset[offset];
-    G_debug(4, "  FID = %ld", FID);
-    
-    /* coordinates */
-    if (line_p != NULL) {
-	/* Read feature to cache if necessary */
-	if (fInfo->feature_cache_id != FID) {
-	    G_debug(4, "Read feature (FID = %ld) to cache", FID);
-	    if (fInfo->feature_cache) {
-		OGR_F_Destroy(fInfo->feature_cache);
-	    }
-	    fInfo->feature_cache =
-		OGR_L_GetFeature(fInfo->layer, FID);
-	    if (fInfo->feature_cache == NULL) {
-		G_fatal_error(_("Unable to get feature geometry, FID %ld"),
-			      FID);
-	    }
-	    fInfo->feature_cache_id = FID;
-	}
-	
-	hGeom = OGR_F_GetGeometryRef(fInfo->feature_cache);
-	if (hGeom == NULL) {
-	    G_fatal_error(_("Unable to get feature geometry, FID %ld"),
-			  FID);
-	}
-	
-	type = read_line(Map, hGeom, offset + 1, line_p);
-    }
-    else {
-	type = get_line_type(Map, FID);
-    }
-
-    /* category */
-    if (line_c != NULL) {
-	Vect_cat_set(line_c, 1, (int) FID);
-    }
-
-    return type;
-#else
-    G_fatal_error(_("GRASS is not compiled with OGR support"));
-    return -1;
-#endif
-}
-
-/*!
-  \brief Reads feature from OGR layer (topology level)
- 
-  This function implements random access on level 2.
-  
-  \param Map pointer to Map_info structure
-  \param[out] line_p container used to store line points within
-  \param[out] line_c container used to store line categories within
-  \param line feature id
-  
-  \return feature type
-  \return -2 no more features
-  \return -1 out of memory
-*/
-int V2_read_line_ogr(struct Map_info *Map, struct line_pnts *line_p,
-		     struct line_cats *line_c, int line)
-{
-#ifdef HAVE_OGR
-    struct P_line *Line;
-    G_debug(4, "V2_read_line_ogr() line = %d", line);
-    
-    Line = Map->plus.Line[line];
-    
-    if (Line == NULL)
-	G_fatal_error(_("Attempt to read dead feature %d"), line);
-
-    if (Line->type == GV_CENTROID) {
-	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, 1);
-		Vect_select_lines_by_box(Map, &box, Line->type, &list);
-		
-		found = 0;
-		for (i = 0; i < list.n_values; i++) {
-		    if (list.id[i] == line) {
-			found = i;
-			break;
-		    }
-		}
-		
-		Vect_append_point(line_p, list.box[found].E, list.box[found].N, 0.0);
-	    }
-	}
-
-	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;
-    }
-    
-    return V1_read_line_ogr(Map, line_p, line_c, Line->offset);
-#else
-    G_fatal_error(_("GRASS is not compiled with OGR support"));
-    return -1;
-#endif
-}

Added: grass/trunk/lib/vector/Vlib/read_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/read_pg.c	                        (rev 0)
+++ grass/trunk/lib/vector/Vlib/read_pg.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -0,0 +1,1028 @@
+/*!
+  \file lib/vector/Vlib/read_pg.c
+  
+  \brief Vector library - reading features (PostGIS format)
+  
+  Higher level functions for reading/writing/manipulating vectors.
+  
+  \todo Currently only points, linestrings and polygons are supported,
+  implement also other types
+  
+  (C) 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 Martin Landa <landa.martin gmail.com>
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <grass/vector.h>
+#include <grass/dbmi.h>
+#include <grass/glocale.h>
+
+#ifdef HAVE_POSTGRES
+#include "pg_local_proto.h"
+
+#define CURSOR_PAGE 500
+
+#define SWAP32(x) \
+        ((unsigned int)( \
+            (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \
+            (((unsigned int)(x) & (unsigned int)0x0000ff00UL) <<  8) | \
+            (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >>  8) | \
+            (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) ))
+
+#define SWAPDOUBLE(x) \
+{                                                                 \
+    unsigned char temp, *data = (unsigned char *) (x);            \
+                                                                  \
+    temp = data[0];                                               \
+    data[0] = data[7];                                            \
+    data[7] = temp;                                               \
+    temp = data[1];                                               \
+    data[1] = data[6];                                            \
+    data[6] = temp;                                               \
+    temp = data[2];                                               \
+    data[2] = data[5];                                            \
+    data[5] = temp;                                               \
+    temp = data[3];                                               \
+    data[3] = data[4];                                            \
+    data[4] = temp;                                               \
+}                                                                    
+
+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);
+static unsigned char *hex_to_wkb(const char *, int *);
+static int point_from_wkb(const unsigned char *, int, int, int,
+			  struct line_pnts *);
+static int line_from_wkb(const unsigned char *, int, int, int,
+			 struct line_pnts *, int);
+static int polygon_from_wkb(const unsigned char *, int, int, int,
+			    struct Format_info_pg *);
+static int error_corrupted_data(const char *);
+static int set_initial_query();
+#endif
+
+/*!
+  \brief Read next feature from PostGIS layer. Skip
+  empty features (level 1 without topology).
+  t
+  This function implements sequential access.
+    
+  The action of this routine can be modified by:
+   - Vect_read_constraint_region()
+   - Vect_read_constraint_type()
+   - Vect_remove_constraints()
+ 
+  \param Map pointer to Map_info structure
+  \param[out] line_p container used to store line points within
+  (pointer to line_pnts struct)
+  \param[out] line_c container used to store line categories within
+  (pointer line_cats struct)
+  
+  \return feature type
+  \return -2 no more features (EOF)
+  \return -1 out of memory
+*/
+int V1_read_next_line_pg(struct Map_info *Map,
+			 struct line_pnts *line_p,
+			 struct line_cats *line_c)
+{
+#ifdef HAVE_POSTGRES
+    G_debug(3, "V1_read_next_line_pg()");
+
+    /* constraints not ignored */ 
+    return read_next_line_pg(Map, line_p, line_c, FALSE);
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+    return -1;
+#endif
+}
+
+/*!
+  \brief Read next feature from PostGIS layer on topological level.
+
+  This function implements sequential access.
+
+  \param Map pointer to Map_info structure
+  \param[out] line_p container used to store line points within
+  (pointer to line_pnts struct)
+  \param[out] line_c container used to store line categories within
+  (pointer to line_cats struct)
+  
+  \return feature type
+  \return -2 no more features (EOF)
+  \return -1 on failure
+*/
+int V2_read_next_line_pg(struct Map_info *Map, struct line_pnts *line_p,
+			 struct line_cats *line_c)
+{
+#ifdef HAVE_POSTGRES
+    int line, ret;
+    struct P_line *Line;
+    struct bound_box lbox, mbox;
+    
+    G_debug(3, "V2_read_next_line_pg()");
+    
+    if (Map->constraint.region_flag)
+	Vect_get_constraint_box(Map, &mbox);
+    
+    ret = -1;
+    while(TRUE) {
+	line = Map->next_line;
+
+	if (Map->next_line > Map->plus.n_lines)
+	    return -2;
+
+	Line = Map->plus.Line[line];
+	if (Line == NULL) {	/* skip dead features */
+	    Map->next_line++;
+	    continue;
+	}
+
+	if (Map->constraint.type_flag) {
+	    /* skip by type */
+	    if (!(Line->type & Map->constraint.type)) {
+		Map->next_line++;
+		continue;
+	    }
+	}
+
+	if (Line->type == GV_CENTROID) {
+	    G_debug(4, "Centroid");
+	    
+	    Map->next_line++;
+	    
+	    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;
+		
+		/* 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 = 0;
+		for (i = 0; i < list.n_values; i++) {
+		    if (list.id[i] == line) {
+			found = i;
+			break;
+		    }
+		}
+		
+		Vect_reset_line(line_p);
+		Vect_append_point(line_p, list.box[found].E, list.box[found].N, 0.0);
+	    }
+	    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);
+	    }
+
+	    ret = GV_CENTROID;
+	}
+	else {
+	    /* ignore constraints, Map->next_line incremented */
+	    ret = read_next_line_pg(Map, line_p, line_c, TRUE);
+	}
+
+	if (Map->constraint.region_flag) {
+	    /* skip by region */
+	    Vect_line_box(line_p, &lbox);
+	    if (!Vect_box_overlap(&lbox, &mbox)) {
+		continue;
+	    }
+	}
+	
+	/* skip by field ignored */
+	
+	return ret;
+    }
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+#endif
+
+    return -1; /* not reached */
+}
+
+/*!
+  \brief Read feature from PostGIS layer at given offset (level 1 without topology)
+  
+  This function implements random access on level 1.
+
+  \param Map pointer to Map_info structure 
+  \param[out] line_p container used to store line points within
+  (pointer line_pnts struct)
+  \param[out] line_c container used to store line categories within
+  (pointer line_cats struct)
+  \param offset given offset 
+  
+  \return line type
+  \return 0 dead line
+  \return -2 no more features
+  \return -1 out of memory
+*/
+int V1_read_line_pg(struct Map_info *Map,
+		    struct line_pnts *line_p, struct line_cats *line_c, off_t offset)
+{
+#ifdef HAVE_POSTGRES
+    long fid;
+    int i, type;
+    SF_FeatureType sf_type;
+    
+    struct line_pnts      *line_i;
+    struct Format_info_pg *pg_info;
+    
+    pg_info = &(Map->fInfo.pg);
+    G_debug(3, "V1_read_line_pg(): offset = %lu offset_num = %lu",
+	    (long) offset, (long) pg_info->offset.array_num);
+    
+    if (offset >= pg_info->offset.array_num)
+	return -2;
+    
+    if (line_p != NULL)
+	Vect_reset_line(line_p);
+    if (line_c != NULL)
+	Vect_reset_cats(line_c);
+
+    fid = pg_info->offset.array[offset];
+    G_debug(4, "  fid = %ld", fid);
+    
+    /* coordinates */
+    if (line_p != NULL) {
+	/* read feature to cache if necessary */
+	if (pg_info->cache.fid != fid) {
+	    G_debug(4, "read feature (fid = %ld) to cache", fid);
+	    sf_type = (int) get_feature(pg_info, fid);
+	    
+	    if ((int) sf_type < 0)
+		return (int) sf_type;
+	}
+	
+	/* get data from cache */
+	type  = pg_info->cache.lines_types[pg_info->cache.lines_next];
+	line_i = pg_info->cache.lines[pg_info->cache.lines_next];
+	for (i = 0; i < line_i->n_points; i++) {
+	    Vect_append_point(line_p,
+			      line_i->x[i], line_i->y[i], line_i->z[i]);
+	}
+    }
+
+    if (line_c != NULL) {
+	Vect_cat_set(line_c, 1, (int) fid);
+    }
+
+    return type;
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+    return -1;
+#endif
+}
+
+/*!
+  \brief Reads feature from PostGIS layer on topological level.
+ 
+  This function implements random access on level 2.
+  
+  \param Map pointer to Map_info structure
+  \param[out] line_p container used to store line points within
+  (pointer to line_pnts struct)
+  \param[out] line_c container used to store line categories within
+  (pointer to line_cats struct)
+  \param line feature id (starts at 1)
+  
+  \return feature type
+  \return -2 no more features
+  \return -1 on failure
+*/
+int V2_read_line_pg(struct Map_info *Map, struct line_pnts *line_p,
+		    struct line_cats *line_c, int line)
+{
+#ifdef HAVE_POSTGRES
+    struct P_line *Line;
+    
+    G_debug(3, "V2_read_line_pg() line = %d", line);
+    
+    Line = Map->plus.Line[line];
+    if (Line == NULL) {
+	G_warning(_("Attempt to read dead feature %d"), line);
+	return -1;
+    }
+
+    if (Line->type == GV_CENTROID) {
+	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, 1);
+		Vect_select_lines_by_box(Map, &box, Line->type, &list);
+		
+		found = 0;
+		for (i = 0; i < list.n_values; i++) {
+		    if (list.id[i] == line) {
+			found = i;
+			break;
+		    }
+		}
+		
+		Vect_append_point(line_p, list.box[found].E, list.box[found].N, 0.0);
+	    }
+	}
+
+	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;
+    }
+    
+    return V1_read_line_pg(Map, line_p, line_c, Line->offset);
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+    return -1;
+#endif
+}
+
+#ifdef HAVE_POSTGRES
+/*!
+  \brief Read next feature from PostGIS layer. 
+ 
+  \param Map pointer to Map_info structure
+  \param[out] line_p container used to store line points within
+  (pointer to line_pnts struct)
+  \param[out] line_c container used to store line categories within
+  (pointer line_cats struct)
+  \param ignore_constraints TRUE to ignore constraints (type, region)
+  
+  \return feature type
+  \return -2 no more features (EOF)
+  \return -1 out of memory
+*/
+int read_next_line_pg(struct Map_info *Map,
+		      struct line_pnts *line_p, struct line_cats *line_c,
+		      int ignore_constraints)
+{
+    int i, ltype;
+    SF_FeatureType sf_type;
+    
+    struct Format_info_pg *pg_info;
+    struct bound_box mbox, lbox;
+    struct line_pnts *line_i;
+
+    pg_info = &(Map->fInfo.pg);
+
+    if (Map->constraint.region_flag && !ignore_constraints)
+	Vect_get_constraint_box(Map, &mbox);
+    
+    while (TRUE) {
+	Map->next_line++; /* level 2 only */
+	
+	/* reset data structures */
+	if (line_p != NULL)
+	    Vect_reset_line(line_p);
+	if (line_c != NULL)
+	    Vect_reset_cats(line_c);
+
+	/* read feature to cache if necessary */
+	while (pg_info->cache.lines_next == pg_info->cache.lines_num) {
+	    pg_info->cache.lines_next = pg_info->cache.lines_num = 0;
+	    /* cache feature -> line_p & line_c */
+	    sf_type = get_feature(pg_info, -1);
+	    
+	    if ((int) sf_type < 0) /* -1 || - 2 */
+		return (int) sf_type;
+
+	    if (sf_type & (SF_UNKNOWN | SF_NONE)) {
+		G_warning(_("Feature without geometry. Skipped."));
+		continue;
+	    }
+	    
+	    G_debug(4, "%d lines read to cache", pg_info->cache.lines_num);
+	}
+	
+	/* get data from cache */
+	ltype  = pg_info->cache.lines_types[pg_info->cache.lines_next];
+	if (line_p) {
+	    line_i = pg_info->cache.lines[pg_info->cache.lines_next];
+	    for (i = 0; i < line_i->n_points; i++) {
+		Vect_append_point(line_p,
+				  line_i->x[i], line_i->y[i], line_i->z[i]);
+	    }
+	}
+	if (line_c) {
+	    Vect_cat_set(line_c, 1, (int) pg_info->cache.fid);
+	}
+	pg_info->cache.lines_next++;
+	
+	/* apply constraints */
+	if (Map->constraint.type_flag && !ignore_constraints) {
+	    /* skip feature by type */
+	    if (!(ltype & Map->constraint.type))
+		continue;
+	}
+
+	if (line_p && Map->constraint.region_flag &&
+	    !ignore_constraints) {
+	    /* skip feature by region */
+	    Vect_line_box(line_p, &lbox);
+	    
+	    if (!Vect_box_overlap(&lbox, &mbox))
+		continue;
+	}
+	
+	/* skip feature by field ignored */
+	
+	return ltype;
+    }
+
+    return -1; /* not reached */
+}
+
+/*!
+  \brief Read feature geometry
+
+  Geometry is stored in lines cache.
+  
+  \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)
+
+  \return simple feature type (SF_POINT, SF_LINESTRING, ...)
+  \return -1 on error
+*/
+SF_FeatureType get_feature(struct Format_info_pg *pg_info, int fid)
+{
+    char *data;
+    char stmt[DB_SQL_MAX];
+    SF_FeatureType ftype;
+
+    if (!pg_info->geom_column) {
+	G_warning(_("No geometry column defined"));
+	return -1;
+    }
+    if (fid < 1) {
+	/* next (read n features) */
+	if (!pg_info->res) {
+	    if (set_initial_query(pg_info) == -1)
+		return -1;
+	}
+    }
+    else {
+	if (!pg_info->fid_column) {
+	    G_warning(_("Random access not supported. "
+			"Primary key not defined."));
+	    return -1;
+	}
+	
+	if (execute(pg_info->conn, "BEGIN") == -1)
+	    return -1;
+	
+	sprintf(stmt, "DECLARE %s%p CURSOR FOR SELECT %s FROM %s "
+		"WHERE %s = %d",
+		pg_info->table_name, pg_info->conn, 
+		pg_info->geom_column, 
+		pg_info->table_name, pg_info->fid_column, fid);
+
+	if (execute(pg_info->conn, stmt) == -1)
+	    return -1;
+    
+	sprintf(stmt, "FETCH ALL in %s%p", 
+		pg_info->table_name, pg_info->conn);
+	pg_info->res = PQexec(pg_info->conn, stmt);
+	pg_info->next_line = 0;
+    }
+
+    if (!pg_info->res || PQresultStatus(pg_info->res) != PGRES_TUPLES_OK) {
+	PQclear(pg_info->res);
+	pg_info->res = NULL;
+	return -1; /* reading failed */
+    }
+        
+    /* do we need to fetch more records ? */
+    if (PQntuples(pg_info->res) == CURSOR_PAGE &&
+        PQntuples(pg_info->res) == pg_info->next_line) {
+	char stmt[DB_SQL_MAX];
+	PQclear(pg_info->res);
+
+	sprintf(stmt, "FETCH %d in %s%p", CURSOR_PAGE,
+		pg_info->table_name, pg_info->conn);
+	pg_info->res = PQexec(pg_info->conn, stmt);
+	pg_info->next_line = 0;
+    }
+
+    /* out of results ? */
+    if (PQntuples(pg_info->res) == pg_info->next_line) {
+	if (pg_info->res) {
+	    PQclear(pg_info->res);
+	    pg_info->res = NULL;
+	    
+	    sprintf(stmt, "CLOSE %s%p",
+		    pg_info->table_name, pg_info->conn);
+	    if (execute(pg_info->conn, stmt) == -1) {
+		G_warning(_("Unable to close cursor"));
+		return -1;
+	    }
+	    execute(pg_info->conn, "COMMIT");
+	}
+	return -2;
+    }
+    data = (char *)PQgetvalue(pg_info->res, pg_info->next_line, 0);
+    
+    ftype = cache_feature(data, FALSE, pg_info);
+    if (fid < 0) {
+	pg_info->cache.fid = atoi(PQgetvalue(pg_info->res, pg_info->next_line, 1));
+	pg_info->next_line++;
+    }
+    else {
+	pg_info->cache.fid = fid;
+
+	PQclear(pg_info->res);
+	pg_info->res = NULL;
+	
+	sprintf(stmt, "CLOSE %s%p",
+		pg_info->table_name, pg_info->conn);
+	if (execute(pg_info->conn, stmt) == -1) {
+	    G_warning(_("Unable to close cursor"));
+	    return -1;
+	}
+
+	if (execute(pg_info->conn, "COMMIT") == -1)
+	    return -1;
+    }
+    
+    return ftype;
+}
+
+/*!
+  \brief Convert HEX to WKB data
+
+  This function is based on CPLHexToBinary() from GDAL/OGR library
+
+  \param hex_data HEX data
+  \param[out] nbytes number of bytes in output buffer
+
+  \return pointer to WKB data buffer
+*/
+static unsigned char *hex_to_wkb(const char *hex_data, int *nbytes)
+{
+    unsigned char *wkb_data;
+    unsigned int length, i_src, i_dst;
+
+    i_src = i_dst = 0;
+    length = strlen(hex_data);
+    wkb_data = G_malloc(length / 2 + 2);
+    
+    while (hex_data[i_src] != '\0' ) {
+        if (hex_data[i_src] >= '0' && hex_data[i_src] <= '9')
+            wkb_data[i_dst] = hex_data[i_src] - '0';
+        else if (hex_data[i_src] >= 'A' && hex_data[i_src] <= 'F')
+            wkb_data[i_dst] = hex_data[i_src] - 'A' + 10;
+        else if (hex_data[i_src] >= 'a' && hex_data[i_src] <= 'f')
+            wkb_data[i_dst] = hex_data[i_src] - 'a' + 10;
+        else 
+            break;
+	
+        wkb_data[i_dst] *= 16;
+
+        i_src++;
+
+        if (hex_data[i_src] >= '0' && hex_data[i_src] <= '9')
+            wkb_data[i_dst] += hex_data[i_src] - '0';
+        else if(hex_data[i_src] >= 'A' && hex_data[i_src] <= 'F')
+            wkb_data[i_dst] += hex_data[i_src] - 'A' + 10;
+        else if(hex_data[i_src] >= 'a' && hex_data[i_src] <= 'f')
+            wkb_data[i_dst] += hex_data[i_src] - 'a' + 10;
+        else
+            break;
+	
+        i_src++;
+        i_dst++;
+    }
+    
+    wkb_data[i_dst] = 0;
+    *nbytes = i_dst;
+
+    return wkb_data;
+}
+
+/*!
+  \brief Read geometry from HEX data
+
+  This code is inspired by OGRGeometryFactory::createFromWkb() from
+  GDAL/OGR library.
+
+  \param data HEX data
+  \param skip_polygon skip polygons (level 1)
+  \param[in,out] pg_info pointer to Format_info_pg struct
+  (geometry is stored in lines cache)
+  
+  \return 0 on success
+  \return -1 on error
+*/
+int cache_feature(const char *data, int skip_polygon,
+		  struct Format_info_pg *pg_info)
+{
+    int ret, byte_order, nbytes, is3D;
+    unsigned char *wkb_data;
+    unsigned int wkb_flags;
+    SF_FeatureType ftype;
+    
+    wkb_flags = 0;
+    wkb_data  = hex_to_wkb(data, &nbytes);
+    
+    if (nbytes < 5) {
+	G_warning(_("Invalid WKB content: %d bytes"), nbytes);
+	G_free(wkb_data);
+	return -1;
+    }
+    
+    /* parsing M coordinate not supported */
+    memcpy(&wkb_flags, wkb_data + 1, 4);
+    byte_order = (wkb_data[0] == 0 ? ENDIAN_BIG : ENDIAN_LITTLE);
+    if (byte_order == ENDIAN_BIG)
+	wkb_flags = SWAP32(wkb_flags);
+    
+    if (wkb_flags & 0x40000000) {
+        G_warning(_("Reading EWKB with 4-dimensional coordinates (XYZM) "
+		    "is not supported"));
+	G_free(wkb_data);
+	return -1;
+    }
+
+    /* PostGIS EWKB format includes an  SRID, but this won't be       
+       understood by OGR, so if the SRID flag is set, we remove the    
+       SRID (bytes at offset 5 to 8).                                 
+    */
+    if (nbytes > 9 &&
+        ((byte_order == ENDIAN_BIG && (wkb_data[1] & 0x20)) ||
+	 (byte_order == ENDIAN_LITTLE && (wkb_data[4] & 0x20)))) {
+        memmove(wkb_data + 5, wkb_data + 9, nbytes -9);
+        nbytes -= 4;
+        if(byte_order == ENDIAN_BIG)
+            wkb_data[1] &= (~0x20);
+        else
+            wkb_data[4] &= (~0x20);
+    }
+    
+    if (nbytes < 9 && nbytes != -1) {
+	G_free(wkb_data);
+	return -1;
+    }
+    
+   /* Get the geometry feature type. For now we assume that geometry
+      type is between 0 and 255 so we only have to fetch one byte.
+   */
+    if (byte_order == ENDIAN_LITTLE) {
+        ftype = (SF_FeatureType) wkb_data[1];
+	is3D = wkb_data[4] & 0x80 || wkb_data[2] & 0x80;
+    }
+    else {
+        ftype = (SF_FeatureType) wkb_data[4];
+	is3D = wkb_data[1] & 0x80 || wkb_data[3] & 0x80;
+    }
+    
+    /* allocate space in lines cache - be minimalistic
+       
+       more lines require eg. polygon with more rings, multi-features
+       or geometry collections
+    */
+    if (!pg_info->cache.lines) {
+	pg_info->cache.lines_alloc = 1;
+	pg_info->cache.lines = (struct line_pnts **) G_malloc(sizeof(struct line_pnts *));
+	
+	pg_info->cache.lines_types = (int *) G_malloc(sizeof(int));
+	pg_info->cache.lines[0] = Vect_new_line_struct();
+	pg_info->cache.lines_types[0] = -1;
+    }
+    pg_info->cache.lines_num = 0;
+    
+    ret = -1;
+    if (ftype == SF_POINT) {
+	pg_info->cache.lines_num = 1;
+	pg_info->cache.lines_types[0] = GV_POINT;
+	ret = point_from_wkb(wkb_data, nbytes, byte_order,
+			     is3D, pg_info->cache.lines[0]);
+    }
+    else if (ftype == SF_LINESTRING) {
+	pg_info->cache.lines_num = 1;
+	pg_info->cache.lines_types[0] = GV_LINE;
+	ret = line_from_wkb(wkb_data, nbytes, byte_order,
+			    is3D, pg_info->cache.lines[0], FALSE);
+    }
+    else if (ftype == SF_POLYGON && !skip_polygon)
+	ret = polygon_from_wkb(wkb_data, nbytes, byte_order,
+			       is3D, pg_info) > 0 ? 0 : -1;
+    else  {
+	G_warning(_("Unsupported geometry type %d"), ftype);
+    }
+    
+    G_free(wkb_data);
+    
+    return ret;
+}
+
+/*!
+  \brief Read point for WKB data
+
+  See OGRPoint::importFromWkb() from GDAL/OGR library
+
+  \param wkb_data WKB data
+  \param nbytes number of bytes (WKB data buffer)
+  \param byte_order byte order (ENDIAN_LITTLE, ENDIAN_BIG)
+  \param with_z WITH_Z for 3D data
+  \param[out] line_p point geometry (pointer to line_pnts struct)
+
+  \return 0 on success
+  \return -1 on error
+*/
+int point_from_wkb(const unsigned char *wkb_data, int nbytes, int byte_order,
+		    int with_z, struct line_pnts *line_p)
+{
+    double x, y, z;
+    if (nbytes < 21 && nbytes != -1 )
+	return -1;
+
+    /* get vertex */
+    memcpy(&x, wkb_data + 5, 8);
+    memcpy(&y, wkb_data + 5 + 8, 8);
+    
+    if (byte_order == ENDIAN_BIG) {
+        SWAPDOUBLE(&x);
+        SWAPDOUBLE(&y);
+    }
+
+    if (with_z) {
+        if (nbytes < 29 && nbytes != -1 )
+            return -1;
+	
+        memcpy(&z, wkb_data + 5 + 16, 8);
+	if (byte_order == ENDIAN_BIG) {
+	    SWAPDOUBLE(&z);
+	}
+    }
+    else {
+        z = 0.0;
+    }
+    
+    if (line_p) {
+	Vect_reset_line(line_p);
+	Vect_append_point(line_p, x, y, z);
+    }
+    
+    return 0;
+}
+
+/*!
+  \brief Read line for WKB data
+
+  See OGRLineString::importFromWkb() from GDAL/OGR library
+
+  \param wkb_data WKB data
+  \param nbytes number of bytes (WKB data buffer)
+  \param byte_order byte order (ENDIAN_LITTLE, ENDIAN_BIG)
+  \param with_z WITH_Z for 3D data
+  \param[out] line_p line geometry (pointer to line_pnts struct)
+
+  \return 0 on success
+  \return -1 on error
+*/
+int line_from_wkb(const unsigned char *wkb_data, int nbytes, int byte_order,
+		  int with_z, struct line_pnts *line_p, int is_ring)
+{
+    int npoints, point_size, buff_min_size, offset;
+    int i;
+    double x, y, z;
+
+    if (is_ring)
+	offset = 5;
+    else
+	offset = 0;
+    
+    if (is_ring && nbytes < 4 && nbytes != -1)
+        return error_corrupted_data(NULL);
+    
+    /* get the vertex count */
+    memcpy(&npoints, wkb_data + (5 - offset), 4);
+    
+    if (byte_order == ENDIAN_BIG) {
+       npoints = SWAP32(npoints);
+    }
+    
+    /* check if the wkb stream buffer is big enough to store fetched
+       number of points.  16 or 24 - size of point structure
+    */
+    point_size = with_z ? 24 : 16;
+    if (npoints < 0 || npoints > INT_MAX / point_size)
+        return error_corrupted_data(NULL);
+    
+    buff_min_size = point_size * npoints;
+    
+    if (nbytes != -1 && buff_min_size > nbytes - (9 - offset))
+        return error_corrupted_data(_("Length of input WKB is too small"));
+    
+    if (line_p)
+	Vect_reset_line(line_p);
+    
+    /* get the vertex */
+    for (i = 0; i < npoints; i++) {
+	memcpy(&x, wkb_data + (9 - offset) + i * point_size, 8);
+	memcpy(&y, wkb_data + (9 - offset) + 8 + i * point_size, 8);
+	if (with_z)
+            memcpy(&z, wkb_data + (9 - offset) + 16 + i * point_size, 8);
+        else
+	    z = 0.0;
+
+	if (byte_order == ENDIAN_BIG) {
+	    SWAPDOUBLE(&x);
+	    SWAPDOUBLE(&y);
+	    if (with_z)
+		SWAPDOUBLE(&z);
+	}
+	
+	if (line_p)
+	    Vect_append_point(line_p, x, y, z);
+    }
+    
+    return 0;
+}
+
+/*!
+  \brief Read polygon for WKB data
+
+  See OGRPolygon::importFromWkb() from GDAL/OGR library
+
+  \param wkb_data WKB data
+  \param nbytes number of bytes (WKB data buffer)
+  \param byte_order byte order (ENDIAN_LITTLE, ENDIAN_BIG)
+  \param with_z WITH_Z for 3D data
+  \param[out] line_p array of rings (pointer to line_pnts struct)
+
+  \return number of rings
+  \return -1 on error
+*/
+int polygon_from_wkb(const unsigned char *wkb_data, int nbytes, int byte_order,
+		     int with_z, struct Format_info_pg *pg_info)
+{
+    int nrings, data_offset, i, nsize;
+    struct line_pnts *line_i;
+    
+    if (nbytes < 9 && nbytes != -1)
+	return -1;
+    
+    /* get the ring count */
+    memcpy(&nrings, wkb_data + 5, 4);
+    if (byte_order == ENDIAN_BIG) {
+        nrings = SWAP32(nrings);
+    }
+    if (nrings < 0) {
+        return -1;
+    }
+    
+    /* reallocate space for islands if needed */
+    if (nrings > pg_info->cache.lines_alloc) {
+	pg_info->cache.lines_alloc += 20;
+	pg_info->cache.lines = (struct line_pnts **) G_realloc(pg_info->cache.lines,
+							       pg_info->cache.lines_alloc *
+							       sizeof(struct line_pnts *));
+	pg_info->cache.lines_types = (int *) G_realloc(pg_info->cache.lines_types,
+						       pg_info->cache.lines_alloc *
+						       sizeof(int));
+	
+	for (i = pg_info->cache.lines_alloc - 20; i < pg_info->cache.lines_alloc; i++) {
+	    pg_info->cache.lines[i] = Vect_new_line_struct();
+	    pg_info->cache.lines_types[i] = -1;
+	}
+    }
+    pg_info->cache.lines_num = nrings;
+    
+    /* each ring has a minimum of 4 bytes (point count) */
+    if (nbytes != -1 && nbytes - 9 < nrings * 4) {
+        return error_corrupted_data(_("Length of input WKB is too small"));
+    }
+
+    data_offset = 9;
+    if (nbytes != -1)
+        nbytes -= data_offset;
+    
+    /* get the rings */
+    nsize = 0;
+    for (i = 0; i < nrings; i++ ) {
+	line_i = pg_info->cache.lines[i];
+	pg_info->cache.lines_types[i] = GV_BOUNDARY;
+	
+	line_from_wkb(wkb_data + data_offset, nbytes, byte_order,
+		      with_z, line_i, TRUE);
+	
+        if (nbytes != -1) {
+	    if (with_z)
+		nsize = 4 + 24 * line_i->n_points;
+	    else
+		nsize = 4 + 16 * line_i->n_points;
+	    
+	    nbytes -= nsize;
+	}
+	
+        data_offset += nsize;
+    }
+    
+    return nrings;
+}
+
+/*!
+  \brief Report error message
+
+  \param msg message (NULL)
+
+  \return -1
+*/
+int error_corrupted_data(const char *msg)
+{
+    if (msg)
+	G_warning(_("Corrupted data. %s."), msg);
+    else
+	G_warning(_("Corrupted data"));
+    
+    return -1;
+}
+
+/*!
+  \brief Set initial SQL query for sequential access
+
+  \param pg_info pointer to Format_info_pg struct
+
+  \return 0 on success
+  \return -1 on error
+*/
+int set_initial_query(struct Format_info_pg *pg_info)
+{
+    char stmt[DB_SQL_MAX];
+    
+    if (execute(pg_info->conn, "BEGIN") == -1)
+	return -1;
+    
+    sprintf(stmt, "DECLARE %s%p CURSOR FOR SELECT %s,%s FROM %s",
+	    pg_info->table_name, pg_info->conn, 
+	    pg_info->geom_column, pg_info->fid_column,
+	    pg_info->table_name);
+
+    if (execute(pg_info->conn, stmt) == -1)
+	return -1;
+    
+    sprintf(stmt, "FETCH %d in %s%p", CURSOR_PAGE,
+	    pg_info->table_name, pg_info->conn);
+    pg_info->res = PQexec(pg_info->conn, stmt);
+    pg_info->next_line = 0;
+    
+    return 0;
+}
+
+/*!
+  \brief Execute SQL statement
+
+  See pg_local_proto.h
+
+  \param conn pointer to PGconn
+  \param stmt query
+
+  \return 0 on success
+  \return -1 on error
+*/
+int execute(PGconn *conn, const char *stmt)
+{
+    PGresult *result;
+
+    result = NULL;
+
+    G_debug(3, "execute(): %s", stmt);
+    result = PQexec(conn, stmt);
+    if (!result || PQresultStatus(result) != PGRES_COMMAND_OK) {
+	PQclear(result);
+
+	G_warning(_("Execution failed: %s"), PQerrorMessage(conn));
+	return -1;
+    }
+
+    PQclear(result);
+    return 0;
+}
+
+#endif


Property changes on: grass/trunk/lib/vector/Vlib/read_pg.c
___________________________________________________________________
Added: svn:mime-type
   + text/x-csrc
Added: svn:eol-style
   + native

Modified: grass/trunk/lib/vector/Vlib/rewind.c
===================================================================
--- grass/trunk/lib/vector/Vlib/rewind.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/rewind.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -17,16 +17,12 @@
 #include <grass/vector.h>
 #include <grass/glocale.h>
 
-
-/*  Rewind vector data file to cause reads to start at beginning */
-/* returns 0 on success, -1 on error */
 static int rew_dummy()
 {
     return -1;
 }
 
-
-#ifndef HAVE_OGR
+#if !defined HAVE_OGR || !defined HAVE_POSTGRES
 static int format()
 {
     G_fatal_error(_("Requested format is not compiled in this version"));
@@ -37,23 +33,29 @@
 
 static int (*Rewind_array[][3]) () = {
     {
-    rew_dummy, V1_rewind_nat, V2_rewind_nat}
+	rew_dummy, V1_rewind_nat, V2_rewind_nat}
 #ifdef HAVE_OGR
     , {
-    rew_dummy, V1_rewind_ogr, V2_rewind_ogr}
+	rew_dummy, V1_rewind_ogr, V2_rewind_ogr}
     , {
-    rew_dummy, V1_rewind_ogr, V2_rewind_ogr}
+	rew_dummy, V1_rewind_ogr, V2_rewind_ogr}
 #else
     , {
-    rew_dummy, format, format}
+	rew_dummy, format, format}
     , {
-    rew_dummy, format, format}
+	rew_dummy, format, format}
 #endif
+#ifdef HAVE_POSTGRES
+    , {
+	rew_dummy, V1_rewind_pg, V2_rewind_pg}
+#else
+    , {
+	rew_dummy, format, format}
+#endif
 };
 
-
 /*!
-   \brief Rewind vector data file to cause reads to start at beginning
+   \brief Rewind vector map to cause reads to start at beginning
 
    \param Map pointer to Map_info structure
 

Modified: grass/trunk/lib/vector/Vlib/rewind_nat.c
===================================================================
--- grass/trunk/lib/vector/Vlib/rewind_nat.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/rewind_nat.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -5,10 +5,10 @@
 
    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.
+   (>=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.
@@ -16,23 +16,23 @@
 
 #include <grass/vector.h>
 
-/*!
-  \brief Rewind vector data file to cause reads to start at beginning (level 1)
+/*! \brief Rewind vector map to cause reads to start at beginning on
+  non-topological level (level 1) - native format - internal use only
+  
+  \param Map pointer to Map_info struct
 
-  \param Map vector map
-
   \return 0 on success
   \return -1 on error
 */
 int V1_rewind_nat(struct Map_info *Map)
 {
-    return (dig_fseek(&(Map->dig_fp), Map->head.head_size, SEEK_SET));
+    return dig_fseek(&(Map->dig_fp), Map->head.head_size, SEEK_SET);
 }
 
-/*!
-  \brief Rewind vector data file to cause reads to start at beginning (level 2)
+/*! \brief Rewind vector map to cause reads to start at beginning on
+  topological level (level 2) - native format - internal use only
 
-  \param Map vector map
+  \param Map pointer to Map_info struct
 
   \return 0 on success
   \return -1 on error

Modified: grass/trunk/lib/vector/Vlib/rewind_ogr.c
===================================================================
--- grass/trunk/lib/vector/Vlib/rewind_ogr.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/rewind_ogr.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -1,14 +1,14 @@
 /*!
-   \file lib/vector/Vlib/rewind.c
+   \file lib/vector/Vlib/rewind_ogr.c
 
-   \brief Vector library - rewind data (native format)
+   \brief Vector library - rewind data (OGR)
 
    Higher level functions for reading/writing/manipulating vectors.
 
-   (C) 2001-2009 by the GRASS Development Team
+   (C) 2001-2009, 2011 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.
+   (>=v2). Read the file COPYING that comes with GRASS for details.
 
    \author Radim Blazek, Piero Cavalieri 
 */
@@ -21,7 +21,7 @@
 #endif
 
 /*!
-  \brief Rewind vector data file to cause reads to start at
+  \brief Rewind vector map (OGR layer) to cause reads to start at
   beginning (level 1)
 
   \param Map pointer to Map_info structure
@@ -33,11 +33,15 @@
 {
     G_debug(2, "V1_rewind_ogr(): name = %s", Map->name);
 #ifdef HAVE_OGR
-    Map->fInfo.ogr.lines_num = 0;
-    Map->fInfo.ogr.lines_next = 0;
+    struct Format_info_ogr *ogr_info;
 
-    OGR_L_ResetReading(Map->fInfo.ogr.layer);
+    ogr_info = &(Map->fInfo.ogr);
+    
+    ogr_info->cache.lines_num = 0;
+    ogr_info->cache.lines_next = 0;
 
+    OGR_L_ResetReading(ogr_info->layer);
+
     return 0;
 #else
     G_fatal_error(_("GRASS is not compiled with OGR support"));
@@ -46,9 +50,9 @@
 }
 
 /*!
-  \brief Rewind vector data file to cause reads to start at
-  beginning (level 2)
-
+  \brief Rewind vector map (OGR layer) to cause reads to start at
+  beginning on topological level (level 2)
+  
   \param Map pointer to Map_info structure
 
   \return 0 on success

Added: grass/trunk/lib/vector/Vlib/rewind_pg.c
===================================================================
--- grass/trunk/lib/vector/Vlib/rewind_pg.c	                        (rev 0)
+++ grass/trunk/lib/vector/Vlib/rewind_pg.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -0,0 +1,93 @@
+/*!
+   \file lib/vector/Vlib/rewind_pg.c
+
+   \brief Vector library - rewind data (PostGIS layers)
+
+   Higher level functions for reading/writing/manipulating vectors.
+
+   (C) 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 Martin Landa <landa.martin gmail.com>
+*/
+
+#include <grass/vector.h>
+#include <grass/glocale.h>
+
+#ifdef HAVE_POSTGRES
+#include "pg_local_proto.h"
+#endif
+
+/*! 
+  \brief Rewind vector map (PostGIS layer) to cause reads to start
+  at beginning (level 1)
+  
+  \param Map pointer to Map_info structure
+  
+  \return 0 on success
+  \return -1 on error
+ */
+int V1_rewind_pg(struct Map_info *Map)
+{
+    G_debug(2, "V1_rewind_pg(): name = %s", Map->name);
+    
+#ifdef HAVE_POSTGRES
+    struct Format_info_pg *pg_info;
+
+    pg_info = &(Map->fInfo.pg);
+    
+    /* reset reading */
+    pg_info->next_line = 0;
+
+    /* reset cache */
+    pg_info->cache.lines_num = pg_info->cache.lines_next = 0;
+    pg_info->cache.fid = -1;
+    
+    /* close DB cursor if necessary */
+    if (pg_info->res) {
+	char stmt[DB_SQL_MAX];
+	
+	PQclear(pg_info->res);
+	pg_info->res = NULL;
+	
+	sprintf(stmt, "CLOSE %s%p",
+		pg_info->table_name, pg_info->conn);
+	if (execute(pg_info->conn, stmt) == -1) {
+	    G_warning(_("Unable to close cursor"));
+	    return -1;
+	}
+	execute(pg_info->conn, "COMMIT");
+    }
+    
+    return 0;
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+    return -1;
+#endif
+}
+
+/*!
+  \brief Rewind vector map (PostGIS layer) to cause reads to start
+  at beginning on topological level (level 2)
+  
+  \param Map pointer to Map_info structure
+
+  \return 0 on success
+  \return -1 on error
+ */
+int V2_rewind_pg(struct Map_info *Map)
+{
+    G_debug(2, "V2_rewind_pg(): name = %s", Map->name);
+#ifdef HAVE_POSTGRES
+    Map->next_line = 1;
+
+    V1_rewind_pg(Map);
+
+    return 0;
+#else
+    G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+    return -1;
+#endif
+}


Property changes on: grass/trunk/lib/vector/Vlib/rewind_pg.c
___________________________________________________________________
Added: svn:mime-type
   + text/x-csrc
Added: svn:eol-style
   + native

Modified: grass/trunk/lib/vector/Vlib/simple_features.c
===================================================================
--- grass/trunk/lib/vector/Vlib/simple_features.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/simple_features.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -19,7 +19,7 @@
 
   Reference: http://www.opengeospatial.org/standards/sfa
 
-  (C) 2009 by the GRASS Development Team
+  (C) 2009, 2011 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.
@@ -32,7 +32,7 @@
 #include <grass/vector.h>
 #include <grass/glocale.h>
 
-static int check_sftype(const struct line_pnts *, int, int, int);
+static int check_sftype(const struct line_pnts *, int, SF_FeatureType, int);
 static int get_sftype(const struct line_pnts *, int, int);
 static void print_point(const struct line_pnts *, int, int, int, FILE *);
 
@@ -41,7 +41,7 @@
 
   List of supported feature types:
    - GV_POINT    -> SF_POINT
-   - GV_LINE     -> SF_LINE / SF_LINESTRING / SF_LINEARRING
+   - GV_LINE     -> SF_LINESTRING / SF_LINEARRING
    - GV_AREA     -> SF_POLYGON
 
   \param Points  pointer to line_pnts structure
@@ -51,12 +51,41 @@
   \return SF type identificator (see list of supported types)
   \return -1 on error
 */
-int Vect_sfa_get_line_type(const struct line_pnts *Points, int type, int with_z)
+SF_FeatureType Vect_sfa_get_line_type(const struct line_pnts *Points, int type, int with_z)
 {
     return get_sftype(Points, type, with_z);
 }
 
 /*!
+  \brief Get relevant GV type
+
+  \param Map pointer to Map_info structure
+  \param type SF geometry type (SF_POINT, SF_LINESTRING, ...)
+
+  \return GV type
+  \return -1 on error
+ */
+int Vect_sfa_get_type(SF_FeatureType sftype)
+{
+    switch(sftype) {
+    case SF_POINT:
+    case SF_POINT25D:
+	return GV_POINT;
+    case SF_LINESTRING:
+    case SF_LINESTRING25D:
+    case SF_LINEARRING:
+	return GV_LINE;
+    case SF_POLYGON:
+    case SF_POLYGON25D:
+	return GV_AREA;
+    default:
+	break;
+    }
+    
+    return -1;
+}
+
+/*!
   \brief Check SF type
 
   E.g. if <em>type</em> is GV_LINE with two or more segments and the
@@ -71,7 +100,8 @@
   \return 1 if type is sftype
   \return 0 type differs from sftype
 */
-int Vect_sfa_check_line_type(const struct line_pnts *Points, int type, int sftype, int with_z)
+int Vect_sfa_check_line_type(const struct line_pnts *Points, int type,
+			     SF_FeatureType sftype, int with_z)
 {
     return check_sftype(Points, type, sftype, with_z);
 }
@@ -110,14 +140,12 @@
 */
 char *Vect_sfa_line_geometry_type(const struct line_pnts *Points, int type)
 {
-    int sftype = Vect_sfa_get_line_type(Points, type, 0);
+    SF_FeatureType sftype = Vect_sfa_get_line_type(Points, type, 0);
 
     if (sftype == SF_POINT)
 	return G_store("POINT");
     if (sftype == SF_LINESTRING)
 	return G_store("LINESTRING");
-    if (sftype == SF_LINE)
-	return G_store("LINE");
     if (sftype == SF_LINEARRING)
 	return G_store("LINEARRING");
 
@@ -149,11 +177,9 @@
 	fprintf(file, ")\n");
 	break;
     }
-    case SF_LINESTRING: case SF_LINE: case SF_LINEARRING: /* line */ {
+    case SF_LINESTRING: case SF_LINEARRING: /* line */ {
 	if (sftype == SF_LINESTRING)
 	    fprintf(file, "LINESTRING(");
-	else if (sftype ==  SF_LINE)
-	    fprintf(file, "LINE(");
 	else
 	    fprintf(file, "LINEARRING(");
 	for (i = 0; i < Points->n_points; i++) {
@@ -197,7 +223,7 @@
 */
 int Vect_sfa_is_line_simple(const struct line_pnts *Points, int type, int with_z)
 {
-    int sftype;
+    SF_FeatureType sftype;
     
     sftype = Vect_sfa_get_line_type(Points, type, with_z);
 
@@ -234,7 +260,8 @@
     return -1;
 }
 
-int check_sftype(const struct line_pnts *points, int type, int sftype, int with_z)
+int check_sftype(const struct line_pnts *points, int type,
+		 SF_FeatureType sftype, int with_z)
 {
     if (type == GV_POINT && sftype == SF_POINT) {
 	return 1;
@@ -244,9 +271,6 @@
 	if (sftype == SF_LINESTRING) {
 	    return 1;
 	}
-	if (sftype == SF_LINE && Vect_get_num_line_points(points) == 2) {
-	    return 1;
-	}
 	if (sftype == SF_LINEARRING) {
 	    if (Vect_sfa_is_line_closed(points, type, with_z))
 		return 1;
@@ -267,9 +291,6 @@
     if (check_sftype(points, type, SF_POINT, with_z))
 	return SF_POINT;
 
-    if (check_sftype(points, type, SF_LINE, with_z))
-	return SF_LINE;
-
     if (check_sftype(points, type, SF_LINEARRING, with_z))
 	return SF_LINEARRING;
 

Modified: grass/trunk/lib/vector/Vlib/write_ogr.c
===================================================================
--- grass/trunk/lib/vector/Vlib/write_ogr.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/Vlib/write_ogr.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -43,7 +43,8 @@
     
     struct bound_box box, abox;
     
-    G_debug(3, "V2__add_line_to_topo_ogr(): line = %d", line);
+    G_debug(3, "V2__add_line_to_topo_ogr(): line = %d npoints = %d", line,
+	    points->n_points);
 
     plus = &(Map->plus);
     Line = plus->Line[line];
@@ -245,19 +246,19 @@
     ret = OGR_L_CreateFeature(fInfo->layer, Ogr_feature);
 
     /* update offset array */
-    if (fInfo->offset_num >= fInfo->offset_alloc) {
-	fInfo->offset_alloc += 1000;
-	fInfo->offset = (int *) G_realloc(fInfo->offset,
-					  fInfo->offset_alloc *
-					  sizeof(int));
+    if (fInfo->offset.array_num >= fInfo->offset.array_alloc) {
+	fInfo->offset.array_alloc += 1000;
+	fInfo->offset.array = (int *) G_realloc(fInfo->offset.array,
+						fInfo->offset.array_alloc *
+						sizeof(int));
     }
 
-    offset = fInfo->offset_num;
+    offset = fInfo->offset.array_num;
     
-    fInfo->offset[fInfo->offset_num++] = (int) OGR_F_GetFID(Ogr_feature);
+    fInfo->offset.array[fInfo->offset.array_num++] = (int) OGR_F_GetFID(Ogr_feature);
     if (Ogr_geom_type == wkbPolygon || Ogr_geom_type == wkbPolygon25D) {
 	/* register exterior ring in offset array */
-	fInfo->offset[fInfo->offset_num++] = 0; 
+	fInfo->offset.array[fInfo->offset.array_num++] = 0; 
     }
       
     /* destroy */
@@ -329,7 +330,7 @@
 		CPoints = Vect_new_line_struct();
 		Vect_append_point(CPoints, x, y, 0.0);
 		
-		FID = Map->fInfo.ogr.offset[offset];
+		FID = Map->fInfo.ogr.offset.array[offset];
 
 		dig_line_box(CPoints, &box);
 		cline = dig_add_line(plus, GV_CENTROID,
@@ -380,6 +381,8 @@
 			  off_t offset,
 			  const struct line_pnts *points, const struct line_cats *cats)
 {
+    G_debug(3, "V1_rewrite_line_ogr(): line=%d type=%d offset=%llu",
+	    line, type, offset);
 #ifdef HAVE_OGR
     if (type != V1_read_line_ogr(Map, NULL, NULL, offset)) {
 	G_warning(_("Unable to rewrite feature (incompatible feature types)"));
@@ -412,6 +415,9 @@
 off_t V2_rewrite_line_ogr(struct Map_info *Map, int line, int type, off_t offset,
 			  const struct line_pnts *points, const struct line_cats *cats)
 {
+    G_debug(3, "V2_rewrite_line_ogr(): line=%d type=%d offset=%llu",
+	    line, type, offset);
+
 #ifdef HAVE_OGR
     if (type != V2_read_line_ogr(Map, NULL, NULL, line)) {
 	G_warning(_("Unable to rewrite feature (incompatible feature types)"));
@@ -446,10 +452,11 @@
 	return -1;
     }
     
-    if (offset >= Map->fInfo.ogr.offset_num)
+    if (offset >= Map->fInfo.ogr.offset.array_num)
 	return -1;
     
-    if (OGR_L_DeleteFeature(Map->fInfo.ogr.layer, Map->fInfo.ogr.offset[offset]) != OGRERR_NONE)
+    if (OGR_L_DeleteFeature(Map->fInfo.ogr.layer,
+			    Map->fInfo.ogr.offset.array[offset]) != OGRERR_NONE)
 	return -1;
     
     return 0;

Modified: grass/trunk/lib/vector/diglib/frmt.c
===================================================================
--- grass/trunk/lib/vector/diglib/frmt.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/diglib/frmt.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -7,16 +7,18 @@
  *
  * PURPOSE:      Lower level functions for reading/writing/manipulating vectors.
  *
- * COPYRIGHT:    (C) 2001 by the GRASS Development Team
+ * COPYRIGHT:    (C) 2001, 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.
+ *               This program is free software under the GNU General
+ *               Public License (>=v2). Read the file COPYING that
+ *               comes with GRASS for details.
  *
  *****************************************************************************/
 #include <string.h>
 #include <stdio.h>
+
 #include <grass/vector.h>
+#include <grass/glocale.h>
 
 /*!
   \brief Read external vector format file
@@ -57,19 +59,37 @@
 		frmt = GV_FORMAT_OGR;
 	    }
 #endif
+#ifdef HAVE_POSTGRES
+	    if (G_strcasecmp(ptr, "postgis") == 0) {
+		frmt = GV_FORMAT_POSTGIS;
+	    }
+#endif
 	}
     }
     if (frmt == -1) {
 	G_warning("Vector format not recognized: %s", buff);
-	return (-1);
+	return -1;
     }
 
     /* init format info values */
 #ifdef HAVE_OGR
-    finfo->ogr.dsn = NULL;
-    finfo->ogr.layer_name = NULL;
+    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;
+    }
 #endif
 
+#ifdef HAVE_POSTGRES
+    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;
+    }
+#endif
+
     while (G_getl2(buff, 2000, dascii)) {
 	G_chop(buff);
 
@@ -86,11 +106,21 @@
 	    ptr++;
 
 #ifdef HAVE_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, "TABLE") == 0)
+		finfo->pg.table_name = G_store(ptr);
+	}
+#endif
     }
 
     return frmt;

Modified: grass/trunk/lib/vector/diglib/plus_struct.c
===================================================================
--- grass/trunk/lib/vector/diglib/plus_struct.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/diglib/plus_struct.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -51,14 +51,14 @@
     int cnt, n_edges;
     struct P_node *ptr;
 
-    G_debug(3, "dig_Rd_P_node()");
+    G_debug(4, "dig_Rd_P_node()");
 
 
     if (0 >= dig__fread_port_P(&cnt, 1, fp))
 	return (-1);
 
     if (cnt == 0) {		/* dead */
-	G_debug(3, "    node is dead");
+	G_debug(4, "    node is dead");
 	Plus->Node[n] = NULL;
 	return 0;
     }
@@ -105,12 +105,12 @@
     int i, n_edges = 0;
     struct P_node *ptr;
 
-    G_debug(3, "dig_Wr_P_node()");
+    G_debug(4, "dig_Wr_P_node()");
     ptr = Plus->Node[n];
 
     /* If NULL i.e. dead write just 0 instead of number of lines */
     if (ptr == NULL) {
-	G_debug(3, "    node is dead -> write 0 only");
+	G_debug(4, "    node is dead -> write 0 only");
 	i = 0;
 	if (0 >= dig__fwrite_port_P(&i, 1, fp))
 	    return (-1);
@@ -151,13 +151,13 @@
     char tp;
     struct P_line *ptr;
 
-    G_debug(3, "dig_Rd_P_line()");
+    G_debug(4, "dig_Rd_P_line()");
 
     if (0 >= dig__fread_port_C(&tp, 1, fp))
 	return (-1);
 
     if (tp == 0) {		/* dead */
-	G_debug(3, "    line is dead");
+	G_debug(4, "    line is dead");
 	Plus->Line[n] = NULL;
 	return 0;
     }
@@ -248,7 +248,7 @@
 
     /* if NULL i.e. dead write just 0 instead of type */
     if (ptr == NULL) {
-	G_debug(3, "    line is dead -> write 0 only");
+	G_debug(4, "    line is dead -> write 0 only");
 	ch = 0;
 	if (0 >= dig__fwrite_port_C(&ch, 1, fp))
 	    return (-1);
@@ -331,7 +331,7 @@
     int cnt;
     struct P_area *ptr;
 
-    G_debug(3, "dig_Rd_P_area(): n = %d", n);
+    G_debug(4, "dig_Rd_P_area(): n = %d", n);
 
     if (0 >= dig__fread_port_P(&cnt, 1, fp))
 	return (-1);
@@ -561,7 +561,7 @@
 	return (-1);
     }
 
-    G_debug(1, "topo off_t size = %d", ptr->off_t_size);
+    G_debug(2, "topo off_t size = %d", ptr->off_t_size);
 
     /* byte 10 : dimension 2D or 3D */
     if (0 >= dig__fread_port_C((char *)buf, 1, fp))

Modified: grass/trunk/lib/vector/diglib/update.c
===================================================================
--- grass/trunk/lib/vector/diglib/update.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/lib/vector/diglib/update.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -35,8 +35,6 @@
  */
 void dig_line_add_updated(struct Plus_head *Plus, int line)
 {
-    int i;
-
     G_debug(3, "dig_line_add_updated(): line = %d", line);
 
     /* Check if already in list

Modified: grass/trunk/vector/v.external/Makefile
===================================================================
--- grass/trunk/vector/v.external/Makefile	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/vector/v.external/Makefile	2012-02-05 17:19:12 UTC (rev 50670)
@@ -2,15 +2,14 @@
 
 PGM=v.external
 
-LIBES = $(VECTORLIB) $(GISLIB) $(GDALLIBS)
-DEPENDENCIES = $(VECTORDEP) $(GISDEP)
+LIBES = $(VECTORLIB) $(GISLIB) $(DBMIBASELIB) $(GDALLIBS) $(PQLIBPATH) $(PQLIB)
+DEPENDENCIES = $(VECTORDEP) $(GISDEP) $(DBMIBASEDEP) 
 
 EXTRA_INC = $(VECT_INC)
 EXTRA_CFLAGS = $(VECT_CFLAGS)
+EXTRA_LDFLAGS = $(PQLIBPATH)
 
 include $(MODULE_TOPDIR)/include/Make/Module.make
 
-ifneq ($(USE_OGR),)
 default: cmd
-endif
 

Modified: grass/trunk/vector/v.external/args.c
===================================================================
--- grass/trunk/vector/v.external/args.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/vector/v.external/args.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -12,11 +12,12 @@
     options->dsn->key = "dsn";
     options->dsn->type = TYPE_STRING;
     options->dsn->gisprompt = "old_file,file,dsn";
-    options->dsn->label = _("Name of input OGR data source");
+    options->dsn->label = _("Name of input OGR/PostGIS data source");
     options->dsn->description = _("Examples:\n"
 				  "\t\tESRI Shapefile: directory containing a shapefile\n"
 				  "\t\tMapInfo File: directory containing a mapinfo file\n"
-				  "\t\tPostGIS database: PG:dbname=<database>");
+				  "\t\tPostGIS database accessed by OGR: PG:dbname=<database> user=grass\n"
+				  "\t\tPostGIS database accessed directly: dbname=<database> user=grass");
     options->dsn->required = YES;
 
     options->layer = G_define_option();
@@ -24,7 +25,7 @@
     options->layer->type = TYPE_STRING;
     options->layer->required = NO;
     options->layer->multiple = NO;
-    options->layer->label = _("Name of input OGR layer");
+    options->layer->label = _("Name of OGR layer or PostGIS feature table to be linked");
     options->layer->description = _("Examples:\n"
 				    "\t\tESRI Shapefile: shapefile name\n"
 				    "\t\tMapInfo File: mapinfo file name\n"
@@ -34,7 +35,7 @@
     
     options->output = G_define_standard_option(G_OPT_V_OUTPUT);
     options->output->required = NO;
-    options->output->description = _("Name for output GRASS vector map");
+    options->output->description = _("Name for output GRASS vector map (default: input layer)");
 
     flags->format = G_define_flag();
     flags->format->key = 'f';
@@ -59,6 +60,10 @@
     flags->topo->key = 'b';
     flags->topo->description = _("Do not build topology");
     
+    flags->postgis = G_define_flag();
+    flags->postgis->key = 'p';
+    flags->postgis->description = _("Link PostGIS tables directly instead of using OGR");
+    
     if (G_parser(argc, argv))
 	exit(EXIT_FAILURE);
 }

Modified: grass/trunk/vector/v.external/list.c
===================================================================
--- grass/trunk/vector/v.external/list.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/vector/v.external/list.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -1,13 +1,28 @@
+#include <string.h>
+
 #include <grass/gis.h>
 #include <grass/vector.h>
+#include <grass/dbmi.h>
 #include <grass/glocale.h>
 
+#ifdef HAVE_OGR
 #include "ogr_api.h"
+#endif
+#ifdef HAVE_POSTGRES
+#include <libpq-fe.h>
+#endif
 #include "local_proto.h"
 
+#ifdef HAVE_OGR
+static int list_layers_ogr(FILE *, const char *, const char *, int, int *);
+#endif
+#ifdef HAVE_POSTGRES
+static int list_layers_pg(FILE *, const char *, const char *, int, int *);
+#endif
+
 void list_formats(FILE *fd) {
+#ifdef HAVE_OGR
     int i;
-    
     OGRSFDriverH Ogr_driver;
     
     G_message(_("Supported OGR formats for reading:"));
@@ -15,10 +30,88 @@
 	Ogr_driver = OGRGetDriver(i);
 	fprintf(fd, "%s\n", OGR_Dr_GetName(Ogr_driver));
     }
+#else
+    G_fatal_error(_("GRASS is not compiled with OGR support"));
+#endif
 }
 
-int list_layers(FILE *fd, const char *dsn, const char *layer, int print_types, int *is3D)
+int list_layers(FILE *fd, const char *dsn, const char *layer, int print_types, int use_postgis, int *is3D)
 {
+    if (use_postgis) {
+#ifdef HAVE_POSTGRES
+	return list_layers_pg(fd, dsn, layer, print_types, is3D);
+#else
+	G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
+#endif
+    }
+#ifdef HAVE_OGR
+    return list_layers_ogr(fd, dsn, layer, print_types, is3D);
+#else
+    G_fatal_error(_("GRASS is not compiled with OGR support"));
+#endif
+
+    return -1;
+}
+
+int list_layers_pg(FILE *fd, const char *conninfo, const char *table, int print_types, int *is3D)
+{
+#ifdef HAVE_POSTGRES
+    int row, ntables, ret;
+    char *value;
+    PGconn *conn;
+    PGresult *res;
+    
+    dbString sql;
+    
+    ret = -1;
+    
+    conn = PQconnectdb(conninfo);
+    G_debug(1, "PQconnectdb(): %s", conninfo);
+    if (PQstatus(conn) == CONNECTION_BAD)
+	G_fatal_error("%s\n%s", _("Connection to PostgreSQL database failed."), 
+		      PQerrorMessage(conn));
+    
+    db_init_string(&sql);
+    db_set_string(&sql, "SELECT f_table_name, type "
+		  "FROM geometry_columns");
+    G_debug(2, "SQL: %s", db_get_string(&sql));
+    res = PQexec(conn, db_get_string(&sql));
+    if (PQresultStatus(res) != PGRES_TUPLES_OK)
+	G_fatal_error("%s\n%s", _("No feature tables found in database."),
+		      PQresultErrorMessage(res));
+    
+    ntables = PQntuples(res);
+    G_debug(3, "   nrows = %d", ntables);
+    if (fd)
+	G_message(_("Database contains %d feature table(s):"), ntables);
+
+    for (row = 0; row < ntables; row++) {
+	value = PQgetvalue(res, row, 0);
+	if (fd) {
+	    if (print_types)
+		fprintf(fd, "%s (%s)\n", value, PQgetvalue(res, row, 1));
+	    else
+		fprintf(fd, "%s\n", value);
+	}
+	if (table && strcmp(value, table) == 0) {
+	    ret = row;
+	    *is3D = WITHOUT_Z;
+	}
+    }
+    
+    PQclear(res);
+    PQfinish(conn);
+    G_debug(1, "PQfinish()");
+    
+    return ret;
+#else
+    G_fatal_error(_("GRASS not compiled with PostgreSQL/PostGIS support"));
+#endif
+}
+
+#ifdef HAVE_OGR
+int list_layers_ogr(FILE *fd, const char *dsn, const char *layer, int print_types, int *is3D)
+{
     int i, ret;
     int nlayers;
     char *layer_name;
@@ -42,6 +135,7 @@
     if (fd)
 	G_message(_("Data source <%s> (format '%s') contains %d layers:"),
 		  dsn, OGR_Dr_GetName(OGR_DS_GetDriver(Ogr_ds)), nlayers);
+    
 
     for (i = 0; i < nlayers; i++) {
 	Ogr_layer = OGR_DS_GetLayer(Ogr_ds, i);
@@ -77,3 +171,4 @@
 
     return ret;
 }
+#endif /* HAVE_OGR */

Modified: grass/trunk/vector/v.external/local_proto.h
===================================================================
--- grass/trunk/vector/v.external/local_proto.h	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/vector/v.external/local_proto.h	2012-02-05 17:19:12 UTC (rev 50670)
@@ -6,7 +6,7 @@
 };
 
 struct _flags {
-    struct Flag *format, *list, *tlist, *topo;
+    struct Flag *format, *layer, *tlist, *topo, *postgis, *list;
 };
 
 /* args.c */
@@ -15,6 +15,6 @@
 
 /* list.c */
 void list_formats(FILE *);
-int list_layers(FILE *, const char *, const char *, int, int *);
+int list_layers(FILE *, const char *, const char *, int, int, int *);
 
 #endif

Modified: grass/trunk/vector/v.external/main.c
===================================================================
--- grass/trunk/vector/v.external/main.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/vector/v.external/main.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -49,14 +49,22 @@
     G_add_keyword(_("import"));
     G_add_keyword(_("input"));
     G_add_keyword(_("external")); 
-    module->description = _("Creates a new pseudo-vector map as a link to an OGR-supported layer.");
     
+    module->description = _("Creates a new pseudo-vector map as a link to an OGR-supported layer "
+			    "or a PostGIS feature table.");
     parse_args(argc, argv,
 	       &options, &flags);
     
-    OGRRegisterAll();
-    
+#ifdef HAVE_OGR
+    if (!flags.postgis->answer)
+	OGRRegisterAll();
+#endif
+
     if (flags.format->answer) {
+	if (flags.postgis->answer) {
+	    G_fatal_error(_("Flags -%c and -%c are mutually exclusive"),
+			  flags.format->key, flags.postgis->key);
+	}
 	list_formats(stdout);
 	exit(EXIT_SUCCESS);
     }
@@ -66,6 +74,7 @@
 	    G_fatal_error(_("Required parameter <%s> not set"), options.dsn->key);
 	list_layers(stdout, options.dsn->answer, NULL,
 		    flags.tlist->answer ? TRUE : FALSE,
+		    flags.postgis->answer,
 		    NULL);
 	exit(EXIT_SUCCESS);
     }
@@ -76,7 +85,7 @@
 	output = options.output->answer;
     
     ilayer = list_layers(NULL, options.dsn->answer, options.layer->answer,
-			 FALSE, &is3D);
+			 FALSE, flags.postgis->answer, &is3D);
     if (ilayer == -1) {
 	G_fatal_error(_("Layer <%s> not available"), options.layer->answer);
     }
@@ -110,19 +119,25 @@
 	G_fatal_error("Unable to create file '%s'", buf);
     }
     
-    fprintf(fd, "FORMAT: ogr\n");
-    fprintf(fd, "DSN: %s\n", options.dsn->answer);
-    fprintf(fd, "LAYER: %s\n", options.layer->answer);
-    
+    if (flags.postgis->answer) {
+	fprintf(fd, "FORMAT: postgis\n");
+	fprintf(fd, "CONNINFO: %s\n", options.dsn->answer);
+	fprintf(fd, "TABLE: %s\n", options.layer->answer);
+    }
+    else {
+	fprintf(fd, "FORMAT: ogr\n");
+	fprintf(fd, "DSN: %s\n", options.dsn->answer);
+	fprintf(fd, "LAYER: %s\n", options.layer->answer);
+    }
     fclose(fd);
     
     if (!flags.topo->answer) {
-      Vect_open_old(&Map, output, G_mapset());
-      Vect_build(&Map);
-      Vect_close(&Map);
+	Vect_open_old(&Map, output, G_mapset());
+	Vect_build(&Map);
+	Vect_close(&Map);
     }
-
+    
     G_done_msg(_("Link to vector map <%s> created."), output);
-
+    
     exit(EXIT_SUCCESS);
 }

Modified: grass/trunk/vector/v.info/print.c
===================================================================
--- grass/trunk/vector/v.info/print.c	2012-02-05 12:36:06 UTC (rev 50669)
+++ grass/trunk/vector/v.info/print.c	2012-02-05 17:19:12 UTC (rev 50670)
@@ -170,7 +170,7 @@
     int map_type;
 
     map_type = Vect_maptype(Map);
-
+    
     fprintf(stdout, "name=%s\n",
 	    Vect_get_name(Map));
     fprintf(stdout, "mapset=%s\n",
@@ -187,12 +187,20 @@
     if (map_type == GV_FORMAT_OGR ||
 	map_type == GV_FORMAT_OGR_DIRECT) {
 	fprintf(stdout, "format=%s,%s\n",
-		Vect_maptype_info(Map), Vect_get_ogr_format_info(Map));
+		Vect_maptype_info(Map), Vect_get_finfo_format_info(Map));
 	fprintf(stdout, "ogr_layer=%s\n",
-		Vect_get_ogr_layer_name(Map));
+		Vect_get_finfo_layer_name(Map));
 	fprintf(stdout, "ogr_dsn=%s\n",
-		Vect_get_ogr_dsn_name(Map));
+		Vect_get_finfo_dsn_name(Map));
     }
+    else if (map_type == GV_FORMAT_POSTGIS) {
+	fprintf(stdout, "format=%s\n",
+		Vect_maptype_info(Map));
+	fprintf(stdout, "pg_table=%s\n",
+		Vect_get_finfo_layer_name(Map));
+	fprintf(stdout, "pg_dbname=%s\n",
+		Vect_get_finfo_dsn_name(Map));
+    }
     else {
 	fprintf(stdout, "format=%s\n",
 		Vect_maptype_info(Map));
@@ -255,7 +263,7 @@
     sprintf(line, "%-17s%s", _("Mapset:"),
 	    Vect_get_mapset(Map));
     printline(line);
-
+    
     sprintf(line, "%-17s%s", _("Location:"),
 	    G_location());
     printline(line);
@@ -273,17 +281,30 @@
     if (map_type == GV_FORMAT_OGR ||
 	map_type == GV_FORMAT_OGR_DIRECT) {
 	sprintf(line, "%-17s%s (%s)", _("Map format:"),
-		Vect_maptype_info(Map), Vect_get_ogr_format_info(Map));
+		Vect_maptype_info(Map), Vect_get_finfo_format_info(Map));
 	printline(line);
 	
 	/* for OGR format print also datasource and layer */
 	sprintf(line, "%-17s%s", _("OGR layer:"),
-		Vect_get_ogr_layer_name(Map));
+		Vect_get_finfo_layer_name(Map));
 	printline(line);
 	sprintf(line, "%-17s%s", _("OGR datasource:"),
-		Vect_get_ogr_dsn_name(Map));
+		Vect_get_finfo_dsn_name(Map));
 	printline(line);
     }
+    else if (map_type == GV_FORMAT_POSTGIS) {
+	sprintf(line, "%-17s%s", _("Map format:"),
+		Vect_maptype_info(Map));
+	printline(line);
+	
+	/* for OGR format print also datasource and layer */
+	sprintf(line, "%-17s%s", _("PostGIS table:"),
+		Vect_get_finfo_layer_name(Map));
+	printline(line);
+	sprintf(line, "%-17s%s", _("PostGIS database:"),
+		Vect_get_finfo_dsn_name(Map));
+	printline(line);
+    }
     else {
 	sprintf(line, "%-17s%s", _("Map format:"),
 		Vect_maptype_info(Map));



More information about the grass-commit mailing list