"Cannot combine a unique query with a non-unique query."
- l_tables = set([a for a in self.tables if self.alias_refcount[a]])
- r_tables = set([a for a in rhs.tables if rhs.alias_refcount[a]])
# Work out how to relabel the rhs aliases, if necessary.
# all joins exclusive to either the lhs or the rhs must be converted
+ l_tables = set(self.tables)
+ r_tables = set(rhs.tables)
# Update r_tables aliases.
+ # r_tables may contain entries that have a refcount of 0
+ # if the query has references to a table that can be
+ # trimmed because only the foreign key is used.
+ # We only need to fix the aliases for the tables that
+ # actually have aliases.
+ if rhs.alias_refcount[alias]:
# Find aliases that are exclusive to rhs or lhs.
# These are promoted to outer joins.
- outer_aliases = (l_tables | r_tables) - (l_tables & r_tables)
- for alias in outer_aliases:
- self.promote_alias(alias, True)
+ outer_tables = (l_tables | r_tables) - (l_tables & r_tables)
+ for alias in outer_tables:
+ # Again, some of the tables won't have aliases due to
+ # the trimming of unnecessary tables.
+ if self.alias_refcount.get(alias) or rhs.alias_refcount.get(alias):
+ self.promote_alias(alias, True)
# Now relabel a copy of the rhs where-clause and add it to the current
False, the join is only promoted if it is nullable, otherwise it is
- Returns True if the join was promoted.
+ Returns True if the join was promoted.
if ((unconditional or self.alias_map[alias][NULLABLE]) and
self.alias_map[alias][JOIN_TYPE] != self.LOUTER):
if (lookup_type == 'isnull' and value is True and not negate and
# If the comparison is against NULL, we may need to use some left
# outer joins when creating the join chain. This is only done when
# needed, as it's less efficient at the database level.
# 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)
# 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
join_it = iter(join_list)
table_it = iter(self.tables)
+ # Once we hit an outer join, all subsequent joins must
+ # also be promoted, regardless of whether they have been
+ # promoted as a result of this pass through the tables.
+ unconditional = (unconditional or
+ self.alias_map[join][JOIN_TYPE] == self.LOUTER)
if join == table and self.alias_refcount[join] > 1:
+ # We have more than one reference to this join table.
+ # This means that we are dealing with two different query
+ # subtrees, so we don't need to do any join promotion.
- join_promote = self.promote_alias(join)
+ join_promote = self.promote_alias(join)
table_promote = self.promote_alias(table)
+ # We only get here if we have found a table that exists
+ # in the join list, but isn't on the original tables list.
+ # This means we've reached the point where we only have
+ # new tables, so we can break out of this promotion loop.
- self.promote_alias_chain(table_it, table_promote)
+ self.promote_alias_chain(table_it, table_promote or join_promote)
if having_clause or force_having:
if (alias, col) not in self.group_by: