]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
refine _include_fn to not include sibling mappers
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 23 Jun 2022 15:15:19 +0000 (11:15 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 23 Jun 2022 15:18:36 +0000 (11:18 -0400)
Fixed regression caused by :ticket:`8064` where a particular check for
column correspondence was made too liberal, resulting in incorrect
rendering for some ORM subqueries such as those using
:meth:`.PropComparator.has` or :meth:`.PropComparator.any` in conjunction
with joined-inheritance queries that also use legacy aliasing features.

Fixes: #8162
Change-Id: Ib1fff33aa219aadf178348dd571bec1e691e606d
(cherry picked from commit 4553f24980c0a23685afdb9ef6958b79f4b22e70)

doc/build/changelog/unreleased_14/8162.rst [new file with mode: 0644]
lib/sqlalchemy/orm/util.py
test/orm/inheritance/_poly_fixtures.py
test/orm/test_deprecations.py

diff --git a/doc/build/changelog/unreleased_14/8162.rst b/doc/build/changelog/unreleased_14/8162.rst
new file mode 100644 (file)
index 0000000..4b59155
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+    :tags: bug, orm, regression
+    :tickets: 8162
+
+    Fixed regression caused by :ticket:`8064` where a particular check for
+    column correspondence was made too liberal, resulting in incorrect
+    rendering for some ORM subqueries such as those using
+    :meth:`.PropComparator.has` or :meth:`.PropComparator.any` in conjunction
+    with joined-inheritance queries that also use legacy aliasing features.
index f95af41d24a3d7fce66e4ffe7da115d7fbc356f5..56aa9ff6c744d6190ccd68b22ee1bc26660f5127 100644 (file)
@@ -415,7 +415,8 @@ class ORMAdapter(sql_util.ColumnAdapter):
 
     def _include_fn(self, elem):
         entity = elem._annotations.get("parentmapper", None)
-        return not entity or entity.common_parent(self.mapper)
+
+        return not entity or entity.isa(self.mapper) or self.mapper.isa(entity)
 
 
 class AliasedClass(object):
index 7efc99913ad1063d8e53ea1cf363272aa53f880c..7ba611f958c9e01f570ab80d3628b16a9bc983dd 100644 (file)
@@ -350,9 +350,10 @@ class _PolymorphicFixtureBase(fixtures.MappedTest, AssertsCompiledSQL):
             inherits=Person,
             polymorphic_identity="engineer",
             properties={
+                "company": relationship(Company, viewonly=True),
                 "machines": relationship(
                     Machine, order_by=machines.c.machine_id
-                )
+                ),
             },
         )
 
index 33a91184c26a490ca8f7a677c6054afaa5a849c1..05bfdf26dab319757dbb1df4ef0017913c9b9df0 100644 (file)
@@ -6416,6 +6416,39 @@ class InheritedJoinTest(
     run_setup_mappers = "once"
     __dialect__ = "default"
 
+    def test_join_w_subq_adapt(self):
+        """test #8162"""
+
+        Company, Manager, Engineer = self.classes(
+            "Company", "Manager", "Engineer"
+        )
+
+        sess = fixture_session()
+
+        with _aliased_join_warning():
+            self.assert_compile(
+                sess.query(Engineer)
+                .join(Company, Company.company_id == Engineer.company_id)
+                .outerjoin(Manager, Company.company_id == Manager.company_id)
+                .filter(~Engineer.company.has()),
+                "SELECT engineers.person_id AS engineers_person_id, "
+                "people.person_id AS people_person_id, "
+                "people.company_id AS people_company_id, "
+                "people.name AS people_name, people.type AS people_type, "
+                "engineers.status AS engineers_status, "
+                "engineers.engineer_name AS engineers_engineer_name, "
+                "engineers.primary_language AS engineers_primary_language "
+                "FROM people JOIN engineers "
+                "ON people.person_id = engineers.person_id "
+                "JOIN companies ON companies.company_id = people.company_id "
+                "LEFT OUTER 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 "
+                "WHERE NOT (EXISTS (SELECT 1 FROM companies "
+                "WHERE companies.company_id = people.company_id))",
+                use_default_dialect=True,
+            )
+
     def test_load_only_alias_subclass(self):
         Manager = self.classes.Manager