dabo Commit
Revision 3314
Date: 2007-08-19 12:07:48 -0700 (Sun, 19 Aug 2007)
Author: Ed
Trac: http://svn.dabodev.com/trac/dabo/changeset/3314

Changed:
U   trunk/dabo/biz/dAutoBizobj.py
U   trunk/dabo/biz/dBizobj.py
U   trunk/dabo/biz/test/test_dBizobj.py
U   trunk/dabo/dApp.py
U   trunk/dabo/dPref.py
U   trunk/dabo/db/dBackend.py
U   trunk/dabo/db/dCursorMixin.py
U   trunk/dabo/db/dbFirebird.py
U   trunk/dabo/db/dbMySQL.py
U   trunk/dabo/db/dbPostgreSQL.py
U   trunk/dabo/db/dbSQLite.py
U   trunk/dabo/db/test/test_dCursorMixin.py

Log:
Major re-write to the way that transactions are handled in the bizobj and 
database layers.

These changes are designed to work within the entire framework; i.e., 
applications, forms, bizobjs and cursors. If you use any single piece of the 
framework separately, such as a raw cursor, you will have to manage 
transactions yourself.

Transactions now happen happen by default when calling biz.save()/saveAll() and 
biz.delete()/deleteAll(). If for some reason you do not want transactions, you 
must call them with the parameter startTransaction=False.

Only one bizobj will begin and commit/rollback. All others do not touch 
transactions, as they are within the current transaction. Upon a save or delete 
method being called, the bizobj will request the transaction 'token' from the 
app. If no other bizobj has started a transaction, it will have True returned 
from the request, and the bizobj will handle the transaction. If there are 
related bizobjs who in turn have their save/delete methods called, their 
requests for the token will be denied, so they will not do anything regarding 
transactions. When the process is completed in the initial method that 
requested the token, either a commit or rollback will be called, and the token 
released.

This design eliminates the problem with nested and chained bizobjs starting 
and/or ending multiple transactions. Only the original bizobj in the process 
can manage transactions, and only from the method that was originally called.

The 'AutoCommit' property has been removed. Defaulting transactions to being 
used by default will handle the call to commit(). Again, if you deal with 
cursors directly (as is done in dPref.py), the commit calls must also be 
handled manually.



Diff:
Modified: trunk/dabo/biz/dAutoBizobj.py
===================================================================
--- trunk/dabo/biz/dAutoBizobj.py       2007-08-14 21:57:09 UTC (rev 3313)
+++ trunk/dabo/biz/dAutoBizobj.py       2007-08-19 19:07:48 UTC (rev 3314)
@@ -43,12 +43,8 @@
 
        g._toExc = {}
        for biz in g._AutoTables.values():
-               ac = biz.AutoCommit
-               biz.AutoCommit = True
-               biz.CreateTable()
+               biz.createTable()
 
-               biz.AutoCommit = ac
-
        if g._toExc:
                if dabo.dAppRef is not None:
                        class DbAdminLogin(dabo.ui.dDialog):
@@ -138,7 +134,7 @@
                                                tempConn = 
