]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed bug where the state tracking within multiple, nested
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 2 Apr 2015 16:19:15 +0000 (12:19 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 2 Apr 2015 16:19:15 +0000 (12:19 -0400)
:meth:`.Session.begin_nested` operations would fail to propagate
the "dirty" flag for an object that had been updated within
the inner savepoint, such that if the enclosing savepoint were
rolled back, the object would not be part of the state that was
expired and therefore reverted to its database state.
fixes #3352

doc/build/changelog/changelog_09.rst
lib/sqlalchemy/orm/session.py
test/orm/test_transaction.py

index 53c4eeaaaba2ccb4b47201e1d848f4f43ab9ba38..89a5d72da55317efd36018a3bca6bb7186ae1593 100644 (file)
 .. changelog::
     :version: 0.9.10
 
+    .. change::
+        :tags: bug, orm
+        :tickets: 3352
+        :versions: 1.0.0b5
+
+        Fixed bug where the state tracking within multiple, nested
+        :meth:`.Session.begin_nested` operations would fail to propagate
+        the "dirty" flag for an object that had been updated within
+        the inner savepoint, such that if the enclosing savepoint were
+        rolled back, the object would not be part of the state that was
+        expired and therefore reverted to its database state.
+
     .. change::
         :tags: bug, mysql, pymysql
         :tickets: 3337
index f3ad2349c397711e0fc13e54b109930f48d4bf87..4619027e5bc417a3b251de475caa02bb6f435dd9 100644 (file)
@@ -305,6 +305,7 @@ class SessionTransaction(object):
             self._deleted.clear()
         elif self.nested:
             self._parent._new.update(self._new)
+            self._parent._dirty.update(self._dirty)
             self._parent._deleted.update(self._deleted)
             self._parent._key_switches.update(self._key_switches)
 
index 6bea5cc7b7b26ecf8c46ee639d4d71367678c957..91846a67e6102347d512e7be66702c05746215d9 100644 (file)
@@ -143,6 +143,34 @@ class SessionTransactionTest(FixtureTest):
         assert session.connection().execute(
             'select count(1) from users').scalar() == 2
 
+    @testing.requires.savepoints
+    def test_dirty_state_transferred_deep_nesting(self):
+        User, users = self.classes.User, self.tables.users
+
+        mapper(User, users)
+
+        s = Session(testing.db)
+        u1 = User(name='u1')
+        s.add(u1)
+        s.commit()
+
+        nt1 = s.begin_nested()
+        nt2 = s.begin_nested()
+        u1.name = 'u2'
+        assert attributes.instance_state(u1) not in nt2._dirty
+        assert attributes.instance_state(u1) not in nt1._dirty
+        s.flush()
+        assert attributes.instance_state(u1) in nt2._dirty
+        assert attributes.instance_state(u1) not in nt1._dirty
+
+        s.commit()
+        assert attributes.instance_state(u1) in nt2._dirty
+        assert attributes.instance_state(u1) in nt1._dirty
+
+        s.rollback()
+        assert attributes.instance_state(u1).expired
+        eq_(u1.name, 'u1')
+
     @testing.requires.independent_connections
     def test_transactions_isolated(self):
         User, users = self.classes.User, self.tables.users