summaryrefslogtreecommitdiff
path: root/django/db/models/sql
diff options
context:
space:
mode:
authorBrian Rosner <brosner@gmail.com>2008-06-26 15:42:33 +0000
committerBrian Rosner <brosner@gmail.com>2008-06-26 15:42:33 +0000
commitc8da0874c78ed4c6e1ad08cc78228799a333f76c (patch)
treebef645a8eb2c1a17f013a1031ed34494547dced0 /django/db/models/sql
parentf15845c573f019fc7f6d7404add122f9b7c52dc4 (diff)
newforms-admin: Merged from trunk up to [7766].
git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@7770 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/db/models/sql')
-rw-r--r--django/db/models/sql/query.py72
-rw-r--r--django/db/models/sql/subqueries.py8
2 files changed, 55 insertions, 25 deletions
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 3044882a86..e8d10bc55b 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -610,6 +610,10 @@ class Query(object):
alias = joins[-1]
col = target.column
+ # Must use left outer joins for nullable fields.
+ for join in joins:
+ self.promote_alias(join)
+
# If we get to this point and the field is a relation to another model,
# append the default ordering for that model.
if field.rel and len(joins) > 1 and opts.ordering:
@@ -631,8 +635,10 @@ class Query(object):
# We have to do the same "final join" optimisation as in
# add_filter, since the final column might not otherwise be part of
# the select set (so we can't order on it).
- join = self.alias_map[alias]
- if col == join[RHS_JOIN_COL]:
+ while 1:
+ join = self.alias_map[alias]
+ if col != join[RHS_JOIN_COL]:
+ break
self.unref_alias(alias)
alias = join[LHS_ALIAS]
col = join[LHS_JOIN_COL]
@@ -679,12 +685,16 @@ class Query(object):
for the join to contain NULL values on the left. If 'unconditional' is
False, the join is only promoted if it is nullable, otherwise it is
always promoted.
+
+ Returns True if the join was promoted.
"""
if ((unconditional or self.alias_map[alias][NULLABLE]) and
self.alias_map[alias] != self.LOUTER):
data = list(self.alias_map[alias])
data[JOIN_TYPE] = self.LOUTER
self.alias_map[alias] = tuple(data)
+ return True
+ return False
def change_aliases(self, change_map):
"""
@@ -826,6 +836,10 @@ class Query(object):
if not always_create:
for alias in self.join_map.get(t_ident, ()):
if alias not in exclusions:
+ if lhs_table and not self.alias_refcount[self.alias_map[alias][LHS_ALIAS]]:
+ # The LHS of this join tuple is no longer part of the
+ # query, so skip this possibility.
+ continue
self.ref_alias(alias)
if promote:
self.promote_alias(alias)
@@ -985,20 +999,22 @@ class Query(object):
col = target.column
alias = join_list[-1]
- if final > 1:
+ while final > 1:
# An optimization: if the final join is against the same column as
# we are comparing against, we can go back one step in the join
- # chain and compare against the lhs of the join instead. The result
- # (potentially) involves one less table join.
+ # chain and compare against the lhs of the join instead (and then
+ # repeat the optimization). The result, potentially, involves less
+ # table joins.
join = self.alias_map[alias]
- if col == join[RHS_JOIN_COL]:
- self.unref_alias(alias)
- alias = join[LHS_ALIAS]
- col = join[LHS_JOIN_COL]
- join_list = join_list[:-1]
- final -= 1
- if final == penultimate:
- penultimate = last.pop()
+ if col != join[RHS_JOIN_COL]:
+ break
+ self.unref_alias(alias)
+ alias = join[LHS_ALIAS]
+ col = join[LHS_JOIN_COL]
+ join_list = join_list[:-1]
+ final -= 1
+ if final == penultimate:
+ penultimate = last.pop()
if (lookup_type == 'isnull' and value is True and not negate and
final > 1):
@@ -1033,17 +1049,27 @@ class Query(object):
self.promote_alias(table)
self.where.add((alias, col, field, lookup_type, value), connector)
+
if negate:
for alias in join_list:
self.promote_alias(alias)
- if final > 1 and lookup_type != 'isnull':
- for alias in join_list:
- if self.alias_map[alias] == self.LOUTER:
- j_col = self.alias_map[alias][RHS_JOIN_COL]
- entry = Node([(alias, j_col, None, 'isnull', True)])
- entry.negate()
- self.where.add(entry, AND)
- break
+ if lookup_type != 'isnull':
+ if final > 1:
+ for alias in join_list:
+ if self.alias_map[alias][JOIN_TYPE] == self.LOUTER:
+ j_col = self.alias_map[alias][RHS_JOIN_COL]
+ entry = Node([(alias, j_col, None, 'isnull', True)])
+ entry.negate()
+ self.where.add(entry, AND)
+ break
+ elif not (lookup_type == 'in' and not value):
+ # Leaky abstraction artifact: We have to specifically
+ # exclude the "foo__in=[]" case from this handling, because
+ # it's short-circuited in the Where class.
+ entry = Node([(alias, col, field, 'isnull', True)])
+ entry.negate()
+ self.where.add(entry, AND)
+
if can_reuse is not None:
can_reuse.update(join_list)
@@ -1294,10 +1320,12 @@ class Query(object):
final_alias = join[LHS_ALIAS]
col = join[LHS_JOIN_COL]
joins = joins[:-1]
+ promote = False
for join in joins[1:]:
# Only nullable aliases are promoted, so we don't end up
# doing unnecessary left outer joins here.
- self.promote_alias(join)
+ if self.promote_alias(join, promote):
+ promote = True
self.select.append((final_alias, col))
self.select_fields.append(field)
except MultiJoin:
diff --git a/django/db/models/sql/subqueries.py b/django/db/models/sql/subqueries.py
index 28436abede..0bb741d706 100644
--- a/django/db/models/sql/subqueries.py
+++ b/django/db/models/sql/subqueries.py
@@ -357,12 +357,14 @@ class DateQuery(Query):
date = typecast_timestamp(str(date))
yield date
- def add_date_select(self, column, lookup_type, order='ASC'):
+ def add_date_select(self, field, lookup_type, order='ASC'):
"""
Converts the query into a date extraction query.
"""
- alias = self.join((None, self.model._meta.db_table, None, None))
- select = Date((alias, column), lookup_type,
+ result = self.setup_joins([field.name], self.get_meta(),
+ self.get_initial_alias(), False)
+ alias = result[3][-1]
+ select = Date((alias, field.column), lookup_type,
self.connection.ops.date_trunc_sql)
self.select = [select]
self.select_fields = [None]