Browse Source

Fixed #34761 -- Dropped support for MySQL < 8.0.11.

Mariusz Felisiak 1 year ago
parent
commit
b719688b21

+ 7 - 23
django/db/backends/mysql/features.py

@@ -11,6 +11,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     # MySQL doesn't support sliced subqueries with IN/ALL/ANY/SOME.
     allow_sliced_subqueries_with_in = False
     has_select_for_update = True
+    has_select_for_update_nowait = True
     supports_forward_references = False
     supports_regex_backreferencing = False
     supports_date_lookup_using_string = False
@@ -23,6 +24,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     supports_temporal_subtraction = True
     supports_slicing_ordering_in_compound = True
     supports_index_on_text_field = False
+    supports_over_clause = True
+    supports_frame_range_fixed_distance = True
     supports_update_conflicts = True
     delete_can_self_reference_subquery = False
     create_test_procedure_without_params_sql = """
@@ -62,7 +65,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
         if self.connection.mysql_is_mariadb:
             return (10, 4)
         else:
-            return (8,)
+            return (8, 0, 11)
 
     @cached_property
     def test_collations(self):
@@ -225,16 +228,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     def is_sql_auto_is_null_enabled(self):
         return self.connection.mysql_server_data["sql_auto_is_null"]
 
-    @cached_property
-    def supports_over_clause(self):
-        if self.connection.mysql_is_mariadb:
-            return True
-        return self.connection.mysql_version >= (8, 0, 2)
-
-    supports_frame_range_fixed_distance = property(
-        operator.attrgetter("supports_over_clause")
-    )
-
     @cached_property
     def supports_column_check_constraints(self):
         if self.connection.mysql_is_mariadb:
@@ -255,20 +248,11 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     def has_select_for_update_skip_locked(self):
         if self.connection.mysql_is_mariadb:
             return self.connection.mysql_version >= (10, 6)
-        return self.connection.mysql_version >= (8, 0, 1)
-
-    @cached_property
-    def has_select_for_update_nowait(self):
-        if self.connection.mysql_is_mariadb:
-            return True
-        return self.connection.mysql_version >= (8, 0, 1)
+        return True
 
     @cached_property
     def has_select_for_update_of(self):
-        return (
-            not self.connection.mysql_is_mariadb
-            and self.connection.mysql_version >= (8, 0, 1)
-        )
+        return not self.connection.mysql_is_mariadb
 
     @cached_property
     def supports_explain_analyze(self):
@@ -319,7 +303,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
             return False
         if self.connection.mysql_is_mariadb:
             return self.connection.mysql_version >= (10, 8)
-        return self.connection.mysql_version >= (8, 0, 1)
+        return True
 
     @cached_property
     def supports_expression_indexes(self):

+ 6 - 8
django/db/backends/mysql/schema.py

@@ -45,14 +45,12 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
 
     @property
     def sql_rename_column(self):
-        # MariaDB >= 10.5.2 and MySQL >= 8.0.4 support an
-        # "ALTER TABLE ... RENAME COLUMN" statement.
-        if self.connection.mysql_is_mariadb:
-            if self.connection.mysql_version >= (10, 5, 2):
-                return super().sql_rename_column
-        elif self.connection.mysql_version >= (8, 0, 4):
-            return super().sql_rename_column
-        return "ALTER TABLE %(table)s CHANGE %(old_column)s %(new_column)s %(type)s"
+        is_mariadb = self.connection.mysql_is_mariadb
+        if is_mariadb and self.connection.mysql_version < (10, 5, 2):
+            # MariaDB < 10.5.2 doesn't support an
+            # "ALTER TABLE ... RENAME COLUMN" statement.
+            return "ALTER TABLE %(table)s CHANGE %(old_column)s %(new_column)s %(type)s"
+        return super().sql_rename_column
 
     def quote_value(self, value):
         self.connection.ensure_connection()

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

@@ -57,7 +57,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                      8+                  :ref:`Limited functionality <mysql-spatial-limitations>`.
+MySQL               GEOS, GDAL                      8.0.11+             :ref:`Limited functionality <mysql-spatial-limitations>`.
 Oracle              GEOS, GDAL                      19+                 XE not supported.
 SQLite              GEOS, GDAL, PROJ, SpatiaLite    3.21.0+             Requires SpatiaLite 4.3+
 ==================  ==============================  ==================  =========================================

+ 7 - 7
docs/ref/databases.txt

@@ -412,7 +412,7 @@ MySQL notes
 Version support
 ---------------
 
-Django supports MySQL 8 and higher.
+Django supports MySQL 8.0.11 and higher.
 
 Django's ``inspectdb`` feature uses the ``information_schema`` database, which
 contains detailed data on all database schemas.
@@ -755,14 +755,14 @@ MySQL and MariaDB do not support some options to the ``SELECT ... FOR UPDATE``
 statement. If ``select_for_update()`` is used with an unsupported option, then
 a :exc:`~django.db.NotSupportedError` is raised.
 
-=============== ========= ==========
+=============== ========= =====
 Option          MariaDB   MySQL
-=============== ========= ==========
-``SKIP LOCKED`` X (≥10.6) X (≥8.0.1)
-``NOWAIT``      X         X (≥8.0.1)
-``OF``                    X (≥8.0.1)
+=============== ========= =====
+``SKIP LOCKED`` X (≥10.6) X
+``NOWAIT``      X         X
+``OF``                    X
 ``NO KEY``
-=============== ========= ==========
+=============== ========= =====
 
 When using ``select_for_update()`` on MySQL, make sure you filter a queryset
 against at least a set of fields contained in unique constraints or only

+ 1 - 1
docs/ref/models/expressions.txt

@@ -880,7 +880,7 @@ from groups to be included:
 
     Support for filtering against window functions was added.
 
-Among Django's built-in database backends, MySQL 8.0.2+, PostgreSQL, and Oracle
+Among Django's built-in database backends, MySQL, PostgreSQL, and Oracle
 support window expressions. Support for different window expression features
 varies among the different databases. For example, the options in
 :meth:`~django.db.models.Expression.asc` and

+ 3 - 3
docs/ref/models/indexes.txt

@@ -82,10 +82,10 @@ field's name.
 For example ``Index(fields=['headline', '-pub_date'])`` would create SQL with
 ``(headline, pub_date DESC)``.
 
-.. admonition:: MySQL and MariaDB
+.. admonition:: MariaDB
 
-    Index ordering isn't supported on MySQL < 8.0.1 and MariaDB < 10.8. In that
-    case, a descending index is created as a normal index.
+    Index ordering isn't supported on MariaDB < 10.8. In that case, a
+    descending index is created as a normal index.
 
 ``name``
 --------

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

@@ -1928,8 +1928,8 @@ them:
 The ``postgresql``, ``oracle``, and ``mysql`` database backends support
 ``select_for_update()``. However, MariaDB only supports the ``nowait``
 argument, MariaDB 10.6+ also supports the ``skip_locked`` argument, and MySQL
-8.0.1+ supports the ``nowait``, ``skip_locked``, and ``of`` arguments. The
-``no_key`` argument is only supported on PostgreSQL.
+supports the ``nowait``, ``skip_locked``, and ``of`` arguments. The ``no_key``
+argument is only supported on PostgreSQL.
 
 Passing ``nowait=True``, ``skip_locked=True``, ``no_key=True``, or ``of`` to
 ``select_for_update()`` using database backends that do not support these

+ 6 - 0
docs/releases/5.0.txt

@@ -463,6 +463,12 @@ backends.
   ``False`` if the database doesn't support the ``DEFAULT`` keyword in bulk
   ``INSERT`` queries.
 
+Dropped support for MySQL < 8.0.11
+----------------------------------
+
+Support for pre-releases of MySQL 8.0.x series is removed. Django 5.0 supports
+MySQL 8.0.11 and higher.
+
 :mod:`django.contrib.gis`
 -------------------------
 

+ 0 - 14
tests/backends/mysql/test_features.py

@@ -23,20 +23,6 @@ class TestFeatures(TestCase):
             self.assertFalse(connection.features.supports_transactions)
         del connection.features.supports_transactions
 
-    def test_skip_locked_no_wait(self):
-        with mock.MagicMock() as _connection:
-            _connection.mysql_version = (8, 0, 1)
-            _connection.mysql_is_mariadb = False
-            database_features = DatabaseFeatures(_connection)
-            self.assertTrue(database_features.has_select_for_update_skip_locked)
-            self.assertTrue(database_features.has_select_for_update_nowait)
-        with mock.MagicMock() as _connection:
-            _connection.mysql_version = (8, 0, 0)
-            _connection.mysql_is_mariadb = False
-            database_features = DatabaseFeatures(_connection)
-            self.assertFalse(database_features.has_select_for_update_skip_locked)
-            self.assertFalse(database_features.has_select_for_update_nowait)
-
     def test_allows_auto_pk_0(self):
         with mock.MagicMock() as _connection:
             _connection.sql_mode = {"NO_AUTO_VALUE_ON_ZERO"}

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

@@ -109,8 +109,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, 7)
-            msg = "MySQL 8 or later is required (found 5.7)."
+            mocked_get_database_version.return_value = (8, 0, 4)
+            msg = "MySQL 8.0.11 or later is required (found 8.0.4)."
 
         with self.assertRaisesMessage(NotSupportedError, msg):
             connection.check_database_version_supported()