From: Mike Bayer Date: Thu, 5 Aug 2021 23:17:07 +0000 (-0400) Subject: accommodate for untracked boundparam lambda in offline_string X-Git-Tag: rel_1_4_23~23^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3729a070d23421c94239bd24520592287476fdde;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git accommodate for untracked boundparam lambda in offline_string Fixed an issue in the ``CacheKey.to_offline_string()`` method used by the dogpile.caching example where attempting to create a proper cache key from the special "lambda" query generated by the lazy loader would fail to include the parameter values, leading to an incorrect cache key. Fixes: #6858 Change-Id: Ice27087583c6f3ff79cf7d5b879e5dd0a4e58158 --- diff --git a/doc/build/changelog/unreleased_14/6858.rst b/doc/build/changelog/unreleased_14/6858.rst new file mode 100644 index 0000000000..0aa9d75380 --- /dev/null +++ b/doc/build/changelog/unreleased_14/6858.rst @@ -0,0 +1,9 @@ +.. change:: + :tags: bug, sql + :tickets: 6858 + + Fixed an issue in the ``CacheKey.to_offline_string()`` method used by the + dogpile.caching example where attempting to create a proper cache key from + the special "lambda" query generated by the lazy loader would fail to + include the parameter values, leading to an incorrect cache key. + diff --git a/examples/dogpile_caching/caching_query.py b/examples/dogpile_caching/caching_query.py index d1199090c8..68f72e5f06 100644 --- a/examples/dogpile_caching/caching_query.py +++ b/examples/dogpile_caching/caching_query.py @@ -139,7 +139,6 @@ class FromCache(UserDefinedOption): key = statement_cache_key.to_offline_string( orm_cache._statement_cache, statement, parameters ) + repr(self.cache_key) - # print("here's our key...%s" % key) return key diff --git a/lib/sqlalchemy/sql/traversals.py b/lib/sqlalchemy/sql/traversals.py index a86d16ef4c..3d377271f9 100644 --- a/lib/sqlalchemy/sql/traversals.py +++ b/lib/sqlalchemy/sql/traversals.py @@ -299,15 +299,15 @@ class CacheKey(namedtuple("CacheKey", ["key", "bindparams"])): else: sql_str = statement_cache[self.key] - return repr( - ( - sql_str, - tuple( - parameters.get(bindparam.key, bindparam.value) - for bindparam in self.bindparams - ), + if not self.bindparams: + param_tuple = tuple(parameters[key] for key in sorted(parameters)) + else: + param_tuple = tuple( + parameters.get(bindparam.key, bindparam.value) + for bindparam in self.bindparams ) - ) + + return repr((sql_str, param_tuple)) def __eq__(self, other): return self.key == other.key diff --git a/test/sql/test_lambdas.py b/test/sql/test_lambdas.py index ea31c9aeca..51530b0791 100644 --- a/test/sql/test_lambdas.py +++ b/test/sql/test_lambdas.py @@ -897,6 +897,42 @@ class LambdaElementTest( checkparams={"q_1": 1}, ) + def test_offline_cache_key_no_paramtrack(self): + def go(): + stmt = lambdas.lambda_stmt( + lambda: select(column("x")).where( + column("y") == bindparam("q") + ), + global_track_bound_values=False, + ) + + return stmt + + s1 = go() + + eq_( + s1._generate_cache_key().to_offline_string({}, s1, {"q": 5}), + "('SELECT x \\nWHERE y = :q', (5,))", + ) + + def test_offline_cache_key_paramtrack(self): + def go(param): + stmt = lambdas.lambda_stmt( + lambda: select(column("x")).where(column("y") == param), + ) + + return stmt + + s1 = go(5) + + param_key = s1._resolved._where_criteria[0].right.key + eq_( + s1._generate_cache_key().to_offline_string( + {}, s1, {param_key: 10} + ), + "('SELECT x \\nWHERE y = :param_1', (10,))", + ) + def test_stmt_lambda_w_list_of_opts(self): def go(opts): stmt = lambdas.lambda_stmt(lambda: select(column("x")))