]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- fixes for PG, mysql, twophase
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 20 Nov 2010 22:57:30 +0000 (17:57 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 20 Nov 2010 22:57:30 +0000 (17:57 -0500)
- added "pool_events" arg to create_engine(), "events" to pool, allowing
establishment of listeners which fire before those of the dialect

lib/sqlalchemy/engine/base.py
lib/sqlalchemy/engine/strategies.py
lib/sqlalchemy/pool.py
test/dialect/test_mysql.py
test/dialect/test_postgresql.py
test/engine/test_execute.py
test/engine/test_transaction.py
test/orm/test_cascade.py

index c07c83a07d040f8e5fc526fce43b9c654ed01634..90d6bda86d69416c5664a3a005de0faac563d124 100644 (file)
@@ -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
 
index 1ef3ae6245d442fa468e52001b6fb9892b9d5a53..fe0abd4b7c07c6d7088a4eb8191473b5fc12947a 100644 (file)
@@ -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)
index e1dc06fe9c251e2506b9b003aff2a467c5f42896..280292908b07f9c02244803922a6a6b386b2d6bf 100644 (file)
@@ -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 "
index 98842b3357a21e52664118050b1e89ef9fdcaa69..499fd7bd25b1153653c372d3221b96a8849b6fca 100644 (file)
@@ -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'])
index 150dacf180a99f0e1e5a2ee02e4b0a57dabe1294..6dbcb9bfd29ed3b6b3d3fcfeea92aa59a3f10a35 100644 (file)
@@ -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()
 
index 90c4e98e54bde5ddbd08b573df6f5f8d6e9de025..7334f755a42341187dfc8ef648cb1ac798ebd3ac 100644 (file)
@@ -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()
index f09c67164125a647b5f1987b3ca2a9599823d317..6f3186addf51be9d392cd61d6edb412fe73661d4 100644 (file)
@@ -270,6 +270,9 @@ class TransactionTest(TestBase):
             [(1, ), (2, )])
         connection.close()
 
+    # PG emergency shutdown:
+    # select * from pg_prepared_xacts
+    # ROLLBACK PREPARED '<xid>'
     @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
index 03cdd456160589aac55fd025761a1f95cfed3c57..0deef18fd1eaf7289576b367bfe5dcea7baf0bde 100644 (file)
@@ -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,