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 #if !LOG_DISABLED
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