Skip to content

Commit

Permalink
Fixed #18461 -- Ensured that last_executed_query returns Unicode
Browse files Browse the repository at this point in the history
Thanks Anssi Kääriäinen for the review.
  • Loading branch information
claudep committed Jun 13, 2012
1 parent a7ef802 commit e9ef977
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 11 deletions.
2 changes: 1 addition & 1 deletion django/db/backends/mysql/base.py
Expand Up @@ -238,7 +238,7 @@ def last_executed_query(self, cursor, sql, params):
# 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 return cursor._last_executed.decode('utf-8')


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
Expand Down
4 changes: 3 additions & 1 deletion django/db/backends/postgresql_psycopg2/operations.py
Expand Up @@ -193,7 +193,9 @@ def distinct_sql(self, fields):
def last_executed_query(self, cursor, sql, params): def last_executed_query(self, cursor, sql, params):
# http://initd.org/psycopg/docs/cursor.html#cursor.query # http://initd.org/psycopg/docs/cursor.html#cursor.query
# The query attribute is a Psycopg extension to the DB API 2.0. # The query attribute is a Psycopg extension to the DB API 2.0.
return cursor.query if cursor.query is not None:
return cursor.query.decode('utf-8')
return None


def return_insert_id(self): def return_insert_id(self):
return "RETURNING %s", () return "RETURNING %s", ()
Expand Down
24 changes: 15 additions & 9 deletions tests/regressiontests/backends/tests.py
Expand Up @@ -125,20 +125,14 @@ def test_django_extract(self):
classes = models.SchoolClass.objects.filter(last_updated__day=20) classes = models.SchoolClass.objects.filter(last_updated__day=20)
self.assertEqual(len(classes), 1) self.assertEqual(len(classes), 1)


class LastExecutedQueryTest(TestCase):

def setUp(self):
# connection.queries will not be filled in without this
settings.DEBUG = True


def tearDown(self): class LastExecutedQueryTest(TestCase):
settings.DEBUG = False # There are no escaping tests for the sqlite backend because it does not

# There are no tests for the sqlite backend because it does not
# implement paramater escaping. See #14091. # implement paramater escaping. See #14091.


@unittest.skipUnless(connection.vendor in ('oracle', 'postgresql'), @unittest.skipUnless(connection.vendor in ('oracle', 'postgresql'),
"These backends use the standard parameter escaping rules") "These backends use the standard parameter escaping rules")
@override_settings(DEBUG=True)
def test_parameter_escaping(self): def test_parameter_escaping(self):
# check that both numbers and string are properly quoted # check that both numbers and string are properly quoted
list(models.Tag.objects.filter(name="special:\\\"':", object_id=12)) list(models.Tag.objects.filter(name="special:\\\"':", object_id=12))
Expand All @@ -148,13 +142,25 @@ def test_parameter_escaping(self):


@unittest.skipUnless(connection.vendor == 'mysql', @unittest.skipUnless(connection.vendor == 'mysql',
"MySQL uses backslashes to escape parameters.") "MySQL uses backslashes to escape parameters.")
@override_settings(DEBUG=True)
def test_parameter_escaping(self): def test_parameter_escaping(self):
list(models.Tag.objects.filter(name="special:\\\"':", object_id=12)) list(models.Tag.objects.filter(name="special:\\\"':", object_id=12))
sql = connection.queries[-1]['sql'] sql = connection.queries[-1]['sql']
# only this line is different from the test above # only this line is different from the test above
self.assertTrue("= 'special:\\\\\\\"\\':' " in sql) self.assertTrue("= 'special:\\\\\\\"\\':' " in sql)
self.assertTrue("= 12 " in sql) self.assertTrue("= 12 " in sql)


def test_query_encoding(self):
"""
Test that last_executed_query() returns an Unicode string
"""
tags = models.Tag.objects.filter(name="й", object_id=12).extra(select={'föö':1})
sql, params = tags.query.sql_with_params()
cursor = tags.query.get_compiler('default').execute_sql(None)
last_sql = cursor.db.ops.last_executed_query(cursor, sql, params)
self.assertTrue(isinstance(last_sql, unicode))


class ParameterHandlingTest(TestCase): class ParameterHandlingTest(TestCase):
def test_bad_parameter_count(self): def test_bad_parameter_count(self):
"An executemany call with too many/not enough parameters will raise an exception (Refs #12612)" "An executemany call with too many/not enough parameters will raise an exception (Refs #12612)"
Expand Down

0 comments on commit e9ef977

Please sign in to comment.