Fixed #33718 -- Dropped support for MySQL 5.7.

This commit is contained in:
Mariusz Felisiak 2022-07-08 13:30:12 +02:00 committed by GitHub
parent ccbf714ebe
commit eb3699ea77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 42 additions and 126 deletions

View File

@ -4,6 +4,7 @@ from django.utils.functional import cached_property
class DatabaseFeatures(BaseSpatialFeatures, MySQLDatabaseFeatures): class DatabaseFeatures(BaseSpatialFeatures, MySQLDatabaseFeatures):
empty_intersection_returns_none = False
has_spatialrefsys_table = False has_spatialrefsys_table = False
supports_add_srs_entry = False supports_add_srs_entry = False
supports_distance_geodetic = False supports_distance_geodetic = False
@ -14,31 +15,7 @@ class DatabaseFeatures(BaseSpatialFeatures, MySQLDatabaseFeatures):
supports_num_points_poly = False supports_num_points_poly = False
unsupported_geojson_options = {"crs"} 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 @cached_property
def supports_geometry_field_unique_index(self): def supports_geometry_field_unique_index(self):
# Not supported in MySQL since https://dev.mysql.com/worklog/task/?id=11808 # Not supported in MySQL since https://dev.mysql.com/worklog/task/?id=11808
return self.connection.mysql_is_mariadb 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

View File

@ -28,10 +28,6 @@ class MySQLIntrospection(DatabaseIntrospection):
return field_type, field_params return field_type, field_params
def supports_spatial_index(self, cursor, table_name): 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) storage_engine = self.get_storage_engine(cursor, table_name)
if storage_engine == "InnoDB": return storage_engine in ("MyISAM", "Aria", "InnoDB")
if self.connection.mysql_is_mariadb:
return True
return self.connection.mysql_version >= (5, 7, 5)
return storage_engine in ("MyISAM", "Aria")

View File

@ -86,8 +86,6 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
if self.connection.mysql_is_mariadb: if self.connection.mysql_is_mariadb:
unsupported.remove("PointOnSurface") unsupported.remove("PointOnSurface")
unsupported.update({"GeoHash", "IsValid"}) unsupported.update({"GeoHash", "IsValid"})
elif self.connection.mysql_version < (5, 7, 5):
unsupported.update({"AsGeoJSON", "GeoHash", "IsValid"})
return unsupported return unsupported
def geo_db_type(self, f): def geo_db_type(self, f):

View File

@ -81,8 +81,7 @@ class MySQLGISSchemaEditor(DatabaseSchemaEditor):
self.execute(sql) self.execute(sql)
except OperationalError: except OperationalError:
logger.error( logger.error(
"Cannot create SPATIAL INDEX %s. Only MyISAM and (as of " f"Cannot create SPATIAL INDEX {sql}. Only MyISAM, Aria, and InnoDB "
"MySQL 5.7.5) InnoDB support them.", f"support them.",
sql,
) )
self.geometry_sql = [] self.geometry_sql = []

View File

