Browse Source

Fixed #28552 -- Dropped support for MySQL 5.5.

Tim Graham 7 năm trước cách đây
mục cha
commit
8a1768432b

+ 1 - 14
django/contrib/gis/db/backends/mysql/operations.py

@@ -15,17 +15,10 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
 
     mysql = True
     name = 'mysql'
+    geom_func_prefix = 'ST_'
 
     Adapter = WKTAdapter
 
-    @cached_property
-    def geom_func_prefix(self):
-        return '' if self.is_mysql_5_5 else 'ST_'
-
-    @cached_property
-    def is_mysql_5_5(self):
-        return self.connection.mysql_version < (5, 6, 1)
-
     @cached_property
     def is_mysql_5_6(self):
         return self.connection.mysql_version < (5, 7, 6)
@@ -56,10 +49,6 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
             'within': SpatialOperator(func='MBRWithin'),
         }
 
-    @cached_property
-    def function_names(self):
-        return {'Length': 'GLength'} if self.is_mysql_5_5 else {}
-
     disallowed_aggregates = (
         aggregates.Collect, aggregates.Extent, aggregates.Extent3D,
         aggregates.MakeLine, aggregates.Union,
@@ -75,8 +64,6 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
         }
         if self.connection.mysql_version < (5, 7, 5):
             unsupported.update({'AsGeoJSON', 'GeoHash', 'IsValid'})
-        if self.is_mysql_5_5:
-            unsupported.update({'Difference', 'Distance', 'Intersection', 'SymDifference', 'Union'})
         return unsupported
 
     def geo_db_type(self, f):

+ 3 - 10
django/db/backends/mysql/base.py

@@ -97,14 +97,14 @@ class DatabaseWrapper(BaseDatabaseWrapper):
     # types, as strings. Column-type strings can contain format strings; they'll
     # be interpolated against the values of Field.__dict__ before being output.
     # If a column type is set to None, it won't be included in the output.
