From: Mike Bayer Date: Sat, 13 Aug 2016 03:35:40 +0000 (-0400) Subject: Ensure final link in subqueryload join is correct X-Git-Tag: rel_1_1_0~51^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b07eb3cb45d1a344759a2eee9d2166fbf3e44888;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Ensure final link in subqueryload join is correct Fixed bug in subquery eager loading where a subqueryload of an "of_type()" object linked to a second subqueryload of a plain mapped class would fail to link the joins correctly. Change-Id: I4be89e6f5e492438464a2ded01eb9c84d7ff7d4e Fixes: #3773 --- diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst index 16a38e6626..f91b9cac1d 100644 --- a/doc/build/changelog/changelog_10.rst +++ b/doc/build/changelog/changelog_10.rst @@ -18,6 +18,15 @@ .. changelog:: :version: 1.0.15 + .. change:: + :tags: bug, orm + :tickets: 3773 + :versions: 1.1.0 + + Fixed bug in subquery eager loading where a subqueryload + of an "of_type()" object linked to a second subqueryload of a plain + mapped class would fail to link the joins correctly. + .. change:: :tags: bug, sql :tickets: 3755 diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index 8260732157..1d0058ca27 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -968,7 +968,7 @@ class SubqueryLoader(AbstractRelationshipLoader): if last and effective_entity is not self.mapper: attr = attr.of_type(effective_entity) else: - if last and effective_entity is not self.mapper: + if last: attr = getattr(parent_alias, key).\ of_type(effective_entity) else: diff --git a/test/orm/test_of_type.py b/test/orm/test_of_type.py index b9ebc2daf7..44ea347e14 100644 --- a/test/orm/test_of_type.py +++ b/test/orm/test_of_type.py @@ -313,6 +313,8 @@ class SubclassRelationshipTest(testing.AssertsCompiledSQL, fixtures.DeclarativeM id = Column(Integer, primary_key=True, test_needs_autoincrement=True) type = Column(String(10)) + widget_id = Column(ForeignKey('widget.id')) + widget = relationship("Widget") container_id = Column(Integer, ForeignKey('data_container.id')) __mapper_args__ = {"polymorphic_on": type} @@ -337,6 +339,13 @@ class SubclassRelationshipTest(testing.AssertsCompiledSQL, fixtures.DeclarativeM name = Column(String(10)) jobs = relationship(Job, order_by=Job.id) + class Widget(ComparableEntity, Base): + __tablename__ = "widget" + + id = Column(Integer, primary_key=True, + test_needs_autoincrement=True) + name = Column(String(10)) + @classmethod def insert_data(cls): s = Session(testing.db) @@ -346,23 +355,24 @@ class SubclassRelationshipTest(testing.AssertsCompiledSQL, fixtures.DeclarativeM @classmethod def _fixture(cls): - ParentThing, DataContainer, SubJob = \ + ParentThing, DataContainer, SubJob, Widget = \ cls.classes.ParentThing,\ cls.classes.DataContainer,\ - cls.classes.SubJob + cls.classes.SubJob,\ + cls.classes.Widget return [ ParentThing( container=DataContainer(name="d1", jobs=[ - SubJob(attr="s1"), - SubJob(attr="s2") + SubJob(attr="s1", widget=Widget(name='w1')), + SubJob(attr="s2", widget=Widget(name='w2')) ]) ), ParentThing( container=DataContainer(name="d2", jobs=[ - SubJob(attr="s3"), - SubJob(attr="s4") + SubJob(attr="s3", widget=Widget(name='w3')), + SubJob(attr="s4", widget=Widget(name='w4')) ]) ), ] @@ -389,7 +399,7 @@ class SubclassRelationshipTest(testing.AssertsCompiledSQL, fixtures.DeclarativeM q.all(), self._dc_fixture() ) - self.assert_sql_count(testing.db, go, 1) + self.assert_sql_count(testing.db, go, 5) def test_joinedload_wpoly(self): ParentThing, DataContainer, Job, SubJob = \ @@ -408,7 +418,7 @@ class SubclassRelationshipTest(testing.AssertsCompiledSQL, fixtures.DeclarativeM q.all(), self._dc_fixture() ) - self.assert_sql_count(testing.db, go, 1) + self.assert_sql_count(testing.db, go, 5) def test_joinedload_wsubclass(self): ParentThing, DataContainer, Job, SubJob = \ @@ -424,7 +434,7 @@ class SubclassRelationshipTest(testing.AssertsCompiledSQL, fixtures.DeclarativeM q.all(), self._dc_fixture() ) - self.assert_sql_count(testing.db, go, 1) + self.assert_sql_count(testing.db, go, 5) def test_lazyload(self): DataContainer = self.classes.DataContainer @@ -438,7 +448,8 @@ class SubclassRelationshipTest(testing.AssertsCompiledSQL, fixtures.DeclarativeM # SELECT data container # SELECT job * 2 container rows # SELECT subjob * 4 rows - self.assert_sql_count(testing.db, go, 7) + # SELECT widget * 4 rows + self.assert_sql_count(testing.db, go, 11) def test_subquery_wsubclass(self): ParentThing, DataContainer, Job, SubJob = \ @@ -454,7 +465,7 @@ class SubclassRelationshipTest(testing.AssertsCompiledSQL, fixtures.DeclarativeM q.all(), self._dc_fixture() ) - self.assert_sql_count(testing.db, go, 2) + self.assert_sql_count(testing.db, go, 6) def test_twolevel_subqueryload_wsubclass(self): ParentThing, DataContainer, Job, SubJob = \ @@ -474,6 +485,25 @@ class SubclassRelationshipTest(testing.AssertsCompiledSQL, fixtures.DeclarativeM q.all(), self._fixture() ) + self.assert_sql_count(testing.db, go, 7) + + def test_twolevel_subqueryload_wsubclass_mapper_term(self): + DataContainer, SubJob = \ + self.classes.DataContainer,\ + self.classes.SubJob + s = Session(testing.db) + sj_alias = aliased(SubJob) + q = s.query(DataContainer).\ + options( + subqueryload_all( + DataContainer.jobs.of_type(sj_alias), + sj_alias.widget + )) + def go(): + eq_( + q.all(), + self._dc_fixture() + ) self.assert_sql_count(testing.db, go, 3) def test_twolevel_joinedload_wsubclass(self): @@ -494,7 +524,7 @@ class SubclassRelationshipTest(testing.AssertsCompiledSQL, fixtures.DeclarativeM q.all(), self._fixture() ) - self.assert_sql_count(testing.db, go, 1) + self.assert_sql_count(testing.db, go, 5) def test_any_wpoly(self): ParentThing, DataContainer, Job, SubJob = \ @@ -514,6 +544,7 @@ class SubclassRelationshipTest(testing.AssertsCompiledSQL, fixtures.DeclarativeM self.assert_compile(q, "SELECT job.id AS job_id, job.type AS job_type, " + "job.widget_id AS job_widget_id, " "job.container_id " "AS job_container_id " "FROM data_container " @@ -542,6 +573,7 @@ class SubclassRelationshipTest(testing.AssertsCompiledSQL, fixtures.DeclarativeM ) self.assert_compile(q, "SELECT job.id AS job_id, job.type AS job_type, " + "job.widget_id AS job_widget_id, " "job.container_id AS job_container_id " "FROM data_container JOIN job ON data_container.id = job.container_id " "WHERE EXISTS (SELECT 1 " @@ -680,6 +712,7 @@ class SubclassRelationshipTest(testing.AssertsCompiledSQL, fixtures.DeclarativeM "data_container.name AS data_container_name " "FROM data_container JOIN " "(SELECT job.id AS job_id, job.type AS job_type, " + "job.widget_id AS job_widget_id, " "job.container_id AS job_container_id, " "subjob.id AS subjob_id, subjob.attr AS subjob_attr " "FROM job LEFT OUTER JOIN subjob ON job.id = subjob.id) "