summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2016-08-12 23:35:40 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2016-08-12 23:35:40 -0400
commitb07eb3cb45d1a344759a2eee9d2166fbf3e44888 (patch)
tree1c3b8a491e7fede02073fd48bb40ae97c77441b6
parentbec5d6991e4eacdba3529ea71d30bb7fd614fdc9 (diff)
downloadsqlalchemy-b07eb3cb45d1a344759a2eee9d2166fbf3e44888.tar.gz
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
-rw-r--r--doc/build/changelog/changelog_10.rst9
-rw-r--r--lib/sqlalchemy/orm/strategies.py2
-rw-r--r--test/orm/test_of_type.py57
3 files changed, 55 insertions, 13 deletions
diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst
index 16a38e662..f91b9cac1 100644
--- a/doc/build/changelog/changelog_10.rst
+++ b/doc/build/changelog/changelog_10.rst
@@ -19,6 +19,15 @@
: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 826073215..1d0058ca2 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 b9ebc2daf..44ea347e1 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) "