summaryrefslogtreecommitdiff
path: root/django/db/models/sql
diff options
context:
space:
mode:
authorMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2011-08-23 03:38:42 +0000
committerMalcolm Tredinnick <malcolm.tredinnick@gmail.com>2011-08-23 03:38:42 +0000
commit2e56066a5b93b528fbce37285bac591b44bc6ed7 (patch)
tree49c3a8f0aa57ceac620cbbe30978e7129d921b2c /django/db/models/sql
parentc3a0dcf6e9e7859a4a990954cbab0a44e7cb1307 (diff)
Fixed an isnull=False filtering edge-case. Fixes #15316.
The bulk of this patch is due to some fine analysis from Aleksandra Sendecka. git-svn-id: http://code.djangoproject.com/svn/django/trunk@16656 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/db/models/sql')
-rw-r--r--django/db/models/sql/query.py19
1 files changed, 14 insertions, 5 deletions
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index fd2e7a6d9a..e5e11f472a 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -1105,7 +1105,10 @@ class Query(object):
# Process the join list to see if we can remove any inner joins from
# the far end (fewer tables in a query is better).
- col, alias, join_list = self.trim_joins(target, join_list, last, trim)
+ nonnull_comparison = (lookup_type == 'isnull' and value is False)
+ col, alias, join_list = self.trim_joins(target, join_list, last, trim,
+ nonnull_comparison)
+
if connector == OR:
# Some joins may need to be promoted when adding a new filter to a
# disjunction. We walk the list of new joins and where it diverges
@@ -1442,7 +1445,7 @@ class Query(object):
return field, target, opts, joins, last, extra_filters
- def trim_joins(self, target, join_list, last, trim):
+ def trim_joins(self, target, join_list, last, trim, nonnull_check=False):
"""
Sometimes joins at the end of a multi-table sequence can be trimmed. If
the final join is against the same column as we are comparing against,
@@ -1463,6 +1466,11 @@ class Query(object):
trimmed before anything. See the documentation of add_filter() for
details about this.
+ The 'nonnull_check' parameter is True when we are using inner joins
+ between tables explicitly to exclude NULL entries. In that case, the
+ tables shouldn't be trimmed, because the very action of joining to them
+ alters the result set.
+
Returns the final active column and table alias and the new active
join_list.
"""
@@ -1470,7 +1478,7 @@ class Query(object):
penultimate = last.pop()
if penultimate == final:
penultimate = last.pop()
- if trim and len(join_list) > 1:
+ if trim and final > 1:
extra = join_list[penultimate:]
join_list = join_list[:penultimate]
final = penultimate
@@ -1483,12 +1491,13 @@ class Query(object):
alias = join_list[-1]
while final > 1:
join = self.alias_map[alias]
- if col != join[RHS_JOIN_COL] or join[JOIN_TYPE] != self.INNER:
+ if (col != join[RHS_JOIN_COL] or join[JOIN_TYPE] != self.INNER or
+ nonnull_check):
break
self.unref_alias(alias)
alias = join[LHS_ALIAS]
col = join[LHS_JOIN_COL]
- join_list = join_list[:-1]
+ join_list.pop()
final -= 1
if final == penultimate:
penultimate = last.pop()