From: Mike Bayer Date: Sat, 20 Nov 2010 22:57:30 +0000 (-0500) Subject: - fixes for PG, mysql, twophase X-Git-Tag: rel_0_7b1~240 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=45cdb17ef0b08f31a42423554ec94ed913fb31fe;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - fixes for PG, mysql, twophase - added "pool_events" arg to create_engine(), "events" to pool, allowing establishment of listeners which fire before those of the dialect --- diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index c07c83a07d..90d6bda86d 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -1962,7 +1962,7 @@ def _listener_connection_cls(cls, dispatch): _savepoint_impl(name=name) def _rollback_to_savepoint_impl(self, name, context): - for fn in dispatch.on_rollback_to_savepoint: + for fn in dispatch.on_rollback_savepoint: fn(self, name, context) return super(EventListenerConnection, self).\ _rollback_to_savepoint_impl(name, context) @@ -1989,13 +1989,13 @@ def _listener_connection_cls(cls, dispatch): for fn in dispatch.on_rollback_twophase: fn(self, xid) return super(EventListenerConnection, self).\ - _rollback_twophase_impl(xid) + _rollback_twophase_impl(xid, is_prepared) def _commit_twophase_impl(self, xid, is_prepared): for fn in dispatch.on_commit_twophase: - fn(self, xid) + fn(self, xid, is_prepared) return super(EventListenerConnection, self).\ - _commit_twophase_impl(xid) + _commit_twophase_impl(xid, is_prepared) return EventListenerConnection diff --git a/lib/sqlalchemy/engine/strategies.py b/lib/sqlalchemy/engine/strategies.py index 1ef3ae6245..fe0abd4b7c 100644 --- a/lib/sqlalchemy/engine/strategies.py +++ b/lib/sqlalchemy/engine/strategies.py @@ -94,6 +94,7 @@ class DefaultEngineStrategy(EngineStrategy): 'echo': 'echo_pool', 'timeout': 'pool_timeout', 'recycle': 'pool_recycle', + 'events':'pool_events', 'use_threadlocal':'pool_threadlocal'} for k in util.get_cls_kwargs(poolclass): tk = translate.get(k, k) diff --git a/lib/sqlalchemy/pool.py b/lib/sqlalchemy/pool.py index e1dc06fe9c..280292908b 100644 --- a/lib/sqlalchemy/pool.py +++ b/lib/sqlalchemy/pool.py @@ -67,6 +67,7 @@ class Pool(log.Identified): logging_name=None, reset_on_return=True, listeners=None, + events=None, _dispatch=None): """ Construct a Pool. @@ -104,7 +105,13 @@ class Pool(log.Identified): connections returned to the pool. This is typically a ROLLBACK to release locks and transaction resources. Disable at your own peril. Defaults to True. - + + :param events: a list of 2-tuples, each of the form + ``(callable, target)`` which will be passed to event.listen() + upon construction. Provided here so that event listeners + can be assigned via ``create_engine`` before dialect-level + listeners are applied. + :param listeners: Deprecated. A list of :class:`~sqlalchemy.interfaces.PoolListener`-like objects or dictionaries of callables that receive events when DB-API @@ -127,6 +134,9 @@ class Pool(log.Identified): self.echo = echo if _dispatch: self.dispatch.update(_dispatch, only_propagate=False) + if events: + for fn, target in events: + event.listen(fn, target, self) if listeners: util.warn_deprecated( "The 'listeners' argument to Pool (and " diff --git a/test/dialect/test_mysql.py b/test/dialect/test_mysql.py index 98842b3357..499fd7bd25 100644 --- a/test/dialect/test_mysql.py +++ b/test/dialect/test_mysql.py @@ -7,7 +7,7 @@ import sets # end Py2K from sqlalchemy import * -from sqlalchemy import sql, exc, schema, types as sqltypes +from sqlalchemy import sql, exc, schema, types as sqltypes, event from sqlalchemy.dialects.mysql import base as mysql from sqlalchemy.test.testing import eq_ from sqlalchemy.test import * @@ -1277,13 +1277,17 @@ class SQLModeDetectionTest(TestBase): __only_on__ = 'mysql' def _options(self, modes): - class SetOptions(object): - def first_connect(self, con, record): - self.connect(con, record) - def connect(self, con, record): - cursor = con.cursor() - cursor.execute("set sql_mode='%s'" % (",".join(modes))) - return engines.testing_engine(options={"listeners":[SetOptions()]}) + def connect(con, record): + cursor = con.cursor() + print "DOING THiS:", "set sql_mode='%s'" % (",".join(modes)) + cursor.execute("set sql_mode='%s'" % (",".join(modes))) + e = engines.testing_engine(options={ + 'pool_events':[ + (connect, 'on_first_connect'), + (connect, 'on_connect') + ] + }) + return e def test_backslash_escapes(self): engine = self._options(['NO_BACKSLASH_ESCAPES']) diff --git a/test/dialect/test_postgresql.py b/test/dialect/test_postgresql.py index 150dacf180..6dbcb9bfd2 100644 --- a/test/dialect/test_postgresql.py +++ b/test/dialect/test_postgresql.py @@ -487,7 +487,7 @@ class InsertTest(TestBase, AssertsExecutionResults): def teardown(self): metadata.drop_all() - metadata.tables.clear() + metadata.clear() if self.engine is not testing.db: self.engine.dispose() diff --git a/test/engine/test_execute.py b/test/engine/test_execute.py index 90c4e98e54..7334f755a4 100644 --- a/test/engine/test_execute.py +++ b/test/engine/test_execute.py @@ -602,9 +602,8 @@ class EngineEventsTest(TestBase): def test_transactional_advanced(self): canary = [] def tracker(name): - def go(conn, exec_, *args, **kw): + def go(*args, **kw): canary.append(name) - return exec_(*args, **kw) return go engine = engines.testing_engine() diff --git a/test/engine/test_transaction.py b/test/engine/test_transaction.py index f09c671641..6f3186addf 100644 --- a/test/engine/test_transaction.py +++ b/test/engine/test_transaction.py @@ -270,6 +270,9 @@ class TransactionTest(TestBase): [(1, ), (2, )]) connection.close() + # PG emergency shutdown: + # select * from pg_prepared_xacts + # ROLLBACK PREPARED '' @testing.requires.two_phase_transactions @testing.requires.savepoints def test_mixed_two_phase_transaction(self): @@ -292,7 +295,7 @@ class TransactionTest(TestBase): order_by(users.c.user_id)).fetchall(), [(1, ), (2, ), (5, )]) connection.close() - + @testing.requires.two_phase_transactions @testing.crashes('mysql+oursql', 'Times out in full test runs only, causing ' @@ -347,7 +350,7 @@ class TransactionTest(TestBase): order_by(users.c.user_id)) eq_(result.fetchall(), [('user1', ), ('user4', )]) conn.close() - + class AutoRollbackTest(TestBase): @classmethod diff --git a/test/orm/test_cascade.py b/test/orm/test_cascade.py index 03cdd45616..0deef18fd1 100644 --- a/test/orm/test_cascade.py +++ b/test/orm/test_cascade.py @@ -337,6 +337,8 @@ class O2OSingleParentTest(_fixtures.FixtureTest): class NoSaveCascadeFlushTest(_fixtures.FixtureTest): """Test related item not present in session, commit proceeds.""" + + run_inserts = None @testing.resolve_artifact_names def _one_to_many_fixture(self, o2m_cascade=True,