diff options
| author | Sergey Fedoseev <fedoseev.sergey@gmail.com> | 2017-04-10 22:26:26 +0500 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2017-04-10 13:26:26 -0400 |
| commit | e7afef13f594eb667f2709c0ef7bca98452ab32b (patch) | |
| tree | f9c50366cb2a015dacaf44a70cb0e0c4f70717f6 /django | |
| parent | 64264c9a19b7dae6cd1d5e112177cdbcafafc93c (diff) | |
Fixed #26788 -- Fixed QuerySet.update() crash when updating a geometry to another one.
Diffstat (limited to 'django')
| -rw-r--r-- | django/contrib/gis/db/backends/base/operations.py | 24 | ||||
| -rw-r--r-- | django/contrib/gis/db/backends/mysql/operations.py | 12 | ||||
| -rw-r--r-- | django/contrib/gis/db/backends/oracle/operations.py | 26 | ||||
| -rw-r--r-- | django/contrib/gis/db/backends/postgis/operations.py | 13 | ||||
| -rw-r--r-- | django/contrib/gis/db/backends/spatialite/operations.py | 26 | ||||
| -rw-r--r-- | django/contrib/gis/db/models/lookups.py | 2 | ||||
| -rw-r--r-- | django/db/backends/mysql/operations.py | 2 | ||||
| -rw-r--r-- | django/db/models/sql/compiler.py | 2 |
8 files changed, 34 insertions, 73 deletions
diff --git a/django/contrib/gis/db/backends/base/operations.py b/django/contrib/gis/db/backends/base/operations.py index 0732d517c6..1b314a9d2b 100644 --- a/django/contrib/gis/db/backends/base/operations.py +++ b/django/contrib/gis/db/backends/base/operations.py @@ -71,7 +71,29 @@ class BaseSpatialOperations: stored procedure call to the transformation function of the spatial backend. """ - raise NotImplementedError('subclasses of BaseSpatialOperations must provide a geo_db_placeholder() method') + def transform_value(value, field): + return ( + not (value is None or value.srid == field.srid) and + self.connection.features.supports_transform + ) + + if hasattr(value, 'as_sql'): + return ( + '%s(%%s, %s)' % (self.spatial_function_name('Transform'), f.srid) + if transform_value(value.output_field, f) + else '%s' + ) + if transform_value(value, f): + # Add Transform() to the SQL placeholder. + return '%s(%s(%%s,%s), %s)' % ( + self.spatial_function_name('Transform'), + self.from_text, value.srid, f.srid, + ) + elif self.connection.features.has_spatialrefsys_table: + return '%s(%%s,%s)' % (self.from_text, f.srid) + else: + # For backwards compatibility on MySQL (#27464). + return '%s(%%s)' % self.from_text def check_expression_support(self, expression): if isinstance(expression, self.disallowed_aggregates): diff --git a/django/contrib/gis/db/backends/mysql/operations.py b/django/contrib/gis/db/backends/mysql/operations.py index 0ea9f8f274..1c850b39d1 100644 --- a/django/contrib/gis/db/backends/mysql/operations.py +++ b/django/contrib/gis/db/backends/mysql/operations.py @@ -86,18 +86,6 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations): def geo_db_type(self, f): return f.geom_type - def get_geom_placeholder(self, f, value, compiler): - """ - The placeholder here has to include MySQL's WKT constructor. Because - MySQL does not support spatial transformations, there is no need to - modify the placeholder based on the contents of the given value. - """ - if hasattr(value, 'as_sql'): - placeholder, _ = compiler.compile(value) - else: - placeholder = '%s(%%s)' % self.from_text - return placeholder - def get_db_converters(self, expression): converters = super().get_db_converters(expression) if isinstance(expression.output_field, GeometryField) and self.uses_invalid_empty_geometry_collection: diff --git a/django/contrib/gis/db/backends/oracle/operations.py b/django/contrib/gis/db/backends/oracle/operations.py index 926209ac40..50f5bed8b9 100644 --- a/django/contrib/gis/db/backends/oracle/operations.py +++ b/django/contrib/gis/db/backends/oracle/operations.py @@ -187,33 +187,9 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations): return [dist_param] def get_geom_placeholder(self, f, value, compiler): - """ - Provide a proper substitution value for Geometries that are not in the - SRID of the field. Specifically, this routine will substitute in the - SDO_CS.TRANSFORM() function call. - """ - tranform_func = self.spatial_function_name('Transform') - if value is None: return 'NULL' - - def transform_value(val, srid): - return val.srid != srid - - if hasattr(value, 'as_sql'): - if transform_value(value, f.srid): - placeholder = '%s(%%s, %s)' % (tranform_func, f.srid) - else: - placeholder = '%s' - # No geometry value used for F expression, substitute in - # the column name instead. - sql, _ = compiler.compile(value) - return placeholder % sql - else: - if transform_value(value, f.srid): - return '%s(SDO_GEOMETRY(%%s, %s), %s)' % (tranform_func, value.srid, f.srid) - else: - return 'SDO_GEOMETRY(%%s, %s)' % f.srid + return super().get_geom_placeholder(f, value, compiler) def spatial_aggregate_name(self, agg_name): """ diff --git a/django/contrib/gis/db/backends/postgis/operations.py b/django/contrib/gis/db/backends/postgis/operations.py index 49662236c0..71302d9eb7 100644 --- a/django/contrib/gis/db/backends/postgis/operations.py +++ b/django/contrib/gis/db/backends/postgis/operations.py @@ -292,6 +292,12 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations): substitute in the ST_Transform() function call. """ tranform_func = self.spatial_function_name('Transform') + if hasattr(value, 'as_sql'): + if value.field.srid == f.srid: + placeholder = '%s' + else: + placeholder = '%s(%%s, %s)' % (tranform_func, f.srid) + return placeholder # Get the srid for this object if value is None: @@ -310,13 +316,6 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations): else: placeholder = '%s(%%s, %s)' % (tranform_func, f.srid) - if hasattr(value, 'as_sql'): - # If this is an F expression, then we don't really want - # a placeholder and instead substitute in the column - # of the expression. - sql, _ = compiler.compile(value) - placeholder = placeholder % sql - return placeholder def _get_postgis_func(self, func): diff --git a/django/contrib/gis/db/backends/spatialite/operations.py b/django/contrib/gis/db/backends/spatialite/operations.py index 42b079bbfa..087a879d07 100644 --- a/django/contrib/gis/db/backends/spatialite/operations.py +++ b/django/contrib/gis/db/backends/spatialite/operations.py @@ -152,32 +152,6 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations): dist_param = value return [dist_param] - def get_geom_placeholder(self, f, value, compiler): - """ - Provide a proper substitution value for Geometries that are not in the - SRID of the field. Specifically, this routine will substitute in the - Transform() and GeomFromText() function call(s). - """ - tranform_func = self.spatial_function_name('Transform') - - def transform_value(value, srid): - return not (value is None or value.srid == srid) - if hasattr(value, 'as_sql'): - if transform_value(value, f.srid): - placeholder = '%s(%%s, %s)' % (tranform_func, f.srid) - else: - placeholder = '%s' - # No geometry value used for F expression, substitute in - # the column name instead. - sql, _ = compiler.compile(value) - return placeholder % sql - else: - if transform_value(value, f.srid): - # Adding Transform() to the SQL placeholder. - return '%s(%s(%%s,%s), %s)' % (tranform_func, self.from_text, value.srid, f.srid) - else: - return '%s(%%s,%s)' % (self.from_text, f.srid) - def _get_spatialite_func(self, func): """ Helper routine for calling SpatiaLite functions and returning diff --git a/django/contrib/gis/db/models/lookups.py b/django/contrib/gis/db/models/lookups.py index 2024df45b0..c34e3391e1 100644 --- a/django/contrib/gis/db/models/lookups.py +++ b/django/contrib/gis/db/models/lookups.py @@ -68,6 +68,8 @@ class GISLookup(Lookup): if not hasattr(geo_fld, 'srid'): raise ValueError('No geographic field found in expression.') self.rhs.srid = geo_fld.srid + sql, _ = compiler.compile(geom) + return connection.ops.get_geom_placeholder(self.lhs.output_field, geom, compiler) % sql, [] elif isinstance(self.rhs, Expression): raise ValueError('Complex expressions not supported for spatial fields.') elif isinstance(self.rhs, (list, tuple)): diff --git a/django/db/backends/mysql/operations.py b/django/db/backends/mysql/operations.py index b47136df26..c1d0451a54 100644 --- a/django/db/backends/mysql/operations.py +++ b/django/db/backends/mysql/operations.py @@ -233,7 +233,7 @@ class DatabaseOperations(BaseDatabaseOperations): return value def binary_placeholder_sql(self, value): - return '_binary %s' if value is not None else '%s' + return '_binary %s' if value is not None and not hasattr(value, 'as_sql') else '%s' def subtract_temporals(self, internal_type, lhs, rhs): lhs_sql, lhs_params = lhs diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index f32d106def..14a727e998 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -1167,7 +1167,7 @@ class SQLUpdateCompiler(SQLCompiler): name = field.column if hasattr(val, 'as_sql'): sql, params = self.compile(val) - values.append('%s = %s' % (qn(name), sql)) + values.append('%s = %s' % (qn(name), placeholder % sql)) update_params.extend(params) elif val is not None: values.append('%s = %s' % (qn(name), placeholder)) |
