浏览代码

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

Mariusz Felisiak 1 年之前
父节点
当前提交
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.
     # MySQL doesn't support sliced subqueries with IN/ALL/ANY/SOME.
     allow_sliced_subqueries_with_in = False
     allow_sliced_subqueries_with_in = False
     has_select_for_update = True
     has_select_for_update = True
+    has_select_for_update_nowait = True
     supports_forward_references = False
     supports_forward_references = False
     supports_regex_backreferencing = False
     supports_regex_backreferencing = False
     supports_date_lookup_using_string = False
     supports_date_lookup_using_string = False
@@ -23,6 +24,8 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     supports_temporal_subtraction = True
     supports_temporal_subtraction = True
     supports_slicing_ordering_in_compound = True
     supports_slicing_ordering_in_compound = True
     supports_index_on_text_field = False
     supports_index_on_text_field = False
+    supports_over_clause = True
+    supports_frame_range_fixed_distance = True
     supports_update_conflicts = True
     supports_update_conflicts = True
     delete_can_self_reference_subquery = False
     delete_can_self_reference_subquery = False
     create_test_procedure_without_params_sql = """
     create_test_procedure_without_params_sql = """
@@ -62,7 +65,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 (8,)
+            return (8, 0, 11)
 
 
     @cached_property
     @cached_property
     def test_collations(self):
     def test_collations(self):
@@ -225,16 +228,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     def is_sql_auto_is_null_enabled(self):
     def is_sql_auto_is_null_enabled(self):
         return self.connection.mysql_server_data["sql_auto_is_null"]
         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
     @cached_property
     def supports_column_check_constraints(self):
     def supports_column_check_constraints(self):
         if self.connection.mysql_is_mariadb:
         if self.connection.mysql_is_mariadb:
@@ -255,20 +248,11 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     def has_select_for_update_skip_locked(self):
     def has_select_for_update_skip_locked(self):
         if self.connection.mysql_is_mariadb:
         if self.connection.mysql_is_mariadb:
             return self.connection.mysql_version >= (10, 6)
             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
     @cached_property
     def has_select_for_update_of(self):
     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
     @cached_property
     def supports_explain_analyze(self):
     def supports_explain_analyze(self):
@@ -319,7 +303,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
             return False
             return False
         if self.connection.mysql_is_mariadb:
         if self.connection.mysql_is_mariadb:
             return self.connection.mysql_version >= (10, 8)
             return self.connection.mysql_version >= (10, 8)
-        return self.connection.mysql_version >= (8, 0, 1)
+        return True
 
 
     @cached_property
     @cached_property
     def supports_expression_indexes(self):
     def supports_expression_indexes(self):

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

@@ -45,14 +45,12 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
 
 
     @property
     @property
     def sql_rename_column(self):
     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):
     def quote_value(self, value):
         self.connection.ensure_connection()
         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
 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                      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.
 Oracle              GEOS, GDAL                      19+                 XE not supported.
 SQLite              GEOS, GDAL, PROJ, SpatiaLite    3.21.0+             Requires SpatiaLite 4.3+
 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
 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
 Django's ``inspectdb`` feature uses the ``information_schema`` database, which
 contains detailed data on all database schemas.
 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
 statement. If ``select_for_update()`` is used with an unsupported option, then
 a :exc:`~django.db.NotSupportedError` is raised.
 a :exc:`~django.db.NotSupportedError` is raised.
 
 
-=============== ========= ==========
+=============== ========= =====
 Option          MariaDB   MySQL
 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``
 ``NO KEY``
-=============== ========= ==========
+=============== ========= =====
 
 
 When using ``select_for_update()`` on MySQL, make sure you filter a queryset
 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
 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.
     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
 support window expressions. Support for different window expression features
 varies among the different databases. For example, the options in
 varies among the different databases. For example, the options in
 :meth:`~django.db.models.Expression.asc` and
 :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
 For example ``Index(fields=['headline', '-pub_date'])`` would create SQL with
 ``(headline, pub_date DESC)``.
 ``(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``
 ``name``
 --------
 --------

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

@@ -1928,8 +1928,8 @@ them:
 The ``postgresql``, ``oracle``, and ``mysql`` database backends support
 The ``postgresql``, ``oracle``, and ``mysql`` database backends support
 ``select_for_update()``. However, MariaDB only supports the ``nowait``
 ``select_for_update()``. However, MariaDB only supports the ``nowait``
 argument, MariaDB 10.6+ also supports the ``skip_locked`` argument, and MySQL
 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
 Passing ``nowait=True``, ``skip_locked=True``, ``no_key=True``, or ``of`` to
 ``select_for_update()`` using database backends that do not support these
 ``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
   ``False`` if the database doesn't support the ``DEFAULT`` keyword in bulk
   ``INSERT`` queries.
   ``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`
 :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)
             self.assertFalse(connection.features.supports_transactions)
         del 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):
     def test_allows_auto_pk_0(self):
         with mock.MagicMock() as _connection:
         with mock.MagicMock() as _connection:
             _connection.sql_mode = {"NO_AUTO_VALUE_ON_ZERO"}
             _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)
             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, 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):
         with self.assertRaisesMessage(NotSupportedError, msg):
             connection.check_database_version_supported()
             connection.check_database_version_supported()