-    _data_types = {
+    data_types = {
         'AutoField': 'integer AUTO_INCREMENT',
         'BigAutoField': 'bigint AUTO_INCREMENT',
         'BinaryField': 'longblob',
         'BooleanField': 'bool',
         'CharField': 'varchar(%(max_length)s)',
         'DateField': 'date',
-        'DateTimeField': 'datetime',
+        'DateTimeField': 'datetime(6)',
         'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
         'DurationField': 'bigint',
         'FileField': 'varchar(%(max_length)s)',
@@ -121,17 +121,10 @@ class DatabaseWrapper(BaseDatabaseWrapper):
         'SlugField': 'varchar(%(max_length)s)',
         'SmallIntegerField': 'smallint',
         'TextField': 'longtext',
-        'TimeField': 'time',
+        'TimeField': 'time(6)',
         'UUIDField': 'char(32)',
     }
 
-    @cached_property
-    def data_types(self):
-        if self.features.supports_microsecond_precision:
-            return dict(self._data_types, DateTimeField='datetime(6)', TimeField='time(6)')
-        else:
-            return self._data_types
-
     # For these columns, MySQL doesn't:
     # - accept default values and implicitly treats these columns as nullable
     # - support a database index

+ 0 - 4
django/db/backends/mysql/features.py

@@ -60,10 +60,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
         "Confirm support for introspected foreign keys"
         return self._mysql_storage_engine != 'MyISAM'
 
-    @cached_property
-    def supports_microsecond_precision(self):
-        return self.connection.mysql_version >= (5, 6, 4)
-
     @cached_property
     def has_zoneinfo_database(self):
         # Test if the time zone definitions are installed.

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

@@ -109,10 +109,7 @@ class DatabaseOperations(BaseDatabaseOperations):
         return "INTERVAL '%06f' SECOND_MICROSECOND" % timedelta.total_seconds()
 
     def format_for_duration_arithmetic(self, sql):
-        if self.connection.features.supports_microsecond_precision:
-            return 'INTERVAL %s MICROSECOND' % sql
-        else:
-            return 'INTERVAL FLOOR(%s / 1000000) SECOND' % sql
+        return 'INTERVAL %s MICROSECOND' % sql
 
     def force_no_ordering(self):
         """
@@ -178,10 +175,6 @@ class DatabaseOperations(BaseDatabaseOperations):
                 value = timezone.make_naive(value, self.connection.timezone)
             else:
                 raise ValueError("MySQL backend does not support timezone-aware datetimes when USE_TZ is False.")
-
-        if not self.connection.features.supports_microsecond_precision:
-            value = value.replace(microsecond=0)
-
         return str(value)
 
     def adapt_timefield_value(self, value):
@@ -258,17 +251,10 @@ class DatabaseOperations(BaseDatabaseOperations):
     def subtract_temporals(self, internal_type, lhs, rhs):
         lhs_sql, lhs_params = lhs
         rhs_sql, rhs_params = rhs
-        if self.connection.features.supports_microsecond_precision:
-            if internal_type == 'TimeField':
-                return (
-                    "((TIME_TO_SEC(%(lhs)s) * POW(10, 6) + MICROSECOND(%(lhs)s)) -"
-                    " (TIME_TO_SEC(%(rhs)s) * POW(10, 6) + MICROSECOND(%(rhs)s)))"
-                ) % {'lhs': lhs_sql, 'rhs': rhs_sql}, lhs_params * 2 + rhs_params * 2
-            else:
-                return "TIMESTAMPDIFF(MICROSECOND, %s, %s)" % (rhs_sql, lhs_sql), rhs_params + lhs_params
-        elif internal_type == 'TimeField':
+        if internal_type == 'TimeField':
             return (
-                "(TIME_TO_SEC(%s) * POW(10, 6) - TIME_TO_SEC(%s) * POW(10, 6))"
-            ) % (lhs_sql, rhs_sql), lhs_params + rhs_params
+                "((TIME_TO_SEC(%(lhs)s) * POW(10, 6) + MICROSECOND(%(lhs)s)) -"
+                " (TIME_TO_SEC(%(rhs)s) * POW(10, 6) + MICROSECOND(%(rhs)s)))"
+            ) % {'lhs': lhs_sql, 'rhs': rhs_sql}, lhs_params * 2 + rhs_params * 2
         else:
-            return "(TIMESTAMPDIFF(SECOND, %s, %s) * POW(10, 6))" % (rhs_sql, lhs_sql), rhs_params + lhs_params
+            return "TIMESTAMPDIFF(MICROSECOND, %s, %s)" % (rhs_sql, lhs_sql), rhs_params + lhs_params

+ 5 - 5
docs/ref/contrib/gis/db-api.txt

@@ -379,12 +379,12 @@ Function                              PostGIS  Oracle          MySQL        Spat
 :class:`Azimuth`                      X                                     X (LWGEOM)
 :class:`BoundingCircle`               X        X
 :class:`Centroid`                     X        X               X            X
-:class:`Difference`                   X        X               X (≥ 5.6.1)  X
-:class:`Distance`                     X        X               X (≥ 5.6.1)  X
+:class:`Difference`                   X        X               X            X
+:class:`Distance`                     X        X               X            X
 :class:`Envelope`                     X                        X            X
 :class:`ForceRHR`                     X
 :class:`GeoHash`                      X                        X (≥ 5.7.5)  X (LWGEOM)
-:class:`Intersection`                 X        X               X (≥ 5.6.1)  X
+:class:`Intersection`                 X        X               X            X
 :class:`IsValid`                      X        X               X (≥ 5.7.5)  X (LWGEOM)
 :class:`Length`                       X        X               X            X
 :class:`LineLocatePoint`              X                                     X
@@ -397,10 +397,10 @@ Function                              PostGIS  Oracle          MySQL        Spat
 :class:`Reverse`                      X        X                            X
 :class:`Scale`                        X                                     X
 :class:`SnapToGrid`                   X                                     X
-:class:`SymDifference`                X        X               X (≥ 5.6.1)  X
+:class:`SymDifference`                X        X               X            X
 :class:`Transform`                    X        X                            X
 :class:`Translate`                    X                                     X
-:class:`Union`                        X        X               X (≥ 5.6.1)  X
+:class:`Union`                        X        X               X            X
 ====================================  =======  ==============  ===========  ==========
 
 Aggregate Functions

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

@@ -208,7 +208,7 @@ value of the geometry.
 
 .. class:: Difference(expr1, expr2, **extra)
 
-*Availability*: MySQL (≥ 5.6.1), `PostGIS
+*Availability*: MySQL, `PostGIS
 <https://postgis.net/docs/ST_Difference.html>`__, Oracle, SpatiaLite
 
 Accepts two geographic fields or expressions and returns the geometric
@@ -220,8 +220,8 @@ geometry B.
 
 .. class:: Distance(expr1, expr2, spheroid=None, **extra)
 
-*Availability*: MySQL (≥ 5.6.1), `PostGIS
-<https://postgis.net/docs/ST_Distance.html>`__, Oracle, SpatiaLite
+*Availability*: MySQL, `PostGIS <https://postgis.net/docs/ST_Distance.html>`__,
+Oracle, SpatiaLite
 
 Accepts two geographic fields or expressions and returns the distance between
 them, as a :class:`~django.contrib.gis.measure.Distance` object. On MySQL, a raw
@@ -307,7 +307,7 @@ __ https://en.wikipedia.org/wiki/Geohash
 
 .. class:: Intersection(expr1, expr2, **extra)
 
-*Availability*: MySQL (≥ 5.6.1), `PostGIS
+*Availability*: MySQL, `PostGIS
 <https://postgis.net/docs/ST_Intersection.html>`__, Oracle, SpatiaLite
 
 Accepts two geographic fields or expressions and returns the geometric
@@ -480,7 +480,7 @@ Number of Arguments  Description
 
 .. class:: SymDifference(expr1, expr2, **extra)
 
-*Availability*: MySQL (≥ 5.6.1), `PostGIS
+*Availability*: MySQL, `PostGIS
 <https://postgis.net/docs/ST_SymDifference.html>`__, Oracle, SpatiaLite
 
 Accepts two geographic fields or expressions and returns the geometric
@@ -522,8 +522,8 @@ parameters.
 
 .. class:: Union(expr1, expr2, **extra)
 
-*Availability*: MySQL (≥ 5.6.1), `PostGIS
-<https://postgis.net/docs/ST_Union.html>`__, Oracle, SpatiaLite
+*Availability*: MySQL, `PostGIS <https://postgis.net/docs/ST_Union.html>`__,
+Oracle, SpatiaLite
 
 Accepts two geographic fields or expressions and returns the union of both
 geometries.

+ 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.4, PostGIS     9.3+                Requires PostGIS.
-MySQL               GEOS, GDAL                      5.5+                Not OGC-compliant; :ref:`limited functionality <mysql-spatial-limitations>`.
+MySQL               GEOS, GDAL                      5.6+                Not OGC-compliant; :ref:`limited functionality <mysql-spatial-limitations>`.
 Oracle              GEOS, GDAL                      12.1+               XE not supported.
 SQLite              GEOS, GDAL, PROJ.4, SpatiaLite  3.6.+               Requires SpatiaLite 4.0+
 ==================  ==============================  ==================  =========================================

+ 9 - 25
docs/ref/databases.txt

@@ -276,7 +276,7 @@ MySQL notes
 Version support
 ---------------
 
-Django supports MySQL 5.5 and higher.
+Django supports MySQL 5.6 and higher.
 
 Django's ``inspectdb`` feature uses the ``information_schema`` database, which
 contains detailed data on all database schemas.
@@ -294,36 +294,20 @@ Storage engines
 MySQL has several `storage engines`_. You can change the default storage engine
 in the server configuration.
 
-Until MySQL 5.5.4, the default engine was MyISAM_ [#]_. The main drawbacks of
-MyISAM are that it doesn't support transactions or enforce foreign-key
-constraints. On the plus side, it was the only engine that supported full-text
-indexing and searching until MySQL 5.6.4.
+MySQL's default storage engine is InnoDB_. This engine is fully transactional
+and supports foreign key references. It's the recommended choice. However, the
+InnoDB autoincrement counter is lost on a MySQL restart because it does not
+remember the ``AUTO_INCREMENT`` value, instead recreating it as "max(id)+1".
+This may result in an inadvertent reuse of :class:`~django.db.models.AutoField`
+values.
 
-Since MySQL 5.5.5, the default storage engine is InnoDB_. This engine is fully
-transactional and supports foreign key references. It's probably the best
-choice at this point. However, note that the InnoDB autoincrement counter
-is lost on a MySQL restart because it does not remember the
-``AUTO_INCREMENT`` value, instead recreating it as "max(id)+1". This may
-result in an inadvertent reuse of :class:`~django.db.models.AutoField` values.
-
-If you upgrade an existing project to MySQL 5.5.5 and subsequently add some
-tables, ensure that your tables are using the same storage engine (i.e. MyISAM
-vs. InnoDB). Specifically, if tables that have a ``ForeignKey`` between them
-use different storage engines, you may see an error like the following when
-running ``migrate``::
-
-    _mysql_exceptions.OperationalError: (
-        1005, "Can't create table '\\db_name\\.#sql-4a8_ab' (errno: 150)"
-    )
+The main drawbacks of MyISAM_ are that it doesn't support transactions or
+enforce foreign-key constraints.
 
 .. _storage engines: https://dev.mysql.com/doc/refman/en/storage-engines.html
 .. _MyISAM: https://dev.mysql.com/doc/refman/en/myisam-storage-engine.html
 .. _InnoDB: https://dev.mysql.com/doc/refman/en/innodb-storage-engine.html
 
-.. [#] Unless this was changed by the packager of your MySQL package. We've
-   had reports that the Windows Community Server installer sets up InnoDB as
-   the default storage engine, for example.
-
 .. _mysql-db-api-drivers:
 
 MySQL DB API Drivers

+ 6 - 0
docs/releases/2.1.txt

@@ -200,6 +200,12 @@ Database backend API
 
 * ...
 
+Dropped support for MySQL 5.5
+-----------------------------
+
+The end of upstream support for MySQL 5.5 is December 2018. Django 2.1 supports
+MySQL 5.6 and higher.
+
 Miscellaneous
 -------------
 

+ 0 - 2
tests/schema/tests.py

@@ -2302,8 +2302,6 @@ class SchemaTests(TransactionTestCase):
         Changing the primary key field name of a model with a self-referential
         foreign key (#26384).
         """
-        if connection.vendor == 'mysql' and connection.mysql_version < (5, 6, 6):
-            self.skipTest('Skip known bug renaming primary keys on older MySQL versions (#24995).')
         with connection.schema_editor() as editor:
             editor.create_model(Node)
         old_field = Node._meta.get_field('node_id')