summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulien Phalip <jphalip@gmail.com>2012-04-09 00:43:08 +0000
committerJulien Phalip <jphalip@gmail.com>2012-04-09 00:43:08 +0000
commit93d1fdb1304ed5b2e5ea2e0f1e84db7fff5eb7fa (patch)
tree908a45af91a033e5b0508ed06ab1f73e52a3dff1
parent5c53e30607014163872e89c221b206992a9acfef (diff)
Fixed #17877 -- Ensured that extra WHERE clauses get correctly ANDed when they contain OR operations. Thanks to Marek Brzóska for the report, to eleather for the test case and to Adrien Lemaire for the patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17880 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--AUTHORS1
-rw-r--r--django/db/models/sql/where.py3
-rw-r--r--docs/ref/models/querysets.txt4
-rw-r--r--tests/regressiontests/extra_regress/tests.py31
4 files changed, 36 insertions, 3 deletions
diff --git a/AUTHORS b/AUTHORS
index 0af0c7961e..fc3cb93406 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -326,6 +326,7 @@ answer newbie questions, and generally made Django that much better:
lcordier@point45.com
Jeong-Min Lee <falsetru@gmail.com>
Tai Lee <real.human@mrmachine.net>
+ Adrien Lemaire <lemaire.adrien@gmail.com>
Christopher Lenz <http://www.cmlenz.net/>
lerouxb@gmail.com
Piotr Lewandowski <piotr.lewandowski@gmail.com>
diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py
index 2bd705dd60..0bc3638b80 100644
--- a/django/db/models/sql/where.py
+++ b/django/db/models/sql/where.py
@@ -281,7 +281,8 @@ class ExtraWhere(object):
self.params = params
def as_sql(self, qn=None, connection=None):
- return " AND ".join(self.sqls), tuple(self.params or ())
+ sqls = ["(%s)" % sql for sql in self.sqls]
+ return " AND ".join(sqls), tuple(self.params or ())
class Constraint(object):
"""
diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt
index e25bea0e69..b20c6e34e5 100644
--- a/docs/ref/models/querysets.txt
+++ b/docs/ref/models/querysets.txt
@@ -968,11 +968,11 @@ of the arguments is required, but you should use at least one of them.
Example::
- Entry.objects.extra(where=['id IN (3, 4, 5, 20)'])
+ Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
...translates (roughly) into the following SQL::
- SELECT * FROM blog_entry WHERE id IN (3, 4, 5, 20);
+ SELECT * FROM blog_entry WHERE (foo='a' OR bar='a') AND (baz='a')
Be careful when using the ``tables`` parameter if you're specifying
tables that are already used in the query. When you add extra tables
diff --git a/tests/regressiontests/extra_regress/tests.py b/tests/regressiontests/extra_regress/tests.py
index 67efb428dd..3fcafef5de 100644
--- a/tests/regressiontests/extra_regress/tests.py
+++ b/tests/regressiontests/extra_regress/tests.py
@@ -313,3 +313,34 @@ class ExtraRegressTests(TestCase):
TestObject.objects.extra(where=["id > %s"], params=[obj.pk]),
['<TestObject: TestObject: first,second,third>']
)
+
+ def test_regression_17877(self):
+ """
+ Ensure that extra WHERE clauses get correctly ANDed, even when they
+ contain OR operations.
+ """
+ # Test Case 1: should appear in queryset.
+ t = TestObject(first='a', second='a', third='a')
+ t.save()
+ # Test Case 2: should appear in queryset.
+ t = TestObject(first='b', second='a', third='a')
+ t.save()
+ # Test Case 3: should not appear in queryset, bug case.
+ t = TestObject(first='a', second='a', third='b')
+ t.save()
+ # Test Case 4: should not appear in queryset.
+ t = TestObject(first='b', second='a', third='b')
+ t.save()
+ # Test Case 5: should not appear in queryset.
+ t = TestObject(first='b', second='b', third='a')
+ t.save()
+ # Test Case 6: should not appear in queryset, bug case.
+ t = TestObject(first='a', second='b', third='b')
+ t.save()
+
+ self.assertQuerysetEqual(
+ TestObject.objects.extra(
+ where=["first = 'a' OR second = 'a'", "third = 'a'"],
+ ),
+ ['<TestObject: TestObject: a,a,a>', '<TestObject: TestObject: b,a,a>']
+ )