From fcee0c1b66019a0e84bc338e76fa31695d5bd4ca Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Sat, 10 Sep 2011 18:58:30 +0000 Subject: [PATCH] Fixed #16809 -- Forced MySQL to behave like a database. This avoids a problem where queries that do IS NONE checks can return the wrong result the first time they are executed if there is a recently inserted row. Thanks to James Pyrich for the debug work and patch. git-svn-id: http://code.djangoproject.com/svn/django/trunk@16785 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/backends/mysql/base.py | 12 ++++++++++-- tests/regressiontests/queries/tests.py | 13 ------------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index a22951a3b7..e9f5b8b6a9 100644 --- a/django/db/backends/mysql/base.py +++ b/django/db/backends/mysql/base.py @@ -309,7 +309,9 @@ class DatabaseWrapper(BaseDatabaseWrapper): return False def _cursor(self): + new_connection = False if not self._valid_connection(): + new_connection = True kwargs = { 'conv': django_conversions, 'charset': 'utf8', @@ -336,8 +338,14 @@ class DatabaseWrapper(BaseDatabaseWrapper): self.connection.encoders[SafeUnicode] = self.connection.encoders[unicode] self.connection.encoders[SafeString] = self.connection.encoders[str] connection_created.send(sender=self.__class__, connection=self) - cursor = CursorWrapper(self.connection.cursor()) - return cursor + cursor = self.connection.cursor() + if new_connection: + # SQL_AUTO_IS_NULL in MySQL controls whether an AUTO_INCREMENT column + # on a recently-inserted row will return when the field is tested for + # NULL. Disabling this value brings this aspect of MySQL in line with + # SQL standards. + cursor.execute('SET SQL_AUTO_IS_NULL = 0') + return CursorWrapper(cursor) def _rollback(self): try: diff --git a/tests/regressiontests/queries/tests.py b/tests/regressiontests/queries/tests.py index 708e60da85..d8fd5bc9ce 100644 --- a/tests/regressiontests/queries/tests.py +++ b/tests/regressiontests/queries/tests.py @@ -1070,10 +1070,6 @@ class Queries4Tests(BaseQuerysetTest): ci3 = CategoryItem.objects.create(category=c3) qs = CategoryItem.objects.exclude(category__specialcategory__isnull=False) - # Under MySQL, this query gives incorrect values on the first attempt. - # If you run exactly the same query twice, it yields the right answer - # the second attempt. Oh, how we do love MySQL. - qs.count() self.assertEqual(qs.count(), 1) self.assertQuerysetEqual(qs, [ci1.pk], lambda x: x.pk) @@ -1136,10 +1132,6 @@ class Queries4Tests(BaseQuerysetTest): ci3 = CategoryItem.objects.create(category=c1) qs = CategoryItem.objects.exclude(category__onetoonecategory__isnull=False) - # Under MySQL, this query gives incorrect values on the first attempt. - # If you run exactly the same query twice, it yields the right answer - # the second attempt. Oh, how we do love MySQL. - qs.count() self.assertEqual(qs.count(), 1) self.assertQuerysetEqual(qs, [ci1.pk], lambda x: x.pk) @@ -1421,11 +1413,6 @@ class Queries6Tests(TestCase): [] ) - # This next makes exactly *zero* sense, but it works. It's needed - # because MySQL fails to give the right results the first time this - # query is executed. If you run the same query a second time, it - # works fine. It's a hack, but it works... - list(Tag.objects.exclude(children=None)) self.assertQuerysetEqual( Tag.objects.exclude(children=None), ['', '']