diff options
| author | Anssi Kääriäinen <akaariai@gmail.com> | 2012-05-26 05:55:33 +0300 |
|---|---|---|
| committer | Anssi Kääriäinen <akaariai@gmail.com> | 2012-07-01 17:21:34 +0300 |
| commit | bd283aa844b04651b7c8b4e85f48c6dced1678f0 (patch) | |
| tree | 327212e84b9640608898257bcdf61861168911fd /django/db/models/sql | |
| parent | 2b9fb2e6443c04e4415b17083d727bd80047b6e5 (diff) | |
Refactored the empty/full result logic in WhereNode.as_sql()
Made sure the WhereNode.as_sql() handles various EmptyResultSet and
FullResultSet conditions correctly. Also, got rid of the FullResultSet
exception class. It is now represented by '', [] return value in the
as_sql() methods.
Diffstat (limited to 'django/db/models/sql')
| -rw-r--r-- | django/db/models/sql/datastructures.py | 3 | ||||
| -rw-r--r-- | django/db/models/sql/where.py | 83 |
2 files changed, 48 insertions, 38 deletions
diff --git a/django/db/models/sql/datastructures.py b/django/db/models/sql/datastructures.py index 92d64e15dd..b8e06daf01 100644 --- a/django/db/models/sql/datastructures.py +++ b/django/db/models/sql/datastructures.py @@ -6,9 +6,6 @@ the SQL domain. class EmptyResultSet(Exception): pass -class FullResultSet(Exception): - pass - class MultiJoin(Exception): """ Used by join construction code to indicate the point at which a diff --git a/django/db/models/sql/where.py b/django/db/models/sql/where.py index 5515bc4f83..70ff5310f7 100644 --- a/django/db/models/sql/where.py +++ b/django/db/models/sql/where.py @@ -10,7 +10,7 @@ from itertools import repeat from django.utils import tree from django.db.models.fields import Field -from django.db.models.sql.datastructures import EmptyResultSet, FullResultSet +from django.db.models.sql.datastructures import EmptyResultSet from django.db.models.sql.aggregates import Aggregate # Connection types @@ -75,17 +75,21 @@ class WhereNode(tree.Node): def as_sql(self, qn, connection): """ Returns the SQL version of the where clause and the value to be - substituted in. Returns None, None if this node is empty. - - If 'node' is provided, that is the root of the SQL generation - (generally not needed except by the internal implementation for - recursion). + substituted in. Returns '', [] if this node matches everything, + None, [] if this node is empty, and raises EmptyResultSet if this + node can't match anything. """ - if not self.children: - return None, [] + # Note that the logic here is made slightly more complex than + # necessary because there are two kind of empty nodes: Nodes + # containing 0 children, and nodes that are known to match everything. + # A match-everything node is different than empty node (which also + # technically matches everything) for backwards compatibility reasons. + # Refs #5261. result = [] result_params = [] - empty = True + everything_childs, nothing_childs = 0, 0 + non_empty_childs = len(self.children) + for child in self.children: try: if hasattr(child, 'as_sql'): @@ -93,39 +97,48 @@ class WhereNode(tree.Node): else: # A leaf node in the tree. sql, params = self.make_atom(child, qn, connection) - except EmptyResultSet: - if self.connector == AND and not self.negated: - # We can bail out early in this particular case (only). - raise - elif self.negated: - empty = False - continue - except FullResultSet: - if self.connector == OR: - if self.negated: - empty = True - break - # We match everything. No need for any constraints. + nothing_childs += 1 + else: + if sql: + result.append(sql) + result_params.extend(params) + else: + if sql is None: + # Skip empty childs totally. + non_empty_childs -= 1 + continue + everything_childs += 1 + # Check if this node matches nothing or everything. + # First check the amount of full nodes and empty nodes + # to make this node empty/full. + if self.connector == AND: + full_needed, empty_needed = non_empty_childs, 1 + else: + full_needed, empty_needed = 1, non_empty_childs + # Now, check if this node is full/empty using the + # counts. + if empty_needed - nothing_childs <= 0: + if self.negated: return '', [] + else: + raise EmptyResultSet + if full_needed - everything_childs <= 0: if self.negated: - empty = True - continue - - empty = False - if sql: - result.append(sql) - result_params.extend(params) - if empty: - raise EmptyResultSet + raise EmptyResultSet + else: + return '', [] + if non_empty_childs == 0: + # All the child nodes were empty, so this one is empty, too. + return None, [] conn = ' %s ' % self.connector sql_string = conn.join(result) if sql_string: - if self.negated: - sql_string = 'NOT (%s)' % sql_string - elif len(self.children) != 1: + if len(result) > 1: sql_string = '(%s)' % sql_string + if self.negated: + sql_string = 'NOT %s' % sql_string return sql_string, result_params def make_atom(self, child, qn, connection): @@ -261,7 +274,7 @@ class EverythingNode(object): """ def as_sql(self, qn=None, connection=None): - raise FullResultSet + return '', [] def relabel_aliases(self, change_map, node=None): return |
