diff --git a/django/contrib/gis/db/models/sql/compiler.py b/django/contrib/gis/db/models/sql/compiler.py
index 07eea32..ca5a43a 100644
|
a
|
b
|
|
| 1 | 1 | from itertools import izip |
| 2 | 2 | from django.db.backends.util import truncate_name, typecast_timestamp |
| 3 | 3 | from django.db.models.sql import compiler |
| 4 | | from django.db.models.sql.constants import TABLE_NAME, MULTI |
| | 4 | from django.db.models.sql.constants import MULTI |
| 5 | 5 | |
| 6 | 6 | SQLCompiler = compiler.SQLCompiler |
| 7 | 7 | |
| … |
… |
class GeoSQLCompiler(compiler.SQLCompiler):
|
| 35 | 35 | for col, field in izip(self.query.select, self.query.select_fields): |
| 36 | 36 | if isinstance(col, (list, tuple)): |
| 37 | 37 | alias, column = col |
| 38 | | table = self.query.alias_map[alias][TABLE_NAME] |
| | 38 | table = self.query.alias_map[alias].table_name |
| 39 | 39 | if table in only_load and column not in only_load[table]: |
| 40 | 40 | continue |
| 41 | 41 | r = self.get_field_select(field, alias, column) |
| … |
… |
class GeoSQLCompiler(compiler.SQLCompiler):
|
| 138 | 138 | # aliases will have already been set up in pre_sql_setup(), so |
| 139 | 139 | # we can save time here. |
| 140 | 140 | alias = self.query.included_inherited_models[model] |
| 141 | | table = self.query.alias_map[alias][TABLE_NAME] |
| | 141 | table = self.query.alias_map[alias].table_name |
| 142 | 142 | if table in only_load and field.column not in only_load[table]: |
| 143 | 143 | continue |
| 144 | 144 | if as_pairs: |
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index 6c516e2..f864fd7 100644
|
a
|
b
|
class SQLCompiler(object):
|
| 188 | 188 | for col in self.query.select: |
| 189 | 189 | if isinstance(col, (list, tuple)): |
| 190 | 190 | alias, column = col |
| 191 | | table = self.query.alias_map[alias][TABLE_NAME] |
| | 191 | table = self.query.alias_map[alias].table_name |
| 192 | 192 | if table in only_load and column not in only_load[table]: |
| 193 | 193 | continue |
| 194 | 194 | r = '%s.%s' % (qn(alias), qn(column)) |
| … |
… |
class SQLCompiler(object):
|
| 289 | 289 | # aliases will have already been set up in pre_sql_setup(), so |
| 290 | 290 | # we can save time here. |
| 291 | 291 | alias = self.query.included_inherited_models[model] |
| 292 | | table = self.query.alias_map[alias][TABLE_NAME] |
| | 292 | table = self.query.alias_map[alias].table_name |
| 293 | 293 | if table in only_load and field.column not in only_load[table]: |
| 294 | 294 | continue |
| 295 | 295 | if as_pairs: |
| … |
… |
class SQLCompiler(object):
|
| 432 | 432 | # Firstly, avoid infinite loops. |
| 433 | 433 | if not already_seen: |
| 434 | 434 | already_seen = set() |
| 435 | | join_tuple = tuple([self.query.alias_map[j][TABLE_NAME] for j in joins]) |
| | 435 | join_tuple = tuple([self.query.alias_map[j].table_name for j in joins]) |
| 436 | 436 | if join_tuple in already_seen: |
| 437 | 437 | raise FieldError('Infinite loop caused by ordering.') |
| 438 | 438 | already_seen.add(join_tuple) |
| … |
… |
class SQLCompiler(object):
|
| 470 | 470 | # Ordering or distinct must not affect the returned set, and INNER |
| 471 | 471 | # JOINS for nullable fields could do this. |
| 472 | 472 | self.query.promote_alias_chain(joins, |
| 473 | | self.query.alias_map[joins[0]][JOIN_TYPE] == self.query.LOUTER) |
| | 473 | self.query.alias_map[joins[0]].join_type == self.query.LOUTER) |
| 474 | 474 | return field, col, alias, joins, opts |
| 475 | 475 | |
| 476 | 476 | def _final_join_removal(self, col, alias): |
| … |
… |
class SQLCompiler(object):
|
| 485 | 485 | if alias: |
| 486 | 486 | while 1: |
| 487 | 487 | join = self.query.alias_map[alias] |
| 488 | | if col != join[RHS_JOIN_COL]: |
| | 488 | if col != join.rhs_join_col: |
| 489 | 489 | break |
| 490 | 490 | self.query.unref_alias(alias) |
| 491 | | alias = join[LHS_ALIAS] |
| 492 | | col = join[LHS_JOIN_COL] |
| | 491 | alias = join.lhs_alias |
| | 492 | col = join.lhs_join_col |
| 493 | 493 | return col, alias |
| 494 | 494 | |
| 495 | 495 | def get_from_clause(self): |
| … |
… |
class SQLCompiler(object):
|
| 641 | 641 | alias_chain.append(alias) |
| 642 | 642 | for (dupe_opts, dupe_col) in dupe_set: |
| 643 | 643 | self.query.update_dupe_avoidance(dupe_opts, dupe_col, alias) |
| 644 | | if self.query.alias_map[root_alias][JOIN_TYPE] == self.query.LOUTER: |
| | 644 | if self.query.alias_map[root_alias].join_type == self.query.LOUTER: |
| 645 | 645 | self.query.promote_alias_chain(alias_chain, True) |
| 646 | 646 | else: |
| 647 | 647 | alias = root_alias |
| … |
… |
class SQLCompiler(object):
|
| 659 | 659 | columns, aliases = self.get_default_columns(start_alias=alias, |
| 660 | 660 | opts=f.rel.to._meta, as_pairs=True) |
| 661 | 661 | self.query.related_select_cols.extend(columns) |
| 662 | | if self.query.alias_map[alias][JOIN_TYPE] == self.query.LOUTER: |
| | 662 | if self.query.alias_map[alias].join_type == self.query.LOUTER: |
| 663 | 663 | self.query.promote_alias_chain(aliases, True) |
| 664 | 664 | self.query.related_select_fields.extend(f.rel.to._meta.fields) |
| 665 | 665 | if restricted: |
diff --git a/django/db/models/sql/constants.py b/django/db/models/sql/constants.py
index 63c704f..12c8aed 100644
|
a
|
b
|
|
| | 1 | from collections import namedtuple |
| 1 | 2 | import re |
| 2 | 3 | |
| 3 | 4 | # Valid query types (a dictionary is used for speedy lookups). |
| … |
… |
LOOKUP_SEP = '__'
|
| 17 | 18 | # Constants to make looking up tuple values clearer. |
| 18 | 19 | # Join lists (indexes into the tuples that are values in the alias_map |
| 19 | 20 | # dictionary in the Query class). |
| 20 | | TABLE_NAME = 0 |
| 21 | | RHS_ALIAS = 1 |
| 22 | | JOIN_TYPE = 2 |
| 23 | | LHS_ALIAS = 3 |
| 24 | | LHS_JOIN_COL = 4 |
| 25 | | RHS_JOIN_COL = 5 |
| 26 | | NULLABLE = 6 |
| | 21 | JoinInfo = namedtuple('JoinInfo', |
| | 22 | 'table_name rhs_alias join_type lhs_alias ' |
| | 23 | 'lhs_join_col rhs_join_col nullable') |
| 27 | 24 | |
| 28 | 25 | # How many results to expect from a cursor.execute call |
| 29 | 26 | MULTI = 'multi' |
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 780f93e..05ccbe2 100644
|
a
|
b
|
class Query(object):
|
| 101 | 101 | def __init__(self, model, where=WhereNode): |
| 102 | 102 | self.model = model |
| 103 | 103 | self.alias_refcount = SortedDict() |
| 104 | | self.alias_map = {} # Maps alias to join information |
| | 104 | # alias_map is the most important data structure regarding joins - |
| | 105 | # this is used for recording which joins there exists in the |
| | 106 | # query, and what type they are. The key is the alias of the |
| | 107 | # joined table (possibly the table name) and the value is JoinInfo |
| | 108 | # from constants.py. |
| | 109 | self.alias_map = {} |
| 105 | 110 | self.table_map = {} # Maps table names to list of aliases. |
| 106 | 111 | self.join_map = {} |
| 107 | 112 | self.quote_cache = {} |
| … |
… |
class Query(object):
|
| 688 | 693 | |
| 689 | 694 | Returns True if the join was promoted by this call. |
| 690 | 695 | """ |
| 691 | | if ((unconditional or self.alias_map[alias][NULLABLE]) and |
| 692 | | self.alias_map[alias][JOIN_TYPE] != self.LOUTER): |
| 693 | | data = list(self.alias_map[alias]) |
| 694 | | data[JOIN_TYPE] = self.LOUTER |
| 695 | | self.alias_map[alias] = tuple(data) |
| | 696 | if ((unconditional or self.alias_map[alias].nullable) and |
| | 697 | self.alias_map[alias].join_type != self.LOUTER): |
| | 698 | data = self.alias_map[alias] |
| | 699 | data = data._replace(join_type=self.LOUTER) |
| | 700 | self.alias_map[alias] = data |
| 696 | 701 | return True |
| 697 | 702 | return False |
| 698 | 703 | |
| … |
… |
class Query(object):
|
| 732 | 737 | continue |
| 733 | 738 | if (alias not in initial_refcounts or |
| 734 | 739 | self.alias_refcount[alias] == initial_refcounts[alias]): |
| 735 | | parent = self.alias_map[alias][LHS_ALIAS] |
| | 740 | parent = self.alias_map[alias].lhs_alias |
| 736 | 741 | must_promote = considered.get(parent, False) |
| 737 | 742 | promoted = self.promote_alias(alias, must_promote) |
| 738 | 743 | considered[alias] = must_promote or promoted |
| … |
… |
class Query(object):
|
| 769 | 774 | aliases = tuple([change_map.get(a, a) for a in aliases]) |
| 770 | 775 | self.join_map[k] = aliases |
| 771 | 776 | for old_alias, new_alias in change_map.iteritems(): |
| 772 | | alias_data = list(self.alias_map[old_alias]) |
| 773 | | alias_data[RHS_ALIAS] = new_alias |
| | 777 | alias_data = self.alias_map[old_alias] |
| | 778 | alias_data = alias_data._replace(rhs_alias=new_alias) |
| 774 | 779 | self.alias_refcount[new_alias] = self.alias_refcount[old_alias] |
| 775 | 780 | del self.alias_refcount[old_alias] |
| 776 | | self.alias_map[new_alias] = tuple(alias_data) |
| | 781 | self.alias_map[new_alias] = alias_data |
| 777 | 782 | del self.alias_map[old_alias] |
| 778 | 783 | |
| 779 | | table_aliases = self.table_map[alias_data[TABLE_NAME]] |
| | 784 | table_aliases = self.table_map[alias_data.table_name] |
| 780 | 785 | for pos, alias in enumerate(table_aliases): |
| 781 | 786 | if alias == old_alias: |
| 782 | 787 | table_aliases[pos] = new_alias |
| … |
… |
class Query(object):
|
| 791 | 796 | |
| 792 | 797 | # 3. Update any joins that refer to the old alias. |
| 793 | 798 | for alias, data in self.alias_map.iteritems(): |
| 794 | | lhs = data[LHS_ALIAS] |
| | 799 | lhs = data.lhs_alias |
| 795 | 800 | if lhs in change_map: |
| 796 | | data = list(data) |
| 797 | | data[LHS_ALIAS] = change_map[lhs] |
| 798 | | self.alias_map[alias] = tuple(data) |
| | 801 | data = data._replace(lhs_alias=change_map[lhs]) |
| | 802 | self.alias_map[alias] = data |
| 799 | 803 | |
| 800 | 804 | def bump_prefix(self, exceptions=()): |
| 801 | 805 | """ |
| … |
… |
class Query(object):
|
| 878 | 882 | """ |
| 879 | 883 | lhs, table, lhs_col, col = connection |
| 880 | 884 | if lhs in self.alias_map: |
| 881 | | lhs_table = self.alias_map[lhs][TABLE_NAME] |
| | 885 | lhs_table = self.alias_map[lhs].table_name |
| 882 | 886 | else: |
| 883 | 887 | lhs_table = lhs |
| 884 | 888 | |
| … |
… |
class Query(object):
|
| 891 | 895 | if not always_create: |
| 892 | 896 | for alias in self.join_map.get(t_ident, ()): |
| 893 | 897 | if alias not in exclusions: |
| 894 | | if lhs_table and not self.alias_refcount[self.alias_map[alias][LHS_ALIAS]]: |
| | 898 | if lhs_table and not self.alias_refcount[self.alias_map[alias].lhs_alias]: |
| 895 | 899 | # The LHS of this join tuple is no longer part of the |
| 896 | 900 | # query, so skip this possibility. |
| 897 | 901 | continue |
| 898 | | if self.alias_map[alias][LHS_ALIAS] != lhs: |
| | 902 | if self.alias_map[alias].lhs_alias != lhs: |
| 899 | 903 | continue |
| 900 | 904 | self.ref_alias(alias) |
| 901 | 905 | if promote: |
| … |
… |
class Query(object):
|
| 912 | 916 | join_type = self.LOUTER |
| 913 | 917 | else: |
| 914 | 918 | join_type = self.INNER |
| 915 | | join = (table, alias, join_type, lhs, lhs_col, col, nullable) |
| | 919 | join = JoinInfo(table, alias, join_type, lhs, lhs_col, col, nullable) |
| 916 | 920 | self.alias_map[alias] = join |
| 917 | 921 | if t_ident in self.join_map: |
| 918 | 922 | self.join_map[t_ident] += (alias,) |
| … |
… |
class Query(object):
|
| 1152 | 1156 | # also be promoted, regardless of whether they have been |
| 1153 | 1157 | # promoted as a result of this pass through the tables. |
| 1154 | 1158 | unconditional = (unconditional or |
| 1155 | | self.alias_map[join][JOIN_TYPE] == self.LOUTER) |
| | 1159 | self.alias_map[join].join_type == self.LOUTER) |
| 1156 | 1160 | if join == table and self.alias_refcount[join] > 1: |
| 1157 | 1161 | # We have more than one reference to this join table. |
| 1158 | 1162 | # This means that we are dealing with two different query |
| … |
… |
class Query(object):
|
| 1183 | 1187 | if lookup_type != 'isnull': |
| 1184 | 1188 | if len(join_list) > 1: |
| 1185 | 1189 | for alias in join_list: |
| 1186 | | if self.alias_map[alias][JOIN_TYPE] == self.LOUTER: |
| 1187 | | j_col = self.alias_map[alias][RHS_JOIN_COL] |
| | 1190 | if self.alias_map[alias].join_type == self.LOUTER: |
| | 1191 | j_col = self.alias_map[alias].rhs_join_col |
| 1188 | 1192 | entry = self.where_class() |
| 1189 | 1193 | entry.add( |
| 1190 | 1194 | (Constraint(alias, j_col, None), 'isnull', True), |
| … |
… |
class Query(object):
|
| 1510 | 1514 | join_list = join_list[:penultimate] |
| 1511 | 1515 | final = penultimate |
| 1512 | 1516 | penultimate = last.pop() |
| 1513 | | col = self.alias_map[extra[0]][LHS_JOIN_COL] |
| | 1517 | col = self.alias_map[extra[0]].lhs_join_col |
| 1514 | 1518 | for alias in extra: |
| 1515 | 1519 | self.unref_alias(alias) |
| 1516 | 1520 | else: |
| … |
… |
class Query(object):
|
| 1518 | 1522 | alias = join_list[-1] |
| 1519 | 1523 | while final > 1: |
| 1520 | 1524 | join = self.alias_map[alias] |
| 1521 | | if (col != join[RHS_JOIN_COL] or join[JOIN_TYPE] != self.INNER or |
| | 1525 | if (col != join.rhs_join_col or join.join_type != self.INNER or |
| 1522 | 1526 | nonnull_check): |
| 1523 | 1527 | break |
| 1524 | 1528 | self.unref_alias(alias) |
| 1525 | | alias = join[LHS_ALIAS] |
| 1526 | | col = join[LHS_JOIN_COL] |
| | 1529 | alias = join.lhs_alias |
| | 1530 | col = join.lhs_join_col |
| 1527 | 1531 | join_list.pop() |
| 1528 | 1532 | final -= 1 |
| 1529 | 1533 | if final == penultimate: |
| … |
… |
class Query(object):
|
| 1646 | 1650 | col = target.column |
| 1647 | 1651 | if len(joins) > 1: |
| 1648 | 1652 | join = self.alias_map[final_alias] |
| 1649 | | if col == join[RHS_JOIN_COL]: |
| | 1653 | if col == join.rhs_join_col: |
| 1650 | 1654 | self.unref_alias(final_alias) |
| 1651 | | final_alias = join[LHS_ALIAS] |
| 1652 | | col = join[LHS_JOIN_COL] |
| | 1655 | final_alias = join.lhs_alias |
| | 1656 | col = join.lhs_join_col |
| 1653 | 1657 | joins = joins[:-1] |
| 1654 | 1658 | self.promote_alias_chain(joins[1:]) |
| 1655 | 1659 | self.select.append((final_alias, col)) |
| … |
… |
class Query(object):
|
| 1923 | 1927 | alias = self.get_initial_alias() |
| 1924 | 1928 | field, col, opts, joins, last, extra = self.setup_joins( |
| 1925 | 1929 | start.split(LOOKUP_SEP), opts, alias, False) |
| 1926 | | select_col = self.alias_map[joins[1]][LHS_JOIN_COL] |
| | 1930 | select_col = self.alias_map[joins[1]].lhs_join_col |
| 1927 | 1931 | select_alias = alias |
| 1928 | 1932 | |
| 1929 | 1933 | # The call to setup_joins added an extra reference to everything in |
| … |
… |
class Query(object):
|
| 1936 | 1940 | # is *always* the same value as lhs). |
| 1937 | 1941 | for alias in joins[1:]: |
| 1938 | 1942 | join_info = self.alias_map[alias] |
| 1939 | | if (join_info[LHS_JOIN_COL] != select_col |
| 1940 | | or join_info[JOIN_TYPE] != self.INNER): |
| | 1943 | if (join_info.lhs_join_col != select_col |
| | 1944 | or join_info.join_type != self.INNER): |
| 1941 | 1945 | break |
| 1942 | 1946 | self.unref_alias(select_alias) |
| 1943 | | select_alias = join_info[RHS_ALIAS] |
| 1944 | | select_col = join_info[RHS_JOIN_COL] |
| | 1947 | select_alias = join_info.rhs_alias |
| | 1948 | select_col = join_info.rhs_join_col |
| 1945 | 1949 | self.select = [(select_alias, select_col)] |
| 1946 | 1950 | self.remove_inherited_models() |
| 1947 | 1951 | |