diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-01-02 18:26:32 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-01-02 18:26:32 -0500 |
commit | ca8fca63916897f1bbc2fa4f1ee440c6b5d9a88a (patch) | |
tree | faedf154f7574d302204e0c556a463e9d01bf451 | |
parent | 504543090213db5b9c7cecb27a78b12fa12e9024 (diff) | |
download | sqlalchemy-ca8fca63916897f1bbc2fa4f1ee440c6b5d9a88a.tar.gz |
- Fixed regression where we apparently still create an implicit
alias when saying query(B).join(B.cs), where "C" is a joined inh
class; however, this implicit alias was created only considering
the immediate left side, and not a longer chain of joins along different
joined-inh subclasses of the same base. As long as we're still
implicitly aliasing in this case, the behavior is dialed back a bit
so that it will alias the right side in a wider variety of cases.
[ticket:2903]
-rw-r--r-- | doc/build/changelog/changelog_09.rst | 15 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/query.py | 24 | ||||
-rw-r--r-- | test/orm/inheritance/test_relationship.py | 1 | ||||
-rw-r--r-- | test/orm/test_joins.py | 35 |
4 files changed, 67 insertions, 8 deletions
diff --git a/doc/build/changelog/changelog_09.rst b/doc/build/changelog/changelog_09.rst index 65da0a39f..069df37a4 100644 --- a/doc/build/changelog/changelog_09.rst +++ b/doc/build/changelog/changelog_09.rst @@ -12,6 +12,21 @@ :start-line: 5 .. changelog:: + :version: 0.9.1 + + .. change:: + :tags: bug, orm + :tickets: 2903 + + Fixed regression where we apparently still create an implicit + alias when saying query(B).join(B.cs), where "C" is a joined inh + class; however, this implicit alias was created only considering + the immediate left side, and not a longer chain of joins along different + joined-inh subclasses of the same base. As long as we're still + implicitly aliasing in this case, the behavior is dialed back a bit + so that it will alias the right side in a wider variety of cases. + +.. changelog:: :version: 0.9.0 :released: December 30, 2013 diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index 4f10a6ada..3815f5a98 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -1842,14 +1842,30 @@ class Query(object): raise sa_exc.InvalidRequestError( "Can't construct a join from %s to %s, they " "are the same entity" % - (left, right)) + (left, right)) l_info = inspect(left) r_info = inspect(right) - overlap = not create_aliases and \ - sql_util.selectables_overlap(l_info.selectable, - r_info.selectable) + + overlap = False + if not create_aliases: + right_mapper = getattr(r_info, "mapper", None) + # if the target is a joined inheritance mapping, + # be more liberal about auto-aliasing. + if right_mapper and ( + right_mapper.with_polymorphic or + isinstance(right_mapper.mapped_table, expression.Join) + ): + for from_obj in self._from_obj or [l_info.selectable]: + if sql_util.selectables_overlap(l_info.selectable, from_obj) and \ + sql_util.selectables_overlap(from_obj, r_info.selectable): + overlap = True + break + elif sql_util.selectables_overlap(l_info.selectable, r_info.selectable): + overlap = True + + if overlap and l_info.selectable is r_info.selectable: raise sa_exc.InvalidRequestError( "Can't join table/selectable '%s' to itself" % diff --git a/test/orm/inheritance/test_relationship.py b/test/orm/inheritance/test_relationship.py index a436ca5fc..5e047cfdb 100644 --- a/test/orm/inheritance/test_relationship.py +++ b/test/orm/inheritance/test_relationship.py @@ -154,6 +154,7 @@ class SelfReferentialJ2JTest(fixtures.MappedTest): managers.c.person_id == engineers.c.reports_to_id, backref='engineers')}) + def test_has(self): m1 = Manager(name='dogbert') e1 = Engineer(name='dilbert', primary_language='java', reports_to=m1) diff --git a/test/orm/test_joins.py b/test/orm/test_joins.py index 21b82f408..5f48b39b1 100644 --- a/test/orm/test_joins.py +++ b/test/orm/test_joins.py @@ -333,7 +333,32 @@ class InheritedJoinTest(fixtures.MappedTest, AssertsCompiledSQL): , use_default_dialect = True ) + def test_auto_aliasing_multi_link(self): + # test [ticket:2903] + sess = create_session() + Company, Engineer, Manager, Boss = self.classes.Company, \ + self.classes.Engineer, \ + self.classes.Manager, self.classes.Boss + q = sess.query(Company).\ + join(Company.employees.of_type(Engineer)).\ + join(Company.employees.of_type(Manager)).\ + join(Company.employees.of_type(Boss)) + + self.assert_compile(q, + "SELECT companies.company_id AS companies_company_id, " + "companies.name AS companies_name FROM companies " + "JOIN (people JOIN engineers ON people.person_id = engineers.person_id) " + "ON companies.company_id = people.company_id " + "JOIN (people AS people_1 JOIN managers AS managers_1 " + "ON people_1.person_id = managers_1.person_id) " + "ON companies.company_id = people_1.company_id " + "JOIN (people AS people_2 JOIN managers AS managers_2 " + "ON people_2.person_id = managers_2.person_id JOIN boss AS boss_1 " + "ON managers_2.person_id = boss_1.boss_id) " + "ON companies.company_id = people_2.company_id", + use_default_dialect=True + ) class JoinTest(QueryTest, AssertsCompiledSQL): @@ -1582,12 +1607,14 @@ class MultiplePathTest(fixtures.MappedTest, AssertsCompiledSQL): self.tables.t1t2_2, self.tables.t1) - class T1(object):pass - class T2(object):pass + class T1(object): + pass + class T2(object): + pass mapper(T1, t1, properties={ - 't2s_1':relationship(T2, secondary=t1t2_1), - 't2s_2':relationship(T2, secondary=t1t2_2), + 't2s_1': relationship(T2, secondary=t1t2_1), + 't2s_2': relationship(T2, secondary=t1t2_2), }) mapper(T2, t2) |