]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Ensure propagate_attrs available on PropComparator
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 29 May 2021 14:05:20 +0000 (10:05 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 29 May 2021 14:10:14 +0000 (10:10 -0400)
Fixed regression caused by just-released performance fix mentioned in #6550
where a query.join() to a relationship could produce an AttributeError if
the query were made against non-ORM structures only, a fairly unusual
calling pattern.

In this fix, since we are no longer going through the production
of ``__clause_element__()`` for Cls.some_relationship, I assumed we
just throw this object away completely but I missed the one little
bit where we might be getting ``_propagate_attrs`` from it.
So we implement ``_propagate_attrs`` on ``PropComparator`` as well,
since this is easy to define.

Fixes: #6558
Change-Id: If781bf844e7e3d3b0841aff1c3668e9d6af9f097

doc/build/changelog/unreleased_14/6558.rst [new file with mode: 0644]
lib/sqlalchemy/orm/interfaces.py
lib/sqlalchemy/sql/coercions.py
test/orm/test_bind.py
test/orm/test_joins.py

diff --git a/doc/build/changelog/unreleased_14/6558.rst b/doc/build/changelog/unreleased_14/6558.rst
new file mode 100644 (file)
index 0000000..030c409
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+    :tags: bug, orm, regression
+    :tickets: 6558
+
+    Fixed regression caused by just-released performance fix mentioned in #6550
+    where a query.join() to a relationship could produce an AttributeError if
+    the query were made against non-ORM structures only, a fairly unusual
+    calling pattern.
index ed38becf7fea35697be77541b009f4d5b66f0cdb..c9a601f9956295dd5cecac7824603a3ce08880ce 100644 (file)
@@ -425,6 +425,18 @@ class PropComparator(operators.ColumnOperators):
         compatible with QueryableAttribute."""
         return inspect(self._parententity).mapper
 
+    @property
+    def _propagate_attrs(self):
+        # this suits the case in coercions where we don't actually
+        # call ``__clause_element__()`` but still need to get
+        # resolved._propagate_attrs.  See #6558.
+        return util.immutabledict(
+            {
+                "compile_state_plugin": "orm",
+                "plugin_subject": self._parentmapper,
+            }
+        )
+
     @property
     def adapter(self):
         """Produce a callable that adapts column expressions
index 82068d7683d552f00c15d890d7160a5479705bc6..ea2289a9daaa996561b20de0f91992f60d2bc166 100644 (file)
@@ -884,6 +884,9 @@ class JoinTargetImpl(RoleImpl):
         self, original_element, resolved, argname=None, legacy=False, **kw
     ):
         if isinstance(original_element, roles.JoinTargetRole):
+            # note that this codepath no longer occurs as of
+            # #6550, unless JoinTargetImpl._skip_clauseelement_for_target_match
+            # were set to False.
             return original_element
         elif legacy and isinstance(resolved, str):
             util.warn_deprecated_20(
index 5c7f3f72e5d200b00234ce7c98d55d8e7c4b8842..42ba6e9be4ff3651a7fd0145561d755665a40376 100644 (file)
@@ -175,6 +175,10 @@ class BindIntegrationTest(_fixtures.FixtureTest):
             },
             "e1",
         ),
+        (
+            lambda users, User: {"clause": select(users).join(User.addresses)},
+            "e1",
+        ),
         (lambda Address: {"mapper": Address}, "e2"),
         (lambda Address: {"clause": Query([Address])._statement_20()}, "e2"),
         (lambda addresses: {"clause": select(addresses)}, "e2"),
@@ -268,6 +272,7 @@ class BindIntegrationTest(_fixtures.FixtureTest):
             e2=e2,
             e3=e3,
             addresses=addresses,
+            users=users,
         )
 
         sess = Session(e3)
index 50fa861070e640ac542ba5758ad5ebdd598e4abb..7f6e1b72eca548d61a39735fe8a5abc0d973fe31 100644 (file)
@@ -6,6 +6,7 @@ from sqlalchemy import desc
 from sqlalchemy import exc as sa_exc
 from sqlalchemy import ForeignKey
 from sqlalchemy import func
+from sqlalchemy import inspect
 from sqlalchemy import Integer
 from sqlalchemy import lateral
 from sqlalchemy import literal_column
@@ -307,6 +308,25 @@ class JoinTest(QueryTest, AssertsCompiledSQL):
                 "WHERE users.name = :name_1",
             )
 
+    def test_join_relationship_propagate_attrs(self):
+        """test #6558"""
+
+        User = self.classes.User
+        users = self.tables.users
+
+        stmt = select(users).join(User.addresses)
+
+        eq_(
+            stmt._propagate_attrs,
+            {"compile_state_plugin": "orm", "plugin_subject": inspect(User)},
+        )
+
+        self.assert_compile(
+            stmt,
+            "SELECT users.id, users.name FROM users "
+            "JOIN addresses ON users.id = addresses.user_id",
+        )
+
     def test_invalid_kwarg_join(self):
         User = self.classes.User
         sess = fixture_session()