]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed regression where we apparently still create an implicit
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 2 Jan 2014 23:26:32 +0000 (18:26 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 2 Jan 2014 23:26:32 +0000 (18:26 -0500)
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]

doc/build/changelog/changelog_09.rst
lib/sqlalchemy/orm/query.py
test/orm/inheritance/test_relationship.py
test/orm/test_joins.py

index 65da0a39fda4f4d91f1d071f5c2fedfaf0538cfc..069df37a4cafbcc50662cc47938abba3dafce8be 100644 (file)
     .. include:: changelog_07.rst
         :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
index 4f10a6ada20d7396dab3f9129417dd1af2271736..3815f5a983560c166f887d79c0cc3963172e2b38 100644 (file)
@@ -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" %
index a436ca5fc46a5169bb063ed48e21bd12974991d3..5e047cfdb1b6d8703810c0067cdeba09febede35 100644 (file)
@@ -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)
index 21b82f4087a46ccf800b47a5f3e4eeb73dd94ef6..5f48b39b14086918b905ce0cf6fb3777a6a275c1 100644 (file)
@@ -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)