From 4178488881f4e703c4e47ea78720dd61e0230ce5 Mon Sep 17 00:00:00 2001 From: Sergey Fedoseev Date: Wed, 22 Jun 2016 00:57:45 +0500 Subject: [PATCH] Refs #26657 -- Fixed a crash induced by invalid WKT returned by MySQL 5.7.5+. --- .../gis/db/backends/mysql/operations.py | 19 ++++++++++++++++++- tests/gis_tests/geoapp/test_functions.py | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/django/contrib/gis/db/backends/mysql/operations.py b/django/contrib/gis/db/backends/mysql/operations.py index 997ebc9a3c..b59060b221 100644 --- a/django/contrib/gis/db/backends/mysql/operations.py +++ b/django/contrib/gis/db/backends/mysql/operations.py @@ -2,7 +2,7 @@ from django.contrib.gis.db.backends.base.adapter import WKTAdapter from django.contrib.gis.db.backends.base.operations import \ BaseSpatialOperations from django.contrib.gis.db.backends.utils import SpatialOperator -from django.contrib.gis.db.models import aggregates +from django.contrib.gis.db.models import GeometryField, aggregates from django.db.backends.mysql.operations import DatabaseOperations from django.utils.functional import cached_property @@ -22,6 +22,10 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations): def is_mysql_5_6(self): return self.connection.mysql_version < (5, 7, 6) + @cached_property + def uses_invalid_empty_geometry_collection(self): + return self.connection.mysql_version >= (5, 7, 5) + @cached_property def select(self): if self.is_mysql_5_5: @@ -105,3 +109,16 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations): else: placeholder = '%s(%%s)' % self.from_text return placeholder + + def get_db_converters(self, expression): + converters = super(MySQLOperations, self).get_db_converters(expression) + if isinstance(expression.output_field, GeometryField) and self.uses_invalid_empty_geometry_collection: + converters.append(self.convert_invalid_empty_geometry_collection) + return converters + + # https://dev.mysql.com/doc/refman/5.7/en/spatial-function-argument-handling.html + # MySQL 5.7.5 adds support for the empty geometry collections, but they are represented with invalid WKT. + def convert_invalid_empty_geometry_collection(self, value, expression, connection, context): + if value == b'GEOMETRYCOLLECTION()': + return b'GEOMETRYCOLLECTION EMPTY' + return value diff --git a/tests/gis_tests/geoapp/test_functions.py b/tests/gis_tests/geoapp/test_functions.py index 3d42a4e407..c0e0a37ab3 100644 --- a/tests/gis_tests/geoapp/test_functions.py +++ b/tests/gis_tests/geoapp/test_functions.py @@ -223,7 +223,7 @@ class GISFunctionsTests(TestCase): geom = Point(5, 23, srid=4326) qs = Country.objects.annotate(inter=functions.Intersection('mpoly', geom)) for c in qs: - if spatialite or mysql or oracle: + if spatialite or (mysql and not connection.ops.uses_invalid_empty_geometry_collection) or oracle: # When the intersection is empty, some databases return None. expected = None else: