Skip to content

Commit 8a17684

Browse files
committed
Fixed #28552 -- Dropped support for MySQL 5.5.
1 parent 6da1407 commit 8a17684

File tree

10 files changed

+38
-88
lines changed

10 files changed

+38
-88
lines changed

django/contrib/gis/db/backends/mysql/operations.py

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,10 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
1515

1616
mysql = True
1717
name = 'mysql'
18+
geom_func_prefix = 'ST_'
1819

1920
Adapter = WKTAdapter
2021

21-
@cached_property
22-
def geom_func_prefix(self):
23-
return '' if self.is_mysql_5_5 else 'ST_'
24-
25-
@cached_property
26-
def is_mysql_5_5(self):
27-
return self.connection.mysql_version < (5, 6, 1)
28-
2922
@cached_property
3023
def is_mysql_5_6(self):
3124
return self.connection.mysql_version < (5, 7, 6)
@@ -56,10 +49,6 @@ def gis_operators(self):
5649
'within': SpatialOperator(func='MBRWithin'),
5750
}
5851

59-
@cached_property
60-
def function_names(self):
61-
return {'Length': 'GLength'} if self.is_mysql_5_5 else {}
62-
6352
disallowed_aggregates = (
6453
aggregates.Collect, aggregates.Extent, aggregates.Extent3D,
6554
aggregates.MakeLine, aggregates.Union,
@@ -75,8 +64,6 @@ def unsupported_functions(self):
7564
}
7665
if self.connection.mysql_version < (5, 7, 5):
7766
unsupported.update({'AsGeoJSON', 'GeoHash', 'IsValid'})
78-
if self.is_mysql_5_5:
79-
unsupported.update({'Difference', 'Distance', 'Intersection', 'SymDifference', 'Union'})
8067
return unsupported
8168

8269
def geo_db_type(self, f):

