mirror of https://github.com/django/django.git
Fixed #19954 -- Fixed MySQL _last_executed decoding
Queries can contain binary data undecodable with utf-8. In this case, using the 'replace' errors mode when decoding seems like an acceptable representation of the query. Thanks Marcel Ryser for the report.
This commit is contained in:
parent
ef348b5298
commit
86b1c31689
|
@ -37,7 +37,7 @@ from django.db.backends.mysql.client import DatabaseClient
|
||||||
from django.db.backends.mysql.creation import DatabaseCreation
|
from django.db.backends.mysql.creation import DatabaseCreation
|
||||||
from django.db.backends.mysql.introspection import DatabaseIntrospection
|
from django.db.backends.mysql.introspection import DatabaseIntrospection
|
||||||
from django.db.backends.mysql.validation import DatabaseValidation
|
from django.db.backends.mysql.validation import DatabaseValidation
|
||||||
from django.utils.encoding import force_str
|
from django.utils.encoding import force_str, force_text
|
||||||
from django.utils.safestring import SafeBytes, SafeText
|
from django.utils.safestring import SafeBytes, SafeText
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -270,7 +270,7 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
# With MySQLdb, cursor objects have an (undocumented) "_last_executed"
|
# With MySQLdb, cursor objects have an (undocumented) "_last_executed"
|
||||||
# attribute where the exact query sent to the database is saved.
|
# attribute where the exact query sent to the database is saved.
|
||||||
# See MySQLdb/cursors.py in the source distribution.
|
# See MySQLdb/cursors.py in the source distribution.
|
||||||
return cursor._last_executed.decode('utf-8')
|
return force_text(cursor._last_executed, errors='replace')
|
||||||
|
|
||||||
def no_limit_value(self):
|
def no_limit_value(self):
|
||||||
# 2**64 - 1, as recommended by the MySQL documentation
|
# 2**64 - 1, as recommended by the MySQL documentation
|
||||||
|
|
|
@ -62,6 +62,7 @@ class Post(models.Model):
|
||||||
class Reporter(models.Model):
|
class Reporter(models.Model):
|
||||||
first_name = models.CharField(max_length=30)
|
first_name = models.CharField(max_length=30)
|
||||||
last_name = models.CharField(max_length=30)
|
last_name = models.CharField(max_length=30)
|
||||||
|
raw_data = models.BinaryField()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s %s" % (self.first_name, self.last_name)
|
return "%s %s" % (self.first_name, self.last_name)
|
||||||
|
|
|
@ -157,18 +157,18 @@ class DateQuotingTest(TestCase):
|
||||||
class LastExecutedQueryTest(TestCase):
|
class LastExecutedQueryTest(TestCase):
|
||||||
|
|
||||||
def test_debug_sql(self):
|
def test_debug_sql(self):
|
||||||
list(models.Tag.objects.filter(name="test"))
|
list(models.Reporter.objects.filter(first_name="test"))
|
||||||
sql = connection.queries[-1]['sql'].lower()
|
sql = connection.queries[-1]['sql'].lower()
|
||||||
self.assertIn("select", sql)
|
self.assertIn("select", sql)
|
||||||
self.assertIn(models.Tag._meta.db_table, sql)
|
self.assertIn(models.Reporter._meta.db_table, sql)
|
||||||
|
|
||||||
def test_query_encoding(self):
|
def test_query_encoding(self):
|
||||||
"""
|
"""
|
||||||
Test that last_executed_query() returns an Unicode string
|
Test that last_executed_query() returns an Unicode string
|
||||||
"""
|
"""
|
||||||
tags = models.Tag.objects.extra(select={'föö': 1})
|
persons = models.Reporter.objects.filter(raw_data=b'\x00\x46 \xFE').extra(select={'föö': 1})
|
||||||
sql, params = tags.query.sql_with_params()
|
sql, params = persons.query.sql_with_params()
|
||||||
cursor = tags.query.get_compiler('default').execute_sql(None)
|
cursor = persons.query.get_compiler('default').execute_sql(None)
|
||||||
last_sql = cursor.db.ops.last_executed_query(cursor, sql, params)
|
last_sql = cursor.db.ops.last_executed_query(cursor, sql, params)
|
||||||
self.assertTrue(isinstance(last_sql, six.text_type))
|
self.assertTrue(isinstance(last_sql, six.text_type))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue