From 4fee39c63ce781e7af827feeabcc911080d81edc Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Sun, 27 Jul 2008 18:16:17 +0000 Subject: [PATCH] Fixed #7872 -- Fixed a missed case of promoting table joins when using 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 --- django/db/models/sql/query.py | 11 ++++++---- tests/regressiontests/queries/models.py | 27 +++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 2577b57a33..93a779e591 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -1089,20 +1089,23 @@ class Query(object): 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) diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py index 4ba519a08e..3a4acf350a 100644 --- a/tests/regressiontests/queries/models.py +++ b/tests/regressiontests/queries/models.py @@ -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') @@ -334,6 +347,16 @@ constraints. >>> Number.objects.filter(Q(num__gt=7) & Q(num__lt=12) | Q(num__lt=4)) [] +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.objects.filter(Q(data='first')|Q(join__b__data='second')) +[] + Bug #6074 Merging two empty result sets shouldn't leave a queryset with no constraints (which would match everything). @@ -430,9 +453,9 @@ Bug #5324, #6704 >>> 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.