Kaydet (Commit) f9a2a7db authored tarafından Claude Paroz's avatar Claude Paroz

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.
üst 0d3c616f
from django.core import checks from django.core import checks
from django.db.backends.base.validation import BaseDatabaseValidation from django.db.backends.base.validation import BaseDatabaseValidation
from django.utils.version import get_docs_version
class DatabaseValidation(BaseDatabaseValidation): 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): def check_field(self, field, **kwargs):
""" """
MySQL has the following field length restriction: MySQL has the following field length restriction:
......
...@@ -592,6 +592,8 @@ If you're using MySQL, the following checks will be performed: ...@@ -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 * **mysql.E001**: MySQL does not allow unique ``CharField``\s to have a
``max_length`` > 255. ``max_length`` > 255.
* **mysql.W002**: MySQL Strict Mode is not set for database connection
'<alias>'. See also :ref:`mysql-sql-mode`.
Templates Templates
--------- ---------
......
...@@ -31,3 +31,28 @@ class DatabaseCheckTests(TestCase): ...@@ -31,3 +31,28 @@ class DatabaseCheckTests(TestCase):
with mock.patch('django.db.backends.base.validation.BaseDatabaseValidation.check') as mocked_check: with mock.patch('django.db.backends.base.validation.BaseDatabaseValidation.check') as mocked_check:
run_checks(tags=[Tags.database]) run_checks(tags=[Tags.database])
self.assertTrue(mocked_check.called) 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'])
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment