diff options
| author | mike bayer <mike_mp@zzzcomputing.com> | 2017-01-19 16:28:58 -0500 |
|---|---|---|
| committer | Gerrit Code Review <gerrit@awstats.zzzcomputing.com> | 2017-01-19 16:28:58 -0500 |
| commit | 81518ae2e2bc622f8cd47287a575ad4c0e43ead1 (patch) | |
| tree | 8ba287eb1b7911b45888544d871a38864e765238 | |
| parent | 42027de3fce1d4ce2e3a684c59ee87f440b51ae8 (diff) | |
| parent | 4ae02f46e944ac11af5ad77e5ff5f06963b63b3d (diff) | |
| download | sqlalchemy-81518ae2e2bc622f8cd47287a575ad4c0e43ead1.tar.gz | |
Merge "Dont set _set_select_from() for alias object"
| -rw-r--r-- | doc/build/changelog/changelog_11.rst | 9 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/strategies.py | 7 | ||||
| -rw-r--r-- | test/orm/test_subquery_relations.py | 79 |
3 files changed, 93 insertions, 2 deletions
diff --git a/doc/build/changelog/changelog_11.rst b/doc/build/changelog/changelog_11.rst index c240515c4..63cdd484e 100644 --- a/doc/build/changelog/changelog_11.rst +++ b/doc/build/changelog/changelog_11.rst @@ -21,6 +21,15 @@ .. changelog:: :version: 1.1.6 + .. change:: 3893 + :tags: bug, orm + :tickets: 3893 + + Fixed bug first introduced in 0.9.7 as a result of :ticket:`3106` + which would cause an incorrect query in some forms of multi-level + subqueryload against aliased entities, with an unnecessary extra + FROM entity in the innermost subquery. + .. changelog:: :version: 1.1.5 :released: January 17, 2017 diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index 4e3574b54..ffd47d17d 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -851,11 +851,14 @@ class SubqueryLoader(AbstractRelationshipLoader): # 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.mapper.isa(leftmost_mapper): + 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) - # select from the identity columns of the outer + # select from the identity columns of the outer. This will remove + # other columns from the query that might suggest the right entity + # which is why we try to _set_select_from above. q._set_entities(target_cols) distinct_target_key = leftmost_relationship.distinct_target_key diff --git a/test/orm/test_subquery_relations.py b/test/orm/test_subquery_relations.py index ce9926058..03b7985c7 100644 --- a/test/orm/test_subquery_relations.py +++ b/test/orm/test_subquery_relations.py @@ -2073,6 +2073,85 @@ class JoinedNoLoadConflictTest(fixtures.DeclarativeMappedTest): ) +class SelfRefInheritanceAliasedTest( + fixtures.DeclarativeMappedTest, + testing.AssertsCompiledSQL): + __dialect__ = 'default' + + @classmethod + def setup_classes(cls): + Base = cls.DeclarativeBasic + + class Foo(Base): + __tablename__ = "foo" + id = Column(Integer, primary_key=True) + type = Column(String(50)) + + foo_id = Column(Integer, ForeignKey("foo.id")) + foo = relationship( + lambda: Foo, foreign_keys=foo_id, remote_side=id) + + __mapper_args__ = { + "polymorphic_on": type, + "polymorphic_identity": "foo", + } + + class Bar(Foo): + __mapper_args__ = { + "polymorphic_identity": "bar", + } + + @classmethod + def insert_data(cls): + Foo, Bar = cls.classes('Foo', 'Bar') + + session = Session() + target = Bar(id=1) + b1 = Bar(id=2, foo=Foo(id=3, foo=target)) + session.add(b1) + session.commit() + + def test_twolevel_subquery_w_polymorphic(self): + Foo, Bar = self.classes('Foo', 'Bar') + + I = with_polymorphic(Foo, "*", aliased=True) + attr1 = Foo.foo.of_type(I) + attr2 = I.foo + + s = Session() + q = s.query(Foo).filter(Foo.id == 2).options( + subqueryload(attr1).subqueryload(attr2)) + + self.assert_sql_execution( + testing.db, + q.all, + CompiledSQL( + "SELECT foo.id AS foo_id_1, foo.type AS foo_type, " + "foo.foo_id AS foo_foo_id FROM foo WHERE foo.id = :id_1", + [{'id_1': 2}] + ), + CompiledSQL( + "SELECT foo_1.id AS foo_1_id, foo_1.type AS foo_1_type, " + "foo_1.foo_id AS foo_1_foo_id, " + "anon_1.foo_foo_id AS anon_1_foo_foo_id " + "FROM (SELECT DISTINCT foo.foo_id AS foo_foo_id " + "FROM foo WHERE foo.id = :id_1) AS anon_1 " + "JOIN foo AS foo_1 ON foo_1.id = anon_1.foo_foo_id " + "ORDER BY anon_1.foo_foo_id", + {'id_1': 2} + ), + CompiledSQL( + "SELECT foo.id AS foo_id_1, foo.type AS foo_type, " + "foo.foo_id AS foo_foo_id, foo_1.foo_id AS foo_1_foo_id " + "FROM (SELECT DISTINCT foo.foo_id AS foo_foo_id FROM foo " + "WHERE foo.id = :id_1) AS anon_1 " + "JOIN foo AS foo_1 ON foo_1.id = anon_1.foo_foo_id " + "JOIN foo ON foo.id = foo_1.foo_id ORDER BY foo_1.foo_id", + {'id_1': 2} + ), + ) + + class TestExistingRowPopulation(fixtures.DeclarativeMappedTest): @classmethod def setup_classes(cls): |
