summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormike bayer <mike_mp@zzzcomputing.com>2017-01-19 16:28:58 -0500
committerGerrit Code Review <gerrit@awstats.zzzcomputing.com>2017-01-19 16:28:58 -0500
commit81518ae2e2bc622f8cd47287a575ad4c0e43ead1 (patch)
tree8ba287eb1b7911b45888544d871a38864e765238
parent42027de3fce1d4ce2e3a684c59ee87f440b51ae8 (diff)
parent4ae02f46e944ac11af5ad77e5ff5f06963b63b3d (diff)
downloadsqlalchemy-81518ae2e2bc622f8cd47287a575ad4c0e43ead1.tar.gz
Merge "Dont set _set_select_from() for alias object"
-rw-r--r--doc/build/changelog/changelog_11.rst9
-rw-r--r--lib/sqlalchemy/orm/strategies.py7
-rw-r--r--test/orm/test_subquery_relations.py79
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):