diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index d92d2f6..f3646c0 100644
a
|
b
|
from django.db.models.sql import aggregates as base_aggregates_module
|
20 | 20 | from django.db.models.sql.expressions import SQLEvaluator |
21 | 21 | from django.db.models.sql.where import WhereNode, Constraint, EverythingNode, AND, OR |
22 | 22 | from django.core.exceptions import FieldError |
23 | | from datastructures import EmptyResultSet, Empty, MultiJoin |
| 23 | from datastructures import EmptyResultSet, FullResultSet, Empty, MultiJoin |
24 | 24 | from constants import * |
25 | 25 | |
26 | 26 | try: |
… |
… |
class BaseQuery(object):
|
400 | 400 | from_, f_params = self.get_from_clause() |
401 | 401 | |
402 | 402 | qn = self.quote_name_unless_alias |
403 | | where, w_params = self.where.as_sql(qn=qn) |
| 403 | try: |
| 404 | where, w_params = self.where.as_sql(qn=qn) |
| 405 | except FullResultSet: |
| 406 | where, w_params = '', [] |
404 | 407 | having, h_params = self.having.as_sql(qn=qn) |
405 | 408 | params = [] |
406 | 409 | for val in self.extra_select.itervalues(): |
diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py
index ec0545c..42f317c 100644
a
|
b
|
class WhereNode(tree.Node):
|
94 | 94 | result = [] |
95 | 95 | result_params = [] |
96 | 96 | empty = True |
| 97 | full = True |
97 | 98 | for child in self.children: |
98 | 99 | try: |
99 | 100 | if hasattr(child, 'as_sql'): |
… |
… |
class WhereNode(tree.Node):
|
103 | 104 | sql, params = self.make_atom(child, qn) |
104 | 105 | |
105 | 106 | except EmptyResultSet: |
106 | | if self.connector == AND and not self.negated: |
107 | | # We can bail out early in this particular case (only). |
108 | | raise |
109 | | elif self.negated: |
110 | | empty = False |
111 | | continue |
| 107 | if self.connector == AND: |
| 108 | # Ignoring negation, the result is empty |
| 109 | empty, full = True, False |
| 110 | break |
| 111 | else: |
| 112 | # Definitely not full, but maybe still empty |
| 113 | full = False |
| 114 | continue |
112 | 115 | except FullResultSet: |
113 | 116 | if self.connector == OR: |
114 | | if self.negated: |
115 | | empty = True |
116 | | break |
117 | | # We match everything. No need for any constraints. |
118 | | return '', [] |
119 | | if self.negated: |
120 | | empty = True |
121 | | continue |
| 117 | # Ignoring negation, the result is full |
| 118 | empty, full = False, True |
| 119 | break |
| 120 | else: |
| 121 | # Definitely not empty, but maybe still full |
| 122 | empty = False |
| 123 | continue |
122 | 124 | |
123 | 125 | empty = False |
| 126 | full = False |
124 | 127 | if sql: |
125 | 128 | result.append(sql) |
126 | 129 | result_params.extend(params) |
127 | | if empty: |
| 130 | |
| 131 | # Take negation into account here and raise the appropriate indicator |
| 132 | if empty and self.negated or full and not self.negated: |
| 133 | raise FullResultSet |
| 134 | if empty and not self.negated or full and self.negated: |
128 | 135 | raise EmptyResultSet |
129 | 136 | |
130 | 137 | conn = ' %s ' % self.connector |
diff --git a/tests/modeltests/or_lookups/models.py b/tests/modeltests/or_lookups/models.py
index 60b40d0..aca2823 100644
a
|
b
|
__test__ = {'API_TESTS':"""
|
133 | 133 | [<Article: Hello>] |
134 | 134 | >>> Article.objects.complex_filter(Q(pk=1) | Q(pk=2)) |
135 | 135 | [<Article: Hello>, <Article: Goodbye>] |
| 136 | |
| 137 | # Empty or full result sets bubble correctly |
| 138 | >>> Article.objects.filter((Q(pk=1) | ~Q(pk__in=[])) & Q(pk=3)) |
| 139 | [<Article: Hello and goodbye>] |
136 | 140 | """} |