Changeset 8853
- Timestamp:
- 09/02/08 08:52:07 (3 months ago)
- Files:
-
- django/trunk/django/db/models/sql/query.py (modified) (9 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/db/models/sql/query.py
r8832 r8853 659 659 660 660 # Must use left outer joins for nullable fields. 661 must_promote = False 662 for join in joins: 663 if self.promote_alias(join, must_promote): 664 must_promote = True 661 self.promote_alias_chain(joins) 665 662 666 663 # If we get to this point and the field is a relation to another model, … … 745 742 return False 746 743 744 def promote_alias_chain(self, chain, must_promote=False): 745 """ 746 Walks along a chain of aliases, promoting the first nullable join and 747 any joins following that. If 'must_promote' is True, all the aliases in 748 the chain are promoted. 749 """ 750 for alias in chain: 751 if self.promote_alias(alias, must_promote): 752 must_promote = True 753 754 def promote_unused_aliases(self, initial_refcounts, used_aliases): 755 """ 756 Given a "before" copy of the alias_refcounts dictionary (as 757 'initial_refcounts') and a collection of aliases that may have been 758 changed or created, works out which aliases have been created since 759 then and which ones haven't been used and promotes all of those 760 aliases, plus any children of theirs in the alias tree, to outer joins. 761 """ 762 # FIXME: There's some (a lot of!) overlap with the similar OR promotion 763 # in add_filter(). It's not quite identical, but is very similar. So 764 # pulling out the common bits is something for later. 765 considered = {} 766 for alias in self.tables: 767 if alias not in used_aliases: 768 continue 769 if (alias not in initial_refcounts or 770 self.alias_refcount[alias] == initial_refcounts[alias]): 771 parent = self.alias_map[alias][LHS_ALIAS] 772 must_promote = considered.get(parent, False) 773 promoted = self.promote_alias(alias, must_promote) 774 considered[alias] = must_promote or promoted 775 747 776 def change_aliases(self, change_map): 748 777 """ … … 808 837 should not be changed. 809 838 """ 810 assert ord(self.alias_prefix) < ord('Z') 811 self.alias_prefix = chr(ord(self.alias_prefix) + 1) 839 current = ord(self.alias_prefix) 840 assert current < ord('Z') 841 prefix = chr(current + 1) 842 self.alias_prefix = prefix 812 843 change_map = {} 813 prefix = self.alias_prefix814 844 for pos, alias in enumerate(self.tables): 815 845 if alias in exceptions: … … 888 918 # The LHS of this join tuple is no longer part of the 889 919 # query, so skip this possibility. 920 continue 921 if self.alias_map[alias][LHS_ALIAS] != lhs: 890 922 continue 891 923 self.ref_alias(alias) … … 1121 1153 join_it.next(), table_it.next() 1122 1154 table_promote = False 1155 join_promote = False 1123 1156 for join in join_it: 1124 1157 table = table_it.next() … … 1129 1162 table_promote = self.promote_alias(table) 1130 1163 break 1131 for join in join_it: 1132 if self.promote_alias(join, join_promote): 1133 join_promote = True 1134 for table in table_it: 1135 # Some of these will have been promoted from the join_list, but 1136 # that's harmless. 1137 if self.promote_alias(table, table_promote): 1138 table_promote = True 1164 self.promote_alias_chain(join_it, join_promote) 1165 self.promote_alias_chain(table_it, table_promote) 1139 1166 1140 1167 self.where.add((alias, col, field, lookup_type, value), connector) 1141 1168 1142 1169 if negate: 1143 for alias in join_list: 1144 self.promote_alias(alias) 1170 self.promote_alias_chain(join_list) 1145 1171 if lookup_type != 'isnull': 1146 1172 if final > 1: … … 1202 1228 # (they shouldn't turn the whole conditional into the empty 1203 1229 # set just because they don't match anything). 1204 # FIXME: There's some (a lot of!) overlap with the similar 1205 # OR promotion in add_filter(). It's not quite identical, 1206 # but is very similar. So pulling out the common bits is 1207 # something for later (code smell: too much indentation 1208 # here) 1209 considered = {} 1210 for alias in self.tables: 1211 if alias not in used_aliases: 1212 continue 1213 if (alias not in refcounts_before or 1214 self.alias_refcount[alias] == 1215 refcounts_before[alias]): 1216 parent = self.alias_map[alias][LHS_ALIAS] 1217 must_promote = considered.get(parent, False) 1218 promoted = self.promote_alias(alias, must_promote) 1219 considered[alias] = must_promote or promoted 1230 self.promote_unused_aliases(refcounts_before, used_aliases) 1220 1231 connector = q_object.connector 1221 1232 if q_object.negated: … … 1440 1451 query = Query(self.model, self.connection) 1441 1452 query.add_filter(filter_expr, can_reuse=can_reuse) 1453 query.bump_prefix() 1442 1454 query.set_start(prefix) 1443 1455 query.clear_ordering(True) … … 1501 1513 col = join[LHS_JOIN_COL] 1502 1514 joins = joins[:-1] 1503 promote = False 1504 for join in joins[1:]: 1505 # Only nullable aliases are promoted, so we don't end up 1506 # doing unnecessary left outer joins here. 1507 if self.promote_alias(join, promote): 1508 promote = True 1515 self.promote_alias_chain(joins[1:]) 1509 1516 self.select.append((final_alias, col)) 1510 1517 self.select_fields.append(field)
