summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-09-22 16:03:57 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2012-09-22 16:03:57 -0400
commit03cb8ce548a99b97852c25f2fec26ed611afbb5c (patch)
treec8843f6b02b22b835458a039d3dcc3b099bbcbad
parent81c1ec33e37c23be58285d4ef607de9b670c547f (diff)
downloadsqlalchemy-03cb8ce548a99b97852c25f2fec26ed611afbb5c.tar.gz
- [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]
-rw-r--r--CHANGES15
-rw-r--r--lib/sqlalchemy/orm/session.py10
-rw-r--r--test/orm/test_transaction.py47
3 files changed, 69 insertions, 3 deletions
diff --git a/CHANGES b/CHANGES
index 205e035ed..3b600d5be 100644
--- 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
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index 36ff5fc84..5e5cf2246 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -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:
diff --git a/test/orm/test_transaction.py b/test/orm/test_transaction.py
index edae617d6..fdbf6ae1f 100644
--- a/test/orm/test_transaction.py
+++ b/test/orm/test_transaction.py
@@ -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