summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2017-06-15 13:12:16 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2017-06-16 13:02:31 -0400
commita991eedcf559e6992ada92913a29ed7022d62caa (patch)
treecb10f9ad9b518ed7269503b53a637ac8d61b32bb /lib/sqlalchemy/orm
parent3a314fcea8539133947d5ec8e42a6c86e30fdf9a (diff)
downloadsqlalchemy-a991eedcf559e6992ada92913a29ed7022d62caa.tar.gz
Set complete FROM list for subquery eagerload's orig query
Instead of checking that the "orig_entity" we receive applies as a correct FROM element for the subquery we're building, set the FROM clause of the query to exactly what it already is based on column_descriptions (assuming there is no FROM list already), thereby ensuring that the FROM list will remain intact, regardless of what orig_entity turns out to be and what the target_cols ultimately refer towards. Fixed issue with subquery eagerloading which continues on from the series of issues fixed in :ticket:`2699`, :ticket:`3106`, :ticket:`3893` involving that the "subquery" contains the correct FROM clause when beginning from a joined inheritance subclass and then subquery eager loading onto a relationship from the base class, while the query also includes criteria against the subclass. The fix in the previous tickets did not accommodate for additional subqueryload operations loading more deeply from the first level, so the fix has been further generalized. Change-Id: Ic909590814f71e577d8266b1dbc4c393dc48e019 Fixes: #4011
Diffstat (limited to 'lib/sqlalchemy/orm')
-rw-r--r--lib/sqlalchemy/orm/strategies.py23
1 files changed, 15 insertions, 8 deletions
diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py
index e48462d35..690984a6a 100644
--- a/lib/sqlalchemy/orm/strategies.py
+++ b/lib/sqlalchemy/orm/strategies.py
@@ -926,16 +926,23 @@ class SubqueryLoader(AbstractRelationshipLoader):
# to look only for significant columns
q = orig_query._clone().correlate(None)
- # set a real "from" if not present, as this is more
- # accurate than just going off of the column expression
- if not q._from_obj and orig_entity.is_mapper and \
- orig_entity.mapper.isa(leftmost_mapper):
- q._set_select_from([orig_entity], False)
- target_cols = q._adapt_col_list(leftmost_attr)
+ # set the query's "FROM" list explicitly to what the
+ # FROM list would be in any case, as we will be limiting
+ # the columns in the SELECT list which may no longer include
+ # all entities mentioned in things like WHERE, JOIN, etc.
+ if not q._from_obj:
+ q._set_select_from(
+ list(set([
+ ent['entity'] for ent in orig_query.column_descriptions
+ ])),
+ False
+ )
- # select from the identity columns of the outer. This will remove
+ # select from the identity columns of the outer (specifically, these
+ # are the 'local_cols' of the property). This will remove
# other columns from the query that might suggest the right entity
- # which is why we try to _set_select_from above.
+ # which is why we do _set_select_from above.
+ target_cols = q._adapt_col_list(leftmost_attr)
q._set_entities(target_cols)
distinct_target_key = leftmost_relationship.distinct_target_key