]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed an issue in baked queries where the .get() method, used either
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 29 Nov 2015 16:42:55 +0000 (11:42 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 29 Nov 2015 16:42:55 +0000 (11:42 -0500)
directly or within lazy loads, didn't consider the mapper's "get clause"
as part of the cache key, causing bound parameter mismatches if the
clause got re-generated.  This clause is cached by mappers
on the fly but in highly concurrent scenarios may be generated more
than once when first accessed.
fixes #3597

doc/build/changelog/changelog_10.rst
lib/sqlalchemy/ext/baked.py
test/ext/test_baked.py

index 7e289a526be0a866a027803cb3bf7b7b08d8e8ac..8d6dcd2a99ac09a858f34dc917339cb3dbed106d 100644 (file)
 .. changelog::
     :version: 1.0.10
 
+    .. change::
+        :tags: bug, ext
+        :versions: 1.1.0b1
+        :tickets: 3597
+
+        Fixed an issue in baked queries where the .get() method, used either
+        directly or within lazy loads, didn't consider the mapper's "get clause"
+        as part of the cache key, causing bound parameter mismatches if the
+        clause got re-generated.  This clause is cached by mappers
+        on the fly but in highly concurrent scenarios may be generated more
+        than once when first accessed.
+
     .. change::
         :tags: feature, sql
         :versions: 1.1.0b1
index ee9f6f9bbc7d222f7aa45d509522918d1628d07e..eb0c36805eb5aee615fc0fb0275ef550170aa2c5 100644 (file)
@@ -354,6 +354,12 @@ class Result(object):
         # (remember, we can map to an OUTER JOIN)
         bq = self.bq
 
+        # add the clause we got from mapper._get_clause to the cache
+        # key so that if a race causes multiple calls to _get_clause,
+        # we've cached on ours
+        bq = bq._clone()
+        bq._cache_key += (_get_clause, )
+
         bq = bq.with_criteria(setup, tuple(elem is None for elem in ident))
 
         params = dict([
index dcf333184c9c6d053a1d392051af658eb9b9957c..7004358fcfa83cd2a8089dc48116b73bd6007f4b 100644 (file)
@@ -271,6 +271,30 @@ class LikeQueryTest(BakedTest):
             eq_(u2.name, 'chuck')
         self.assert_sql_count(testing.db, go, 0)
 
+    def test_get_includes_getclause(self):
+        # test issue #3597
+        User = self.classes.User
+
+        bq = self.bakery(lambda s: s.query(User))
+
+        for i in range(5):
+            sess = Session()
+            u1 = bq(sess).get(7)
+            eq_(u1.name, 'jack')
+
+        eq_(len(bq._bakery), 2)
+
+        # simulate race where mapper._get_clause
+        # may be generated more than once
+        from sqlalchemy import inspect
+        del inspect(User).__dict__['_get_clause']
+
+        for i in range(5):
+            sess = Session()
+            u1 = bq(sess).get(7)
+            eq_(u1.name, 'jack')
+        eq_(len(bq._bakery), 4)
+
 
 class ResultTest(BakedTest):
     __backend__ = True