Browse Source

Fixed #33718 -- Dropped support for MySQL 5.7.

Mariusz Felisiak 2 years ago
parent
commit
eb3699ea77

+ 1 - 24
django/contrib/gis/db/backends/mysql/features.py

@@ -4,6 +4,7 @@ from django.utils.functional import cached_property
 
 
 class DatabaseFeatures(BaseSpatialFeatures, MySQLDatabaseFeatures):
+    empty_intersection_returns_none = False
     has_spatialrefsys_table = False
     supports_add_srs_entry = False
     supports_distance_geodetic = False
@@ -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

+ 2 - 6
django/contrib/gis/db/backends/mysql/introspection.py

@@ -28,10 +28,6 @@ class MySQLIntrospection(DatabaseIntrospection):
         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")

+ 0 - 2
django/contrib/gis/db/backends/mysql/operations.py

@@ -86,8 +86,6 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
         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):

+ 2 - 3
django/contrib/gis/db/backends/mysql/schema.py

@@ -81,8 +81,7 @@ class MySQLGISSchemaEditor(DatabaseSchemaEditor):
                 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 = []

+ 3 - 53
django/db/backends/mysql/features.py

@@ -61,15 +61,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
         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):
@@ -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 (
             10,
             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:
             skips.update(
                 {
@@ -341,17 +297,11 @@ class DatabaseFeatures(BaseDatabaseFeatures):
         # 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):

+ 2 - 6
django/db/backends/mysql/operations.py

@@ -389,12 +389,8 @@ class DatabaseOperations(BaseDatabaseOperations):
         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"

+ 7 - 9
docs/ref/contrib/gis/db-api.txt

@@ -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
 --------------
@@ -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
@@ -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
@@ -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)

+ 3 - 3
docs/ref/contrib/gis/functions.txt

@@ -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
@@ -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)
 
@@ -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.

+ 2 - 2
docs/ref/contrib/gis/geoquerysets.txt

@@ -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.
 

+ 1 - 1
docs/ref/contrib/gis/install/index.txt

@@ -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+
 ==================  ==============================  ==================  =========================================

+ 5 - 6
docs/ref/databases.txt

@@ -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.
@@ -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
 

+ 2 - 2
docs/ref/models/fields.txt

@@ -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
 

+ 6 - 0
docs/releases/4.2.txt

@@ -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
 ---------------------------------
 

+ 3 - 3
tests/aggregation/tests.py

@@ -1837,7 +1837,7 @@ class AggregateTestCase(TestCase):
             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(
@@ -1887,7 +1887,7 @@ class AggregateTestCase(TestCase):
     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(
@@ -1938,7 +1938,7 @@ class AggregateTestCase(TestCase):
             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(

+ 2 - 2
tests/backends/mysql/tests.py

@@ -110,8 +110,8 @@ class Tests(TestCase):
             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()

+ 1 - 4
tests/gis_tests/geoapp/tests.py

@@ -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))")
         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