Permalink
Browse files

Corrected logic for multiple same-connection joins in qs.combine

When OR-combining a qs having two joins with identical join connections
on the rhs side, then the combined query must have two joins, too. This
is a regression fix for removing exclude arg from .join().
  • Loading branch information...
akaariai committed Sep 16, 2012
1 parent b42280f commit da96154a72c4c4ca53cce198a82bb6af3f87ff64
Showing with 18 additions and 2 deletions.
  1. +6 −2 django/db/models/sql/query.py
  2. +12 −0 tests/regressiontests/queries/tests.py
@@ -478,7 +478,7 @@ def combine(self, rhs, connector):
#
# Note that we will be creating duplicate joins for non-m2m joins in
# the AND case. This is something that could be fixed later on.
reusability = None if conjunction else REUSE_ALL
reuse = set() if conjunction else set(self.tables)
# Make sure the first table is already in the query - this is the same
# table on both sides.
@@ -494,8 +494,12 @@ def combine(self, rhs, connector):
# updated alias.
lhs = change_map.get(lhs, lhs)
new_alias = self.join((lhs, table, lhs_col, col),
reuse=reusability, promote=promote,
reuse=reuse, promote=promote,
outer_if_first=not conjunction, nullable=nullable)
# We can't reuse the same join again. We might have two joins
# for the same join connection in the rhs query, and this must be
# the case in the combined query, too.
reuse.discard(new_alias)
change_map[alias] = new_alias
# So that we don't exclude valid results in an "or" query combination,
@@ -1046,6 +1046,18 @@ def test_ticket14876(self):
self.assertQuerysetEqual(q1, ["<Item: i1>"])
self.assertEqual(str(q1.query), str(q2.query))
def test_combine_join_reuse(self):
# Test that we correctly recreate joins having identical connections
# in the rhs query, in case the query is ORed together. Related to
# ticket #18748
Report.objects.create(name='r4', creator=self.a1)
q1 = Author.objects.filter(report__name='r5')
q2 = Author.objects.filter(report__name='r4').filter(report__name='r1')
combined = q1|q2
self.assertEquals(str(combined.query).count('JOIN'), 2)
self.assertEquals(len(combined), 1)
self.assertEquals(combined[0].name, 'a1')
def test_ticket7095(self):
# Updates that are filtered on the model being updated are somewhat
# tricky in MySQL. This exercises that case.

0 comments on commit da96154

Please sign in to comment.