]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Fix lambda statements with non-lambda criteria
authorcjc0013 <cjc0013@users.noreply.github.com>
Mon, 25 May 2026 16:46:50 +0000 (12:46 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 27 May 2026 22:39:11 +0000 (18:39 -0400)
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

doc/build/changelog/unreleased_20/10827.rst [new file with mode: 0644]
lib/sqlalchemy/sql/lambdas.py
test/sql/test_lambdas.py

diff --git a/doc/build/changelog/unreleased_20/10827.rst b/doc/build/changelog/unreleased_20/10827.rst
new file mode 100644 (file)
index 0000000..879fa1d
--- /dev/null
@@ -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.
index 38fa97b0e36297336bee645c2f21af9fa8e8bc27..6ec217e8f87c0e9636824091b8be4ca95f3ba917 100644 (file)
@@ -314,7 +314,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):
index 007f3e189ccc6568104ae0ac86c0eac86caf9fe3..e327bf979024a49d19d7852b5f8b1d8977db88f3 100644 (file)
@@ -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))