mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	[1.7.x] Fixed #23605 -- Fixed nested subquery regression
Added relabeled_clone() method to sql.Query to fix the problem. It
manifested itself in rare cases where at least double nested subquery's
filter condition might target non-existing alias.
Thanks to Trac alias ris for reporting the problem.
Backport of 5c481db295 from master
			
			
This commit is contained in:
		
				
					committed by
					
						 Tim Graham
						Tim Graham
					
				
			
			
				
	
			
			
			
						parent
						
							2e2607870d
						
					
				
				
					commit
					01f2cf2aec
				
			| @@ -56,7 +56,7 @@ class SQLCompiler(object): | ||||
|         if name in self.quote_cache: | ||||
|             return self.quote_cache[name] | ||||
|         if ((name in self.query.alias_map and name not in self.query.table_map) or | ||||
|                 name in self.query.extra_select): | ||||
|                 name in self.query.extra_select or name in self.query.external_aliases): | ||||
|             self.quote_cache[name] = name | ||||
|             return name | ||||
|         r = self.connection.ops.quote_name(name) | ||||
|   | ||||
| @@ -114,6 +114,10 @@ class Query(object): | ||||
|         # type they are. The key is the alias of the joined table (possibly | ||||
|         # the table name) and the value is JoinInfo from constants.py. | ||||
|         self.alias_map = {} | ||||
|         # Sometimes the query contains references to aliases in outer queries (as | ||||
|         # a result of split_exclude). Correct alias quoting needs to know these | ||||
|         # aliases too. | ||||
|         self.external_aliases = set() | ||||
|         self.table_map = {}     # Maps table names to list of aliases. | ||||
|         self.join_map = {} | ||||
|         self.default_cols = True | ||||
| @@ -241,6 +245,7 @@ class Query(object): | ||||
|         obj.model = self.model | ||||
|         obj.alias_refcount = self.alias_refcount.copy() | ||||
|         obj.alias_map = self.alias_map.copy() | ||||
|         obj.external_aliases = self.external_aliases.copy() | ||||
|         obj.table_map = self.table_map.copy() | ||||
|         obj.join_map = self.join_map.copy() | ||||
|         obj.default_cols = self.default_cols | ||||
| @@ -335,6 +340,11 @@ class Query(object): | ||||
|             # Return value depends on the type of the field being processed. | ||||
|             return self.convert_values(value, aggregate.field, connection) | ||||
|  | ||||
|     def relabeled_clone(self, change_map): | ||||
|         clone = self.clone() | ||||
|         clone.change_aliases(change_map) | ||||
|         return clone | ||||
|  | ||||
|     def get_aggregation(self, using, force_subq=False): | ||||
|         """ | ||||
|         Returns the dictionary with the values of the existing aggregations. | ||||
| @@ -788,7 +798,9 @@ class Query(object): | ||||
|             ident = (change_map.get(ident[0], ident[0]),) + ident[1:] | ||||
|             self.join_map[ident] = aliases | ||||
|         for old_alias, new_alias in six.iteritems(change_map): | ||||
|             alias_data = self.alias_map[old_alias] | ||||
|             alias_data = self.alias_map.get(old_alias) | ||||
|             if alias_data is None: | ||||
|                 continue | ||||
|             alias_data = alias_data._replace(rhs_alias=new_alias) | ||||
|             self.alias_refcount[new_alias] = self.alias_refcount[old_alias] | ||||
|             del self.alias_refcount[old_alias] | ||||
| @@ -815,6 +827,9 @@ class Query(object): | ||||
|                 data = data._replace(lhs_alias=change_map[lhs]) | ||||
|                 self.alias_map[alias] = data | ||||
|  | ||||
|         self.external_aliases = {change_map.get(alias, alias) | ||||
|                                  for alias in self.external_aliases} | ||||
|  | ||||
|     def bump_prefix(self, outer_query): | ||||
|         """ | ||||
|         Changes the alias prefix to the next letter in the alphabet in a way | ||||
| @@ -1048,6 +1063,9 @@ class Query(object): | ||||
|         elif isinstance(value, ExpressionNode): | ||||
|             # If value is a query expression, evaluate it | ||||
|             value = SQLEvaluator(value, self, reuse=can_reuse) | ||||
|         # Subqueries need to use a different set of aliases than the | ||||
|         # outer query. Call bump_prefix to change aliases of the inner | ||||
|         # query (the value). | ||||
|         if hasattr(value, 'query') and hasattr(value.query, 'bump_prefix'): | ||||
|             value = value._clone() | ||||
|             value.query.bump_prefix(self) | ||||
| @@ -1509,6 +1527,7 @@ class Query(object): | ||||
|             lookup = lookup_class(Col(query.select[0].col[0], pk, pk), | ||||
|                                   Col(alias, pk, pk)) | ||||
|             query.where.add(lookup, AND) | ||||
|             query.external_aliases.add(alias) | ||||
|  | ||||
|         condition, needed_inner = self.build_filter( | ||||
|             ('%s__in' % trimmed_prefix, query), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user