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 
create(Database * db,PassRefPtr<SQLTransactionCallback> callback,PassRefPtr<SQLTransactionErrorCallback> errorCallback,PassRefPtr<VoidCallback> successCallback,PassRefPtr<SQLTransactionWrapper> wrapper,bool readOnly)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 
SQLTransaction(Database * db,PassRefPtr<SQLTransactionCallback> callback,PassRefPtr<SQLTransactionErrorCallback> errorCallback,PassRefPtr<VoidCallback> successCallback,PassRefPtr<SQLTransactionWrapper> wrapper,bool readOnly)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 
~SQLTransaction()85 SQLTransaction::~SQLTransaction()
86 {
87     ASSERT(!m_sqliteTransaction);
88 }
89 
executeSQL(const String & sqlStatement,const Vector<SQLValue> & arguments,PassRefPtr<SQLStatementCallback> callback,PassRefPtr<SQLStatementErrorCallback> callbackError,ExceptionCode & e)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 
enqueueStatement(PassRefPtr<SQLStatement> statement)114 void SQLTransaction::enqueueStatement(PassRefPtr<SQLStatement> statement)
115 {
116     MutexLocker locker(m_statementMutex);
117     m_statementQueue.append(statement);
118 }
119 
120 #ifndef NDEBUG
debugStepName(SQLTransaction::TransactionStepMethod step)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 
checkAndHandleClosedOrInterruptedDatabase()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 
performNextStep()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 
performPendingCallback()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 
notifyDatabaseThreadIsShuttingDown()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 
acquireLock()227 void SQLTransaction::acquireLock()
228 {
229     m_database->transactionCoordinator()->acquireLock(this);
230 }
231 
lockAcquired()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 
openTransactionAndPreflight()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 
deliverTransactionCallback()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 
scheduleToRunStatements()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 
runStatements()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 
getNextStatement()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 
runCurrentStatement()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 
handleCurrentStatementError()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 
deliverStatementCallback()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 
deliverQuotaIncreaseCallback()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 
postflightAndCommit()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 
deliverSuccessCallback()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 
cleanupAfterSuccessCallback()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 
handleTransactionError(bool inCallback)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 
deliverTransactionErrorCallback()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 
cleanupAfterTransactionErrorCallback()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