summaryrefslogtreecommitdiff
path: root/django/db
diff options
context:
space:
mode:
authorAnssi Kääriäinen <akaariai@gmail.com>2014-01-08 19:35:47 +0200
committerAnssi Kääriäinen <akaariai@gmail.com>2014-02-04 19:06:37 +0200
commitfd3fa851b592700a8b04af46f626454db0db02e4 (patch)
treed26538d93939d45c162da265dfe03a0accfa6fc0 /django/db
parent0f272629ca18e440aef67b4a3fd9377a57fb25a8 (diff)
[1.6.x] Fixed #21748 -- join promotion for negated AND conditions
Made sure Django treats case .filter(NOT (a AND b)) the same way as .filter((NOT a OR NOT b)) for join promotion. Heavily modified backpatch of 35cecb1ebd0ccda0be7a518d1b7273333d26fbae from master. Conflicts: django/db/models/sql/query.py tests/queries/tests.py
Diffstat (limited to 'django/db')
-rw-r--r--django/db/models/sql/query.py16
1 files changed, 9 insertions, 7 deletions
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index bb05c94e14..7868c19ab8 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -1211,16 +1211,18 @@ class Query(object):
connector = q_object.connector
current_negated = current_negated ^ q_object.negated
branch_negated = branch_negated or q_object.negated
- # Note that if the connector happens to match what we have already in
- # the tree, the add will be a no-op.
target_clause = self.where_class(connector=connector,
negated=q_object.negated)
-
- if connector == OR:
+ # Treat case NOT (a AND b) like case ((NOT a) OR (NOT b)) for join
+ # promotion. See ticket #21748.
+ effective_connector = connector
+ if current_negated:
+ effective_connector = OR if effective_connector == AND else AND
+ if effective_connector == OR:
alias_usage_counts = dict()
aliases_before = set(self.tables)
for child in q_object.children:
- if connector == OR:
+ if effective_connector == OR:
refcounts_before = self.alias_refcount.copy()
if isinstance(child, Node):
child_clause = self._add_q(
@@ -1231,11 +1233,11 @@ class Query(object):
child, can_reuse=used_aliases, branch_negated=branch_negated,
current_negated=current_negated)
target_clause.add(child_clause, connector)
- if connector == OR:
+ if effective_connector == OR:
used = alias_diff(refcounts_before, self.alias_refcount)
for alias in used:
alias_usage_counts[alias] = alias_usage_counts.get(alias, 0) + 1
- if connector == OR:
+ if effective_connector == OR:
self.promote_disjunction(aliases_before, alias_usage_counts,
len(q_object.children))
return target_clause