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