From c4ee403e139d523ac554fcbb24a924a26f5261bd Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Thu, 23 Jun 2022 11:15:19 -0400 Subject: [PATCH] refine _include_fn to not include sibling mappers 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 | 9 ++++++ lib/sqlalchemy/orm/util.py | 3 +- test/orm/inheritance/_poly_fixtures.py | 3 +- test/orm/test_deprecations.py | 33 ++++++++++++++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 doc/build/changelog/unreleased_14/8162.rst diff --git a/doc/build/changelog/unreleased_14/8162.rst b/doc/build/changelog/unreleased_14/8162.rst new file mode 100644 index 0000000000..4b59155e21 --- /dev/null +++ b/doc/build/changelog/unreleased_14/8162.rst @@ -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. diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py index f95af41d24..56aa9ff6c7 100644 --- a/lib/sqlalchemy/orm/util.py +++ b/lib/sqlalchemy/orm/util.py @@ -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): diff --git a/test/orm/inheritance/_poly_fixtures.py b/test/orm/inheritance/_poly_fixtures.py index 7efc99913a..7ba611f958 100644 --- a/test/orm/inheritance/_poly_fixtures.py +++ b/test/orm/inheritance/_poly_fixtures.py @@ -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 - ) + ), }, ) diff --git a/test/orm/test_deprecations.py b/test/orm/test_deprecations.py index 33a91184c2..05bfdf26da 100644 --- a/test/orm/test_deprecations.py +++ b/test/orm/test_deprecations.py @@ -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 -- 2.47.2