Fixed #10888 -- May now insert NULL `GeometryField` values on Oracle.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@10631 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Justin Bronn 2009-04-24 20:24:50 +00:00
parent d6829782d0
commit 44c062344f
4 changed files with 54 additions and 16 deletions

View File

@ -94,7 +94,7 @@ class OracleSpatialField(Field):
SDO_CS.TRANSFORM() function call. SDO_CS.TRANSFORM() function call.
""" """
if value is None: if value is None:
return '%s' return 'NULL'
elif value.srid != self.srid: elif value.srid != self.srid:
# Adding Transform() to the SQL placeholder. # Adding Transform() to the SQL placeholder.
return '%s(SDO_GEOMETRY(%%s, %s), %s)' % (TRANSFORM, value.srid, self.srid) return '%s(SDO_GEOMETRY(%%s, %s), %s)' % (TRANSFORM, value.srid, self.srid)

View File

@ -1,5 +1,6 @@
from django.db.models.manager import Manager from django.db.models.manager import Manager
from django.contrib.gis.db.models.query import GeoQuerySet from django.contrib.gis.db.models.query import GeoQuerySet
from django.contrib.gis.db.models.sql.subqueries import insert_query
class GeoManager(Manager): class GeoManager(Manager):
"Overrides Manager to return Geographic QuerySets." "Overrides Manager to return Geographic QuerySets."
@ -86,3 +87,6 @@ class GeoManager(Manager):
def unionagg(self, *args, **kwargs): def unionagg(self, *args, **kwargs):
return self.get_query_set().unionagg(*args, **kwargs) return self.get_query_set().unionagg(*args, **kwargs)
def _insert(self, values, **kwargs):
return insert_query(self.model, values, **kwargs)

View File

@ -0,0 +1,39 @@
from django.contrib.gis.db.backend import SpatialBackend
from django.db.models.query import insert_query
if SpatialBackend.oracle:
from django.db import connection
from django.db.models.sql.subqueries import InsertQuery
class OracleGeoInsertQuery(InsertQuery):
def insert_values(self, insert_values, raw_values=False):
"""
This routine is overloaded from InsertQuery so that no parameter is
passed into cx_Oracle for NULL geometries. The reason is that
cx_Oracle has no way to bind Oracle object values (like
MDSYS.SDO_GEOMETRY).
"""
placeholders, values = [], []
for field, val in insert_values:
if hasattr(field, 'get_placeholder'):
ph = field.get_placeholder(val)
else:
ph = '%s'
placeholders.append(ph)
self.columns.append(field.column)
# If 'NULL' for the placeholder, omit appending None
# to the values list (which is used for db params).
if not ph == 'NULL':
values.append(val)
if raw_values:
self.values.extend(values)
else:
self.params += tuple(values)
self.values.extend(placeholders)
def insert_query(model, values, return_id=False, raw_values=False):
query = OracleGeoInsertQuery(model, connection)
query.insert_values(values, raw_values)
return query.execute_sql(return_id)

View File

@ -30,7 +30,7 @@ class GeoModelTest(unittest.TestCase):
data_dir = os.path.join(os.path.dirname(__file__), 'sql') data_dir = os.path.join(os.path.dirname(__file__), 'sql')
def get_file(wkt_file): def get_file(wkt_file):
return os.path.join(data_dir, wkt_file) return os.path.join(data_dir, wkt_file)
State(name='Puerto Rico', poly=None).save()
State(name='Colorado', poly=fromfile(get_file('co.wkt'))).save() State(name='Colorado', poly=fromfile(get_file('co.wkt'))).save()
State(name='Kansas', poly=fromfile(get_file('ks.wkt'))).save() State(name='Kansas', poly=fromfile(get_file('ks.wkt'))).save()
Country(name='Texas', mpoly=fromfile(get_file('tx.wkt'))).save() Country(name='Texas', mpoly=fromfile(get_file('tx.wkt'))).save()
@ -39,13 +39,7 @@ class GeoModelTest(unittest.TestCase):
# Ensuring that data was loaded from initial SQL. # Ensuring that data was loaded from initial SQL.
self.assertEqual(2, Country.objects.count()) self.assertEqual(2, Country.objects.count())
self.assertEqual(8, City.objects.count()) self.assertEqual(8, City.objects.count())
self.assertEqual(3, State.objects.count())
# Only PostGIS can handle NULL geometries
if SpatialBackend.postgis or SpatialBackend.spatialite:
n_state = 3
else:
n_state = 2
self.assertEqual(n_state, State.objects.count())
def test02_proxy(self): def test02_proxy(self):
"Testing Lazy-Geometry support (using the GeometryProxy)." "Testing Lazy-Geometry support (using the GeometryProxy)."
@ -369,10 +363,6 @@ class GeoModelTest(unittest.TestCase):
m1.save() m1.save()
self.assertEqual(-1, m1.geom.srid) self.assertEqual(-1, m1.geom.srid)
# Oracle does not support NULL geometries in its spatial index for
# some routines (e.g., SDO_GEOM.RELATE).
@no_oracle
@no_spatialite
def test12_null_geometries(self): def test12_null_geometries(self):
"Testing NULL geometry support, and the `isnull` lookup type." "Testing NULL geometry support, and the `isnull` lookup type."
if DISABLE: return if DISABLE: return
@ -391,9 +381,14 @@ class GeoModelTest(unittest.TestCase):
self.assertEqual(True, 'Kansas' in state_names) self.assertEqual(True, 'Kansas' in state_names)
# Saving another commonwealth w/a NULL geometry. # Saving another commonwealth w/a NULL geometry.
if not SpatialBackend.oracle: nmi = State.objects.create(name='Northern Mariana Islands', poly=None)
# TODO: Fix saving w/NULL geometry on Oracle. self.assertEqual(nmi.poly, None)
State(name='Northern Mariana Islands', poly=None).save()
# Assigning a geomery and saving -- then UPDATE back to NULL.
nmi.poly = 'POLYGON((0 0,1 0,1 1,1 0,0 0))'
nmi.save()
State.objects.filter(name='Northern Mariana Islands').update(poly=None)
self.assertEqual(None, State.objects.get(name='Northern Mariana Islands').poly)
@no_oracle # No specific `left` or `right` operators in Oracle. @no_oracle # No specific `left` or `right` operators in Oracle.
@no_spatialite # No `left` or `right` operators in SpatiaLite. @no_spatialite # No `left` or `right` operators in SpatiaLite.