From f110f91a0399afad8db9b2925737074d185d20bf Mon Sep 17 00:00:00 2001 From: Justin Bronn Date: Tue, 21 Apr 2009 21:25:47 +0000 Subject: [PATCH] [1.0.X] Fixed various Oracle errata and test failures present in this branch (including not going to 11). Backport of Oracle-related changes from trunk in r10197. git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@10614 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/gis/db/models/sql/query.py | 15 ++++-- django/contrib/gis/tests/__init__.py | 13 ++--- django/contrib/gis/tests/distapp/tests.py | 22 +++++++-- django/contrib/gis/tests/geoapp/tests.py | 2 +- django/contrib/gis/tests/relatedapp/tests.py | 50 ++++++++++++++------ 5 files changed, 68 insertions(+), 34 deletions(-) diff --git a/django/contrib/gis/db/models/sql/query.py b/django/contrib/gis/db/models/sql/query.py index 77a7796be0..0376e266e1 100644 --- a/django/contrib/gis/db/models/sql/query.py +++ b/django/contrib/gis/db/models/sql/query.py @@ -201,7 +201,7 @@ class GeoQuery(sql.Query): """ if SpatialBackend.oracle: # Running through Oracle's first. - value = super(GeoQuery, self).convert_values(value, field) + value = super(GeoQuery, self).convert_values(value, field or GeomField()) if isinstance(field, DistanceField): # Using the field's distance attribute, can instantiate # `Distance` with the right context. @@ -325,15 +325,22 @@ class GeoQuery(sql.Query): return self._check_geo_field(self.model, field_name) ### Field Classes for `convert_values` #### -class AreaField(object): +class BaseField(object): + def get_internal_type(self): + "Overloaded method so OracleQuery.convert_values doesn't balk." + return None + +if SpatialBackend.oracle: BaseField.empty_strings_allowed = False + +class AreaField(BaseField): def __init__(self, area_att): self.area_att = area_att -class DistanceField(object): +class DistanceField(BaseField): def __init__(self, distance_att): self.distance_att = distance_att # Rather than use GeometryField (which requires a SQL query # upon instantiation), use this lighter weight class. -class GeomField(object): +class GeomField(BaseField): pass diff --git a/django/contrib/gis/tests/__init__.py b/django/contrib/gis/tests/__init__.py index fe7e33311c..071b708f7f 100644 --- a/django/contrib/gis/tests/__init__.py +++ b/django/contrib/gis/tests/__init__.py @@ -13,7 +13,7 @@ def geo_suite(): from django.contrib.gis.utils import HAS_GEOIP # Tests that require use of a spatial database (e.g., creation of models) - test_models = ['geoapp',] + test_models = ['geoapp', 'layermap', 'relatedapp'] # Tests that do not require setting up and tearing down a spatial database. test_suite_names = [ @@ -21,15 +21,8 @@ def geo_suite(): 'test_measure', ] if HAS_GDAL: - if oracle: - # TODO: There's a problem with `select_related` and GeoQuerySet on - # Oracle -- e.g., GeoModel.objects.distance(geom, field_name='fk__point') - # doesn't work so we don't test `relatedapp`. - test_models += ['distapp', 'layermap'] - elif postgis: - test_models += ['distapp', 'layermap', 'relatedapp'] - elif mysql: - test_models += ['relatedapp', 'layermap'] + if oracle or postgis: + test_models.append('distapp') test_suite_names += [ 'test_gdal_driver', diff --git a/django/contrib/gis/tests/distapp/tests.py b/django/contrib/gis/tests/distapp/tests.py index 057e2f715e..05bb4a2a0a 100644 --- a/django/contrib/gis/tests/distapp/tests.py +++ b/django/contrib/gis/tests/distapp/tests.py @@ -115,8 +115,12 @@ class DistanceTest(unittest.TestCase): # with different projected coordinate systems. dist1 = SouthTexasCity.objects.distance(lagrange, field_name='point') dist2 = SouthTexasCity.objects.distance(lagrange) # Using GEOSGeometry parameter - dist3 = SouthTexasCityFt.objects.distance(lagrange.ewkt) # Using EWKT string parameter. - dist4 = SouthTexasCityFt.objects.distance(lagrange) + if oracle: + dist_qs = [dist1, dist2] + else: + dist3 = SouthTexasCityFt.objects.distance(lagrange.ewkt) # Using EWKT string parameter. + dist4 = SouthTexasCityFt.objects.distance(lagrange) + dist_qs = [dist1, dist2, dist3, dist4] # Original query done on PostGIS, have to adjust AlmostEqual tolerance # for Oracle. @@ -124,7 +128,7 @@ class DistanceTest(unittest.TestCase): else: tol = 5 # Ensuring expected distances are returned for each distance queryset. - for qs in [dist1, dist2, dist3, dist4]: + for qs in dist_qs: for i, c in enumerate(qs): self.assertAlmostEqual(m_distances[i], c.distance.m, tol) self.assertAlmostEqual(ft_distances[i], c.distance.survey_ft, tol) @@ -194,8 +198,16 @@ class DistanceTest(unittest.TestCase): # (thus, Houston and Southside place will be excluded as tested in # the `test02_dwithin` above). qs1 = SouthTexasCity.objects.filter(point__distance_gte=(self.stx_pnt, D(km=7))).filter(point__distance_lte=(self.stx_pnt, D(km=20))) - qs2 = SouthTexasCityFt.objects.filter(point__distance_gte=(self.stx_pnt, D(km=7))).filter(point__distance_lte=(self.stx_pnt, D(km=20))) - for qs in qs1, qs2: + + # Oracle 11 incorrectly thinks spatial reference system for the + # SouthTexasCityFt model is not projected, so omit. + if oracle: + dist_qs = (qs1,) + else: + qs2 = SouthTexasCityFt.objects.filter(point__distance_gte=(self.stx_pnt, D(km=7))).filter(point__distance_lte=(self.stx_pnt, D(km=20))) + dist_qs = (qs1, qs2) + + for qs in dist_qs: cities = self.get_names(qs) self.assertEqual(cities, ['Bellaire', 'Pearland', 'West University Place']) diff --git a/django/contrib/gis/tests/geoapp/tests.py b/django/contrib/gis/tests/geoapp/tests.py index 2a146d5f59..404e406786 100644 --- a/django/contrib/gis/tests/geoapp/tests.py +++ b/django/contrib/gis/tests/geoapp/tests.py @@ -150,7 +150,7 @@ class GeoModelTest(unittest.TestCase): if SpatialBackend.oracle: # No precision parameter for Oracle :-/ import re - gml_regex = re.compile(r'-104.60925199\d+,38.25500\d+ ') + gml_regex = re.compile(r'-104.60925\d+,38.25500\d+ ') for ptown in [ptown1, ptown2]: self.assertEqual(True, bool(gml_regex.match(ptown.gml))) else: diff --git a/django/contrib/gis/tests/relatedapp/tests.py b/django/contrib/gis/tests/relatedapp/tests.py index 827ea1d989..a35836773a 100644 --- a/django/contrib/gis/tests/relatedapp/tests.py +++ b/django/contrib/gis/tests/relatedapp/tests.py @@ -1,6 +1,6 @@ import os, unittest from django.contrib.gis.geos import * -from django.contrib.gis.tests.utils import no_mysql, postgis +from django.contrib.gis.tests.utils import no_mysql, no_oracle, oracle, postgis from django.conf import settings from models import City, Location, DirectoryEntry @@ -19,6 +19,7 @@ class RelatedGeoModelTest(unittest.TestCase): c = City(name=name, state=state, location=loc) c.save() + @no_oracle # There are problems w/spatial Oracle pagination and select_related() def test02_select_related(self): "Testing `select_related` on geographic models (see #7126)." qs1 = City.objects.all() @@ -33,6 +34,7 @@ class RelatedGeoModelTest(unittest.TestCase): self.assertEqual(Point(lon, lat), c.location.point) @no_mysql + @no_oracle # Pagination problem is implicated in this test as well. def test03_transform_related(self): "Testing the `transform` GeoQuerySet method on related geographic models." # All the transformations are to state plane coordinate systems using @@ -71,22 +73,42 @@ class RelatedGeoModelTest(unittest.TestCase): #self.assertEqual(nqueries, len(connection.queries)) @no_mysql - def test04_related_aggregate(self): - "Testing the `extent` and `unionagg` GeoQuerySet aggregates on related geographic models." - if postgis: - # One for all locations, one that excludes Roswell. - all_extent = (-104.528060913086, 33.0583305358887,-79.4607315063477, 40.1847610473633) - txpa_extent = (-97.51611328125, 33.0583305358887,-79.4607315063477, 40.1847610473633) - e1 = City.objects.extent(field_name='location__point') - e2 = City.objects.exclude(name='Roswell').extent(field_name='location__point') - for ref, e in [(all_extent, e1), (txpa_extent, e2)]: - for ref_val, e_val in zip(ref, e): self.assertAlmostEqual(ref_val, e_val) + @no_oracle + def test04a_related_extent_aggregate(self): + "Testing the `extent` GeoQuerySet aggregates on related geographic models." + # One for all locations, one that excludes Roswell. + all_extent = (-104.528060913086, 33.0583305358887,-79.4607315063477, 40.1847610473633) + txpa_extent = (-97.51611328125, 33.0583305358887,-79.4607315063477, 40.1847610473633) + e1 = City.objects.extent(field_name='location__point') + e2 = City.objects.exclude(name='Roswell').extent(field_name='location__point') + tol = 9 + for ref, e in [(all_extent, e1), (txpa_extent, e2)]: + for ref_val, e_val in zip(ref, e): self.assertAlmostEqual(ref_val, e_val, tol) + + @no_mysql + def test04b_related_union_aggregate(self): + "Testing the `unionagg` GeoQuerySet aggregates on related geographic models." + # These are the points that are components of the aggregate geographic + # union that is returned. + p1 = Point(-104.528056, 33.387222) + p2 = Point(-97.516111, 33.058333) + p3 = Point(-79.460734, 40.18476) + + # Creating the reference union geometry depending on the spatial backend, + # as Oracle will have a different internal ordering of the component + # geometries than PostGIS. The second union aggregate is for a union + # query that includes limiting information in the WHERE clause (in other + # words a `.filter()` precedes the call to `.unionagg()`). + if oracle: + ref_u1 = MultiPoint(p3, p1, p2, srid=4326) + ref_u2 = MultiPoint(p3, p2, srid=4326) + else: + ref_u1 = MultiPoint(p1, p2, p3, srid=4326) + ref_u2 = MultiPoint(p2, p3, srid=4326) - # The second union is for a query that has something in the WHERE clause. - ref_u1 = GEOSGeometry('MULTIPOINT(-104.528056 33.387222,-97.516111 33.058333,-79.460734 40.18476)', 4326) - ref_u2 = GEOSGeometry('MULTIPOINT(-97.516111 33.058333,-79.460734 40.18476)', 4326) u1 = City.objects.unionagg(field_name='location__point') u2 = City.objects.exclude(name='Roswell').unionagg(field_name='location__point') + self.assertEqual(ref_u1, u1) self.assertEqual(ref_u2, u2)