From: cjc0013 Date: Mon, 25 May 2026 16:46:50 +0000 (-0400) Subject: Fix lambda statements with non-lambda criteria X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=a6e2dd6bc97ec0a42d80ef565765f2c4b884dcd4;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Fix lambda statements with non-lambda criteria Fixed issue where :class:`_sql.StatementLambdaElement` would proxy attribute access through the cached "expected" expression rather than the resolved expression, causing stale closure-bound parameter values to be used when a lambda statement was extended with non-lambda criteria such as an additional ``.where()`` clause. Courtesy cjc0013. Fixes: #10827 Closes: #13327 Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13327 Pull-request-sha: ec3e6735bf95d62d768f214dd5a49bbfc4fecaa5 Change-Id: I8a32c11f3da63109cf37c39541df8ebfee52b8c5 (cherry picked from commit c41f25b17031d8e9ca3d7e613c0d4dcd78b693fe) --- diff --git a/doc/build/changelog/unreleased_20/10827.rst b/doc/build/changelog/unreleased_20/10827.rst new file mode 100644 index 0000000000..879fa1dd1d --- /dev/null +++ b/doc/build/changelog/unreleased_20/10827.rst @@ -0,0 +1,9 @@ +.. change:: + :tags: bug, sql + :tickets: 10827 + + Fixed issue where :class:`_sql.StatementLambdaElement` would proxy + attribute access through the cached "expected" expression rather than the + resolved expression, causing stale closure-bound parameter values to be + used when a lambda statement was extended with non-lambda criteria such as + an additional ``.where()`` clause. Courtesy cjc0013. diff --git a/lib/sqlalchemy/sql/lambdas.py b/lib/sqlalchemy/sql/lambdas.py index 4d53240c51..1b0d478371 100644 --- a/lib/sqlalchemy/sql/lambdas.py +++ b/lib/sqlalchemy/sql/lambdas.py @@ -313,7 +313,7 @@ class LambdaElement(elements.ClauseElement): return rec def __getattr__(self, key): - return getattr(self._rec.expected_expr, key) + return getattr(self._resolved, key) @property def _is_sequence(self): diff --git a/test/sql/test_lambdas.py b/test/sql/test_lambdas.py index c665c33658..798779d1a3 100644 --- a/test/sql/test_lambdas.py +++ b/test/sql/test_lambdas.py @@ -346,6 +346,34 @@ class LambdaElementTest( eq_(s2key[0], s4key[0]) ne_(s1key[0], s2key[0]) + def test_stmt_lambda_w_additional_non_lambda_and_closure_var(self): + def go(q): + stmt = lambdas.lambda_stmt( + lambda: select(column("x")).where(column("x") == q) + ) + stmt = stmt.where(column("y") == column("z")) + + return stmt + + s1 = go(5) + s2 = go(10) + + self.assert_compile( + s1, + "SELECT x WHERE x = :q_1 AND y = z", + checkparams={"q_1": 5}, + ) + self.assert_compile( + s2, + "SELECT x WHERE x = :q_1 AND y = z", + checkparams={"q_1": 10}, + ) + + s1key = s1._generate_cache_key() + s2key = s2._generate_cache_key() + + eq_(s1key[0], s2key[0]) + def test_stmt_lambda_w_atonce_whereclause_values_notrack(self): def go(col_expr, whereclause): stmt = lambdas.lambda_stmt(lambda: select(col_expr))