@ -61,15 +61,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
if self.connection.mysql_is_mariadb: if self.connection.mysql_is_mariadb:
return (10, 4) return (10, 4)
else: else:
return (5, 7) return (8,)
@cached_property
def bare_select_suffix(self):
if not self.connection.mysql_is_mariadb and self.connection.mysql_version < (
8,
):
return " FROM DUAL"
return ""
@cached_property @cached_property
def test_collations(self): def test_collations(self):
@ -128,27 +120,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
}, },
} }
) )
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 ( if self.connection.mysql_is_mariadb and (
10, 10,
4, 4,
@ -175,21 +146,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
}, },
} }
) )
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: if not self.supports_explain_analyze:
skips.update( skips.update(
{ {
@ -341,17 +297,11 @@ class DatabaseFeatures(BaseDatabaseFeatures):
# To be added in https://jira.mariadb.org/browse/MDEV-12981. # To be added in https://jira.mariadb.org/browse/MDEV-12981.
return not self.connection.mysql_is_mariadb 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 @cached_property
def can_introspect_json_field(self): def can_introspect_json_field(self):
if self.connection.mysql_is_mariadb: if self.connection.mysql_is_mariadb:
return self.supports_json_field and self.can_introspect_check_constraints return self.can_introspect_check_constraints
return self.supports_json_field return True
@cached_property @cached_property
def supports_index_column_ordering(self): def supports_index_column_ordering(self):

View File

@ -389,12 +389,8 @@ class DatabaseOperations(BaseDatabaseOperations):
return prefix return prefix
def regex_lookup(self, lookup_type): def regex_lookup(self, lookup_type):
# REGEXP BINARY doesn't work correctly in MySQL 8+ and REGEXP_LIKE # REGEXP_LIKE doesn't exist in MariaDB.
# doesn't exist in MySQL 5.x or in MariaDB. if self.connection.mysql_is_mariadb:
if (
self.connection.mysql_version < (8, 0, 0)
or self.connection.mysql_is_mariadb
):
if lookup_type == "regex": if lookup_type == "regex":
return "%s REGEXP BINARY %s" return "%s REGEXP BINARY %s"
return "%s REGEXP %s" return "%s REGEXP %s"

View File

@ -22,11 +22,9 @@ GeoDjango currently provides the following spatial database backends:
MySQL Spatial Limitations MySQL Spatial Limitations
------------------------- -------------------------
Before MySQL 5.6.1, spatial extensions only support bounding box operations Django supports spatial functions operating on real geometries available in
(what MySQL calls minimum bounding rectangles, or MBR). Specifically, MySQL did modern MySQL versions. However, the spatial functions are not as rich as other
not conform to the OGC standard. Django supports spatial functions operating on backends like PostGIS.
real geometries available in modern MySQL versions. However, the spatial
functions are not as rich as other backends like PostGIS.
Raster Support Raster Support
-------------- --------------
@ -318,7 +316,7 @@ Lookup Type PostGIS Oracle MariaDB MySQL [#]_ Sp
:lookup:`equals` X X X X X C :lookup:`equals` X X X X X C
:lookup:`exact <same_as>` X X X X X B :lookup:`exact <same_as>` X X X X X B
:lookup:`intersects` 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:`overlaps` X X X X X B
:lookup:`relate` X X X X C :lookup:`relate` X X X X C
:lookup:`same_as` X X X X X B :lookup:`same_as` X X X X X B
@ -348,7 +346,7 @@ functions are available on each spatial backend.
Function PostGIS Oracle MariaDB MySQL SpatiaLite Function PostGIS Oracle MariaDB MySQL SpatiaLite
==================================== ======= ============== ============ =========== ================= ==================================== ======= ============== ============ =========== =================
:class:`Area` X X X X X :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:`AsGML` X X X
:class:`AsKML` X X :class:`AsKML` X X
:class:`AsSVG` X X :class:`AsSVG` X X
@ -361,9 +359,9 @@ Function PostGIS Oracle MariaDB MySQL
:class:`Distance` X X X X X :class:`Distance` X X X X X
:class:`Envelope` X X X X X :class:`Envelope` X X X X X
:class:`ForcePolygonCW` 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:`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:`Length` X X X X X
:class:`LineLocatePoint` X X :class:`LineLocatePoint` X X
:class:`MakeValid` X X (LWGEOM/RTTOPO) :class:`MakeValid` X X (LWGEOM/RTTOPO)

View File

@ -53,7 +53,7 @@ geographic SRSes.
.. class:: AsGeoJSON(expression, bbox=False, crs=False, precision=8, **extra) .. class:: AsGeoJSON(expression, bbox=False, crs=False, precision=8, **extra)
*Availability*: MariaDB, `MySQL *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 Oracle, `PostGIS <https://postgis.net/docs/ST_AsGeoJSON.html>`__, SpatiaLite
Accepts a single geographic field or expression and returns a `GeoJSON Accepts a single geographic field or expression and returns a `GeoJSON
@ -333,7 +333,7 @@ are returned unchanged.
.. class:: GeoHash(expression, precision=None, **extra) .. class:: GeoHash(expression, precision=None, **extra)
*Availability*: `MySQL *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 `PostGIS <https://postgis.net/docs/ST_GeoHash.html>`__, SpatiaLite
(LWGEOM/RTTOPO) (LWGEOM/RTTOPO)
@ -374,7 +374,7 @@ intersection between them.
.. class:: IsValid(expr) .. class:: IsValid(expr)
*Availability*: `MySQL *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 `PostGIS <https://postgis.net/docs/ST_IsValid.html>`__, Oracle, SpatiaLite
Accepts a geographic field or expression and tests if the value is well formed. Accepts a geographic field or expression and tests if the value is well formed.

View File

@ -351,8 +351,8 @@ SpatiaLite ``Intersects(poly, geom)``
``isvalid`` ``isvalid``
----------- -----------
*Availability*: MySQL (≥ 5.7.5), `PostGIS *Availability*: MySQL, `PostGIS <https://postgis.net/docs/ST_IsValid.html>`__,
<https://postgis.net/docs/ST_IsValid.html>`__, Oracle, SpatiaLite Oracle, SpatiaLite
Tests if the geometry is valid. Tests if the geometry is valid.

View File

@ -59,7 +59,7 @@ supported versions, and any notes for each of the supported database backends:
Database Library Requirements Supported Versions Notes Database Library Requirements Supported Versions Notes
================== ============================== ================== ========================================= ================== ============================== ================== =========================================
PostgreSQL GEOS, GDAL, PROJ, PostGIS 12+ Requires PostGIS. 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. Oracle GEOS, GDAL 19+ XE not supported.
SQLite GEOS, GDAL, PROJ, SpatiaLite 3.9.0+ Requires SpatiaLite 4.3+ SQLite GEOS, GDAL, PROJ, SpatiaLite 3.9.0+ Requires SpatiaLite 4.3+
================== ============================== ================== ========================================= ================== ============================== ================== =========================================

View File

@ -352,7 +352,7 @@ MySQL notes
Version support 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 Django's ``inspectdb`` feature uses the ``information_schema`` database, which
contains detailed data on all database schemas. contains detailed data on all database schemas.
@ -535,11 +535,10 @@ Several other `MySQLdb connection options`_ may be useful, such as ``ssl``,
Setting ``sql_mode`` Setting ``sql_mode``
~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
From MySQL 5.7 onward, the default value of the ``sql_mode`` option contains The default value of the ``sql_mode`` option contains ``STRICT_TRANS_TABLES``.
``STRICT_TRANS_TABLES``. That option escalates warnings into errors when data That option escalates warnings into errors when data are truncated upon
are truncated upon insertion, so Django highly recommends activating a insertion, so Django highly recommends activating a `strict mode`_ for MySQL to
`strict mode`_ for MySQL to prevent data loss (either ``STRICT_TRANS_TABLES`` prevent data loss (either ``STRICT_TRANS_TABLES`` or ``STRICT_ALL_TABLES``).
or ``STRICT_ALL_TABLES``).
.. _strict mode: https://dev.mysql.com/doc/refman/en/sql-mode.html#sql-mode-strict .. _strict mode: https://dev.mysql.com/doc/refman/en/sql-mode.html#sql-mode-strict

View File

@ -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 Python native format: dictionaries, lists, strings, numbers, booleans and
``None``. ``None``.
``JSONField`` is supported on MariaDB, MySQL 5.7.8+, Oracle, PostgreSQL, and ``JSONField`` is supported on MariaDB, MySQL, Oracle, PostgreSQL, and SQLite
SQLite (with the :ref:`JSON1 extension enabled <sqlite-json1>`). (with the :ref:`JSON1 extension enabled <sqlite-json1>`).
.. attribute:: JSONField.encoder .. attribute:: JSONField.encoder

View File

@ -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 Upstream support for MariaDB 10.3 ends in May 2023. Django 4.2 supports MariaDB
10.4 and higher. 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 Dropped support for PostgreSQL 11
--------------------------------- ---------------------------------

View File

@ -1837,7 +1837,7 @@ class AggregateTestCase(TestCase):
default=datetime.time(17), default=datetime.time(17),
) )
if connection.vendor == "mysql": if connection.vendor == "mysql":
# Workaround for #30224 for MySQL 8.0+ & MariaDB. # Workaround for #30224 for MySQL & MariaDB.
expr.default = Cast(expr.default, TimeField()) expr.default = Cast(expr.default, TimeField())
queryset = Book.objects.annotate(oldest_store_opening=expr).order_by("isbn") queryset = Book.objects.annotate(oldest_store_opening=expr).order_by("isbn")
self.assertSequenceEqual( self.assertSequenceEqual(
@ -1887,7 +1887,7 @@ class AggregateTestCase(TestCase):
def test_aggregation_default_using_date_from_python(self): def test_aggregation_default_using_date_from_python(self):
expr = Min("book__pubdate", default=datetime.date(1970, 1, 1)) expr = Min("book__pubdate", default=datetime.date(1970, 1, 1))
if connection.vendor == "mysql": if connection.vendor == "mysql":
# Workaround for #30224 for MySQL 5.7+ & MariaDB. # Workaround for #30224 for MySQL & MariaDB.
expr.default = Cast(expr.default, DateField()) expr.default = Cast(expr.default, DateField())
queryset = Publisher.objects.annotate(earliest_pubdate=expr).order_by("name") queryset = Publisher.objects.annotate(earliest_pubdate=expr).order_by("name")
self.assertSequenceEqual( self.assertSequenceEqual(
@ -1938,7 +1938,7 @@ class AggregateTestCase(TestCase):
default=datetime.datetime(1970, 1, 1), default=datetime.datetime(1970, 1, 1),
) )
if connection.vendor == "mysql": if connection.vendor == "mysql":
# Workaround for #30224 for MySQL 8.0+ & MariaDB. # Workaround for #30224 for MySQL & MariaDB.
expr.default = Cast(expr.default, DateTimeField()) expr.default = Cast(expr.default, DateTimeField())
queryset = Book.objects.annotate(oldest_store_opening=expr).order_by("isbn") queryset = Book.objects.annotate(oldest_store_opening=expr).order_by("isbn")
self.assertSequenceEqual( self.assertSequenceEqual(

View File

@ -110,8 +110,8 @@ class Tests(TestCase):
mocked_get_database_version.return_value = (10, 3) mocked_get_database_version.return_value = (10, 3)
msg = "MariaDB 10.4 or later is required (found 10.3)." msg = "MariaDB 10.4 or later is required (found 10.3)."
else: else:
mocked_get_database_version.return_value = (5, 6) mocked_get_database_version.return_value = (5, 7)
msg = "MySQL 5.7 or later is required (found 5.6)." msg = "MySQL 8 or later is required (found 5.7)."
with self.assertRaisesMessage(NotSupportedError, msg): with self.assertRaisesMessage(NotSupportedError, msg):
connection.check_database_version_supported() connection.check_database_version_supported()

View File

@ -345,12 +345,9 @@ class GeoLookupTest(TestCase):
invalid_geom = fromstr("POLYGON((0 0, 0 1, 1 1, 1 0, 1 1, 1 0, 0 0))") 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) State.objects.create(name="invalid", poly=invalid_geom)
qs = State.objects.all() qs = State.objects.all()
if connection.ops.oracle or ( if connection.ops.oracle:
connection.ops.mysql and connection.mysql_version < (8, 0, 0)
):
# Kansas has adjacent vertices with distance 6.99244813842e-12 # Kansas has adjacent vertices with distance 6.99244813842e-12
# which is smaller than the default Oracle tolerance. # which is smaller than the default Oracle tolerance.
# It's invalid on MySQL < 8 also.
qs = qs.exclude(name="Kansas") qs = qs.exclude(name="Kansas")
self.assertEqual( self.assertEqual(
State.objects.filter(name="Kansas", poly__isvalid=False).count(), 1 State.objects.filter(name="Kansas", poly__isvalid=False).count(), 1