1 /* 2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "config.h" 30 #include "SQLTransaction.h" 31 32 #if ENABLE(DATABASE) 33 34 #include "Database.h" 35 #include "DatabaseAuthorizer.h" 36 #include "DatabaseThread.h" 37 #include "Logging.h" 38 #include "PlatformString.h" 39 #include "ScriptExecutionContext.h" 40 #include "SQLError.h" 41 #include "SQLiteTransaction.h" 42 #include "SQLStatement.h" 43 #include "SQLStatementCallback.h" 44 #include "SQLStatementErrorCallback.h" 45 #include "SQLTransactionCallback.h" 46 #include "SQLTransactionClient.h" 47 #include "SQLTransactionCoordinator.h" 48 #include "SQLTransactionErrorCallback.h" 49 #include "SQLValue.h" 50 #include "VoidCallback.h" 51 #include <wtf/OwnPtr.h> 52 #include <wtf/PassRefPtr.h> 53 #include <wtf/RefPtr.h> 54 55 // There's no way of knowing exactly how much more space will be required when a statement hits the quota limit. 56 // For now, we'll arbitrarily choose currentQuota + 1mb. 57 // In the future we decide to track if a size increase wasn't enough, and ask for larger-and-larger increases until its enough. 58 static const int DefaultQuotaSizeIncrease = 1048576; 59 60 namespace WebCore { 61 62 PassRefPtr<SQLTransaction> SQLTransaction::create(Database* db, PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, 63 PassRefPtr<VoidCallback> successCallback, PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly) 64 { 65 return adoptRef(new SQLTransaction(db, callback, errorCallback, successCallback, wrapper, readOnly)); 66 } 67 68 SQLTransaction::SQLTransaction(Database* db, PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, 69 PassRefPtr<VoidCallback> successCallback, PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly) 70 : m_nextStep(&SQLTransaction::acquireLock) 71 , m_executeSqlAllowed(false) 72 , m_database(db) 73 , m_wrapper(wrapper) 74 , m_callbackWrapper(callback, db->scriptExecutionContext()) 75 , m_successCallbackWrapper(successCallback, db->scriptExecutionContext()) 76 , m_errorCallbackWrapper(errorCallback, db->scriptExecutionContext()) 77 , m_shouldRetryCurrentStatement(false) 78 , m_modifiedDatabase(false) 79 , m_lockAcquired(false) 80 , m_readOnly(readOnly) 81 { 82 ASSERT(m_database); 83 } 84 85 SQLTransaction::~SQLTransaction() 86 { 87 ASSERT(!m_sqliteTransaction); 88 } 89 90 void SQLTransaction::executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> callbackError, ExceptionCode& e) 91 { 92 if (!m_executeSqlAllowed || !m_database->opened()) { 93 e = INVALID_STATE_ERR; 94 return; 95 } 96 97 int permissions = DatabaseAuthorizer::ReadWriteMask; 98 if (!m_database->scriptExecutionContext()->allowDatabaseAccess()) 99 permissions |= DatabaseAuthorizer::NoAccessMask; 100 else if (m_readOnly) 101 permissions |= DatabaseAuthorizer::ReadOnlyMask; 102 103 RefPtr<SQLStatement> statement = SQLStatement::create(m_database.get(), sqlStatement, arguments, callback, callbackError, permissions); 104 105 if (m_database->deleted()) 106 statement->setDatabaseDeletedError(); 107 108 if (!m_database->versionMatchesExpected()) 109 statement->setVersionMismatchedError(); 110 111 enqueueStatement(statement); 112 } 113 114 void SQLTransaction::enqueueStatement(PassRefPtr<SQLStatement> statement) 115 { 116 MutexLocker locker(m_statementMutex); 117 m_statementQueue.append(statement); 118 } 119 120 #if !LOG_DISABLED 121 const char* SQLTransaction::debugStepName(SQLTransaction::TransactionStepMethod step) 122 { 123 if (step == &SQLTransaction::acquireLock) 124 return "acquireLock"; 125 else if (step == &SQLTransaction::openTransactionAndPreflight) 126 return "openTransactionAndPreflight"; 127 else if (step == &SQLTransaction::runStatements) 128 return "runStatements"; 129 else if (step == &SQLTransaction::postflightAndCommit) 130 return "postflightAndCommit"; 131 else if (step == &SQLTransaction::cleanupAfterTransactionErrorCallback) 132 return "cleanupAfterTransactionErrorCallback"; 133 else if (step == &SQLTransaction::deliverTransactionCallback) 134 return "deliverTransactionCallback"; 135 else if (step == &SQLTransaction::deliverTransactionErrorCallback) 136 return "deliverTransactionErrorCallback"; 137 else if (step == &SQLTransaction::deliverStatementCallback) 138 return "deliverStatementCallback"; 139 else if (step == &SQLTransaction::deliverQuotaIncreaseCallback) 140 return "deliverQuotaIncreaseCallback"; 141 else if (step == &SQLTransaction::deliverSuccessCallback) 142 return "deliverSuccessCallback"; 143 else if (step == &SQLTransaction::cleanupAfterSuccessCallback) 144 return "cleanupAfterSuccessCallback"; 145 else 146 return "UNKNOWN"; 147 } 148 #endif 149 150 void SQLTransaction::checkAndHandleClosedOrInterruptedDatabase() 151 { 152 if (m_database->opened() && !m_database->isInterrupted()) 153 return; 154 155 // If the database was stopped, don't do anything and cancel queued work 156 LOG(StorageAPI, "Database was stopped or interrupted - cancelling work for this transaction"); 157 MutexLocker locker(m_statementMutex); 158 m_statementQueue.clear(); 159 m_nextStep = 0; 160 161 // Release the unneeded callbacks, to break reference cycles. 162 m_callbackWrapper.clear(); 163 m_successCallbackWrapper.clear(); 164 m_errorCallbackWrapper.clear(); 165 166 // The next steps should be executed only if we're on the DB thread. 167 if (currentThread() != database()->scriptExecutionContext()->databaseThread()->getThreadID()) 168 return; 169 170 // The current SQLite transaction should be stopped, as well 171 if (m_sqliteTransaction) { 172 m_sqliteTransaction->stop(); 173 m_sqliteTransaction.clear(); 174 } 175 176 if (m_lockAcquired) 177 m_database->transactionCoordinator()->releaseLock(this); 178 } 179 180 181 bool SQLTransaction::performNextStep() 182 { 183 LOG(StorageAPI, "Step %s\n", debugStepName(m_nextStep)); 184 185 ASSERT(m_nextStep == &SQLTransaction::acquireLock || 186 m_nextStep == &SQLTransaction::openTransactionAndPreflight || 187 m_nextStep == &SQLTransaction::runStatements || 188 m_nextStep == &SQLTransaction::postflightAndCommit || 189 m_nextStep == &SQLTransaction::cleanupAfterSuccessCallback || 190 m_nextStep == &SQLTransaction::cleanupAfterTransactionErrorCallback); 191 192 checkAndHandleClosedOrInterruptedDatabase(); 193 194 if (m_nextStep) 195 (this->*m_nextStep)(); 196 197 // If there is no nextStep after performing the above step, the transaction is complete 198 return !m_nextStep; 199 } 200 201 void SQLTransaction::performPendingCallback() 202 { 203 LOG(StorageAPI, "Callback %s\n", debugStepName(m_nextStep)); 204 205 ASSERT(m_nextStep == &SQLTransaction::deliverTransactionCallback || 206 m_nextStep == &SQLTransaction::deliverTransactionErrorCallback || 207 m_nextStep == &SQLTransaction::deliverStatementCallback || 208 m_nextStep == &SQLTransaction::deliverQuotaIncreaseCallback || 209 m_nextStep == &SQLTransaction::deliverSuccessCallback); 210 211 checkAndHandleClosedOrInterruptedDatabase(); 212 213 if (m_nextStep) 214 (this->*m_nextStep)(); 215 } 216 217 void SQLTransaction::notifyDatabaseThreadIsShuttingDown() 218 { 219 ASSERT(currentThread() == database()->scriptExecutionContext()->databaseThread()->getThreadID()); 220 221 // If the transaction is in progress, we should roll it back here, since this is our last 222 // oportunity to do something related to this transaction on the DB thread. 223 // Clearing m_sqliteTransaction invokes SQLiteTransaction's destructor which does just that. 224 m_sqliteTransaction.clear(); 225 } 226 227 void SQLTransaction::acquireLock() 228 { 229 m_database->transactionCoordinator()->acquireLock(this); 230 } 231 232 void SQLTransaction::lockAcquired() 233 { 234 m_lockAcquired = true; 235 m_nextStep = &SQLTransaction::openTransactionAndPreflight; 236 LOG(StorageAPI, "Scheduling openTransactionAndPreflight immediately for transaction %p\n", this); 237 m_database->scheduleTransactionStep(this, true); 238 } 239 240 void SQLTransaction::openTransactionAndPreflight() 241 { 242 ASSERT(!m_database->sqliteDatabase().transactionInProgress()); 243 ASSERT(m_lockAcquired); 244 245 LOG(StorageAPI, "Opening and preflighting transaction %p", this); 246 247 // If the database was deleted, jump to the error callback 248 if (m_database->deleted()) { 249 m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unable to open a transaction, because the user deleted the database"); 250 handleTransactionError(false); 251 return; 252 } 253 254 // Set the maximum usage for this transaction if this transactions is not read-only 255 if (!m_readOnly) 256 m_database->sqliteDatabase().setMaximumSize(m_database->maximumSize()); 257 258 ASSERT(!m_sqliteTransaction); 259 m_sqliteTransaction = adoptPtr(new SQLiteTransaction(m_database->sqliteDatabase(), m_readOnly)); 260 261 m_database->resetDeletes(); 262 m_database->disableAuthorizer(); 263 m_sqliteTransaction->begin(); 264 m_database->enableAuthorizer(); 265 266 // Transaction Steps 1+2 - Open a transaction to the database, jumping to the error callback if that fails 267 if (!m_sqliteTransaction->inProgress()) { 268 ASSERT(!m_database->sqliteDatabase().transactionInProgress()); 269 m_sqliteTransaction.clear(); 270 m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "unable to open a transaction to the database"); 271 handleTransactionError(false); 272 return; 273 } 274 275 // Transaction Steps 3 - Peform preflight steps, jumping to the error callback if they fail 276 if (m_wrapper && !m_wrapper->performPreflight(this)) { 277 m_sqliteTransaction.clear(); 278 m_transactionError = m_wrapper->sqlError(); 279 if (!m_transactionError) 280 m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unknown error occured setting up transaction"); 281 282 handleTransactionError(false); 283 return; 284 } 285 286 // Transaction Step 4 - Invoke the transaction callback with the new SQLTransaction object 287 m_nextStep = &SQLTransaction::deliverTransactionCallback; 288 LOG(StorageAPI, "Scheduling deliverTransactionCallback for transaction %p\n", this); 289 m_database->scheduleTransactionCallback(this); 290 } 291 292 void SQLTransaction::deliverTransactionCallback() 293 { 294 bool shouldDeliverErrorCallback = false; 295 296 RefPtr<SQLTransactionCallback> callback = m_callbackWrapper.unwrap(); 297 if (callback) { 298 m_executeSqlAllowed = true; 299 shouldDeliverErrorCallback = !callback->handleEvent(this); 300 m_executeSqlAllowed = false; 301 } 302 303 // Transaction Step 5 - If the transaction callback was null or raised an exception, jump to the error callback 304 if (shouldDeliverErrorCallback) { 305 m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the SQLTransactionCallback was null or threw an exception"); 306 deliverTransactionErrorCallback(); 307 } else 308 scheduleToRunStatements(); 309 } 310 311 void SQLTransaction::scheduleToRunStatements() 312 { 313 m_nextStep = &SQLTransaction::runStatements; 314 LOG(StorageAPI, "Scheduling runStatements for transaction %p\n", this); 315 m_database->scheduleTransactionStep(this); 316 } 317 318 void SQLTransaction::runStatements() 319 { 320 ASSERT(m_lockAcquired); 321 322 // If there is a series of statements queued up that are all successful and have no associated 323 // SQLStatementCallback objects, then we can burn through the queue 324 do { 325 if (m_shouldRetryCurrentStatement && !m_sqliteTransaction->wasRolledBackBySqlite()) { 326 m_shouldRetryCurrentStatement = false; 327 // FIXME - Another place that needs fixing up after <rdar://problem/5628468> is addressed. 328 // See ::openTransactionAndPreflight() for discussion 329 330 // Reset the maximum size here, as it was increased to allow us to retry this statement. 331 // m_shouldRetryCurrentStatement is set to true only when a statement exceeds 332 // the quota, which can happen only in a read-write transaction. Therefore, there 333 // is no need to check here if the transaction is read-write. 334 m_database->sqliteDatabase().setMaximumSize(m_database->maximumSize()); 335 } else { 336 // If the current statement has already been run, failed due to quota constraints, and we're not retrying it, 337 // that means it ended in an error. Handle it now 338 if (m_currentStatement && m_currentStatement->lastExecutionFailedDueToQuota()) { 339 handleCurrentStatementError(); 340 break; 341 } 342 343 // Otherwise, advance to the next statement 344 getNextStatement(); 345 } 346 } while (runCurrentStatement()); 347 348 // If runCurrentStatement() returned false, that means either there was no current statement to run, 349 // or the current statement requires a callback to complete. In the later case, it also scheduled 350 // the callback or performed any other additional work so we can return 351 if (!m_currentStatement) 352 postflightAndCommit(); 353 } 354 355 void SQLTransaction::getNextStatement() 356 { 357 m_currentStatement = 0; 358 359 MutexLocker locker(m_statementMutex); 360 if (!m_statementQueue.isEmpty()) { 361 m_currentStatement = m_statementQueue.takeFirst(); 362 } 363 } 364 365 bool SQLTransaction::runCurrentStatement() 366 { 367 if (!m_currentStatement) 368 return false; 369 370 m_database->resetAuthorizer(); 371 372 if (m_currentStatement->execute(m_database.get())) { 373 if (m_database->lastActionChangedDatabase()) { 374 // Flag this transaction as having changed the database for later delegate notification 375 m_modifiedDatabase = true; 376 // Also dirty the size of this database file for calculating quota usage 377 m_database->transactionClient()->didExecuteStatement(database()); 378 } 379 380 if (m_currentStatement->hasStatementCallback()) { 381 m_nextStep = &SQLTransaction::deliverStatementCallback; 382 LOG(StorageAPI, "Scheduling deliverStatementCallback for transaction %p\n", this); 383 m_database->scheduleTransactionCallback(this); 384 return false; 385 } 386 return true; 387 } 388 389 if (m_currentStatement->lastExecutionFailedDueToQuota()) { 390 m_nextStep = &SQLTransaction::deliverQuotaIncreaseCallback; 391 LOG(StorageAPI, "Scheduling deliverQuotaIncreaseCallback for transaction %p\n", this); 392 m_database->scheduleTransactionCallback(this); 393 return false; 394 } 395 396 handleCurrentStatementError(); 397 398 return false; 399 } 400 401 void SQLTransaction::handleCurrentStatementError() 402 { 403 // Transaction Steps 6.error - Call the statement's error callback, but if there was no error callback, 404 // or the transaction was rolled back, jump to the transaction error callback 405 if (m_currentStatement->hasStatementErrorCallback() && !m_sqliteTransaction->wasRolledBackBySqlite()) { 406 m_nextStep = &SQLTransaction::deliverStatementCallback; 407 LOG(StorageAPI, "Scheduling deliverStatementCallback for transaction %p\n", this); 408 m_database->scheduleTransactionCallback(this); 409 } else { 410 m_transactionError = m_currentStatement->sqlError(); 411 if (!m_transactionError) 412 m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "the statement failed to execute"); 413 handleTransactionError(false); 414 } 415 } 416 417 void SQLTransaction::deliverStatementCallback() 418 { 419 ASSERT(m_currentStatement); 420 421 // Transaction Step 6.6 and 6.3(error) - If the statement callback went wrong, jump to the transaction error callback 422 // Otherwise, continue to loop through the statement queue 423 m_executeSqlAllowed = true; 424 bool result = m_currentStatement->performCallback(this); 425 m_executeSqlAllowed = false; 426 427 if (result) { 428 m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the statement callback raised an exception or statement error callback did not return false"); 429 handleTransactionError(true); 430 } else 431 scheduleToRunStatements(); 432 } 433 434 void SQLTransaction::deliverQuotaIncreaseCallback() 435 { 436 ASSERT(m_currentStatement); 437 ASSERT(!m_shouldRetryCurrentStatement); 438 439 m_shouldRetryCurrentStatement = m_database->transactionClient()->didExceedQuota(database()); 440 441 m_nextStep = &SQLTransaction::runStatements; 442 LOG(StorageAPI, "Scheduling runStatements for transaction %p\n", this); 443 m_database->scheduleTransactionStep(this); 444 } 445 446 void SQLTransaction::postflightAndCommit() 447 { 448 ASSERT(m_lockAcquired); 449 450 // Transaction Step 7 - Peform postflight steps, jumping to the error callback if they fail 451 if (m_wrapper && !m_wrapper->performPostflight(this)) { 452 m_transactionError = m_wrapper->sqlError(); 453 if (!m_transactionError) 454 m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unknown error occured setting up transaction"); 455 handleTransactionError(false); 456 return; 457 } 458 459 // Transacton Step 8+9 - Commit the transaction, jumping to the error callback if that fails 460 ASSERT(m_sqliteTransaction); 461 462 m_database->disableAuthorizer(); 463 m_sqliteTransaction->commit(); 464 m_database->enableAuthorizer(); 465 466 // If the commit failed, the transaction will still be marked as "in progress" 467 if (m_sqliteTransaction->inProgress()) { 468 m_successCallbackWrapper.clear(); 469 m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "failed to commit the transaction"); 470 handleTransactionError(false); 471 return; 472 } 473 474 // Vacuum the database if anything was deleted. 475 if (m_database->hadDeletes()) 476 m_database->incrementalVacuumIfNeeded(); 477 478 // The commit was successful. If the transaction modified this database, notify the delegates. 479 if (m_modifiedDatabase) 480 m_database->transactionClient()->didCommitWriteTransaction(database()); 481 482 // Now release our unneeded callbacks, to break reference cycles. 483 m_errorCallbackWrapper.clear(); 484 485 // Transaction Step 10 - Deliver success callback, if there is one 486 if (m_successCallbackWrapper.hasCallback()) { 487 m_nextStep = &SQLTransaction::deliverSuccessCallback; 488 LOG(StorageAPI, "Scheduling deliverSuccessCallback for transaction %p\n", this); 489 m_database->scheduleTransactionCallback(this); 490 } else 491 cleanupAfterSuccessCallback(); 492 } 493 494 void SQLTransaction::deliverSuccessCallback() 495 { 496 // Transaction Step 10 - Deliver success callback 497 RefPtr<VoidCallback> successCallback = m_successCallbackWrapper.unwrap(); 498 if (successCallback) 499 successCallback->handleEvent(); 500 501 // Schedule a "post-success callback" step to return control to the database thread in case there 502 // are further transactions queued up for this Database 503 m_nextStep = &SQLTransaction::cleanupAfterSuccessCallback; 504 LOG(StorageAPI, "Scheduling cleanupAfterSuccessCallback for transaction %p\n", this); 505 m_database->scheduleTransactionStep(this); 506 } 507 508 void SQLTransaction::cleanupAfterSuccessCallback() 509 { 510 ASSERT(m_lockAcquired); 511 512 // Transaction Step 11 - End transaction steps 513 // There is no next step 514 LOG(StorageAPI, "Transaction %p is complete\n", this); 515 ASSERT(!m_database->sqliteDatabase().transactionInProgress()); 516 m_sqliteTransaction.clear(); 517 m_nextStep = 0; 518 519 // Release the lock on this database 520 m_database->transactionCoordinator()->releaseLock(this); 521 } 522 523 void SQLTransaction::handleTransactionError(bool inCallback) 524 { 525 if (m_errorCallbackWrapper.hasCallback()) { 526 if (inCallback) 527 deliverTransactionErrorCallback(); 528 else { 529 m_nextStep = &SQLTransaction::deliverTransactionErrorCallback; 530 LOG(StorageAPI, "Scheduling deliverTransactionErrorCallback for transaction %p\n", this); 531 m_database->scheduleTransactionCallback(this); 532 } 533 return; 534 } 535 536 // No error callback, so fast-forward to: 537 // Transaction Step 12 - Rollback the transaction. 538 if (inCallback) { 539 m_nextStep = &SQLTransaction::cleanupAfterTransactionErrorCallback; 540 LOG(StorageAPI, "Scheduling cleanupAfterTransactionErrorCallback for transaction %p\n", this); 541 m_database->scheduleTransactionStep(this); 542 } else { 543 cleanupAfterTransactionErrorCallback(); 544 } 545 } 546 547 void SQLTransaction::deliverTransactionErrorCallback() 548 { 549 ASSERT(m_transactionError); 550 551 // Transaction Step 12 - If exists, invoke error callback with the last 552 // error to have occurred in this transaction. 553 RefPtr<SQLTransactionErrorCallback> errorCallback = m_errorCallbackWrapper.unwrap(); 554 if (errorCallback) 555 errorCallback->handleEvent(m_transactionError.get()); 556 557 m_nextStep = &SQLTransaction::cleanupAfterTransactionErrorCallback; 558 LOG(StorageAPI, "Scheduling cleanupAfterTransactionErrorCallback for transaction %p\n", this); 559 m_database->scheduleTransactionStep(this); 560 } 561 562 void SQLTransaction::cleanupAfterTransactionErrorCallback() 563 { 564 ASSERT(m_lockAcquired); 565 566 m_database->disableAuthorizer(); 567 if (m_sqliteTransaction) { 568 // Transaction Step 12 - Rollback the transaction. 569 m_sqliteTransaction->rollback(); 570 571 ASSERT(!m_database->sqliteDatabase().transactionInProgress()); 572 m_sqliteTransaction.clear(); 573 } 574 m_database->enableAuthorizer(); 575 576 // Transaction Step 12 - Any still-pending statements in the transaction are discarded. 577 { 578 MutexLocker locker(m_statementMutex); 579 m_statementQueue.clear(); 580 } 581 582 // Transaction is complete! There is no next step 583 LOG(StorageAPI, "Transaction %p is complete with an error\n", this); 584 ASSERT(!m_database->sqliteDatabase().transactionInProgress()); 585 m_nextStep = 0; 586 587 // Now release the lock on this database 588 m_database->transactionCoordinator()->releaseLock(this); 589 } 590 591 } // namespace WebCore 592 593 #endif // ENABLE(DATABASE) 594