Skip to content

Commit

Permalink
Fixed #33718 -- Dropped support for MySQL 5.7.
Browse files Browse the repository at this point in the history
  • Loading branch information
felixxm committed Jul 8, 2022
1 parent ccbf714 commit eb3699e
Show file tree
Hide file tree
Showing 16 changed files with 42 additions and 126 deletions.
25 changes: 1 addition & 24 deletions django/contrib/gis/db/backends/mysql/features.py
Expand Up @@ -4,6 +4,7 @@


class DatabaseFeatures(BaseSpatialFeatures, MySQLDatabaseFeatures):
empty_intersection_returns_none = False
has_spatialrefsys_table = False
supports_add_srs_entry = False
supports_distance_geodetic = False
Expand All @@ -14,31 +15,7 @@ class DatabaseFeatures(BaseSpatialFeatures, MySQLDatabaseFeatures):
supports_num_points_poly = False
unsupported_geojson_options = {"crs"}

@cached_property
def empty_intersection_returns_none(self):
return (
not self.connection.mysql_is_mariadb
and self.connection.mysql_version < (5, 7, 5)
)

@cached_property
def supports_geometry_field_unique_index(self):
# Not supported in MySQL since https://dev.mysql.com/worklog/task/?id=11808
return self.connection.mysql_is_mariadb

@cached_property
def django_test_skips(self):
skips = super().django_test_skips
if not self.connection.mysql_is_mariadb and self.connection.mysql_version < (
8,
0,
0,
):
skips.update(
{
"MySQL < 8 gives different results.": {
"gis_tests.geoapp.tests.GeoLookupTest.test_disjoint_lookup",
},
}
)
return skips
8 changes: 2 additions & 6 deletions django/contrib/gis/db/backends/mysql/introspection.py
Expand Up @@ -28,10 +28,6 @@ def get_geometry_type(self, table_name, description):
return field_type, field_params

def supports_spatial_index(self, cursor, table_name):
# Supported with MyISAM/Aria, or InnoDB on MySQL 5.7.5+/MariaDB.
# Supported with MyISAM, Aria, or InnoDB.
storage_engine = self.get_storage_engine(cursor, table_name)
if storage_engine == "InnoDB":
if self.connection.mysql_is_mariadb:
return True
return self.connection.mysql_version >= (5, 7, 5)
return storage_engine in ("MyISAM", "Aria")
return storage_engine in ("MyISAM", "Aria", "InnoDB")
2 changes: 0 additions & 2 deletions django/contrib/gis/db/backends/mysql/operations.py
Expand Up @@ -86,8 +86,6 @@ def unsupported_functions(self):
if self.connection.mysql_is_mariadb:
unsupported.remove("PointOnSurface")
unsupported.update({"GeoHash", "IsValid"})
elif self.connection.mysql_version < (5, 7, 5):
unsupported.update({"AsGeoJSON", "GeoHash", "IsValid"})
return unsupported

def geo_db_type(self, f):
Expand Down
5 changes: 2 additions & 3 deletions django/contrib/gis/db/backends/mysql/schema.py
Expand Up @@ -81,8 +81,7 @@ def create_spatial_indexes(self):
self.execute(sql)
except OperationalError:
logger.error(
"Cannot create SPATIAL INDEX %s. Only MyISAM and (as of "
"MySQL 5.7.5) InnoDB support them.",
sql,
f"Cannot create SPATIAL INDEX {sql}. Only MyISAM, Aria, and InnoDB "
f"support them.",
)
self.geometry_sql = []
56 changes: 3 additions & 53 deletions django/db/backends/mysql/features.py
Expand Up @@ -61,15 +61,7 @@ def minimum_database_version(self):
if self.connection.mysql_is_mariadb:
return (10, 4)
else:
return (5, 7)

@cached_property
def bare_select_suffix(self):
if not self.connection.mysql_is_mariadb and self.connection.mysql_version < (
8,
):
return " FROM DUAL"
return ""
return (8,)

