Home | History | Annotate | Download | only in storage
      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 #ifndef NDEBUG
    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