django/db/backends/mysql/base.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,14 @@ class DatabaseWrapper(BaseDatabaseWrapper):
9797
# types, as strings. Column-type strings can contain format strings; they'll
9898
# be interpolated against the values of Field.__dict__ before being output.
9999
# If a column type is set to None, it won't be included in the output.
100-
_data_types = {
100+
data_types = {
101101
'AutoField': 'integer AUTO_INCREMENT',
102102
'BigAutoField': 'bigint AUTO_INCREMENT',
103103
'BinaryField': 'longblob',
104104
'BooleanField': 'bool',
105105
'CharField': 'varchar(%(max_length)s)',
106106
'DateField': 'date',
107-
'DateTimeField': 'datetime',
107+
'DateTimeField': 'datetime(6)',
108108
'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
109109
'DurationField': 'bigint',
110110
'FileField': 'varchar(%(max_length)s)',
@@ -121,17 +121,10 @@ class DatabaseWrapper(BaseDatabaseWrapper):
121121
'SlugField': 'varchar(%(max_length)s)',
122122
'SmallIntegerField': 'smallint',
123123
'TextField': 'longtext',
124-
'TimeField': 'time',
124+
'TimeField': 'time(6)',
125125
'UUIDField': 'char(32)',
126126
}
127127

128-
@cached_property
129-
def data_types(self):
130-
if self.features.supports_microsecond_precision:
131-
return dict(self._data_types, DateTimeField='datetime(6)', TimeField='time(6)')
132-
else:
133-
return self._data_types
134-
135128
# For these columns, MySQL doesn't:
136129
# - accept default values and implicitly treats these columns as nullable
137130
# - support a database index

django/db/backends/mysql/features.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,6 @@ def can_introspect_foreign_keys(self):
6060
"Confirm support for introspected foreign keys"
6161
return self._mysql_storage_engine != 'MyISAM'
6262

63-
@cached_property
64-
def supports_microsecond_precision(self):
65-
return self.connection.mysql_version >= (5, 6, 4)
66-
6763
@cached_property
6864
def has_zoneinfo_database(self):
6965
# Test if the time zone definitions are installed.

django/db/backends/mysql/operations.py

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,7 @@ def date_interval_sql(self, timedelta):
109109
return "INTERVAL '%06f' SECOND_MICROSECOND" % timedelta.total_seconds()
110110

111111
def format_for_duration_arithmetic(self, sql):
112-
if self.connection.features.supports_microsecond_precision:
113-
return 'INTERVAL %s MICROSECOND' % sql
114-
else:
115-
return 'INTERVAL FLOOR(%s / 1000000) SECOND' % sql
112+
return 'INTERVAL %s MICROSECOND' % sql
116113

117114
def force_no_ordering(self):
118115
"""
@@ -178,10 +175,6 @@ def adapt_datetimefield_value(self, value):
178175
value = timezone.make_naive(value, self.connection.timezone)
179176
else:
180177
raise ValueError("MySQL backend does not support timezone-aware datetimes when USE_TZ is False.")
181-
182-
if not self.connection.features.supports_microsecond_precision:
183-
value = value.replace(microsecond=0)
184-
185178
return str(value)
186179

187180
def adapt_timefield_value(self, value):
@@ -258,17 +251,10 @@ def binary_placeholder_sql(self, value):
258251
def subtract_temporals(self, internal_type, lhs, rhs):
259252
lhs_sql, lhs_params = lhs
260253
rhs_sql, rhs_params = rhs
261-
if self.connection.features.supports_microsecond_precision:
262-
if internal_type == 'TimeField':
263-
return (
264-
"((TIME_TO_SEC(%(lhs)s) * POW(10, 6) + MICROSECOND(%(lhs)s)) -"
265-
" (TIME_TO_SEC(%(rhs)s) * POW(10, 6) + MICROSECOND(%(rhs)s)))"
266-
) % {'lhs': lhs_sql, 'rhs': rhs_sql}, lhs_params * 2 + rhs_params * 2
267-
else:
268-
return "TIMESTAMPDIFF(MICROSECOND, %s, %s)" % (rhs_sql, lhs_sql), rhs_params + lhs_params
269-
elif internal_type == 'TimeField':
254+
if internal_type == 'TimeField':
270255
return (
271-
"(TIME_TO_SEC(%s) * POW(10, 6) - TIME_TO_SEC(%s) * POW(10, 6))"
272-
) % (lhs_sql, rhs_sql), lhs_params + rhs_params
256+
"((TIME_TO_SEC(%(lhs)s) * POW(10, 6) + MICROSECOND(%(lhs)s)) -"
257+
" (TIME_TO_SEC(%(rhs)s) * POW(10, 6) + MICROSECOND(%(rhs)s)))"
258+
) % {'lhs': lhs_sql, 'rhs': rhs_sql}, lhs_params * 2 + rhs_params * 2
273259
else:
274-
return "(TIMESTAMPDIFF(SECOND, %s, %s) * POW(10, 6))" % (rhs_sql, lhs_sql), rhs_params + lhs_params
260+
return "TIMESTAMPDIFF(MICROSECOND, %s, %s)" % (rhs_sql, lhs_sql), rhs_params + lhs_params

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -379,12 +379,12 @@ Function PostGIS Oracle MySQL Spat
379379
:class:`Azimuth` X X (LWGEOM)
380380
:class:`BoundingCircle` X X
381381
:class:`Centroid` X X X X
382-
:class:`Difference` X X X (≥ 5.6.1) X
383-
:class:`Distance` X X X (≥ 5.6.1) X
382+
:class:`Difference` X X X X
383+
:class:`Distance` X X X X
384384
:class:`Envelope` X X X
385385
:class:`ForceRHR` X
386386
:class:`GeoHash` X X (≥ 5.7.5) X (LWGEOM)
387-
:class:`Intersection` X X X (≥ 5.6.1) X
387+
:class:`Intersection` X X X X
388388
:class:`IsValid` X X X (≥ 5.7.5) X (LWGEOM)
389389
:class:`Length` X X X X
390390
:class:`LineLocatePoint` X X
@@ -397,10 +397,10 @@ Function PostGIS Oracle MySQL Spat
397397
:class:`Reverse` X X X
398398
:class:`Scale` X X
399399
:class:`SnapToGrid` X X
400-
:class:`SymDifference` X X X (≥ 5.6.1) X
400+
:class:`SymDifference` X X X X
401401
:class:`Transform` X X X
402402
:class:`Translate` X X
403-
:class:`Union` X X X (≥ 5.6.1) X
403+
:class:`Union` X X X X
404404
==================================== ======= ============== =========== ==========
405405

406406
Aggregate Functions

docs/ref/contrib/gis/functions.txt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ value of the geometry.
208208

209209
.. class:: Difference(expr1, expr2, **extra)
210210

211-
*Availability*: MySQL (≥ 5.6.1), `PostGIS
211+
*Availability*: MySQL, `PostGIS
212212
<https://postgis.net/docs/ST_Difference.html>`__, Oracle, SpatiaLite
213213

214214
Accepts two geographic fields or expressions and returns the geometric
@@ -220,8 +220,8 @@ geometry B.
220220

221221
.. class:: Distance(expr1, expr2, spheroid=None, **extra)
222222

223-
*Availability*: MySQL (≥ 5.6.1), `PostGIS
224-
<https://postgis.net/docs/ST_Distance.html>`__, Oracle, SpatiaLite
223+
*Availability*: MySQL, `PostGIS <https://postgis.net/docs/ST_Distance.html>`__,
224+
Oracle, SpatiaLite
225225

226226
Accepts two geographic fields or expressions and returns the distance between
227227
them, as a :class:`~django.contrib.gis.measure.Distance` object. On MySQL, a raw
@@ -307,7 +307,7 @@ __ https://en.wikipedia.org/wiki/Geohash
307307

308308
.. class:: Intersection(expr1, expr2, **extra)
309309

310-
*Availability*: MySQL (≥ 5.6.1), `PostGIS
310+
*Availability*: MySQL, `PostGIS
311311
<https://postgis.net/docs/ST_Intersection.html>`__, Oracle, SpatiaLite
312312

313313
Accepts two geographic fields or expressions and returns the geometric
@@ -480,7 +480,7 @@ Number of Arguments Description
480480

481481
.. class:: SymDifference(expr1, expr2, **extra)
482482

483-
*Availability*: MySQL (≥ 5.6.1), `PostGIS
483+
*Availability*: MySQL, `PostGIS
484484
<https://postgis.net/docs/ST_SymDifference.html>`__, Oracle, SpatiaLite
485485

486486
Accepts two geographic fields or expressions and returns the geometric
@@ -522,8 +522,8 @@ parameters.
522522

523523
.. class:: Union(expr1, expr2, **extra)
524524

525-
*Availability*: MySQL (≥ 5.6.1), `PostGIS
526-
<https://postgis.net/docs/ST_Union.html>`__, Oracle, SpatiaLite
525+
*Availability*: MySQL, `PostGIS <https://postgis.net/docs/ST_Union.html>`__,
526+
Oracle, SpatiaLite
527527

528528
Accepts two geographic fields or expressions and returns the union of both
529529
geometries.

docs/ref/contrib/gis/install/index.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ supported versions, and any notes for each of the supported database backends:
5959
Database Library Requirements Supported Versions Notes
6060
================== ============================== ================== =========================================
6161
PostgreSQL GEOS, GDAL, PROJ.4, PostGIS 9.3+ Requires PostGIS.
62-
MySQL GEOS, GDAL 5.5+ Not OGC-compliant; :ref:`limited functionality <mysql-spatial-limitations>`.
62+
MySQL GEOS, GDAL 5.6+ Not OGC-compliant; :ref:`limited functionality <mysql-spatial-limitations>`.
6363
Oracle GEOS, GDAL 12.1+ XE not supported.
6464
SQLite GEOS, GDAL, PROJ.4, SpatiaLite 3.6.+ Requires SpatiaLite 4.0+
6565
================== ============================== ================== =========================================

docs/ref/databases.txt

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ MySQL notes
276276
Version support
277277
---------------
278278

279-
Django supports MySQL 5.5 and higher.
279+
Django supports MySQL 5.6 and higher.
280280

281281
Django's ``inspectdb`` feature uses the ``information_schema`` database, which
282282
contains detailed data on all database schemas.
@@ -294,36 +294,20 @@ Storage engines
294294
MySQL has several `storage engines`_. You can change the default storage engine
295295
in the server configuration.
296296

297-
Until MySQL 5.5.4, the default engine was MyISAM_ [#]_. The main drawbacks of
298-
MyISAM are that it doesn't support transactions or enforce foreign-key
299-
constraints. On the plus side, it was the only engine that supported full-text
300-
indexing and searching until MySQL 5.6.4.
297+
MySQL's default storage engine is InnoDB_. This engine is fully transactional
298+
and supports foreign key references. It's the recommended choice. However, the
299+
InnoDB autoincrement counter is lost on a MySQL restart because it does not
300+
remember the ``AUTO_INCREMENT`` value, instead recreating it as "max(id)+1".
301+
This may result in an inadvertent reuse of :class:`~django.db.models.AutoField`
302+
values.
301303

302-
Since MySQL 5.5.5, the default storage engine is InnoDB_. This engine is fully
303-
transactional and supports foreign key references. It's probably the best
304-
choice at this point. However, note that the InnoDB autoincrement counter
305-
is lost on a MySQL restart because it does not remember the
306-
``AUTO_INCREMENT`` value, instead recreating it as "max(id)+1". This may
307-
result in an inadvertent reuse of :class:`~django.db.models.AutoField` values.
308-
309-
If you upgrade an existing project to MySQL 5.5.5 and subsequently add some
310-
tables, ensure that your tables are using the same storage engine (i.e. MyISAM
311-
vs. InnoDB). Specifically, if tables that have a ``ForeignKey`` between them
312-
use different storage engines, you may see an error like the following when
313-
running ``migrate``::
314-
315-
_mysql_exceptions.OperationalError: (
316-
1005, "Can't create table '\\db_name\\.#sql-4a8_ab' (errno: 150)"
317-
)
304+
The main drawbacks of MyISAM_ are that it doesn't support transactions or
305+
enforce foreign-key constraints.
318306

319307
.. _storage engines: https://dev.mysql.com/doc/refman/en/storage-engines.html
320308
.. _MyISAM: https://dev.mysql.com/doc/refman/en/myisam-storage-engine.html
321309
.. _InnoDB: https://dev.mysql.com/doc/refman/en/innodb-storage-engine.html
322310

323-
.. [#] Unless this was changed by the packager of your MySQL package. We've
324-
had reports that the Windows Community Server installer sets up InnoDB as
325-
the default storage engine, for example.
326-
327311
.. _mysql-db-api-drivers:
328312

329313
MySQL DB API Drivers

docs/releases/2.1.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,12 @@ Database backend API
200200

201201
* ...
202202

203+
Dropped support for MySQL 5.5
204+
-----------------------------
205+
206+
The end of upstream support for MySQL 5.5 is December 2018. Django 2.1 supports
207+
MySQL 5.6 and higher.
208+
203209
Miscellaneous
204210
-------------
205211

tests/schema/tests.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2302,8 +2302,6 @@ def test_alter_pk_with_self_referential_field(self):
23022302
Changing the primary key field name of a model with a self-referential
23032303
foreign key (#26384).
23042304
"""
2305-
if connection.vendor == 'mysql' and connection.mysql_version < (5, 6, 6):
2306-
self.skipTest('Skip known bug renaming primary keys on older MySQL versions (#24995).')
23072305
with connection.schema_editor() as editor:
23082306
editor.create_model(Node)
23092307
old_field = Node._meta.get_field('node_id')

0 commit comments

Comments
 (0)