[Checkins] SVN: zope.sqlalchemy/branches/savepoint-release/ savepoint.release() support

Laurence Rowe l at lrowe.co.uk
Sat Jan 16 16:36:26 EST 2010


Log message for revision 108183:
  savepoint.release() support

Changed:
  A   zope.sqlalchemy/branches/savepoint-release/
  U   zope.sqlalchemy/branches/savepoint-release/buildout.cfg
  A   zope.sqlalchemy/branches/savepoint-release/postgres.cfg
  U   zope.sqlalchemy/branches/savepoint-release/src/zope/sqlalchemy/datamanager.py
  U   zope.sqlalchemy/branches/savepoint-release/src/zope/sqlalchemy/tests.py

-=-
Modified: zope.sqlalchemy/branches/savepoint-release/buildout.cfg
===================================================================
--- zope.sqlalchemy/trunk/buildout.cfg	2010-01-16 19:29:40 UTC (rev 108182)
+++ zope.sqlalchemy/branches/savepoint-release/buildout.cfg	2010-01-16 21:36:25 UTC (rev 108183)
@@ -1,8 +1,23 @@
 [buildout]
+allow-hosts = pypi.python.org
 develop = .
-parts = test scripts
-allow-hosts = pypi.python.org
+parts =
+    test
+    scripts
+    test_transaction
 
+extensions = mr.developer
+sources = sources
+sources-dir = devel
+auto-checkout = transaction
+
+[sources]
+transaction = svn http://svn.zope.org/repos/main/transaction/branches/elro-savepoint-release
+
+[test_transaction]
+recipe = zc.recipe.testrunner
+eggs = transaction
+
 [test]
 recipe = zc.recipe.testrunner
 eggs = zope.sqlalchemy [test]

Added: zope.sqlalchemy/branches/savepoint-release/postgres.cfg
===================================================================
--- zope.sqlalchemy/branches/savepoint-release/postgres.cfg	                        (rev 0)
+++ zope.sqlalchemy/branches/savepoint-release/postgres.cfg	2010-01-16 21:36:25 UTC (rev 108183)
@@ -0,0 +1,61 @@
+# parts/postgresql/bin/postgres -D var/postgresql/ -d 1
+[buildout]
+extends = buildout.cfg
+find-links = http://initd.org/pub/software/psycopg/
+allow-hosts += initd.org
+
+parts +=
+    postgresql
+    postgresqlinit
+    psycopg2
+    test_pg
+    scripts
+
+[test_pg]
+recipe = zc.recipe.testrunner
+eggs =
+    zope.sqlalchemy [test]
+    psycopg2
+environment = testenv
+
+[scripts]
+eggs = ${test:eggs}
+
+[testenv]
+TEST_DSN = postgres://zope_sqlalchemy_tests:zope_sqlalchemy_tests@localhost:24004/zope_sqlalchemy_tests
+
+[postgresql]
+recipe = zc.recipe.cmmi
+url = ftp://ftp.postgresql.org/pub/source/v8.4.2/postgresql-8.4.2.tar.bz2
+md5sum = d738227e2f1f742d2f2d4ab56496c5c6
+extra_options =
+    --with-pgport=24004
+    --with-readline
+
+[postgresqlinit]
+recipe = iw.recipe.cmd
+on_install = true
+on_update = true
+datadir = ${buildout:directory}/var/postgresql
+cmds =
+    test -e ${buildout:directory}/bin/psql || \
+        ln -s ${postgresql:location}/bin/psql ${buildout:directory}/bin/psql
+    test -e ${postgresqlinit:datadir} && exit 0
+    ${postgresql:location}/bin/initdb ${postgresqlinit:datadir}
+    ${postgresql:location}/bin/postgres --single -D ${postgresqlinit:datadir} \
+            template1 << EOF
+        CREATE USER zope_sqlalchemy_tests WITH PASSWORD 'zope_sqlalchemy_tests';
+        CREATE DATABASE zope_sqlalchemy_tests OWNER zope_sqlalchemy_tests;
+    EOF
+    echo 'host all zope_sqlalchemy_tests 0.0.0.0/0 md5' \
+        >> ${postgresqlinit:datadir}/pg_hba.conf
+    echo "listen_addresses = '*'" >> ${postgresqlinit:datadir}/postgresql.conf
+
+[psycopg2]
+recipe = zc.recipe.egg:custom
+environment = psycopg2-env
+rpath = ${postgresql:location}/lib
+
+[psycopg2-env]
+# This is needed to help psycopg2 find the pg_config script
+PATH=${postgresql:location}/bin:%(PATH)s

