From 7c32b4c2a61e52c1eceb63ebc154c9cc528feb9e Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Thu, 2 Apr 2015 12:19:15 -0400 Subject: [PATCH] - 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. fixes #3352 (cherry picked from commit 359f471a1203cafd5dc99b5b078ba7d788b67cec) --- doc/build/changelog/changelog_09.rst | 12 ++++++++++++ lib/sqlalchemy/orm/session.py | 1 + test/orm/test_transaction.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/doc/build/changelog/changelog_09.rst b/doc/build/changelog/changelog_09.rst index 32339a1544..ab1292f494 100644 --- a/doc/build/changelog/changelog_09.rst +++ b/doc/build/changelog/changelog_09.rst @@ -25,6 +25,18 @@ :meth:`.Query.select_from` has been called, a warning is emitted. As of 1.0.0b5 this will raise an error. + .. 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 diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index f976be9428..e285245656 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -298,6 +298,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) diff --git a/test/orm/test_transaction.py b/test/orm/test_transaction.py index 6bea5cc7b7..91846a67e6 100644 --- a/test/orm/test_transaction.py +++ b/test/orm/test_transaction.py @@ -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 -- 2.47.3