From 60b0a693c97e7ab504a0d36497b71ccba24ac8e8 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Wed, 14 Apr 2021 18:53:25 -0400 Subject: Fix with_expression() cache leak; don't adapt singletons Fixed a cache leak involving the :func:`_orm.with_expression` loader option, where the given SQL expression would not be correctly considered as part of the cache key. Additionally, fixed regression involving the corresponding :func:`_orm.query_expression` feature. While the bug technically exists in 1.3 as well, it was not exposed until 1.4. The "default expr" value of ``null()`` would be rendered when not needed, and additionally was also not adapted correctly when the ORM rewrites statements such as when using joined eager loading. The fix ensures "singleton" expressions like ``NULL`` and ``true`` aren't "adapted" to refer to columns in ORM statements, and additionally ensures that a :func:`_orm.query_expression` with no default expression doesn't render in the statement if a :func:`_orm.with_expression` isn't used. Fixes: #6259 Change-Id: I5a70bc12dadad125bbc4324b64048c8d4a18916c --- lib/sqlalchemy/sql/base.py | 9 +++++++++ lib/sqlalchemy/sql/util.py | 1 + 2 files changed, 10 insertions(+) (limited to 'lib/sqlalchemy/sql') diff --git a/lib/sqlalchemy/sql/base.py b/lib/sqlalchemy/sql/base.py index 81685dfe0..d9f05e823 100644 --- a/lib/sqlalchemy/sql/base.py +++ b/lib/sqlalchemy/sql/base.py @@ -54,6 +54,8 @@ class Immutable(object): class SingletonConstant(Immutable): + """Represent SQL constants like NULL, TRUE, FALSE""" + def __new__(cls, *arg, **kw): return cls._singleton @@ -63,6 +65,13 @@ class SingletonConstant(Immutable): obj.__init__() cls._singleton = obj + # don't proxy singletons. this means that a SingletonConstant + # will never be a "corresponding column" in a statement; the constant + # can be named directly and as it is often/usually compared against using + # "IS", it can't be adapted to a subquery column in any case. + # see :ticket:`6259`. + proxy_set = frozenset() + def _from_objects(*elements): return itertools.chain.from_iterable( diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py index 4dec30a80..85b20a568 100644 --- a/lib/sqlalchemy/sql/util.py +++ b/lib/sqlalchemy/sql/util.py @@ -829,6 +829,7 @@ class ClauseAdapter(visitors.ReplacingExternalTraversal): def _corresponding_column( self, col, require_embedded, _seen=util.EMPTY_SET ): + newcol = self.selectable.corresponding_column( col, require_embedded=require_embedded ) -- cgit v1.2.1