Modified: zope.sqlalchemy/branches/savepoint-release/src/zope/sqlalchemy/datamanager.py
===================================================================
--- zope.sqlalchemy/trunk/src/zope/sqlalchemy/datamanager.py	2010-01-16 19:29:40 UTC (rev 108182)
+++ zope.sqlalchemy/branches/savepoint-release/src/zope/sqlalchemy/datamanager.py	2010-01-16 21:36:25 UTC (rev 108183)
@@ -22,6 +22,8 @@
 STATUS_ACTIVE = 'active' # session joined to transaction, writes allowed.
 STATUS_CHANGED = 'changed' # data has been written
 STATUS_READONLY = 'readonly' # session joined to transaction, no writes allowed.
+STATUS_COMMITTING = 'committing' # session about to commit.
+
 STATUS_INVALIDATED = STATUS_CHANGED # BBB
 
 NO_SAVEPOINT_SUPPORT = set(['sqlite'])
@@ -74,6 +76,7 @@
     def tpc_vote(self, trans):
         # for a one phase data manager commit last in tpc_vote
         if self.tx is not None: # there may have been no work to do
+            _SESSION_STATE[id(self.session)] = STATUS_COMMITTING
             self.tx.commit()
             self._finish('committed')
                 
@@ -120,6 +123,7 @@
                 
     def tpc_finish(self, trans):
         if self.tx is not None:
+            _SESSION_STATE[id(self.session)] = STATUS_COMMITTING
             self.tx.commit()
             self._finish('committed')
 
@@ -138,15 +142,25 @@
 
     def __init__(self, session):
         self.session = session
+        self.state = _SESSION_STATE[id(session)]
         self.transaction = session.begin_nested()
-        session.flush() # do I want to do this? Probably.
+        session.flush() # do I want to do this? Not needed in 0.5.
 
     def rollback(self):
         # no need to check validity, sqlalchemy should raise an exception. I think.
         self.transaction.rollback()
+        _SESSION_STATE[id(self.session)] = self.state
         self.session.clear() # remove when Session.rollback does an attribute_manager.rollback
 
+    def release(self):
+        state = _SESSION_STATE[id(self.session)]
+        try:
+            _SESSION_STATE[id(self.session)] = STATUS_COMMITTING
+            self.transaction.commit()
+        finally:
+            _SESSION_STATE[id(self.session)] = state
 
+
 def join_transaction(session, initial_state=STATUS_ACTIVE):
     """Join a session to a transaction using the appropriate datamanager.
        
@@ -198,4 +212,4 @@
         mark_changed(session)
     
     def before_commit(self, session):
-        assert zope_transaction.get().status == 'Committing', "Transaction must be committed using the transaction manager"
+        assert _SESSION_STATE[id(session)] == STATUS_COMMITTING, "Transaction must be committed using the transaction manager"

Modified: zope.sqlalchemy/branches/savepoint-release/src/zope/sqlalchemy/tests.py
===================================================================
--- zope.sqlalchemy/trunk/src/zope/sqlalchemy/tests.py	2010-01-16 19:29:40 UTC (rev 108182)
+++ zope.sqlalchemy/branches/savepoint-release/src/zope/sqlalchemy/tests.py	2010-01-16 21:36:25 UTC (rev 108183)
@@ -297,6 +297,32 @@
         s1.rollback()
         self.failIf(query.all(), "Users table should be empty")
     
+    def testSavepointRelease(self):
+        use_savepoint = not engine.url.drivername in tx.NO_SAVEPOINT_SUPPORT
+        t = transaction.get()
+        session = Session()
+        query = session.query(User)
+        self.failIf(query.all(), "Users table should be empty")
+        
+        s0 = t.savepoint(optimistic=True) # this should always work
+        self.failIf(query.all(), "Users table should be empty")
+        
+        s1 = t.savepoint(optimistic=True)
+        session.add(User(id=1, firstname='udo', lastname='juergens'))
+        session.flush()
+        self.failUnless(len(query.all())==1, "Users table should have one row")
+        
+        s2 = t.savepoint(optimistic=True)
+        session.add(User(id=2, firstname='heino', lastname='n/a'))
+        session.flush()
+        self.failUnless(len(query.all())==2, "Users table should have two rows")
+        
+        s1.release()
+        
+        if use_savepoint:
+            s0.rollback()
+            self.failIf(query.all(), "Users table should be empty")
+    
     def testCommit(self):
         session = Session()
         



More information about the checkins mailing list