[Featureserver] PostGis w/o OGR

Josh Livni mailing_lists at umbrellaconsulting.com
Sun Dec 16 13:25:07 EST 2007


Please note, I've attached a new patch for the PostGIS Datasource, for 
those who want/need to be able to use it without the OGR requirement.  
This patch:
 - Fixes bug my previous patch had with parsing multipolygons in a mixed 
multi-simple-polygon table
 - Ensures that if you're applying a bbox filter in your query, that 
gets used in addition, rather than instead of, other filters you may 
have requested
 - Allows for use of 'order=columnName', to return features in some 
ascending order

Nobody else seems to have responded to say if my last patch was of 
interest, but in case you've been using it on the quiet, you will 
probably want to use this one instead.

Cheers,

 -Josh


Christopher Schmidt wrote:
> On Tue, Dec 11, 2007 at 10:16:30AM -0800, Josh Livni wrote:
>   
>> I recently had the need to remove the OGR dependency from PostGIS.py, 
>> which is nice if you want to run FeatureServer with PostGIS on a box 
>> where installing OGR could be a hassle.
>>
>> If anyone else would find this simple modification helpful, please feel 
>> free to make use of the attached patch.
>>
>> Note:  I've tested the patch with simple and multi geometries, on tables 
>> with mixed simple and multi geometries.  As far as I can tell I've got 
>> it so it returns the same thing it used to (eg it strips out all but the 
>> first geometry in a multigeometry situation), however it's extremely 
>> possible that I missed a case in there somewhere. 
>>
>> If anyone else wants to test this patch so Chris might feel extra 
>> comfortable committing it (as he noted, it could be considered a 
>> regression going from OGR parsing to kludgy string manipulation), please 
>> test away and post results.  Either way, hopefully someone finds it useful.
>>     
>
> I hope to be able to write some test cases for this and integrate this
> myself at some point, but additional feedback from other users will
> accelerate the process. Dropping the OGR dependancy for PostGIS
> datasources would be a big win if we can do it.
>
> Regards,
>   
-------------- next part --------------
Index: PostGIS.py
===================================================================
--- PostGIS.py	(revision 359)
+++ PostGIS.py	(working copy)
@@ -1,13 +1,12 @@
 from FeatureServer.DataSource import DataSource, Feature
-from FeatureServer.DataSource.OGR import OGR
-import psycopg, copy, re, ogr
+import psycopg, copy, re
 
 class PostGIS (DataSource):
     """PostGIS datasource. Setting up the table is beyond the scope of
        FeatureServer."""
     wkt_linestring_match = re.compile(r'\(([^()]+)\)')
 
-    def __init__(self, name, srid = 4326, fid = "ogc_fid", geometry = "wkb_geometry", order = "", writable = True, **args):
+    def __init__(self, name, srid = 4326, fid = "ogc_fid", geometry = "the_geom", order = "", writable = True, **args):
         DataSource.__init__(self, name, **args)
         self.table      = args["layer"]
         self.fid_col    = fid
@@ -77,13 +76,6 @@
         else:
             raise Exception("Couldn't create WKT from geometry of type %s (%s). Only Point, Line, Polygon are supported." % (geom['type'], geom)) 
 
-    def from_wkb (self, geom):
-        try:
-            ogrgeom = ogr.CreateGeometryFromWkb(geom)
-            return OGR.freeze_geometry(ogrgeom)
-        except:
-            return None 
-
     def from_wkt (self, geom):
         coords = []
         for line in self.wkt_linestring_match.findall(geom):
@@ -99,9 +91,21 @@
             coords = coords[0]
         elif geom.startswith("POLYGON"):
             geomtype = "Polygon"