dabo.db.dConnection(ci)
                                        except dException.DBNoAccessException:
                                                dabo.ui.stop(_("Could not 
access the database with the given username and password."))
-                                               _WriteQueriesToFile(g._toExc)
+                                               _writeQueriesToFile(g._toExc)
                                                raise 
dException.DBNoAccessException
                                        else:
                                                cur = tempConn.getDaboCursor()
@@ -149,20 +145,20 @@
                                                                
cur.execute(query)
                                                        except 
dException.DBNoAccessExeption:
                                                                
dabo.ui.stop(_("Could not setup the database. Access was denied."))
-                                                               
_WriteQueriesToFile(g._toExc)
+                                                               
_writeQueriesToFile(g._toExc)
                                                                raise 
dException.DBNoAccessException
 
                                else:
                                        login.release()
-                                       _WriteQueriesToFile(g._toExc)
+                                       _writeQueriesToFile(g._toExc)
                                        raise dException.DBNoAccessException
 
                else:
-                       _WriteQueriesToFile(g._toExc)
+                       _writeQueriesToFile(g._toExc)
                        raise dException.DBNoAccessException
 
 
-def _WriteQueriesToFile(queries):
+def _writeQueriesToFile(queries):
        f = open("queries.sql", "w")
        for k in queries.keys():
                f.write(_("#Queries for DB '%s' on host '%s':\n") % 
(k.ConnectInfo.Database, k.ConnectInfo.Host))
@@ -171,6 +167,8 @@
 
        f.close()
 
+
+
 class dAutoBizobj(dBizobj):
        """This class is just like bBizobj but is supports the auto creation of
        the table by setting the table property.
@@ -244,7 +242,7 @@
                #Override in subclass
 
 
-       def CreateTable(self):
+       def createTable(self):
                """Create the tables that has been asigned to this bizobj."""
                if self._table is None:
                        raise dException.dException(_("No table has been 
defined for this bizobj."))

Modified: trunk/dabo/biz/dBizobj.py
===================================================================
--- trunk/dabo/biz/dBizobj.py   2007-08-14 21:57:09 UTC (rev 3313)
+++ trunk/dabo/biz/dBizobj.py   2007-08-19 19:07:48 UTC (rev 3314)
@@ -60,7 +60,6 @@
                self._restorePositionOnRequery = True
 
                # Various attributes used for Properties
-               self._autoCommit = False
                self._caption = ""
                self._dataSource = ""
                self._nonUpdateFields = []
@@ -166,7 +165,6 @@
                crs.AutoQuoteNames = self.AutoQuoteNames
                crs.BackendObject = cf.getBackendObject()
                crs.sqlManager = self.SqlManager
-               crs.AutoCommit = self.AutoCommit
                crs._bizobj = self
                if self.RequeryOnLoad:
                        crs.requery()
@@ -262,45 +260,49 @@
                self.afterLast()
 
 
-       def saveAll(self, startTransaction=False, topLevel=True):
+       def saveAll(self, startTransaction=True):
                """Saves all changes to the bizobj and children."""
-               useTransact = startTransaction or topLevel
                cursor = self._CurrentCursor
                current_row = self.RowNumber
+               app = self.Application
+               isTransactionManager = False
+               if startTransaction:
+                       isTransactionManager = app.getTransactionToken(self)
+                       if isTransactionManager:
+                               cursor.beginTransaction()
 
-               if useTransact:
-                       # Tell the cursor to begin a transaction, if needed.
-                       cursor.beginTransaction()
-
                try:
                        self.scanChangedRows(self.save, 
includeNewUnchanged=self.SaveNewUnchanged,
-                                       startTransaction=False, topLevel=False)
+                                       startTransaction=False)
+                       if isTransactionManager:
+                               cursor.commitTransaction()
+                               app.releaseTransactionToken(self)
+
                except dException.ConnectionLostException, e:
                        self.RowNumber = current_row
                        raise dException.ConnectionLostException, e
                except dException.DBQueryException, e:
                        # Something failed; reset things.
-                       if useTransact:
+                       if isTransactionManager:
                                cursor.rollbackTransaction()
+                               app.releaseTransactionToken(self)
                        # Pass the exception to the UI
                        self.RowNumber = current_row
                        raise dException.DBQueryException, e
                except dException.dException, e:
-                       if useTransact:
+                       if isTransactionManager:
                                cursor.rollbackTransaction()
+                               app.releaseTransactionToken(self)
                        self.RowNumber = current_row
                        raise
 
-               if useTransact:
-                       cursor.commitTransaction()
-
                if current_row >= 0:
                        try:
                                self.RowNumber = current_row
                        except: pass
 
 
-       def save(self, startTransaction=False, topLevel=True):
+       def save(self, startTransaction=True):
                """Save any changes that have been made in the current row.
 
                If the save is successful, the saveAll() of all child bizobjs 
will be
@@ -318,10 +320,12 @@
                # validation, an Exception will be raised.
                self._validate()
 
-               useTransact = startTransaction or topLevel
-               if useTransact:
-                       # Tell the cursor to begin a transaction, if needed.
-                       cursor.beginTransaction()
+               app = self.Application
+               isTransactionManager = False
+               if startTransaction:
+                       isTransactionManager = app.getTransactionToken(self)
+                       if isTransactionManager:
+                               cursor.beginTransaction()
 
                # Save to the Database, but first save the IsAdding flag as the 
save() call
                # will reset it to False:
@@ -337,11 +341,12 @@
                                # No need to start another transaction. And 
since this is a child bizobj,
                                # we need to save all rows that have changed.
                                if child.RowCount > 0:
-                                       child.saveAll(startTransaction=False, 
topLevel=False)
+                                       child.saveAll(startTransaction=False)
 
                        # Finish the transaction, and requery the children if 
needed.
-                       if useTransact:
+                       if isTransactionManager:
                                cursor.commitTransaction()
+                               app.releaseTransactionToken(self)
                        if self.RequeryChildOnSave:
                                self.requeryAllChildren()
 
@@ -353,22 +358,20 @@
 
                except dException.DBQueryException, e:
                        # Something failed; reset things.
-                       if useTransact:
+                       if isTransactionManager:
                                cursor.rollbackTransaction()
+                               app.releaseTransactionToken(self)
                        # Pass the exception to the UI
                        raise dException.DBQueryException, e
 
                except dException.dException, e:
                        # Something failed; reset things.
-                       if useTransact:
+                       if isTransactionManager:
                                cursor.rollbackTransaction()
+                               app.releaseTransactionToken(self)
                        # Pass the exception to the UI
                        raise
 
-               # Some backends (Firebird particularly) need to be told to write
-               # their changes even if no explicit transaction was started.
-               cursor.flush()
-
                # Two hook methods: one specific to Save(), and one which is 
called after any change
                # to the data (either save() or delete()).
                self.afterChange()
@@ -404,37 +407,45 @@
                self.afterCancel()
 
 
-       def deleteAllChildren(self, startTransaction=False):
+       def deleteAllChildren(self, startTransaction=True):
                """Delete all children associated with the current record 
without
                deleting the current record in this bizobj.
                """
                cursor = self._CurrentCursor
+               app = self.Application
                errMsg = self.beforeDeleteAllChildren()
                if errMsg:
                        raise dException.BusinessRuleViolation, errMsg
 
+               isTransactionManager = False
                if startTransaction:
-                       cursor.beginTransaction()
+                       isTransactionManager = app.getTransactionToken(self)
+                       if isTransactionManager:
+                               cursor.beginTransaction()
 
                try:
                        for child in self.__children:
                                child.deleteAll(startTransaction=False)
-                       if startTransaction:
+                       if isTransactionManager:
                                cursor.commitTransaction()
-                       self.afterDeleteAllChildren()
+                               app.releaseTransactionToken(self)
 
                except dException.DBQueryException, e:
-                       if startTransaction:
+                       if isTransactionManager:
                                cursor.rollbackTransaction()
+                               app.releaseTransactionToken(self)
                        raise dException.DBQueryException, e
                except StandardError, e:
-                       if startTransaction:
+                       if isTransactionManager:
                                cursor.rollbackTransaction()
+                               app.releaseTransactionToken(self)
                        raise StandardError, e
+               self.afterDeleteAllChildren()
 
 
-       def delete(self, startTransaction=False):
+       def delete(self, startTransaction=True, inLoop=False):
                """Delete the current row of the data set."""
+               app = self.Application
                cursor = self._CurrentCursor
                errMsg = self.beforeDelete()
                if not errMsg:
@@ -451,8 +462,11 @@
                                if child.RowCount > 0:
                                        raise dException.dException, 
_("Deletion prohibited - there are related child records.")
 
+               isTransactionManager = False
                if startTransaction:
-                       cursor.beginTransaction()
+                       isTransactionManager = app.getTransactionToken(self)
+                       if isTransactionManager:
+                               cursor.beginTransaction()
 
                try:
                        cursor.delete()
@@ -469,33 +483,56 @@
                                        child.cancelAll()
                                        child.requery()
 
-                       if startTransaction:
+                       if isTransactionManager:
                                cursor.commitTransaction()
+                               app.releaseTransactionToken(self)
 
-                       # Some backends (Firebird particularly) need to be told 
to write
-                       # their changes even if no explicit transaction was 
started.
-                       cursor.flush()
+                       if not inLoop:
+                               self.afterPointerMove()
+                               self.afterChange()
+                               self.afterDelete()
+               except dException.DBQueryException, e:
+                       if isTransactionManager:
+                               cursor.rollbackTransaction()
+                               app.releaseTransactionToken(self)
+                       raise dException.DBQueryException, e
+               except StandardError, e:
+                       if isTransactionManager:
+                               cursor.rollbackTransaction()
+                               app.releaseTransactionToken(self)
+                       raise StandardError, e
 
+
+       def deleteAll(self, startTransaction=True):
+               """ Delete all rows in the data set."""
+               isTransactionManager = False
+               if startTransaction:
+                       isTransactionManager = app.getTransactionToken(self)
+                       if isTransactionManager:
+                               cursor.beginTransaction()
+               try:
+                       while self.RowCount > 0:
+                               self.first()
+                               ret = self.delete(startTransaction=False, 
inLoop=True)
+                       if isTransactionManager:
+                               cursor.commitTransaction()
+                               app.releaseTransactionToken(self)
+
                        self.afterPointerMove()
                        self.afterChange()
                        self.afterDelete()
                except dException.DBQueryException, e:
-                       if startTransaction:
+                       if isTransactionManager:
                                cursor.rollbackTransaction()
+                               app.releaseTransactionToken(self)
                        raise dException.DBQueryException, e
                except StandardError, e:
-                       if startTransaction:
+                       if isTransactionManager:
                                cursor.rollbackTransaction()
+                               app.releaseTransactionToken(self)
                        raise StandardError, e
 
 
-       def deleteAll(self, startTransaction=False):
-               """ Delete all rows in the data set."""
-               while self.RowCount > 0:
-                       self.first()
-                       ret = self.delete(startTransaction)
-
-
        def execute(self, sql):
                """Execute the sql on the cursor. Dangerous. Use executeSafe 
instead."""
                self._syncWithCursors()
@@ -758,19 +795,14 @@
                        raise dException.ConnectionLostException, e
 
                except dException.DBQueryException, e:
-                       # Something failed; reset things.
-                       cursor.rollbackTransaction()
                        # Pass the exception to the UI
                        raise dException.DBQueryException, e
 
                except dException.NoRecordsException:
-                       # No need to abort the transaction because of this, but
-                       # we still need to pass the exception to the UI
+                       # Pass the exception to the UI
                        uiException = dException.NoRecordsException
 
                except dException.dException, e:
-                       # Something failed; reset things.
-                       cursor.rollbackTransaction()
                        # Pass the exception to the UI
                        raise dException.dException, e
 
@@ -1467,7 +1499,6 @@
                such cursors are in sync with the bizobj.
                """
                for crs in self.__cursors.values():
-                       crs.AutoCommit = self._autoCommit
                        crs.AutoPopulatePK = self._autoPopulatePK
                        crs.AutoQuoteNames = self._autoQuoteNames
                        crs.Table = self._dataSource
@@ -1477,14 +1508,7 @@
                        crs.setNonUpdateFields(self._nonUpdateFields)
        
 
-       def _getAutoCommit(self):
-               return self._CurrentCursor.AutoCommit
-
-       def _setAutoCommit(self, val):
-               self._autoCommit = val
-               self._syncWithCursors()
-
-
+       ## Property getter/setter methods ##
        def _getAutoPopulatePK(self):
                try:
                        return self._autoPopulatePK
@@ -1841,9 +1865,6 @@
 
 
        ### -------------- Property Definitions ------------------  ##
-       AutoCommit = property(_getAutoCommit, _setAutoCommit, None,
-                       _("Do we need explicit begin/commit/rollback commands 
for transactions?  (bool)"))
-
        AutoPopulatePK = property(_getAutoPopulatePK, _setAutoPopulatePK, None,
                        _("Determines if we are using a table that 
auto-generates its PKs. (bool)"))
 

Modified: trunk/dabo/biz/test/test_dBizobj.py
===================================================================
--- trunk/dabo/biz/test/test_dBizobj.py 2007-08-14 21:57:09 UTC (rev 3313)
+++ trunk/dabo/biz/test/test_dBizobj.py 2007-08-19 19:07:48 UTC (rev 3314)
@@ -44,12 +44,6 @@
 """ % self.temp_table_name)
 
        ## - Begin property unit tests -
-       def test_AutoCommit(self):
-               biz = self.biz
-               self.assertEqual(biz.AutoCommit, False)
-               biz.AutoCommit = True
-               self.assertEqual(biz.AutoCommit, True)
-
        def test_AutoSQL(self):
                biz = self.biz
                self.assertEqual(biz.AutoSQL, "select *\n  from %s\n limit 
1000" % self.temp_table_name)

Modified: trunk/dabo/dApp.py
===================================================================
--- trunk/dabo/dApp.py  2007-08-14 21:57:09 UTC (rev 3313)
+++ trunk/dabo/dApp.py  2007-08-19 19:07:48 UTC (rev 3314)
@@ -186,6 +186,9 @@
                self.getTempFile = self._tempFileHolder.getTempFile
                # Create the framework-level preference manager
                self._frameworkPrefs = dabo.dPref(key="dabo_framework")
+               # Hold a reference to the bizobj, if any, controlling the 
current 
+               # database transaction
+               self._transactionBizobj = None
 
                # List of form classes to open on App Startup
                self.formsToOpen = []  
@@ -397,7 +400,7 @@
                        except:
                                vers = -1
                        localVers = self._currentUpdateVersion()
-                       ret = localVers < vers
+                       ret = (localVers != vers)
                prf.setValue("last_check", now)
                return ret
 
@@ -708,6 +711,35 @@
                                self.dbConnectionNameToFiles[k] = connFile
 
 
+       def getTransactionToken(self, biz):
+               """Only one bizobj at a time can begin and end transactions. 
This allows the bizobj
+               to query the app for the 'token', which is simply an 
acknowledgement that there
+               is no other transaction pending. If the bizobj gets the token, 
further requests for the
+               token will receive a reply of False, meaning that they should 
not be handling the transaction.
+               """
+               print "TOKEN REQUEST", biz
+               if self._transactionBizobj is None:
+                       print "TOKEN SET TO ", biz
+                       self._transactionBizobj = biz
+                       return True
+               else:
+                       print "TOKEN DENIED; holder=", self._transactionBizobj
+                       return False
+
+
+       def releaseTransactionToken(self, biz):
+               """When a process that would normally close a transaction 
happens, the bizobj that is
+               holding the transaction token calls this message to return the 
token. A check is run to 
+               ensure that the releasing bizobj is the one currently holding 
the token; if it is, the 
+               internal attribute is reset.
+               """
+               print "APP RELEASE TOKEN FROM:", biz,
+               if biz is self._transactionBizobj:
+                       self._transactionBizobj = None
+                       print "RELEASED",
+               print ""
+
+
        def setLanguage(self, lang, charset=None):
                """Allows you to change the language used for localization. If 
the language
                passed is not one for which there is a translation file, an 
IOError exception

Modified: trunk/dabo/dPref.py
===================================================================
--- trunk/dabo/dPref.py 2007-08-14 21:57:09 UTC (rev 3313)
+++ trunk/dabo/dPref.py 2007-08-19 19:07:48 UTC (rev 3314)
@@ -72,11 +72,10 @@
                        # Make sure that the table exists
                        if not  "daboprefs" in self._cursor.getTables():
                                self._cursor.execute("create table daboprefs 
(ckey text not null, ctype text not null, cvalue text not null)")
+                               self._cursor.commitTransaction()
                else:
                        self._cursor = crs
                        self._cxn = cxn
-               if self._cursor:
-                       self._cursor.AutoCommit = True
                
                
        def __getattr__(self, att):
@@ -220,6 +219,7 @@
                        sql = "insert into daboprefs (ckey, ctype, cvalue) 
values (?, ?, ?)"
                        prm = (key, typ, val)
                        crs.execute(sql, prm)
+               self._cursor.commitTransaction()
        
        
        def persist(self):
@@ -234,6 +234,7 @@
                for key in self._deletionCache.keys():
                        self._cursor.execute("delete from daboprefs where ckey 
like ? ", (key, ))
                self._deletionCache = {}
+               self._cursor.commitTransaction()
        
        
        def deletePref(self, att, nested=False):
@@ -260,7 +261,8 @@
                        self._deletionCache[key] = None
                        if self._cache.has_key(att):
                                del self._cache[att]
-                       
+               self._cursor.commitTransaction()
+
        
        def deleteAllPrefs(self):
                """Deletes all preferences for this object, and all sub-prefs 
as well."""
@@ -281,7 +283,8 @@
                        # Update the caches
                        self._cache = {}
                        self._deletionCache[key] = None
-                       
+               self._cursor.commitTransaction()
+
        
        def flushCache(self):
                """Clear the cache, forcing fresh reads from the database."""
@@ -376,6 +379,7 @@
                sql = "insert into daboprefs (ckey, ctype, cvalue) values (?, 
?, ?)"
                prm = (key, newTyp, val)
                self._cursor.execute(sql, prm)
+               self._cursor.commitTransaction()
        
        
        def setValue(self, key, val):

Modified: trunk/dabo/db/dBackend.py
===================================================================
--- trunk/dabo/db/dBackend.py   2007-08-14 21:57:09 UTC (rev 3313)
+++ trunk/dabo/db/dBackend.py   2007-08-19 19:07:48 UTC (rev 3314)
@@ -25,9 +25,6 @@
 
        def __init__(self):
                self._baseClass = dBackend
-               self._autoCommit = False
-               # This forces the setting on the connection
-               self.AutoCommit = False
                super(dBackend, self).__init__()
                self.dbModuleName = None
                self._connection = None
@@ -196,31 +193,16 @@
                return tuple([(d[0], self.getDaboFieldType(d[1]), None) for d 
in cursorDescription])
 
 
-       def getAutoCommitStatus(self, cursor):
-               return self._autoCommit
-
-
-       def setAutoCommitStatus(self, cursor, val):
-               if hasattr(self._connection, "autocommit"):
-                       self._connection.autocommit(val)
-                       self._autoCommit = val
-               else:
-                       # Without an autocommit method, assume no autocommit.
-                       self._autoCommit = False
-                       if val:
-                               raise ValueError, "Can't set AutoCommit to True 
for this backend."
-
-
        def beginTransaction(self, cursor):
                """ Begin a SQL transaction. Override in subclasses if 
needed."""
-               pass
+               self._connection.begin()
+               dabo.dbActivityLog.write("SQL: begin")
 
 
        def commitTransaction(self, cursor):
                """ Commit a SQL transaction."""
-               if not cursor.AutoCommit:
-                       self._connection.commit()
-                       dabo.dbActivityLog.write("SQL: commit")
+               self._connection.commit()
+               dabo.dbActivityLog.write("SQL: commit")
 
 
        def rollbackTransaction(self, cursor):

Modified: trunk/dabo/db/dCursorMixin.py
===================================================================
--- trunk/dabo/db/dCursorMixin.py       2007-08-14 21:57:09 UTC (rev 3313)
+++ trunk/dabo/db/dCursorMixin.py       2007-08-19 19:07:48 UTC (rev 3314)
@@ -352,7 +352,6 @@
                        # Redundant!
                        return
                ac = self.AuxCursor
-               ac.AutoCommit = self.AutoCommit
                ac.AutoPopulatePK = self.AutoPopulatePK
                ac.AutoQuoteNames = self.AutoQuoteNames
                ac.DataStructure = self.DataStructure
@@ -1056,7 +1055,7 @@
                        raise dException.NoRecordsException, _("No records in 
data set")
 
 
-       def save(self, allRows=False, useTransaction=False):
+       def save(self, allRows=False):
                """ Save any changes to the data back to the data store."""
                # Make sure that there is data to save
                if self.RowCount <= 0:
@@ -1068,26 +1067,20 @@
                        try:
                                self.__saverow(row)
                        except dException.DBQueryException, e:
-                               # Error was raised. Exit and rollback the 
changes if
-                               # this object started the transaction.
+                               # Error was encountered. Raise an exception so 
that the
+                               # calling bizobj can rollback the transaction 
if necessary
                                dabo.dbActivityLog.write(_("DBQueryException 
encountered in save(): %s") % e)
-                               if useTransaction:
-                                       self.rollbackTransaction()
                                raise dException.DBQueryException, e
                        except StandardError, e:
                                if "connect" in str(e).lower():
                                        dabo.dbActivityLog.write(_("Connection 
Lost exception encountered in saverow(): %s") % e)
                                        raise 
dException.ConnectionLostException, e
                                else:
-                                       # Error was raised. Exit and rollback 
the changes if
-                                       # this object started the transaction.
-                                       if useTransaction:
-                                               self.rollbackTransaction()
+                                       # Error was encountered. Raise an 
exception so that the
+                                       # calling bizobj can rollback the 
transaction if necessary
                                        raise
 
                self._syncAuxProperties()
-               if useTransaction:
-                       self.beginTransaction()
 
                # Faster to deal with 2 specific cases: all rows or just 
current row
                if allRows:
@@ -1100,10 +1093,7 @@
                        if pk in self._mementos.keys():
                                saverow(self.RowNumber)
 
-               if useTransaction:
-                       self.commitTransaction()
 
-
        def __saverow(self, row):
                rec = self._records[row]
                recKey = self.pkExpression(rec)
@@ -1726,8 +1716,7 @@
                """ Begin a SQL transaction."""
                ret = None
                if self.BackendObject:
-                       if not self.AutoCommit:
-                               ret = 
self.BackendObject.beginTransaction(self.AuxCursor)
+                       ret = 
self.BackendObject.beginTransaction(self.AuxCursor)
                return ret
 
 
@@ -1735,8 +1724,7 @@
                """ Commit a SQL transaction."""
                ret = None
                if self.BackendObject:
-                       if not self.AutoCommit:
-                               ret = 
self.BackendObject.commitTransaction(self.AuxCursor)
+                       ret = 
self.BackendObject.commitTransaction(self.AuxCursor)
                return ret
 
 
@@ -2014,14 +2002,6 @@
 
 
        ## Property getter/setter methods ##
-       def _getAutoCommit(self):
-               return self.BackendObject.getAutoCommitStatus(self)
-
-
-       def _setAutoCommit(self, val):
-               self.BackendObject.setAutoCommitStatus(self, val)
-
-
        def _getAutoSQL(self):
                return self.getSQL()
 
@@ -2252,9 +2232,6 @@
                self._virtualFields = val
 
 
-       AutoCommit = property(_getAutoCommit, _setAutoCommit, None,
-                       _("Do we need explicit begin/commit/rollback commands 
for transactions?  (bool)"))
-
        AutoPopulatePK = property(_getAutoPopulatePK, _setAutoPopulatePK, None,
                        _("When inserting a new record, does the backend 
populate the PK field?"))
 

Modified: trunk/dabo/db/dbFirebird.py
===================================================================
--- trunk/dabo/db/dbFirebird.py 2007-08-14 21:57:09 UTC (rev 3313)
+++ trunk/dabo/db/dbFirebird.py 2007-08-19 19:07:48 UTC (rev 3314)
@@ -193,8 +193,8 @@
        
        def beginTransaction(self, cursor):
                """ Begin a SQL transaction."""
-               if not cursor.connection._has_transaction():
-                       cursor.connection.begin()
+               if not self._connection._has_transaction():
+                       self._connection.begin()
                        dabo.dbActivityLog.write("SQL: begin")
 
                
@@ -202,7 +202,7 @@
                """ Firebird requires an explicit commit in order to have 
changes
                to the database written to disk.
                """
-               cursor.connection.commit()
+               self._connection.commit()
                dabo.dbActivityLog.write("SQL: commit")
 
        

Modified: trunk/dabo/db/dbMySQL.py
===================================================================
--- trunk/dabo/db/dbMySQL.py    2007-08-14 21:57:09 UTC (rev 3313)
+++ trunk/dabo/db/dbMySQL.py    2007-08-19 19:07:48 UTC (rev 3314)
@@ -4,6 +4,7 @@
        import decimal
 except ImportError:
        decimal = None
+import dabo
 from dabo.dLocalize import _
 from dBackend import dBackend
 import dabo.dException as dException
@@ -60,6 +61,24 @@
                return cursors.DictCursor
 
 
+       def beginTransaction(self, cursor):
+               """ Begin a SQL transaction."""
+               cursor.execute("START TRANSACTION")
+               dabo.dbActivityLog.write("SQL: begin")
+
+
+       def commitTransaction(self, cursor):
+               """ Commit a SQL transaction."""
+               cursor.execute("COMMIT")
+               dabo.dbActivityLog.write("SQL: commit")
+
+
+       def rollbackTransaction(self, cursor):
+               """ Rollback a SQL transaction."""
+               cursor.execute("ROLLBACK")
+               dabo.dbActivityLog.write("SQL: rollback")
+
+
        def escQuote(self, val):
                # escape backslashes and single quotes, and
                # wrap the result in single quotes

Modified: trunk/dabo/db/dbPostgreSQL.py
===================================================================
--- trunk/dabo/db/dbPostgreSQL.py       2007-08-14 21:57:09 UTC (rev 3313)
+++ trunk/dabo/db/dbPostgreSQL.py       2007-08-19 19:07:48 UTC (rev 3314)
@@ -13,7 +13,6 @@
                #self.dbModuleName = "pgdb"
                #self.dbModuleName = "PgSQL"
                self.dbModuleName = "psycopg"
-               self.useTransactions = True  # this does not appear to be 
required
                self.conn_user = ''
 
 
@@ -222,7 +221,8 @@
                to the database written to disk.
                """
                self.commitTransaction(cursor)
-               
+
+
        def getLastInsertID(self, cursor):
                """ Return the ID of the last inserted row, or None.
                

Modified: trunk/dabo/db/dbSQLite.py
===================================================================
--- trunk/dabo/db/dbSQLite.py   2007-08-14 21:57:09 UTC (rev 3313)
+++ trunk/dabo/db/dbSQLite.py   2007-08-19 19:07:48 UTC (rev 3314)
@@ -2,7 +2,9 @@
 import sys
 import os
 import re
+import dabo
 from dabo.dLocalize import _
+from dabo.dException import dException
 from dBackend import dBackend
 from dNoEscQuoteStr import dNoEscQuoteStr as dNoEQ
 from dCursorMixin import dCursorMixin
@@ -69,25 +71,35 @@
                return qt + val.replace(sl, sl+sl).replace(qt, qt+qt) + qt
        
        
-       def setAutoCommitStatus(self, cursor, val):
-               """SQLite doesn't use an 'autocommit()' method. Instead,
-               set the isolation_level property of the connection.
-               """
-               if val:
-                       self._connection.isolation_level = None
-               else:
-                       self._connection.isolation_level = ""
-               self._autoCommit = val
-               
-       
        def beginTransaction(self, cursor):
                """ Begin a SQL transaction. Since pysqlite does an implicit
-               'begin' even when not using autocommit, simply do nothing.
+               'begin' all the time, simply do nothing.
                """
+               dabo.dbActivityLog.write("SQL: begin (implicit, nothing done)")
                pass
+
+
+       def commitTransaction(self, cursor):
+               """ Commit a SQL transaction."""
+               try:
+                       cursor.execute("COMMIT")
+                       dabo.dbActivityLog.write("SQL: commit")
+               except Exception, e:
+                       if "no transaction is active" in str(e):
+                               pass
+                       else:
+                               dabo.dbActivityLog.write("SQL: commit failed: 
%s" % e)
+                               raise dException.DBQueryException, e            
        
+
+
+       def rollbackTransaction(self, cursor):
+               """ Rollback a SQL transaction."""
+               cursor.execute("ROLLBACK")
+               dabo.dbActivityLog.write("SQL: rollback")
+
        
-       
        def flush(self, crs):
+               dabo.dbActivityLog.write("SQL: flush")
                self._connection.commit()
 
 

Modified: trunk/dabo/db/test/test_dCursorMixin.py
===================================================================
--- trunk/dabo/db/test/test_dCursorMixin.py     2007-08-14 21:57:09 UTC (rev 
3313)
+++ trunk/dabo/db/test/test_dCursorMixin.py     2007-08-19 19:07:48 UTC (rev 
3314)
@@ -45,16 +45,6 @@
                return ""
 
        ## - Begin property unit tests -
-       def test_AutoCommit(self):
-               cur = self.cur
-               self.assertEqual(cur.AutoCommit, False)
-               try:
-                       cur.AutoCommit = True
-                       self.assertEqual(cur.AutoCommit, True)
-               except ValueError:
-                       # Okay; this db didn't allow the setting of AutoCommit.
-                       self.assertEqual(cur.AutoCommit, False)
-
        def test_AutoSQL(self):
                cur = self.cur
                self.assertEqual(cur.AutoSQL, "select *\n  from %s\n limit 
1000" % self.temp_table_name)




_______________________________________________
Post Messages to: [email protected]
Subscription Maintenance: http://leafe.com/mailman/listinfo/dabo-dev
Searchable Archives: http://leafe.com/archives/search/dabo-dev
This message: http://leafe.com/archives/byMID/dabo-dev/[EMAIL PROTECTED]

Reply via email to