@cached_property
def test_collations(self):
Expand Down Expand Up @@ -128,27 +120,6 @@ def django_test_skips(self):
},
}
)
if not self.connection.mysql_is_mariadb and self.connection.mysql_version < (
8,
):
skips.update(
{
"Casting to datetime/time is not supported by MySQL < 8.0. "
"(#30224)": {
"aggregation.tests.AggregateTestCase."
"test_aggregation_default_using_time_from_python",
"aggregation.tests.AggregateTestCase."
"test_aggregation_default_using_datetime_from_python",
},
"MySQL < 8.0 returns string type instead of datetime/time. "
"(#30224)": {
"aggregation.tests.AggregateTestCase."
"test_aggregation_default_using_time_from_database",
"aggregation.tests.AggregateTestCase."
"test_aggregation_default_using_datetime_from_database",
},
}
)
if self.connection.mysql_is_mariadb and (
10,
4,
Expand All @@ -175,21 +146,6 @@ def django_test_skips(self):
},
}
)
if not self.connection.mysql_is_mariadb and self.connection.mysql_version < (
8,
):
skips.update(
{
"Parenthesized combined queries are not supported on MySQL < 8.": {
"queries.test_qs_combinators.QuerySetSetOperationTests."
"test_union_in_subquery",
"queries.test_qs_combinators.QuerySetSetOperationTests."
"test_union_in_subquery_related_outerref",
"queries.test_qs_combinators.QuerySetSetOperationTests."
"test_union_in_with_ordering",
}
}
)
if not self.supports_explain_analyze:
skips.update(
{
Expand Down Expand Up @@ -341,17 +297,11 @@ def supports_default_in_lead_lag(self):
# To be added in https://jira.mariadb.org/browse/MDEV-12981.
return not self.connection.mysql_is_mariadb

@cached_property
def supports_json_field(self):
if self.connection.mysql_is_mariadb:
return True
return self.connection.mysql_version >= (5, 7, 8)

@cached_property
def can_introspect_json_field(self):
if self.connection.mysql_is_mariadb:
return self.supports_json_field and self.can_introspect_check_constraints
return self.supports_json_field
return self.can_introspect_check_constraints
return True

@cached_property
def supports_index_column_ordering(self):
Expand Down
8 changes: 2 additions & 6 deletions django/db/backends/mysql/operations.py
Expand Up @@ -389,12 +389,8 @@ def explain_query_prefix(self, format=None, **options):
return prefix

def regex_lookup(self, lookup_type):
# REGEXP BINARY doesn't work correctly in MySQL 8+ and REGEXP_LIKE
# doesn't exist in MySQL 5.x or in MariaDB.
if (
self.connection.mysql_version < (8, 0, 0)
or self.connection.mysql_is_mariadb
):
# REGEXP_LIKE doesn't exist in MariaDB.
if self.connection.mysql_is_mariadb:
if lookup_type == "regex":
return "%s REGEXP BINARY %s"
return "%s REGEXP %s"
Expand Down
16 changes: 7 additions & 9 deletions docs/ref/contrib/gis/db-api.txt
Expand Up @@ -22,11 +22,9 @@ GeoDjango currently provides the following spatial database backends:
MySQL Spatial Limitations
-------------------------

Before MySQL 5.6.1, spatial extensions only support bounding box operations
(what MySQL calls minimum bounding rectangles, or MBR). Specifically, MySQL did
not conform to the OGC standard. Django supports spatial functions operating on
real geometries available in modern MySQL versions. However, the spatial
functions are not as rich as other backends like PostGIS.
Django supports spatial functions operating on real geometries available in
modern MySQL versions. However, the spatial functions are not as rich as other
backends like PostGIS.

Raster Support
--------------
Expand Down Expand Up @@ -318,7 +316,7 @@ Lookup Type PostGIS Oracle MariaDB MySQL [#]_ Sp
:lookup:`equals` X X X X X C
:lookup:`exact <same_as>` X X X X X B
:lookup:`intersects` X X X X X B
:lookup:`isvalid` X X X (≥ 5.7.5) X
:lookup:`isvalid` X X X X
:lookup:`overlaps` X X X X X B
:lookup:`relate` X X X X C
:lookup:`same_as` X X X X X B
Expand Down Expand Up @@ -348,7 +346,7 @@ functions are available on each spatial backend.
Function PostGIS Oracle MariaDB MySQL SpatiaLite
==================================== ======= ============== ============ =========== =================
:class:`Area` X X X X X
:class:`AsGeoJSON` X X X X (≥ 5.7.5) X
:class:`AsGeoJSON` X X X X X
:class:`AsGML` X X X
:class:`AsKML` X X
:class:`AsSVG` X X
Expand All @@ -361,9 +359,9 @@ Function PostGIS Oracle MariaDB MySQL
:class:`Distance` X X X X X
:class:`Envelope` X X X X X
:class:`ForcePolygonCW` X X
:class:`GeoHash` X X (≥ 5.7.5) X (LWGEOM/RTTOPO)
:class:`GeoHash` X X X (LWGEOM/RTTOPO)
:class:`Intersection` X X X X X
:class:`IsValid` X X X (≥ 5.7.5) X
:class:`IsValid` X X X X
:class:`Length` X X X X X
:class:`LineLocatePoint` X X
:class:`MakeValid` X X (LWGEOM/RTTOPO)
Expand Down
6 changes: 3 additions & 3 deletions docs/ref/contrib/gis/functions.txt
Expand Up @@ -53,7 +53,7 @@ geographic SRSes.
.. class:: AsGeoJSON(expression, bbox=False, crs=False, precision=8, **extra)

*Availability*: MariaDB, `MySQL
<https://dev.mysql.com/doc/refman/en/spatial-geojson-functions.html#function_st-asgeojson>`__ (≥ 5.7.5),
<https://dev.mysql.com/doc/refman/en/spatial-geojson-functions.html#function_st-asgeojson>`__,
Oracle, `PostGIS <https://postgis.net/docs/ST_AsGeoJSON.html>`__, SpatiaLite

Accepts a single geographic field or expression and returns a `GeoJSON
Expand Down Expand Up @@ -333,7 +333,7 @@ are returned unchanged.
.. class:: GeoHash(expression, precision=None, **extra)

*Availability*: `MySQL
<https://dev.mysql.com/doc/refman/en/spatial-geohash-functions.html#function_st-geohash>`__ (≥ 5.7.5),
<https://dev.mysql.com/doc/refman/en/spatial-geohash-functions.html#function_st-geohash>`__,
`PostGIS <https://postgis.net/docs/ST_GeoHash.html>`__, SpatiaLite
(LWGEOM/RTTOPO)

Expand Down Expand Up @@ -374,7 +374,7 @@ intersection between them.
.. class:: IsValid(expr)

*Availability*: `MySQL
<https://dev.mysql.com/doc/refman/en/spatial-convenience-functions.html#function_st-isvalid>`__ (≥ 5.7.5),
<https://dev.mysql.com/doc/refman/en/spatial-convenience-functions.html#function_st-isvalid>`__,
`PostGIS <https://postgis.net/docs/ST_IsValid.html>`__, Oracle, SpatiaLite

Accepts a geographic field or expression and tests if the value is well formed.
Expand Down
4 changes: 2 additions & 2 deletions docs/ref/contrib/gis/geoquerysets.txt
Expand Up @@ -351,8 +351,8 @@ SpatiaLite ``Intersects(poly, geom)``
``isvalid``
-----------

*Availability*: MySQL (≥ 5.7.5), `PostGIS
<https://postgis.net/docs/ST_IsValid.html>`__, Oracle, SpatiaLite
*Availability*: MySQL, `PostGIS <https://postgis.net/docs/ST_IsValid.html>`__,
Oracle, SpatiaLite

Tests if the geometry is valid.

Expand Down
2 changes: 1 addition & 1 deletion docs/ref/contrib/gis/install/index.txt
Expand Up @@ -59,7 +59,7 @@ supported versions, and any notes for each of the supported database backends:
Database Library Requirements Supported Versions Notes
================== ============================== ================== =========================================
PostgreSQL GEOS, GDAL, PROJ, PostGIS 12+ Requires PostGIS.
MySQL GEOS, GDAL 5.7+ :ref:`Limited functionality <mysql-spatial-limitations>`.
MySQL GEOS, GDAL 8+ :ref:`Limited functionality <mysql-spatial-limitations>`.
Oracle GEOS, GDAL 19+ XE not supported.
SQLite GEOS, GDAL, PROJ, SpatiaLite 3.9.0+ Requires SpatiaLite 4.3+
================== ============================== ================== =========================================
Expand Down
11 changes: 5 additions & 6 deletions docs/ref/databases.txt
Expand Up @@ -352,7 +352,7 @@ MySQL notes
Version support
---------------

Django supports MySQL 5.7 and higher.
Django supports MySQL 8 and higher.

Django's ``inspectdb`` feature uses the ``information_schema`` database, which
contains detailed data on all database schemas.
Expand Down Expand Up @@ -535,11 +535,10 @@ Several other `MySQLdb connection options`_ may be useful, such as ``ssl``,
Setting ``sql_mode``
~~~~~~~~~~~~~~~~~~~~

From MySQL 5.7 onward, the default value of the ``sql_mode`` option contains
``STRICT_TRANS_TABLES``. That option escalates warnings into errors when data
are truncated upon insertion, so Django highly recommends activating a
`strict mode`_ for MySQL to prevent data loss (either ``STRICT_TRANS_TABLES``
or ``STRICT_ALL_TABLES``).
The default value of the ``sql_mode`` option contains ``STRICT_TRANS_TABLES``.
That option escalates warnings into errors when data are truncated upon
insertion, so Django highly recommends activating a `strict mode`_ for MySQL to
prevent data loss (either ``STRICT_TRANS_TABLES`` or ``STRICT_ALL_TABLES``).

.. _strict mode: https://dev.mysql.com/doc/refman/en/sql-mode.html#sql-mode-strict

Expand Down
4 changes: 2 additions & 2 deletions docs/ref/models/fields.txt
Expand Up @@ -1200,8 +1200,8 @@ A field for storing JSON encoded data. In Python the data is represented in its
Python native format: dictionaries, lists, strings, numbers, booleans and
``None``.

``JSONField`` is supported on MariaDB, MySQL 5.7.8+, Oracle, PostgreSQL, and
SQLite (with the :ref:`JSON1 extension enabled <sqlite-json1>`).
``JSONField`` is supported on MariaDB, MySQL, Oracle, PostgreSQL, and SQLite
(with the :ref:`JSON1 extension enabled <sqlite-json1>`).

.. attribute:: JSONField.encoder

Expand Down
6 changes: 6 additions & 0 deletions docs/releases/4.2.txt
Expand Up @@ -249,6 +249,12 @@ Dropped support for MariaDB 10.3
Upstream support for MariaDB 10.3 ends in May 2023. Django 4.2 supports MariaDB
10.4 and higher.

Dropped support for MySQL 5.7
-----------------------------

Upstream support for MySQL 5.7 ends in October 2023. Django 4.2 supports MySQL
8 and higher.

Dropped support for PostgreSQL 11
---------------------------------

Expand Down
6 changes: 3 additions & 3 deletions tests/aggregation/tests.py
Expand Up @@ -1837,7 +1837,7 @@ def test_aggregation_default_using_time_from_python(self):
default=datetime.time(17),
)
if connection.vendor == "mysql":
# Workaround for #30224 for MySQL 8.0+ & MariaDB.
# Workaround for #30224 for MySQL & MariaDB.
expr.default = Cast(expr.default, TimeField())
queryset = Book.objects.annotate(oldest_store_opening=expr).order_by("isbn")
self.assertSequenceEqual(
Expand Down Expand Up @@ -1887,7 +1887,7 @@ def test_aggregation_default_using_time_from_database(self):
def test_aggregation_default_using_date_from_python(self):
expr = Min("book__pubdate", default=datetime.date(1970, 1, 1))
if connection.vendor == "mysql":
# Workaround for #30224 for MySQL 5.7+ & MariaDB.
# Workaround for #30224 for MySQL & MariaDB.
expr.default = Cast(expr.default, DateField())
queryset = Publisher.objects.annotate(earliest_pubdate=expr).order_by("name")
self.assertSequenceEqual(
Expand Down Expand Up @@ -1938,7 +1938,7 @@ def test_aggregation_default_using_datetime_from_python(self):
default=datetime.datetime(1970, 1, 1),
)
if connection.vendor == "mysql":
# Workaround for #30224 for MySQL 8.0+ & MariaDB.
# Workaround for #30224 for MySQL & MariaDB.
expr.default = Cast(expr.default, DateTimeField())
queryset = Book.objects.annotate(oldest_store_opening=expr).order_by("isbn")
self.assertSequenceEqual(
Expand Down
4 changes: 2 additions & 2 deletions tests/backends/mysql/tests.py
Expand Up @@ -110,8 +110,8 @@ def test_check_database_version_supported(self, mocked_get_database_version):
mocked_get_database_version.return_value = (10, 3)
msg = "MariaDB 10.4 or later is required (found 10.3)."
else:
mocked_get_database_version.return_value = (5, 6)
msg = "MySQL 5.7 or later is required (found 5.6)."
mocked_get_database_version.return_value = (5, 7)
msg = "MySQL 8 or later is required (found 5.7)."

with self.assertRaisesMessage(NotSupportedError, msg):
connection.check_database_version_supported()
Expand Down
5 changes: 1 addition & 4 deletions tests/gis_tests/geoapp/tests.py
Expand Up @@ -345,12 +345,9 @@ def test_isvalid_lookup(self):
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)
qs = State.objects.all()
if connection.ops.oracle or (
connection.ops.mysql and connection.mysql_version < (8, 0, 0)
):
if connection.ops.oracle:
# Kansas has adjacent vertices with distance 6.99244813842e-12
# which is smaller than the default Oracle tolerance.
# It's invalid on MySQL < 8 also.
qs = qs.exclude(name="Kansas")
self.assertEqual(
State.objects.filter(name="Kansas", poly__isvalid=False).count(), 1
Expand Down

0 comments on commit eb3699e

Please sign in to comment.