Changeset 3314
- Timestamp:
- 08/19/07 12:07:48 (1 year ago)
- Files:
-
- trunk/dabo/biz/dAutoBizobj.py (modified) (5 diffs)
- trunk/dabo/biz/dBizobj.py (modified) (17 diffs)
- trunk/dabo/biz/test/test_dBizobj.py (modified) (1 diff)
- trunk/dabo/dApp.py (modified) (3 diffs)
- trunk/dabo/dPref.py (modified) (6 diffs)
- trunk/dabo/db/dBackend.py (modified) (2 diffs)
- trunk/dabo/db/dCursorMixin.py (modified) (9 diffs)
- trunk/dabo/db/dbFirebird.py (modified) (2 diffs)
- trunk/dabo/db/dbMySQL.py (modified) (2 diffs)
- trunk/dabo/db/dbPostgreSQL.py (modified) (2 diffs)
- trunk/dabo/db/dbSQLite.py (modified) (2 diffs)
- trunk/dabo/db/test/test_dCursorMixin.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/dabo/biz/dAutoBizobj.py
r3303 r3314 44 44 g._toExc = {} 45 45 for biz in g._AutoTables.values(): 46 ac = biz.AutoCommit 47 biz.AutoCommit = True 48 biz.CreateTable() 49 50 biz.AutoCommit = ac 46 biz.createTable() 51 47 52 48 if g._toExc: … … 139 135 except dException.DBNoAccessException: 140 136 dabo.ui.stop(_("Could not access the database with the given username and password.")) 141 _ WriteQueriesToFile(g._toExc)137 _writeQueriesToFile(g._toExc) 142 138 raise dException.DBNoAccessException 143 139 else: … … 150 146 except dException.DBNoAccessExeption: 151 147 dabo.ui.stop(_("Could not setup the database. Access was denied.")) 152 _ WriteQueriesToFile(g._toExc)148 _writeQueriesToFile(g._toExc) 153 149 raise dException.DBNoAccessException 154 150 155 151 else: 156 152 login.release() 157 _ WriteQueriesToFile(g._toExc)153 _writeQueriesToFile(g._toExc) 158 154 raise dException.DBNoAccessException 159 155 160 156 else: 161 _ WriteQueriesToFile(g._toExc)157 _writeQueriesToFile(g._toExc) 162 158 raise dException.DBNoAccessException 163 159 164 160 165 def _ WriteQueriesToFile(queries):161 def _writeQueriesToFile(queries): 166 162 f = open("queries.sql", "w") 167 163 for k in queries.keys(): … … 171 167 172 168 f.close() 169 170 173 171 174 172 class dAutoBizobj(dBizobj): … … 245 243 246 244 247 def CreateTable(self):245 def createTable(self): 248 246 """Create the tables that has been asigned to this bizobj.""" 249 247 if self._table is None: trunk/dabo/biz/dBizobj.py
r3303 r3314 61 61 62 62 # Various attributes used for Properties 63 self._autoCommit = False64 63 self._caption = "" 65 64 self._dataSource = "" … … 167 166 crs.BackendObject = cf.getBackendObject() 168 167 crs.sqlManager = self.SqlManager 169 crs.AutoCommit = self.AutoCommit170 168 crs._bizobj = self 171 169 if self.RequeryOnLoad: … … 263 261 264 262 265 def saveAll(self, startTransaction= False, topLevel=True):263 def saveAll(self, startTransaction=True): 266 264 """Saves all changes to the bizobj and children.""" 267 useTransact = startTransaction or topLevel268 265 cursor = self._CurrentCursor 269 266 current_row = self.RowNumber 270 271 if useTransact: 272 # Tell the cursor to begin a transaction, if needed. 273 cursor.beginTransaction() 267 app = self.Application 268 isTransactionManager = False 269 if startTransaction: 270 isTransactionManager = app.getTransactionToken(self) 271 if isTransactionManager: 272 cursor.beginTransaction() 274 273 275 274 try: 276 275 self.scanChangedRows(self.save, includeNewUnchanged=self.SaveNewUnchanged, 277 startTransaction=False, topLevel=False) 276 startTransaction=False) 277 if isTransactionManager: 278 cursor.commitTransaction() 279 app.releaseTransactionToken(self) 280 278 281 except dException.ConnectionLostException, e: 279 282 self.RowNumber = current_row … … 281 284 except dException.DBQueryException, e: 282 285 # Something failed; reset things. 283 if useTransact:286 if isTransactionManager: 284 287 cursor.rollbackTransaction() 288 app.releaseTransactionToken(self) 285 289 # Pass the exception to the UI 286 290 self.RowNumber = current_row 287 291 raise dException.DBQueryException, e 288 292 except dException.dException, e: 289 if useTransact:293 if isTransactionManager: 290 294 cursor.rollbackTransaction() 295 app.releaseTransactionToken(self) 291 296 self.RowNumber = current_row 292 297 raise 293 294 if useTransact:295 cursor.commitTransaction()296 298 297 299 if current_row >= 0: … … 301 303 302 304 303 def save(self, startTransaction= False, topLevel=True):305 def save(self, startTransaction=True): 304 306 """Save any changes that have been made in the current row. 305 307 … … 319 321 self._validate() 320 322 321 useTransact = startTransaction or topLevel 322 if useTransact: 323 # Tell the cursor to begin a transaction, if needed. 324 cursor.beginTransaction() 323 app = self.Application 324 isTransactionManager = False 325 if startTransaction: 326 isTransactionManager = app.getTransactionToken(self) 327 if isTransactionManager: 328 cursor.beginTransaction() 325 329 326 330 # Save to the Database, but first save the IsAdding flag as the save() call … … 338 342 # we need to save all rows that have changed. 339 343 if child.RowCount > 0: 340 child.saveAll(startTransaction=False , topLevel=False)344 child.saveAll(startTransaction=False) 341 345 342 346 # Finish the transaction, and requery the children if needed. 343 if useTransact:347 if isTransactionManager: 344 348 cursor.commitTransaction() 349 app.releaseTransactionToken(self) 345 350 if self.RequeryChildOnSave: 346 351 self.requeryAllChildren() … … 354 359 except dException.DBQueryException, e: 355 360 # Something failed; reset things. 356 if useTransact:361 if isTransactionManager: 357 362 cursor.rollbackTransaction() 363 app.releaseTransactionToken(self) 358 364 # Pass the exception to the UI 359 365 raise dException.DBQueryException, e … … 361 367 except dException.dException, e: 362 368 # Something failed; reset things. 363 if useTransact:369 if isTransactionManager: 364 370 cursor.rollbackTransaction() 371 app.releaseTransactionToken(self) 365 372 # Pass the exception to the UI 366 373 raise 367 368 # Some backends (Firebird particularly) need to be told to write369 # their changes even if no explicit transaction was started.370 cursor.flush()371 374 372 375 # Two hook methods: one specific to Save(), and one which is called after any change … … 405 408 406 409 407 def deleteAllChildren(self, startTransaction= False):410 def deleteAllChildren(self, startTransaction=True): 408 411 """Delete all children associated with the current record without 409 412 deleting the current record in this bizobj. 410 413 """ 411 414 cursor = self._CurrentCursor 415 app = self.Application 412 416 errMsg = self.beforeDeleteAllChildren() 413 417 if errMsg: 414 418 raise dException.BusinessRuleViolation, errMsg 415 419 420 isTransactionManager = False 416 421 if startTransaction: 417 cursor.beginTransaction() 422 isTransactionManager = app.getTransactionToken(self) 423 if isTransactionManager: 424 cursor.beginTransaction() 418 425 419 426 try: 420 427 for child in self.__children: 421 428 child.deleteAll(startTransaction=False) 422 if startTransaction:429 if isTransactionManager: 423 430 cursor.commitTransaction() 424 self.afterDeleteAllChildren()431 app.releaseTransactionToken(self) 425 432 426 433 except dException.DBQueryException, e: 427 if startTransaction:434 if isTransactionManager: 428 435 cursor.rollbackTransaction() 436 app.releaseTransactionToken(self) 429 437 raise dException.DBQueryException, e 430 438 except StandardError, e: 431 if startTransaction:439 if isTransactionManager: 432 440 cursor.rollbackTransaction() 441 app.releaseTransactionToken(self) 433 442 raise StandardError, e 434 435 436 def delete(self, startTransaction=False): 443 self.afterDeleteAllChildren() 444 445 446 def delete(self, startTransaction=True, inLoop=False): 437 447 """Delete the current row of the data set.""" 448 app = self.Application 438 449 cursor = self._CurrentCursor 439 450 errMsg = self.beforeDelete() … … 452 463 raise dException.dException, _("Deletion prohibited - there are related child records.") 453 464 465 isTransactionManager = False 454 466 if startTransaction: 455 cursor.beginTransaction() 467 isTransactionManager = app.getTransactionToken(self) 468 if isTransactionManager: 469 cursor.beginTransaction() 456 470 457 471 try: … … 470 484 child.requery() 471 485 472 if startTransaction:486 if isTransactionManager: 473 487 cursor.commitTransaction() 474 475 # Some backends (Firebird particularly) need to be told to write 476 # their changes even if no explicit transaction was started. 477 cursor.flush() 488 app.releaseTransactionToken(self) 489 490 if not inLoop: 491 self.afterPointerMove() 492 self.afterChange() 493 self.afterDelete() 494 except dException.DBQueryException, e: 495 if isTransactionManager: 496 cursor.rollbackTransaction() 497 app.releaseTransactionToken(self) 498 raise dException.DBQueryException, e 499 except StandardError, e: 500 if isTransactionManager: 501 cursor.rollbackTransaction() 502 app.releaseTransactionToken(self) 503 raise StandardError, e 504 505 506 def deleteAll(self, startTransaction=True): 507 """ Delete all rows in the data set.""" 508 isTransactionManager = False 509 if startTransaction: 510 isTransactionManager = app.getTransactionToken(self) 511 if isTransactionManager: 512 cursor.beginTransaction() 513 try: 514 while self.RowCount > 0: 515 self.first() 516 ret = self.delete(startTransaction=False, inLoop=True) 517 if isTransactionManager: 518 cursor.commitTransaction() 519 app.releaseTransactionToken(self) 478 520 479 521 self.afterPointerMove() … … 481 523 self.afterDelete() 482 524 except dException.DBQueryException, e: 483 if startTransaction:525 if isTransactionManager: 484 526 cursor.rollbackTransaction() 527 app.releaseTransactionToken(self) 485 528 raise dException.DBQueryException, e 486 529 except StandardError, e: 487 if startTransaction:530 if isTransactionManager: 488 531 cursor.rollbackTransaction() 532 app.releaseTransactionToken(self) 489 533 raise StandardError, e 490 491 492 def deleteAll(self, startTransaction=False):493 """ Delete all rows in the data set."""494 while self.RowCount > 0:495 self.first()496 ret = self.delete(startTransaction)497 534 498 535 … … 759 796 760 797 except dException.DBQueryException, e: 761 # Something failed; reset things.762 cursor.rollbackTransaction()763 798 # Pass the exception to the UI 764 799 raise dException.DBQueryException, e 765 800 766 801 except dException.NoRecordsException: 767 # No need to abort the transaction because of this, but 768 # we still need to pass the exception to the UI 802 # Pass the exception to the UI 769 803 uiException = dException.NoRecordsException 770 804 771 805 except dException.dException, e: 772 # Something failed; reset things.773 cursor.rollbackTransaction()774 806 # Pass the exception to the UI 775 807 raise dException.dException, e … … 1468 1500 """ 1469 1501 for crs in self.__cursors.values(): 1470 crs.AutoCommit = self._autoCommit1471 1502 crs.AutoPopulatePK = self._autoPopulatePK 1472 1503 crs.AutoQuoteNames = self._autoQuoteNames … … 1478 1509 1479 1510 1480 def _getAutoCommit(self): 1481 return self._CurrentCursor.AutoCommit 1482 1483 def _setAutoCommit(self, val): 1484 self._autoCommit = val 1485 self._syncWithCursors() 1486 1487 1511 ## Property getter/setter methods ## 1488 1512 def _getAutoPopulatePK(self): 1489 1513 try: … … 1842 1866 1843 1867 ### -------------- Property Definitions ------------------ ## 1844 AutoCommit = property(_getAutoCommit, _setAutoCommit, None,1845 _("Do we need explicit begin/commit/rollback commands for transactions? (bool)"))1846 1847 1868 AutoPopulatePK = property(_getAutoPopulatePK, _setAutoPopulatePK, None, 1848 1869 _("Determines if we are using a table that auto-generates its PKs. (bool)")) trunk/dabo/biz/test/test_dBizobj.py
r3271 r3314 45 45 46 46 ## - Begin property unit tests - 47 def test_AutoCommit(self):48 biz = self.biz49 self.assertEqual(biz.AutoCommit, False)50 biz.AutoCommit = True51 self.assertEqual(biz.AutoCommit, True)52 53 47 def test_AutoSQL(self): 54 48 biz = self.biz trunk/dabo/dApp.py
r3303 r3314 187 187 # Create the framework-level preference manager 188 188 self._frameworkPrefs = dabo.dPref(key="dabo_framework") 189 # Hold a reference to the bizobj, if any, controlling the current 190 # database transaction 191 self._transactionBizobj = None 189 192 190 193 # List of form classes to open on App Startup … … 398 401 vers = -1 399 402 localVers = self._currentUpdateVersion() 400 ret = localVers < vers403 ret = (localVers != vers) 401 404 prf.setValue("last_check", now) 402 405 return ret … … 707 710 self.dbConnectionDefs[k] = ci 708 711 self.dbConnectionNameToFiles[k] = connFile 712 713 714 def getTransactionToken(self, biz): 715 """Only one bizobj at a time can begin and end transactions. This allows the bizobj 716 to query the app for the 'token', which is simply an acknowledgement that there 717 is no other transaction pending. If the bizobj gets the token, further requests for the 718 token will receive a reply of False, meaning that they should not be handling the transaction. 719 """ 720 print "TOKEN REQUEST", biz 721 if self._transactionBizobj is None: 722 print "TOKEN SET TO ", biz 723 self._transactionBizobj = biz 724 return True 725 else: 726 print "TOKEN DENIED; holder=", self._transactionBizobj 727 return False 728 729 730 def releaseTransactionToken(self, biz): 731 """When a process that would normally close a transaction happens, the bizobj that is 732 holding the transaction token calls this message to return the token. A check is run to 733 ensure that the releasing bizobj is the one currently holding the token; if it is, the 734 internal attribute is reset. 735 """ 736 print "APP RELEASE TOKEN FROM:", biz, 737 if biz is self._transactionBizobj: 738 self._transactionBizobj = None 739 print "RELEASED", 740 print "" 709 741 710 742 trunk/dabo/dPref.py
r3303 r3314 73 73 if not "daboprefs" in self._cursor.getTables(): 74 74 self._cursor.execute("create table daboprefs (ckey text not null, ctype text not null, cvalue text not null)") 75 self._cursor.commitTransaction() 75 76 else: 76 77 self._cursor = crs 77 78 self._cxn = cxn 78 if self._cursor:79 self._cursor.AutoCommit = True80 79 81 80 … … 221 220 prm = (key, typ, val) 222 221 crs.execute(sql, prm) 222 self._cursor.commitTransaction() 223 223 224 224 … … 235 235 self._cursor.execute("delete from daboprefs where ckey like ? ", (key, )) 236 236 self._deletionCache = {} 237 self._cursor.commitTransaction() 237 238 238 239 … … 261 262 if self._cache.has_key(att): 262 263 del self._cache[att] 263 264 self._cursor.commitTransaction() 265 264 266 265 267 def deleteAllPrefs(self): … … 282 284 self._cache = {} 283 285 self._deletionCache[key] = None 284 286 self._cursor.commitTransaction() 287 285 288 286 289 def flushCache(self): … … 377 380 prm = (key, newTyp, val) 378 381 self._cursor.execute(sql, prm) 382 self._cursor.commitTransaction() 379 383 380 384 trunk/dabo/db/dBackend.py
r3303 r3314 26 26 def __init__(self): 27 27 self._baseClass = dBackend 28 self._autoCommit = False29 # This forces the setting on the connection30 self.AutoCommit = False31 28 super(dBackend, self).__init__() 32 29 self.dbModuleName = None … … 197 194 198 195 199 def getAutoCommitStatus(self, cursor):200 return self._autoCommit201 202 203 def setAutoCommitStatus(self, cursor, val):204 if hasattr(self._connection, "autocommit"):205 self._connection.autocommit(val)206 self._autoCommit = val207 else:208 # Without an autocommit method, assume no autocommit.209 self._autoCommit = False210 if val:211 raise ValueError, "Can't set AutoCommit to True for this backend."212 213 214 196 def beginTransaction(self, cursor): 215 197 """ Begin a SQL transaction. Override in subclasses if needed.""" 216 pass 198 self._connection.begin() 199 dabo.dbActivityLog.write("SQL: begin") 217 200 218 201 219 202 def commitTransaction(self, cursor): 220 203 """ Commit a SQL transaction.""" 221 if not cursor.AutoCommit: 222 self._connection.commit() 223 dabo.dbActivityLog.write("SQL: commit") 204 self._connection.commit() 205 dabo.dbActivityLog.write("SQL: commit") 224 206 225 207 trunk/dabo/db/dCursorMixin.py
r3303 r3314 353 353 return 354 354 ac = self.AuxCursor 355 ac.AutoCommit = self.AutoCommit356 355 ac.AutoPopulatePK = self.AutoPopulatePK 357 356 ac.AutoQuoteNames = self.AutoQuoteNames … … 1057 1056 1058 1057 1059 def save(self, allRows=False , useTransaction=False):1058 def save(self, allRows=False): 1060 1059 """ Save any changes to the data back to the data store.""" 1061 1060 # Make sure that there is data to save … … 1069 1068 self.__saverow(row) 1070 1069 except dException.DBQueryException, e: 1071 # Error was raised. Exit and rollback the changes if1072 # this object started the transaction.1070 # Error was encountered. Raise an exception so that the 1071 # calling bizobj can rollback the transaction if necessary 1073 1072 dabo.dbActivityLog.write(_("DBQueryException encountered in save(): %s") % e) 1074 if useTransaction:1075 self.rollbackTransaction()1076 1073 raise dException.DBQueryException, e 1077 1074 except StandardError, e: … … 1080 1077 raise dException.ConnectionLostException, e 1081 1078 else: 1082 # Error was raised. Exit and rollback the changes if 1083 # this object started the transaction. 1084 if useTransaction: 1085 self.rollbackTransaction() 1079 # Error was encountered. Raise an exception so that the 1080 # calling bizobj can rollback the transaction if necessary 1086 1081 raise 1087 1082 1088 1083 self._syncAuxProperties() 1089 if useTransaction:1090 self.beginTransaction()1091 1084 1092 1085 # Faster to deal with 2 specific cases: all rows or just current row … … 1100 1093 if pk in self._mementos.keys(): 1101 1094 saverow(self.RowNumber) 1102 1103 if useTransaction:1104 self.commitTransaction()1105 1095 1106 1096 … … 1727 1717 ret = None 1728 1718 if self.BackendObject: 1729 if not self.AutoCommit: 1730 ret = self.BackendObject.beginTransaction(self.AuxCursor) 1719 ret = self.BackendObject.beginTransaction(self.AuxCursor) 1731 1720 return ret 1732 1721 … … 1736 1725 ret = None 1737 1726 if self.BackendObject: 1738 if not self.AutoCommit: 1739 ret = self.BackendObject.commitTransaction(self.AuxCursor) 1727 ret = self.BackendObject.commitTransaction(self.AuxCursor) 1740 1728 return ret 1741 1729 … … 2015 2003 2016 2004 ## Property getter/setter methods ## 2017 def _getAutoCommit(self):2018 return self.BackendObject.getAutoCommitStatus(self)2019 2020 2021 def _setAutoCommit(self, val):2022 self.BackendObject.setAutoCommitStatus(self, val)2023 2024 2025 2005 def _getAutoSQL(self): 2026 2006 return self.getSQL() … … 2253 2233 2254 2234 2255 AutoCommit = property(_getAutoCommit, _setAutoCommit, None,2256 _("Do we need explicit begin/commit/rollback commands for transactions? (bool)"))2257 2258 2235 AutoPopulatePK = property(_getAutoPopulatePK, _setAutoPopulatePK, None, 2259 2236 _("When inserting a new record, does the backend populate the PK field?")) trunk/dabo/db/dbFirebird.py
r3303 r3314 194 194 def beginTransaction(self, cursor): 195 195 """ Begin a SQL transaction.""" 196 if not cursor.connection._has_transaction():197 cursor.connection.begin()196 if not self._connection._has_transaction(): 197 self._connection.begin() 198 198 dabo.dbActivityLog.write("SQL: begin") 199 199 … … 203 203 to the database written to disk. 204 204 """ 205 cursor.connection.commit()205 self._connection.commit() 206 206 dabo.dbActivityLog.write("SQL: commit") 207 207 trunk/dabo/db/dbMySQL.py
r3303 r3314 5 5 except ImportError: 6 6 decimal = None 7 import dabo 7 8 from dabo.dLocalize import _ 8 9 from dBackend import dBackend … … 59 60 import MySQLdb.cursors as cursors 60 61 return cursors.DictCursor 62 63 64 def beginTransaction(self, cursor): 65 """ Begin a SQL transaction.""" 66 cursor.execute("START TRANSACTION") 67 dabo.dbActivityLog.write("SQL: begin") 68 69 70 def commitTransaction(self, cursor): 71 """ Commit a SQL transaction.""" 72 cursor.execute("COMMIT") 73 dabo.dbActivityLog.write("SQL: commit") 74 75 76 def rollbackTransaction(self, cursor): 77 """ Rollback a SQL transaction.""" 78 cursor.execute("ROLLBACK") 79 dabo.dbActivityLog.write("SQL: rollback") 61 80 62 81 trunk/dabo/db/dbPostgreSQL.py
r3303 r3314 14 14 #self.dbModuleName = "PgSQL" 15 15 self.dbModuleName = "psycopg" 16 self.useTransactions = True # this does not appear to be required17 16 self.conn_user = '' 18 17 … … 223 222 """ 224 223 self.commitTransaction(cursor) 225 224 225 226 226 def getLastInsertID(self, cursor): 227 227 """ Return the ID of the last inserted row, or None. trunk/dabo/db/dbSQLite.py
r3303 r3314 3 3 import os 4 4 import re 5 import dabo 5 6 from dabo.dLocalize import _ 7 from dabo.dException import dException 6 8 from dBackend import dBackend 7 9 from dNoEscQuoteStr import dNoEscQuoteStr as dNoEQ … … 70 72 71 73 72 def setAutoCommitStatus(self, cursor, val):73 """SQLite doesn't use an 'autocommit()' method. Instead,74 set the isolation_level property of the connection.75 """76 if val:77 self._connection.isolation_level = None78 else:79 self._connection.isolation_level = ""80 self._autoCommit = val81 82 83 74 def beginTransaction(self, cursor): 84 75 """ Begin a SQL transaction. Since pysqlite does an implicit 85 'begin' even when not using autocommit, simply do nothing.76 'begin' all the time, simply do nothing. 86 77 """ 78 dabo.dbActivityLog.write("SQL: begin (implicit, nothing done)") 87 79 pass 88 80 81 82 def commitTransaction(self, cursor): 83 """ Commit a SQL transaction.""" 84 try: 85 cursor.execute("COMMIT") 86 dabo.dbActivityLog.write("SQL: commit") 87 except Exception, e: 88 if "no transaction is active" in str(e): 89 pass 90 else: 91 dabo.dbActivityLog.write("SQL: commit failed: %s" % e) 92 raise dException.DBQueryException, e 93 94 95 def rollbackTransaction(self, cursor): 96 """ Rollback a SQL transaction.""" 97 cursor.execute("ROLLBACK") 98 dabo.dbActivityLog.write("SQL: rollback") 99 89 100 90 101 def flush(self, crs): 102 dabo.dbActivityLog.write("SQL: flush") 91 103 self._connection.commit() 92 104 trunk/dabo/db/test/test_dCursorMixin.py
r3054 r3314 46 46 47 47 ## - Begin property unit tests - 48 def test_AutoCommit(self):49 cur = self.cur50 self.assertEqual(cur.AutoCommit, False)51 try:52 cur.AutoCommit = True53 self.assertEqual(cur.AutoCommit, True)54 except ValueError:55 # Okay; this db didn't allow the setting of AutoCommit.56 self.assertEqual(cur.AutoCommit, False)57 58 48 def test_AutoSQL(self): 59 49 cur = self.cur
