]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- [bug] Extra logic has been added to the "flush"
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 22 Sep 2012 20:03:57 +0000 (16:03 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 22 Sep 2012 20:03:57 +0000 (16:03 -0400)
    that occurs within Session.commit(), such that the
    extra state added by an after_flush() or
    after_flush_postexec() hook is also flushed in a
    subsequent flush, before the "commit" completes.
    Subsequent calls to flush() will continue until
    the after_flush hooks stop adding new state.
    An "overflow" counter of 100 is also in place,
    in the event of a broken after_flush() hook
    adding new content each time. [ticket:2566]

CHANGES
lib/sqlalchemy/orm/session.py
test/orm/test_transaction.py

diff --git a/CHANGES b/CHANGES
index 205e035edf61ba96c820a269746898a251f02b96..3b600d5beedc21df0461a2eba61022ca88bd74e3 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -612,8 +612,8 @@ underneath "0.7.xx".
     needs to be modified to use column.in_(select)
     explicitly.  [ticket:2277]
 
-  - [feature] updated support for the mxodbc 
-    driver; mxodbc 3.2.1 is recommended for full 
+  - [feature] updated support for the mxodbc
+    driver; mxodbc 3.2.1 is recommended for full
     compatibility.
 
 - postgresql
@@ -743,6 +743,17 @@ are also present in 0.8.
     "version" column, when using the "version" feature.
     Tests courtesy Daniel Miller.  [ticket:2539]
 
+  - [bug] Extra logic has been added to the "flush"
+    that occurs within Session.commit(), such that the
+    extra state added by an after_flush() or
+    after_flush_postexec() hook is also flushed in a
+    subsequent flush, before the "commit" completes.
+    Subsequent calls to flush() will continue until
+    the after_flush hooks stop adding new state.
+    An "overflow" counter of 100 is also in place,
+    in the event of a broken after_flush() hook
+    adding new content each time. [ticket:2566]
+
 - sql
   - [bug] Fixed CTE bug whereby positional
     bound parameters present in the CTEs themselves
index 36ff5fc84e81a7b5fda3cd1c70c5a65cd52b9d9f..5e5cf2246a2cb3eebf07319d9727c7cedec2e28f 100644 (file)
@@ -294,7 +294,15 @@ class SessionTransaction(object):
                 subtransaction.commit()
 
         if not self.session._flushing:
-            self.session.flush()
+            for _flush_guard in xrange(100):
+                if self.session._is_clean():
+                    break
+                self.session.flush()
+            else:
+                raise exc.FlushError(
+                        "Over 100 subsequent flushes have occurred within "
+                        "session.commit() - is an after_flush() hook "
+                        "creating new objects?")
 
         if self._parent is None and self.session.twophase:
             try:
index edae617d688053cb89c1618a754390e38e284499..fdbf6ae1f23407fec0652a4d3c5e3fa0a135bd19 100644 (file)
@@ -297,6 +297,53 @@ class SessionTransactionTest(FixtureTest):
 
         eq_(len(sess.query(User).all()), 1)
 
+    def test_continue_flushing_on_commit(self):
+        """test that post-flush actions get flushed also if
+        we're in commit()"""
+        users, User = self.tables.users, self.classes.User
+
+        mapper(User, users)
+        sess = Session()
+
+        to_flush = [User(name='ed'), User(name='jack'), User(name='wendy')]
+        @event.listens_for(sess, "after_flush_postexec")
+        def add_another_user(session, ctx):
+            if to_flush:
+                session.add(to_flush.pop(0))
+
+        x = [1]
+        @event.listens_for(sess, "after_commit")
+        def add_another_user(session):
+            x[0] += 1
+
+        sess.add(to_flush.pop())
+        sess.commit()
+        eq_(x, [2])
+        eq_(
+            sess.scalar(select([func.count(users.c.id)])), 3
+        )
+
+    def test_continue_flushing_guard(self):
+        users, User = self.tables.users, self.classes.User
+
+        mapper(User, users)
+        sess = Session()
+
+        @event.listens_for(sess, "after_flush_postexec")
+        def add_another_user(session, ctx):
+            session.add(User(name='x'))
+        sess.add(User(name='x'))
+        assert_raises_message(
+            orm_exc.FlushError,
+            "Over 100 subsequent flushes have occurred",
+            sess.commit
+        )
+
+
+
+
+
+
     def test_error_on_using_inactive_session_commands(self):
         users, User = self.tables.users, self.classes.User