diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-05-28 08:29:24 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-05-28 10:35:51 -0400 |
commit | 460bed7cfd8a6dd035caff5f5b1b33edf96fa3bb (patch) | |
tree | f693d05af509b210fe64255459b73bb425bb054e /lib/sqlalchemy/sql/coercions.py | |
parent | aaba0650d7410f579b2c14f8f1b0680a1d1852c4 (diff) | |
download | sqlalchemy-460bed7cfd8a6dd035caff5f5b1b33edf96fa3bb.tar.gz |
Fix adaption in AnnotatedLabel; repair needless expense in coercion
Fixed regression involving clause adaption of labeled ORM compound
elements, such as single-table inheritance discriminator expressions with
conditionals or CASE expressions, which could cause aliased expressions
such as those used in ORM join / joinedload operations to not be adapted
correctly, such as referring to the wrong table in the ON clause in a join.
This change also improves a performance bump that was located within the
process of invoking :meth:`_sql.Select.join` given an ORM attribute
as a target.
Fixes: #6550
Change-Id: I98906476f0cce6f41ea00b77c789baa818e9d167
Diffstat (limited to 'lib/sqlalchemy/sql/coercions.py')
-rw-r--r-- | lib/sqlalchemy/sql/coercions.py | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/lib/sqlalchemy/sql/coercions.py b/lib/sqlalchemy/sql/coercions.py index 36ac507ad..82068d768 100644 --- a/lib/sqlalchemy/sql/coercions.py +++ b/lib/sqlalchemy/sql/coercions.py @@ -151,12 +151,25 @@ def expect( is_clause_element = False - while hasattr(element, "__clause_element__"): + # this is a special performance optimization for ORM + # joins used by JoinTargetImpl that we don't go through the + # work of creating __clause_element__() when we only need the + # original QueryableAttribute, as the former will do clause + # adaption and all that which is just thrown away here. + if ( + impl._skip_clauseelement_for_target_match + and isinstance(element, role) + and hasattr(element, "__clause_element__") + ): is_clause_element = True - if not getattr(element, "is_clause_element", False): - element = element.__clause_element__() - else: - break + else: + while hasattr(element, "__clause_element__"): + is_clause_element = True + + if not getattr(element, "is_clause_element", False): + element = element.__clause_element__() + else: + break if not is_clause_element: if impl._use_inspection: @@ -230,6 +243,7 @@ class RoleImpl(object): _post_coercion = None _resolve_literal_only = False + _skip_clauseelement_for_target_match = False def __init__(self, role_class): self._role_class = role_class @@ -860,6 +874,8 @@ class HasCTEImpl(ReturnsRowsImpl): class JoinTargetImpl(RoleImpl): __slots__ = () + _skip_clauseelement_for_target_match = True + def _literal_coercion(self, element, legacy=False, **kw): if isinstance(element, str): return element |