]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed bug where items that were persisted, deleted, or had a
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 1 Jul 2014 16:12:27 +0000 (12:12 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 1 Jul 2014 16:12:51 +0000 (12:12 -0400)
primary key change within a savepoint block would not
participate in being restored to their former state (not in
session, in session, previous PK) after the outer transaction
were rolled back. fixes #3108

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

index fa83c4b34635b8a815bf94bd0b4f46d5917e5cf9..f3389ffdaa8b64d9aa608d13371dbe8ed57b85b6 100644 (file)
     :version: 0.9.7
     :released:
 
+    .. change::
+        :tags: bug, orm
+        :tickets: 3108
+        :versions: 1.0.0
+
+        Fixed bug where items that were persisted, deleted, or had a
+        primary key change within a savepoint block would not
+        participate in being restored to their former state (not in
+        session, in session, previous PK) after the outer transaction
+        were rolled back.
+
     .. change::
         :tags: bug, orm
         :tickets: 3106
index 3cc03a2d4575d704b222d5fd9ca3a5f02ddff4b5..714c42a84e0350caa47072cec34aa955dcbdd188 100644 (file)
@@ -292,7 +292,10 @@ class SessionTransaction(object):
             for s in self._deleted:
                 s.session_id = None
             self._deleted.clear()
-
+        elif self.nested:
+            self._parent._new.update(self._new)
+            self._parent._deleted.update(self._deleted)
+            self._parent._key_switches.update(self._key_switches)
 
     def _connection_for_bind(self, bind):
         self._assert_active()
index 011667651c8eb5e68f640dece1c6292f2fe255d6..b394b46ca0e8aa0a4aaef5e7621f53b664fc496f 100644 (file)
@@ -546,6 +546,36 @@ class ReversePKsTest(fixtures.MappedTest):
         assert session.query(User).get([1, PUBLISHED]) is a_published
         assert session.query(User).get([1, EDITABLE]) is a_editable
 
+    @testing.requires.savepoints
+    def test_reverse_savepoint(self):
+        user, User = self.tables.user, self.classes.User
+
+        PUBLISHED, EDITABLE, ARCHIVED = 1, 2, 3
+
+        mapper(User, user)
+
+        session = sa.orm.sessionmaker()()
+
+        a_published = User(1, PUBLISHED, 'a')
+        session.add(a_published)
+        session.commit()
+
+        a_editable = User(1, EDITABLE, 'a')
+
+        session.add(a_editable)
+        session.commit()
+
+        # testing #3108
+        session.begin_nested()
+
+        a_published.status = ARCHIVED
+        a_editable.status = PUBLISHED
+
+        session.commit()
+
+        session.rollback()
+        eq_(a_published.status, PUBLISHED)
+        eq_(a_editable.status, EDITABLE)
 
 class SelfReferentialTest(fixtures.MappedTest):
     # mssql, mysql don't allow
index 22d759bb8eafd728a4f291d39c78a54dafda848c..32bc27c92d548482f705b733206adac8fbf78da2 100644 (file)
@@ -85,6 +85,43 @@ class SessionTransactionTest(FixtureTest):
             raise
 
 
+    @testing.requires.savepoints
+    def test_nested_accounting_new_items_removed(self):
+        User, users = self.classes.User, self.tables.users
+
+        mapper(User, users)
+
+        session = create_session(bind=testing.db)
+        session.begin()
+        session.begin_nested()
+        u1 = User(name='u1')
+        session.add(u1)
+        session.commit()
+        assert u1 in session
+        session.rollback()
+        assert u1 not in session
+
+    @testing.requires.savepoints
+    def test_nested_accounting_deleted_items_restored(self):
+        User, users = self.classes.User, self.tables.users
+
+        mapper(User, users)
+
+        session = create_session(bind=testing.db)
+        session.begin()
+        u1 = User(name='u1')
+        session.add(u1)
+        session.commit()
+
+        session.begin()
+        u1 = session.query(User).first()
+
+        session.begin_nested()
+        session.delete(u1)
+        session.commit()
+        assert u1 not in session
+        session.rollback()
+        assert u1 in session
 
     @testing.requires.savepoints
     def test_heavy_nesting(self):