+        elif geom.startswith("MULTIPOINT"):
+            return self.from_wkt('POINT' + geom[10:14] + ')')
+        elif geom.startswith("MULTILINESTRING"):
+            if geom.find(',(') >= 0:
+                return self.from_wkt('LINESTRING' + geom[11:geom.index(',(')])
+            else:
+                return self.from_wkt('LINESTRING' + geom[11:])
+        elif geom.startswith("MULTIPOLYGON"):
+            if geom.find(',((') >= 0:
+                return self.from_wkt('POLYGON' + geom[13:geom.index(',((')])
+            else:
+                return self.from_wkt('POLYGON' + geom[13:])
         else:
             geomtype = geom[:geom.index["("]]
-            raise Error("Unsupported geometry type %s" % geomtype)
+            raise Exception("Unsupported geometry type %s" % geomtype)
         return {"type": geomtype, "coordinates": coords}
 
     def id_sequence (self):
@@ -142,32 +146,33 @@
         cursor = self.db.cursor()
 
         if action.id:
-            sql = "SELECT AsBinary(%s) as fs_binary_geom_col, * FROM \"%s\" WHERE %s = %%(%s)d" % (
+            sql = "SELECT AsText(%s) as fs_text_geom, * FROM \"%s\" WHERE %s = %%(%s)d" % (
                     self.geom_col, self.table, self.fid_col, self.fid_col )
             cursor.execute(str(sql), {self.fid_col: action.id})
             result = [cursor.fetchone()]
         else:
             filters = []
             attrs   = {}
-            if action.bbox:
-                filters.append( "%s && SetSRID('BOX3D(%f %f,%f %f)'::box3d, %s) and intersects(%s, SetSRID('BOX3D(%f %f,%f %f)'::box3d, %s))" % (
-                                        (self.geom_col,) + tuple(action.bbox) + (self.srid,) + (self.geom_col,) + (tuple(action.bbox) + (self.srid,))))
             if action.attributes:
                 match = Feature(props = action.attributes)
                 filters = self.feature_predicates(match)
                 attrs = action.attributes
+            if action.bbox:
+                filters.append( "%s && SetSRID('BOX3D(%f %f,%f %f)'::box3d, %s) and intersects(%s, SetSRID('BOX3D(%f %f,%f %f)'::box3d, %s))" % (
+                                        (self.geom_col,) + tuple(action.bbox) + (self.srid,) + (self.geom_col,) + (tuple(action.bbox) + (self.srid,))))
 
-            sql = "SELECT AsBinary(%s) as fs_binary_geom_col, * FROM \"%s\"" % (self.geom_col, self.table)
+            sql = "SELECT AsText(%s) as fs_text_geom, * FROM \"%s\"" % (self.geom_col, self.table)
             if filters:
                 sql += " WHERE " + " AND ".join(filters)
             if self.order:
-                sql += self.order
+                sql += " ORDER BY " + self.order
             if action.maxfeatures:
                 sql += " LIMIT %d" % action.maxfeatures
             else:   
                 sql += " LIMIT 1000"
             if action.startfeature:
                 sql += " OFFSET %d" % action.startfeature
+
             cursor.execute(str(sql), attrs)
             result = cursor.fetchall() # should use fetchmany(action.maxfeatures)
 
@@ -175,13 +180,14 @@
         features = []
         for row in result:
             props = dict(zip(columns, row))
-            geom  = self.from_wkb(props['fs_binary_geom_col'])
+            geom  = self.from_wkt(props['fs_text_geom'])
             id = props[self.fid_col]
-	    del props[self.fid_col]
+            del props[self.fid_col]
             del props[self.geom_col]
-            del props['fs_binary_geom_col']
+            del props['fs_text_geom']
             for key, value in props.items():
-	    	if isinstance(value, str): props[key] = unicode(value, "utf-8")
-	    if (geom):
-	    	features.append( Feature( id, geom, props ) ) 
+                if isinstance(value, str): 
+                        props[key] = unicode(value, "utf-8")
+            if (geom):
+                features.append( Feature( id, geom, props ) ) 
         return features


More information about the Featureserver mailing list