Fixed #27556 -- Added Oracle support for IsValid function and isvalid lookup.
This commit is contained in:
parent
e17f40f4b5
commit
4464b9b9ad
|
@ -52,6 +52,10 @@ class SDORelate(SpatialOperator):
|
||||||
return super(SDORelate, self).as_sql(connection, lookup, template_params, sql_params)
|
return super(SDORelate, self).as_sql(connection, lookup, template_params, sql_params)
|
||||||
|
|
||||||
|
|
||||||
|
class SDOIsValid(SpatialOperator):
|
||||||
|
sql_template = "%%(func)s(%%(lhs)s, %s) = 'TRUE'" % DEFAULT_TOLERANCE
|
||||||
|
|
||||||
|
|
||||||
class OracleOperations(BaseSpatialOperations, DatabaseOperations):
|
class OracleOperations(BaseSpatialOperations, DatabaseOperations):
|
||||||
|
|
||||||
name = 'oracle'
|
name = 'oracle'
|
||||||
|
@ -85,6 +89,7 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
|
||||||
'Difference': 'SDO_GEOM.SDO_DIFFERENCE',
|
'Difference': 'SDO_GEOM.SDO_DIFFERENCE',
|
||||||
'Distance': 'SDO_GEOM.SDO_DISTANCE',
|
'Distance': 'SDO_GEOM.SDO_DISTANCE',
|
||||||
'Intersection': 'SDO_GEOM.SDO_INTERSECTION',
|
'Intersection': 'SDO_GEOM.SDO_INTERSECTION',
|
||||||
|
'IsValid': 'SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT',
|
||||||
'Length': 'SDO_GEOM.SDO_LENGTH',
|
'Length': 'SDO_GEOM.SDO_LENGTH',
|
||||||
'NumGeometries': 'SDO_UTIL.GETNUMELEM',
|
'NumGeometries': 'SDO_UTIL.GETNUMELEM',
|
||||||
'NumPoints': 'SDO_UTIL.GETNUMVERTICES',
|
'NumPoints': 'SDO_UTIL.GETNUMVERTICES',
|
||||||
|
@ -109,6 +114,7 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
|
||||||
'covers': SDOOperator(func='SDO_COVERS'),
|
'covers': SDOOperator(func='SDO_COVERS'),
|
||||||
'disjoint': SDODisjoint(),
|
'disjoint': SDODisjoint(),
|
||||||
'intersects': SDOOperator(func='SDO_OVERLAPBDYINTERSECT'), # TODO: Is this really the same as ST_Intersects()?
|
'intersects': SDOOperator(func='SDO_OVERLAPBDYINTERSECT'), # TODO: Is this really the same as ST_Intersects()?
|
||||||
|
'isvalid': SDOIsValid(func='SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT'),
|
||||||
'equals': SDOOperator(func='SDO_EQUAL'),
|
'equals': SDOOperator(func='SDO_EQUAL'),
|
||||||
'exact': SDOOperator(func='SDO_EQUAL'),
|
'exact': SDOOperator(func='SDO_EQUAL'),
|
||||||
'overlaps': SDOOperator(func='SDO_OVERLAPS'),
|
'overlaps': SDOOperator(func='SDO_OVERLAPS'),
|
||||||
|
@ -128,7 +134,7 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
|
||||||
unsupported_functions = {
|
unsupported_functions = {
|
||||||
'AsGeoJSON', 'AsGML', 'AsKML', 'AsSVG',
|
'AsGeoJSON', 'AsGML', 'AsKML', 'AsSVG',
|
||||||
'BoundingCircle', 'Envelope',
|
'BoundingCircle', 'Envelope',
|
||||||
'ForceRHR', 'GeoHash', 'IsValid', 'MakeValid', 'MemSize', 'Scale',
|
'ForceRHR', 'GeoHash', 'MakeValid', 'MemSize', 'Scale',
|
||||||
'SnapToGrid', 'Translate',
|
'SnapToGrid', 'Translate',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -285,9 +285,13 @@ class Intersection(OracleToleranceMixin, GeoFuncWithGeoParam):
|
||||||
arity = 2
|
arity = 2
|
||||||
|
|
||||||
|
|
||||||
class IsValid(GeoFunc):
|
class IsValid(OracleToleranceMixin, GeoFunc):
|
||||||
output_field_class = BooleanField
|
output_field_class = BooleanField
|
||||||
|
|
||||||
|
def as_oracle(self, compiler, connection, **extra_context):
|
||||||
|
sql, params = super(IsValid, self).as_oracle(compiler, connection, **extra_context)
|
||||||
|
return "CASE %s WHEN 'TRUE' THEN 1 ELSE 0 END" % sql, params
|
||||||
|
|
||||||
|
|
||||||
class Length(DistanceResultMixin, OracleToleranceMixin, GeoFunc):
|
class Length(DistanceResultMixin, OracleToleranceMixin, GeoFunc):
|
||||||
output_field_class = FloatField
|
output_field_class = FloatField
|
||||||
|
|
|
@ -5,7 +5,7 @@ import re
|
||||||
from django.core.exceptions import FieldDoesNotExist
|
from django.core.exceptions import FieldDoesNotExist
|
||||||
from django.db.models.constants import LOOKUP_SEP
|
from django.db.models.constants import LOOKUP_SEP
|
||||||
from django.db.models.expressions import Col, Expression
|
from django.db.models.expressions import Col, Expression
|
||||||
from django.db.models.lookups import BuiltinLookup, Lookup, Transform
|
from django.db.models.lookups import Lookup, Transform
|
||||||
from django.db.models.sql.query import Query
|
from django.db.models.sql.query import Query
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
|
@ -352,15 +352,16 @@ class IntersectsLookup(GISLookup):
|
||||||
gis_lookups['intersects'] = IntersectsLookup
|
gis_lookups['intersects'] = IntersectsLookup
|
||||||
|
|
||||||
|
|
||||||
class IsValidLookup(BuiltinLookup):
|
class IsValidLookup(GISLookup):
|
||||||
lookup_name = 'isvalid'
|
lookup_name = 'isvalid'
|
||||||
|
sql_template = '%(func)s(%(lhs)s)'
|
||||||
|
|
||||||
def as_sql(self, compiler, connection):
|
def as_sql(self, compiler, connection):
|
||||||
if self.lhs.field.geom_type == 'RASTER':
|
if self.lhs.field.geom_type == 'RASTER':
|
||||||
raise ValueError('The isvalid lookup is only available on geometry fields.')
|
raise ValueError('The isvalid lookup is only available on geometry fields.')
|
||||||
gis_op = connection.ops.gis_operators[self.lookup_name]
|
gis_op = connection.ops.gis_operators[self.lookup_name]
|
||||||
sql, params = self.process_lhs(compiler, connection)
|
sql, params = self.process_lhs(compiler, connection)
|
||||||
sql = '%(func)s(%(lhs)s)' % {'func': gis_op.func, 'lhs': sql}
|
sql, params = gis_op.as_sql(connection, self, {'func': gis_op.func, 'lhs': sql}, params)
|
||||||
if not self.rhs:
|
if not self.rhs:
|
||||||
sql = 'NOT ' + sql
|
sql = 'NOT ' + sql
|
||||||
return sql, params
|
return sql, params
|
||||||
|
|
|
@ -347,7 +347,7 @@ Lookup Type PostGIS Oracle MySQL [#]_ SpatiaLite
|
||||||
:lookup:`equals` X X X X C
|
:lookup:`equals` X X X X C
|
||||||
:lookup:`exact` X X X X B
|
:lookup:`exact` X X X X B
|
||||||
:lookup:`intersects` X X X X B
|
:lookup:`intersects` X X X X B
|
||||||
:lookup:`isvalid` X X (LWGEOM)
|
:lookup:`isvalid` X X X (LWGEOM)
|
||||||
:lookup:`overlaps` X X X X B
|
:lookup:`overlaps` X X X X B
|
||||||
:lookup:`relate` X X X C
|
:lookup:`relate` X X X C
|
||||||
:lookup:`same_as` X X X X B
|
:lookup:`same_as` X X X X B
|
||||||
|
@ -390,7 +390,7 @@ Function PostGIS Oracle MySQL SpatiaLite
|
||||||
:class:`ForceRHR` X
|
:class:`ForceRHR` X
|
||||||
:class:`GeoHash` X X (LWGEOM)
|
:class:`GeoHash` X X (LWGEOM)
|
||||||
:class:`Intersection` X X X (≥ 5.6.1) X
|
:class:`Intersection` X X X (≥ 5.6.1) X
|
||||||
:class:`IsValid` X X (LWGEOM)
|
:class:`IsValid` X X X (LWGEOM)
|
||||||
:class:`Length` X X X X
|
:class:`Length` X X X X
|
||||||
:class:`MakeValid` X X (LWGEOM)
|
:class:`MakeValid` X X (LWGEOM)
|
||||||
:class:`MemSize` X
|
:class:`MemSize` X
|
||||||
|
|
|
@ -298,14 +298,14 @@ intersection between them.
|
||||||
|
|
||||||
.. versionadded:: 1.10
|
.. versionadded:: 1.10
|
||||||
|
|
||||||
*Availability*: PostGIS, SpatiaLite (LWGEOM)
|
*Availability*: PostGIS, Oracle, SpatiaLite (LWGEOM)
|
||||||
|
|
||||||
Accepts a geographic field or expression and tests if the value is well formed.
|
Accepts a geographic field or expression and tests if the value is well formed.
|
||||||
Returns ``True`` if its value is a valid geometry and ``False`` otherwise.
|
Returns ``True`` if its value is a valid geometry and ``False`` otherwise.
|
||||||
|
|
||||||
.. versionchanged:: 1.11
|
.. versionchanged:: 1.11
|
||||||
|
|
||||||
SpatiaLite support was added.
|
SpatiaLite and Oracle support was added.
|
||||||
|
|
||||||
``Length``
|
``Length``
|
||||||
==========
|
==========
|
||||||
|
|
|
@ -159,6 +159,10 @@ Minor features
|
||||||
:class:`~django.contrib.gis.db.models.functions.MakeValid` function, and
|
:class:`~django.contrib.gis.db.models.functions.MakeValid` function, and
|
||||||
:lookup:`isvalid` lookup.
|
:lookup:`isvalid` lookup.
|
||||||
|
|
||||||
|
* Added Oracle support for the
|
||||||
|
:class:`~django.contrib.gis.db.models.functions.IsValid` function and
|
||||||
|
:lookup:`isvalid` lookup.
|
||||||
|
|
||||||
:mod:`django.contrib.messages`
|
:mod:`django.contrib.messages`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -295,8 +295,14 @@ class GeoLookupTest(TestCase):
|
||||||
def test_isvalid_lookup(self):
|
def test_isvalid_lookup(self):
|
||||||
invalid_geom = fromstr('POLYGON((0 0, 0 1, 1 1, 1 0, 1 1, 1 0, 0 0))')
|
invalid_geom = fromstr('POLYGON((0 0, 0 1, 1 1, 1 0, 1 1, 1 0, 0 0))')
|
||||||
State.objects.create(name='invalid', poly=invalid_geom)
|
State.objects.create(name='invalid', poly=invalid_geom)
|
||||||
self.assertEqual(State.objects.filter(poly__isvalid=False).count(), 1)
|
qs = State.objects.all()
|
||||||
self.assertEqual(State.objects.filter(poly__isvalid=True).count(), State.objects.count() - 1)
|
if oracle:
|
||||||
|
# Kansas has adjacent vertices with distance 6.99244813842e-12
|
||||||
|
# which is smaller than the default Oracle tolerance.
|
||||||
|
qs = qs.exclude(name='Kansas')
|
||||||
|
self.assertEqual(State.objects.filter(name='Kansas', poly__isvalid=False).count(), 1)
|
||||||
|
self.assertEqual(qs.filter(poly__isvalid=False).count(), 1)
|
||||||
|
self.assertEqual(qs.filter(poly__isvalid=True).count(), qs.count() - 1)
|
||||||
|
|
||||||
@skipUnlessDBFeature("supports_left_right_lookups")
|
@skipUnlessDBFeature("supports_left_right_lookups")
|
||||||
def test_left_right_lookups(self):
|
def test_left_right_lookups(self):
|
||||||
|
|
Loading…
Reference in New Issue