Skip to content

Commit

Permalink
Fixed #7872 -- Fixed a missed case of promoting table joins when using
Browse files Browse the repository at this point in the history
disjunctive filters. Thanks to Michael Radziej for the failing test case.
problem.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@8107 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
malcolmt committed Jul 27, 2008
1 parent 4774c8d commit 4fee39c
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 6 deletions.
11 changes: 7 additions & 4 deletions django/db/models/sql/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -1089,20 +1089,23 @@ def add_filter(self, filter_expr, connector=AND, negate=False, trim=False,
join_it = iter(join_list)
table_it = iter(self.tables)
join_it.next(), table_it.next()
table_promote = False
for join in join_it:
table = table_it.next()
if join == table and self.alias_refcount[join] > 1:
continue
self.promote_alias(join)
join_promote = self.promote_alias(join)
if table != join:
self.promote_alias(table)
table_promote = self.promote_alias(table)
break
for join in join_it:
self.promote_alias(join)
if self.promote_alias(join, join_promote):
join_promote = True
for table in table_it:
# Some of these will have been promoted from the join_list, but
# that's harmless.
self.promote_alias(table)
if self.promote_alias(table, table_promote):
table_promote = True

self.where.add((alias, col, field, lookup_type, value), connector)

Expand Down
27 changes: 25 additions & 2 deletions tests/regressiontests/queries/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,19 @@ class TvChef(Celebrity):
class Fan(models.Model):
fan_of = models.ForeignKey(Celebrity)

# Multiple foreign keys
class LeafA(models.Model):
data = models.CharField(max_length=10)

def __unicode__(self):
return self.data

class LeafB(models.Model):
data = models.CharField(max_length=10)

class Join(models.Model):
a = models.ForeignKey(LeafA)
b = models.ForeignKey(LeafB)

__test__ = {'API_TESTS':"""
>>> t1 = Tag.objects.create(name='t1')
Expand Down Expand Up @@ -334,6 +347,16 @@ class Fan(models.Model):
>>> Number.objects.filter(Q(num__gt=7) & Q(num__lt=12) | Q(num__lt=4))
[<Number: 8>]
Bug #7872
Another variation on the disjunctive filtering theme.
# For the purposes of this regression test, it's important that there is no
# Join object releated to the LeafA we create.
>>> LeafA.objects.create(data='first')
<LeafA: first>
>>> LeafA.objects.filter(Q(data='first')|Q(join__b__data='second'))
[<LeafA: first>]
Bug #6074
Merging two empty result sets shouldn't leave a queryset with no constraints
(which would match everything).
Expand Down Expand Up @@ -430,9 +453,9 @@ class Fan(models.Model):
>>> query.LOUTER not in [x[2] for x in query.alias_map.values()]
True
Similarly, when one of the joins cannot possibly, ever, involve NULL values (Author -> ExtraInfo, in the following), it should never be promoted to a left outer join. So hte following query should only involve one "left outer" join (Author -> Item is 0-to-many).
Similarly, when one of the joins cannot possibly, ever, involve NULL values (Author -> ExtraInfo, in the following), it should never be promoted to a left outer join. So the following query should only involve one "left outer" join (Author -> Item is 0-to-many).
>>> qs = Author.objects.filter(id=a1.id).filter(Q(extra__note=n1)|Q(item__note=n3))
>>> len([x[2] for x in qs.query.alias_map.values() if x[2] == query.LOUTER])
>>> len([x[2] for x in qs.query.alias_map.values() if x[2] == query.LOUTER and qs.query.alias_refcount[x[1]]])
1
The previous changes shouldn't affect nullable foreign key joins.
Expand Down

0 comments on commit 4fee39c

Please sign in to comment.