summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2016-03-19 12:15:59 +0100
committerClaude Paroz <claude@2xlibre.net>2016-04-08 20:34:16 +0200
commitf9a2a7db173b53f9cb0cd2d3def80d4eed72631c (patch)
treefa6cfafbf9e6473ca8300d3e43d7481b6b9cdb19
parent0d3c616fbb2f49fa7ff6809e5a6777275352b35b (diff)
Fixed #26351 -- Added MySQL check to warn about strict mode option
Thanks Adam Chainz for the initial implementation in django-mysql. Thanks Adam Chainz, Tim Graham, and Shai Berger for the reviews.
-rw-r--r--django/db/backends/mysql/validation.py23
-rw-r--r--docs/ref/checks.txt2
-rw-r--r--tests/check_framework/test_database.py25
3 files changed, 50 insertions, 0 deletions
diff --git a/django/db/backends/mysql/validation.py b/django/db/backends/mysql/validation.py
index 2e3bb0279b..e62a6e4c7e 100644
--- a/django/db/backends/mysql/validation.py
+++ b/django/db/backends/mysql/validation.py
@@ -1,8 +1,31 @@
from django.core import checks
from django.db.backends.base.validation import BaseDatabaseValidation
+from django.utils.version import get_docs_version
class DatabaseValidation(BaseDatabaseValidation):
+ def check(self, **kwargs):
+ issues = super(DatabaseValidation, self).check(**kwargs)
+ issues.extend(self._check_sql_mode(**kwargs))
+ return issues
+
+ def _check_sql_mode(self, **kwargs):
+ with self.connection.cursor() as cursor:
+ cursor.execute("SELECT @@sql_mode")
+ sql_mode = cursor.fetchone()
+ modes = set(sql_mode[0].split(','))
+ if not (modes & {'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES'}):
+ return [checks.Warning(
+ "MySQL Strict Mode is not set for database connection '%s'" % self.connection.alias,
+ hint="MySQL's Strict Mode fixes many data integrity problems in MySQL, "
+ "such as data truncation upon insertion, by escalating warnings into "
+ "errors. It is strongly recommended you activate it. See: "
+ "https://docs.djangoproject.com/en/%s/ref/databases/#mysql-sql-mode"
+ % (get_docs_version(),),
+ id='mysql.W002',
+ )]
+ return []
+
def check_field(self, field, **kwargs):
"""
MySQL has the following field length restriction:
diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt
index a332df2071..7c15bbeb7b 100644
--- a/docs/ref/checks.txt
+++ b/docs/ref/checks.txt
@@ -592,6 +592,8 @@ If you're using MySQL, the following checks will be performed:
* **mysql.E001**: MySQL does not allow unique ``CharField``\s to have a
``max_length`` > 255.
+* **mysql.W002**: MySQL Strict Mode is not set for database connection
+ '<alias>'. See also :ref:`mysql-sql-mode`.
Templates
---------
diff --git a/tests/check_framework/test_database.py b/tests/check_framework/test_database.py
index 73edd6234c..594f4ccee6 100644
--- a/tests/check_framework/test_database.py
+++ b/tests/check_framework/test_database.py
@@ -31,3 +31,28 @@ class DatabaseCheckTests(TestCase):
with mock.patch('django.db.backends.base.validation.BaseDatabaseValidation.check') as mocked_check:
run_checks(tags=[Tags.database])
self.assertTrue(mocked_check.called)
+
+ @unittest.skipUnless(connection.vendor == 'mysql', 'Test only for MySQL')
+ def test_mysql_strict_mode(self):
+ good_sql_modes = [
+ 'STRICT_TRANS_TABLES,STRICT_ALL_TABLES',
+ 'STRICT_TRANS_TABLES',
+ 'STRICT_ALL_TABLES',
+ ]
+ for response in good_sql_modes:
+ with mock.patch(
+ 'django.db.backends.utils.CursorWrapper.fetchone', create=True,
+ return_value=(response,)
+ ):
+ self.assertEqual(self.func(None), [])
+
+ bad_sql_modes = ['', 'WHATEVER']
+ for response in bad_sql_modes:
+ with mock.patch(
+ 'django.db.backends.utils.CursorWrapper.fetchone', create=True,
+ return_value=(response,)
+ ):
+ # One warning for each database alias
+ result = self.func(None)
+ self.assertEqual(len(result), 2)
+ self.assertEqual([r.id for r in result], ['mysql.W002', 'mysql.W002'])