From 33f1181c31e0ee5bc5e20ca2a8549508de807623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anssi=20K=C3=A4=C3=A4ri=C3=A4inen?= Date: Thu, 15 Nov 2012 14:23:02 +0200 Subject: [PATCH] [1.5.x] Fixed #19058 -- Fixed Oracle GIS crash The problem is the same as in #10888 which was reintroduced when bulk_insert was added. Thanks to Jani Tiainen for report, patch and also testing the final patch on Oracle GIS. Backpatch of 92d7f541da8b59520c833b19fbba52d3ecef2428 --- .../gis/db/backends/oracle/compiler.py | 24 +------------------ .../gis/db/backends/oracle/operations.py | 9 +++++++ django/db/backends/__init__.py | 5 ++++ django/db/models/sql/compiler.py | 2 ++ 4 files changed, 17 insertions(+), 23 deletions(-) diff --git a/django/contrib/gis/db/backends/oracle/compiler.py b/django/contrib/gis/db/backends/oracle/compiler.py index f0eb5cad00..98da0163ba 100644 --- a/django/contrib/gis/db/backends/oracle/compiler.py +++ b/django/contrib/gis/db/backends/oracle/compiler.py @@ -7,29 +7,7 @@ class GeoSQLCompiler(BaseGeoSQLCompiler, SQLCompiler): pass class SQLInsertCompiler(compiler.SQLInsertCompiler, GeoSQLCompiler): - def placeholder(self, field, val): - if field is None: - # A field value of None means the value is raw. - return val - elif hasattr(field, 'get_placeholder'): - # Some fields (e.g. geo fields) need special munging before - # they can be inserted. - ph = field.get_placeholder(val, self.connection) - if ph == 'NULL': - # If the placeholder returned is 'NULL', then we need to - # to remove None from the Query parameters. Specifically, - # cx_Oracle will assume a CHAR type when a placeholder ('%s') - # is used for columns of MDSYS.SDO_GEOMETRY. Thus, we use - # 'NULL' for the value, and remove None from the query params. - # See also #10888. - param_idx = self.query.columns.index(field.column) - params = list(self.query.params) - params.pop(param_idx) - self.query.params = tuple(params) - return ph - else: - # Return the common case for the placeholder - return '%s' + pass class SQLDeleteCompiler(compiler.SQLDeleteCompiler, GeoSQLCompiler): pass diff --git a/django/contrib/gis/db/backends/oracle/operations.py b/django/contrib/gis/db/backends/oracle/operations.py index 35a4d9491d..4e42b4cf00 100644 --- a/django/contrib/gis/db/backends/oracle/operations.py +++ b/django/contrib/gis/db/backends/oracle/operations.py @@ -288,3 +288,12 @@ class OracleOperations(DatabaseOperations, BaseSpatialOperations): def spatial_ref_sys(self): from django.contrib.gis.db.backends.oracle.models import SpatialRefSys return SpatialRefSys + + def modify_insert_params(self, placeholders, params): + """Drop out insert parameters for NULL placeholder. Needed for Oracle Spatial + backend due to #10888 + """ + # This code doesn't work for bulk insert cases. + assert len(placeholders) == 1 + return [[param for pholder,param + in six.moves.zip(placeholders[0], params[0]) if pholder != 'NULL'], ] diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index 02d2a16a46..8dd0212dbb 100644 --- a/django/db/backends/__init__.py +++ b/django/db/backends/__init__.py @@ -916,6 +916,11 @@ class BaseDatabaseOperations(object): conn = ' %s ' % connector return conn.join(sub_expressions) + def modify_insert_params(self, placeholders, params): + """Allow modification of insert parameters. Needed for Oracle Spatial + backend due to #10888. + """ + return params class BaseDatabaseIntrospection(object): """ diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 9d59503799..30b9bed8b4 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -905,6 +905,8 @@ class SQLInsertCompiler(SQLCompiler): [self.placeholder(field, v) for field, v in zip(fields, val)] for val in values ] + # Oracle Spatial needs to remove some values due to #10888 + params = self.connection.ops.modify_insert_params(placeholders, params) if self.return_id and self.connection.features.can_return_id_from_insert: params = params[0] col = "%s.%s" % (qn(opts.db_table), qn(opts.pk.column))