1/*
2 * Copyright (C) 2007, 2008, 2013 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 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#include "Database.h"
33#include "DatabaseAuthorizer.h"
34#include "DatabaseContext.h"
35#include "DatabaseThread.h"
36#include "DatabaseTracker.h"
37#include "Logging.h"
38#include "OriginLock.h"
39#include "SQLError.h"
40#include "SQLStatement.h"
41#include "SQLStatementCallback.h"
42#include "SQLStatementErrorCallback.h"
43#include "SQLTransactionBackend.h"
44#include "SQLTransactionCallback.h"
45#include "SQLTransactionCoordinator.h"
46#include "SQLTransactionErrorCallback.h"
47#include "SQLiteTransaction.h"
48#include "VoidCallback.h"
49#include <wtf/Optional.h>
50#include <wtf/StdLibExtras.h>
51#include <wtf/Vector.h>
52
53namespace WebCore {
54
55Ref<SQLTransaction> SQLTransaction::create(Ref<Database>&& database, RefPtr<SQLTransactionCallback>&& callback, RefPtr<VoidCallback>&& successCallback, RefPtr<SQLTransactionErrorCallback>&& errorCallback, RefPtr<SQLTransactionWrapper>&& wrapper, bool readOnly)
56{
57 return adoptRef(*new SQLTransaction(WTFMove(database), WTFMove(callback), WTFMove(successCallback), WTFMove(errorCallback), WTFMove(wrapper), readOnly));
58}
59
60SQLTransaction::SQLTransaction(Ref<Database>&& database, RefPtr<SQLTransactionCallback>&& callback, RefPtr<VoidCallback>&& successCallback, RefPtr<SQLTransactionErrorCallback>&& errorCallback, RefPtr<SQLTransactionWrapper>&& wrapper, bool readOnly)
61 : m_database(WTFMove(database))
62 , m_callbackWrapper(WTFMove(callback), &m_database->scriptExecutionContext())
63 , m_successCallbackWrapper(WTFMove(successCallback), &m_database->scriptExecutionContext())
64 , m_errorCallbackWrapper(WTFMove(errorCallback), &m_database->scriptExecutionContext())
65 , m_wrapper(WTFMove(wrapper))
66 , m_nextStep(&SQLTransaction::acquireLock)
67 , m_readOnly(readOnly)
68 , m_backend(*this)
69{
70}
71
72SQLTransaction::~SQLTransaction() = default;
73
74ExceptionOr<void> SQLTransaction::executeSql(const String& sqlStatement, Optional<Vector<SQLValue>>&& arguments, RefPtr<SQLStatementCallback>&& callback, RefPtr<SQLStatementErrorCallback>&& callbackError)
75{
76 if (!m_executeSqlAllowed || !m_database->opened())
77 return Exception { InvalidStateError };
78
79 int permissions = DatabaseAuthorizer::ReadWriteMask;
80 if (!m_database->databaseContext().allowDatabaseAccess())
81 permissions |= DatabaseAuthorizer::NoAccessMask;
82 else if (m_readOnly)
83 permissions |= DatabaseAuthorizer::ReadOnlyMask;
84
85 auto statement = std::make_unique<SQLStatement>(m_database, sqlStatement, arguments.valueOr(Vector<SQLValue> { }), WTFMove(callback), WTFMove(callbackError), permissions);
86
87 if (m_database->deleted())
88 statement->setDatabaseDeletedError();
89
90 enqueueStatement(WTFMove(statement));
91
92 return { };
93}
94
95void SQLTransaction::lockAcquired()
96{
97 m_lockAcquired = true;
98
99 m_backend.m_requestedState = SQLTransactionState::OpenTransactionAndPreflight;
100 m_database->scheduleTransactionStep(*this);
101}
102
103void SQLTransaction::performNextStep()
104{
105 m_backend.computeNextStateAndCleanupIfNeeded();
106 m_backend.runStateMachine();
107}
108
109void SQLTransaction::performPendingCallback()
110{
111 LOG(StorageAPI, "Callback %s\n", debugStepName(m_nextStep));
112
113 ASSERT(m_nextStep == &SQLTransaction::deliverTransactionCallback
114 || m_nextStep == &SQLTransaction::deliverTransactionErrorCallback
115 || m_nextStep == &SQLTransaction::deliverStatementCallback
116 || m_nextStep == &SQLTransaction::deliverQuotaIncreaseCallback
117 || m_nextStep == &SQLTransaction::deliverSuccessCallback);
118
119 checkAndHandleClosedDatabase();
120
121 if (m_nextStep)
122 (this->*m_nextStep)();
123}
124
125void SQLTransaction::notifyDatabaseThreadIsShuttingDown()
126{
127 m_backend.notifyDatabaseThreadIsShuttingDown();
128}
129
130void SQLTransaction::enqueueStatement(std::unique_ptr<SQLStatement> statement)
131{
132 LockHolder locker(m_statementMutex);
133 m_statementQueue.append(WTFMove(statement));
134}
135
136SQLTransaction::StateFunction SQLTransaction::stateFunctionFor(SQLTransactionState state)
137{
138 static const StateFunction stateFunctions[] = {
139 &SQLTransaction::unreachableState, // 0. illegal
140 &SQLTransaction::unreachableState, // 1. idle
141 &SQLTransaction::unreachableState, // 2. acquireLock
142 &SQLTransaction::unreachableState, // 3. openTransactionAndPreflight
143 &SQLTransaction::unreachableState, // 4. runStatements
144 &SQLTransaction::unreachableState, // 5. postflightAndCommit
145 &SQLTransaction::unreachableState, // 6. cleanupAndTerminate
146 &SQLTransaction::unreachableState, // 7. cleanupAfterTransactionErrorCallback
147 &SQLTransaction::deliverTransactionCallback, // 8.
148 &SQLTransaction::deliverTransactionErrorCallback, // 9.
149 &SQLTransaction::deliverStatementCallback, // 10.
150 &SQLTransaction::deliverQuotaIncreaseCallback, // 11.
151 &SQLTransaction::deliverSuccessCallback // 12.
152 };
153
154 ASSERT(WTF_ARRAY_LENGTH(stateFunctions) == static_cast<int>(SQLTransactionState::NumberOfStates));
155 ASSERT(state < SQLTransactionState::NumberOfStates);
156
157 return stateFunctions[static_cast<int>(state)];
158}
159
160// requestTransitToState() can be called from the backend. Hence, it should
161// NOT be modifying SQLTransactionBackend in general. The only safe field to
162// modify is m_requestedState which is meant for this purpose.
163void SQLTransaction::requestTransitToState(SQLTransactionState nextState)
164{
165 LOG(StorageAPI, "Scheduling %s for transaction %p\n", nameForSQLTransactionState(nextState), this);
166 m_requestedState = nextState;
167 m_database->scheduleTransactionCallback(this);
168}
169
170void SQLTransaction::checkAndHandleClosedDatabase()
171{
172 if (m_database->opened())
173 return;
174
175 // If the database was stopped, don't do anything and cancel queued work
176 LOG(StorageAPI, "Database was stopped or interrupted - cancelling work for this transaction");
177
178 LockHolder locker(m_statementMutex);
179 m_statementQueue.clear();
180 m_nextStep = nullptr;
181
182 // Release the unneeded callbacks, to break reference cycles.
183 m_callbackWrapper.clear();
184 m_successCallbackWrapper.clear();
185 m_errorCallbackWrapper.clear();
186
187 // The next steps should be executed only if we're on the DB thread.
188 if (m_database->databaseThread().getThread() != &Thread::current())
189 return;
190
191 // The current SQLite transaction should be stopped, as well
192 if (m_sqliteTransaction) {
193 m_sqliteTransaction->stop();
194 m_sqliteTransaction = nullptr;
195 }
196
197 if (m_lockAcquired)
198 m_database->transactionCoordinator()->releaseLock(*this);
199}
200
201void SQLTransaction::scheduleCallback(void (SQLTransaction::*step)())
202{
203 m_nextStep = step;
204
205 LOG(StorageAPI, "Scheduling %s for transaction %p\n", debugStepName(step), this);
206 m_database->scheduleTransactionCallback(this);
207}
208
209void SQLTransaction::acquireLock()
210{
211 m_database->transactionCoordinator()->acquireLock(*this);
212}
213
214void SQLTransaction::openTransactionAndPreflight()
215{
216 ASSERT(!m_database->sqliteDatabase().transactionInProgress());
217 ASSERT(m_lockAcquired);
218
219 LOG(StorageAPI, "Opening and preflighting transaction %p", this);
220
221 // If the database was deleted, jump to the error callback
222 if (m_database->deleted()) {
223 m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unable to open a transaction, because the user deleted the database");
224
225 handleTransactionError();
226 return;
227 }
228
229 // Set the maximum usage for this transaction if this transactions is not read-only
230 if (!m_readOnly) {
231 acquireOriginLock();
232 m_database->sqliteDatabase().setMaximumSize(m_database->maximumSize());
233 }
234
235 ASSERT(!m_sqliteTransaction);
236 m_sqliteTransaction = std::make_unique<SQLiteTransaction>(m_database->sqliteDatabase(), m_readOnly);
237
238 m_database->resetDeletes();
239 m_database->disableAuthorizer();
240 m_sqliteTransaction->begin();
241 m_database->enableAuthorizer();
242
243 // Spec 4.3.2.1+2: Open a transaction to the database, jumping to the error callback if that fails
244 if (!m_sqliteTransaction->inProgress()) {
245 ASSERT(!m_database->sqliteDatabase().transactionInProgress());
246 m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "unable to begin transaction", m_database->sqliteDatabase().lastError(), m_database->sqliteDatabase().lastErrorMsg());
247 m_sqliteTransaction = nullptr;
248
249 handleTransactionError();
250 return;
251 }
252
253 // Note: We intentionally retrieve the actual version even with an empty expected version.
254 // In multi-process browsers, we take this opportinutiy to update the cached value for
255 // the actual version. In single-process browsers, this is just a map lookup.
256 String actualVersion;
257 if (!m_database->getActualVersionForTransaction(actualVersion)) {
258 m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "unable to read version", m_database->sqliteDatabase().lastError(), m_database->sqliteDatabase().lastErrorMsg());
259 m_database->disableAuthorizer();
260 m_sqliteTransaction = nullptr;
261 m_database->enableAuthorizer();
262
263 handleTransactionError();
264 return;
265 }
266
267 m_hasVersionMismatch = !m_database->expectedVersion().isEmpty() && (m_database->expectedVersion() != actualVersion);
268
269 // Spec 4.3.2.3: Perform preflight steps, jumping to the error callback if they fail
270 if (m_wrapper && !m_wrapper->performPreflight(*this)) {
271 m_database->disableAuthorizer();
272 m_sqliteTransaction = nullptr;
273 m_database->enableAuthorizer();
274 m_transactionError = m_wrapper->sqlError();
275 if (!m_transactionError)
276 m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unknown error occurred during transaction preflight");
277
278 handleTransactionError();
279 return;
280 }
281
282 // Spec 4.3.2.4: Invoke the transaction callback with the new SQLTransaction object
283 if (m_callbackWrapper.hasCallback()) {
284 scheduleCallback(&SQLTransaction::deliverTransactionCallback);
285 return;
286 }
287
288 // If we have no callback to make, skip pass to the state after:
289 runStatements();
290}
291
292void SQLTransaction::runStatements()
293{
294 ASSERT(m_lockAcquired);
295
296 // If there is a series of statements queued up that are all successful and have no associated
297 // SQLStatementCallback objects, then we can burn through the queue
298 do {
299 if (m_shouldRetryCurrentStatement && !m_sqliteTransaction->wasRolledBackBySqlite()) {
300 m_shouldRetryCurrentStatement = false;
301 // FIXME - Another place that needs fixing up after <rdar://problem/5628468> is addressed.
302 // See ::openTransactionAndPreflight() for discussion
303
304 // Reset the maximum size here, as it was increased to allow us to retry this statement.
305 // m_shouldRetryCurrentStatement is set to true only when a statement exceeds
306 // the quota, which can happen only in a read-write transaction. Therefore, there
307 // is no need to check here if the transaction is read-write.
308 m_database->sqliteDatabase().setMaximumSize(m_database->maximumSize());
309 } else {
310 // If the current statement has already been run, failed due to quota constraints, and we're not retrying it,
311 // that means it ended in an error. Handle it now
312 if (m_currentStatement && m_currentStatement->lastExecutionFailedDueToQuota()) {
313 handleCurrentStatementError();
314 break;
315 }
316
317 // Otherwise, advance to the next statement
318 getNextStatement();
319 }
320 } while (runCurrentStatement());
321
322 // If runCurrentStatement() returned false, that means either there was no current statement to run,
323 // or the current statement requires a callback to complete. In the later case, it also scheduled
324 // the callback or performed any other additional work so we can return.
325 if (!m_currentStatement)
326 postflightAndCommit();
327}
328
329void SQLTransaction::cleanupAndTerminate()
330{
331 ASSERT(m_lockAcquired);
332
333 // Spec 4.3.2.9: End transaction steps. There is no next step.
334 LOG(StorageAPI, "Transaction %p is complete\n", this);
335 ASSERT(!m_database->sqliteDatabase().transactionInProgress());
336
337 // Phase 5 cleanup. See comment on the SQLTransaction life-cycle above.
338 m_backend.doCleanup();
339 m_database->inProgressTransactionCompleted();
340}
341
342void SQLTransaction::cleanupAfterTransactionErrorCallback()
343{
344 ASSERT(m_lockAcquired);
345
346 LOG(StorageAPI, "Transaction %p is complete with an error\n", this);
347 m_database->disableAuthorizer();
348 if (m_sqliteTransaction) {
349 // Spec 4.3.2.10: Rollback the transaction.
350 m_sqliteTransaction->rollback();
351
352 ASSERT(!m_database->sqliteDatabase().transactionInProgress());
353 m_sqliteTransaction = nullptr;
354 }
355 m_database->enableAuthorizer();
356
357 releaseOriginLockIfNeeded();
358
359 ASSERT(!m_database->sqliteDatabase().transactionInProgress());
360
361 cleanupAndTerminate();
362}
363
364void SQLTransaction::deliverTransactionCallback()
365{
366 bool shouldDeliverErrorCallback = false;
367
368 // Spec 4.3.2 4: Invoke the transaction callback with the new SQLTransaction object
369 RefPtr<SQLTransactionCallback> callback = m_callbackWrapper.unwrap();
370 if (callback) {
371 m_executeSqlAllowed = true;
372
373 auto result = callback->handleEvent(*this);
374 shouldDeliverErrorCallback = result.type() == CallbackResultType::ExceptionThrown;
375
376 m_executeSqlAllowed = false;
377 }
378
379 // Spec 4.3.2 5: If the transaction callback was null or raised an exception, jump to the error callback
380 if (shouldDeliverErrorCallback) {
381 m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the SQLTransactionCallback was null or threw an exception");
382 return deliverTransactionErrorCallback();
383 }
384
385 m_backend.requestTransitToState(SQLTransactionState::RunStatements);
386}
387
388void SQLTransaction::deliverTransactionErrorCallback()
389{
390 ASSERT(m_transactionError);
391
392 // Spec 4.3.2.10: If exists, invoke error callback with the last
393 // error to have occurred in this transaction.
394 RefPtr<SQLTransactionErrorCallback> errorCallback = m_errorCallbackWrapper.unwrap();
395 if (errorCallback)
396 errorCallback->handleEvent(*m_transactionError);
397
398 clearCallbackWrappers();
399
400 // Spec 4.3.2.10: Rollback the transaction.
401 m_backend.requestTransitToState(SQLTransactionState::CleanupAfterTransactionErrorCallback);
402}
403
404void SQLTransaction::deliverStatementCallback()
405{
406 ASSERT(m_currentStatement);
407
408 // Spec 4.3.2.6.6 and 4.3.2.6.3: If the statement callback went wrong, jump to the transaction error callback
409 // Otherwise, continue to loop through the statement queue
410 m_executeSqlAllowed = true;
411 bool result = m_currentStatement->performCallback(*this);
412 m_executeSqlAllowed = false;
413
414 if (result) {
415 m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "the statement callback raised an exception or statement error callback did not return false");
416
417 if (m_errorCallbackWrapper.hasCallback())
418 return deliverTransactionErrorCallback();
419
420 // No error callback, so fast-forward to:
421 // Transaction Step 11 - Rollback the transaction.
422 m_backend.requestTransitToState(SQLTransactionState::CleanupAfterTransactionErrorCallback);
423 return;
424 }
425
426 m_backend.requestTransitToState(SQLTransactionState::RunStatements);
427}
428
429void SQLTransaction::deliverQuotaIncreaseCallback()
430{
431 ASSERT(m_currentStatement);
432 ASSERT(!m_shouldRetryCurrentStatement);
433
434 m_shouldRetryCurrentStatement = m_database->didExceedQuota();
435
436 m_backend.requestTransitToState(SQLTransactionState::RunStatements);
437}
438
439void SQLTransaction::deliverSuccessCallback()
440{
441 // Spec 4.3.2.8: Deliver success callback.
442 RefPtr<VoidCallback> successCallback = m_successCallbackWrapper.unwrap();
443 if (successCallback)
444 successCallback->handleEvent();
445
446 clearCallbackWrappers();
447
448 // Schedule a "post-success callback" step to return control to the database thread in case there
449 // are further transactions queued up for this Database
450 m_backend.requestTransitToState(SQLTransactionState::CleanupAndTerminate);
451}
452
453// This state function is used as a stub function to plug unimplemented states
454// in the state dispatch table. They are unimplemented because they should
455// never be reached in the course of correct execution.
456void SQLTransaction::unreachableState()
457{
458 ASSERT_NOT_REACHED();
459}
460
461void SQLTransaction::computeNextStateAndCleanupIfNeeded()
462{
463 // Only honor the requested state transition if we're not supposed to be
464 // cleaning up and shutting down:
465 if (m_database->opened()) {
466 setStateToRequestedState();
467 ASSERT(m_nextState == SQLTransactionState::End
468 || m_nextState == SQLTransactionState::DeliverTransactionCallback
469 || m_nextState == SQLTransactionState::DeliverTransactionErrorCallback
470 || m_nextState == SQLTransactionState::DeliverStatementCallback
471 || m_nextState == SQLTransactionState::DeliverQuotaIncreaseCallback
472 || m_nextState == SQLTransactionState::DeliverSuccessCallback);
473
474 LOG(StorageAPI, "Callback %s\n", nameForSQLTransactionState(m_nextState));
475 return;
476 }
477
478 clearCallbackWrappers();
479 m_backend.requestTransitToState(SQLTransactionState::CleanupAndTerminate);
480}
481
482void SQLTransaction::clearCallbackWrappers()
483{
484 // Release the unneeded callbacks, to break reference cycles.
485 m_callbackWrapper.clear();
486 m_successCallbackWrapper.clear();
487 m_errorCallbackWrapper.clear();
488}
489
490void SQLTransaction::getNextStatement()
491{
492 m_currentStatement = nullptr;
493
494 LockHolder locker(m_statementMutex);
495 if (!m_statementQueue.isEmpty())
496 m_currentStatement = m_statementQueue.takeFirst();
497}
498
499bool SQLTransaction::runCurrentStatement()
500{
501 if (!m_currentStatement) {
502 // No more statements to run. So move on to the next state.
503 return false;
504 }
505
506 m_database->resetAuthorizer();
507
508 if (m_hasVersionMismatch)
509 m_currentStatement->setVersionMismatchedError();
510
511 if (m_currentStatement->execute(m_database)) {
512 if (m_database->lastActionChangedDatabase()) {
513 // Flag this transaction as having changed the database for later delegate notification
514 m_modifiedDatabase = true;
515 }
516
517 if (m_currentStatement->hasStatementCallback()) {
518 scheduleCallback(&SQLTransaction::deliverStatementCallback);
519 return false;
520 }
521
522 // If we get here, then the statement doesn't have a callback to invoke.
523 // We can move on to the next statement. Hence, stay in this state.
524 return true;
525 }
526
527 if (m_currentStatement->lastExecutionFailedDueToQuota()) {
528 scheduleCallback(&SQLTransaction::deliverQuotaIncreaseCallback);
529 return false;
530 }
531
532 handleCurrentStatementError();
533 return false;
534}
535
536void SQLTransaction::handleCurrentStatementError()
537{
538 // Spec 4.3.2.6.6: error - Call the statement's error callback, but if there was no error callback,
539 // or the transaction was rolled back, jump to the transaction error callback
540 if (m_currentStatement->hasStatementErrorCallback() && !m_sqliteTransaction->wasRolledBackBySqlite()) {
541 scheduleCallback(&SQLTransaction::deliverStatementCallback);
542 return;
543 }
544
545 m_transactionError = m_currentStatement->sqlError();
546 if (!m_transactionError)
547 m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "the statement failed to execute");
548
549 handleTransactionError();
550}
551
552void SQLTransaction::handleTransactionError()
553{
554 ASSERT(m_transactionError);
555 if (m_errorCallbackWrapper.hasCallback()) {
556 scheduleCallback(&SQLTransaction::deliverTransactionErrorCallback);
557 return;
558 }
559
560 // No error callback, so fast-forward to the next state and rollback the
561 // transaction.
562 m_backend.cleanupAfterTransactionErrorCallback();
563}
564
565void SQLTransaction::postflightAndCommit()
566{
567 ASSERT(m_lockAcquired);
568
569 // Spec 4.3.2.7: Perform postflight steps, jumping to the error callback if they fail.
570 if (m_wrapper && !m_wrapper->performPostflight(*this)) {
571 m_transactionError = m_wrapper->sqlError();
572 if (!m_transactionError)
573 m_transactionError = SQLError::create(SQLError::UNKNOWN_ERR, "unknown error occurred during transaction postflight");
574
575 handleTransactionError();
576 return;
577 }
578
579 // Spec 4.3.2.7: Commit the transaction, jumping to the error callback if that fails.
580 ASSERT(m_sqliteTransaction);
581
582 m_database->disableAuthorizer();
583 m_sqliteTransaction->commit();
584 m_database->enableAuthorizer();
585
586 releaseOriginLockIfNeeded();
587
588 // If the commit failed, the transaction will still be marked as "in progress"
589 if (m_sqliteTransaction->inProgress()) {
590 if (m_wrapper)
591 m_wrapper->handleCommitFailedAfterPostflight(*this);
592 m_transactionError = SQLError::create(SQLError::DATABASE_ERR, "unable to commit transaction", m_database->sqliteDatabase().lastError(), m_database->sqliteDatabase().lastErrorMsg());
593
594 handleTransactionError();
595 return;
596 }
597
598 // Vacuum the database if anything was deleted.
599 if (m_database->hadDeletes())
600 m_database->incrementalVacuumIfNeeded();
601
602 // The commit was successful. If the transaction modified this database, notify the delegates.
603 if (m_modifiedDatabase)
604 m_database->didCommitWriteTransaction();
605
606 // Spec 4.3.2.8: Deliver success callback, if there is one.
607 scheduleCallback(&SQLTransaction::deliverSuccessCallback);
608}
609
610void SQLTransaction::acquireOriginLock()
611{
612 ASSERT(!m_originLock);
613 m_originLock = DatabaseTracker::singleton().originLockFor(m_database->securityOrigin());
614 m_originLock->lock();
615}
616
617void SQLTransaction::releaseOriginLockIfNeeded()
618{
619 if (m_originLock) {
620 m_originLock->unlock();
621 m_originLock = nullptr;
622 }
623}
624
625#if !LOG_DISABLED
626const char* SQLTransaction::debugStepName(void (SQLTransaction::*step)())
627{
628 if (step == &SQLTransaction::acquireLock)
629 return "acquireLock";
630 if (step == &SQLTransaction::openTransactionAndPreflight)
631 return "openTransactionAndPreflight";
632 if (step == &SQLTransaction::runStatements)
633 return "runStatements";
634 if (step == &SQLTransaction::postflightAndCommit)
635 return "postflightAndCommit";
636 if (step == &SQLTransaction::cleanupAfterTransactionErrorCallback)
637 return "cleanupAfterTransactionErrorCallback";
638 if (step == &SQLTransaction::deliverTransactionCallback)
639 return "deliverTransactionCallback";
640 if (step == &SQLTransaction::deliverTransactionErrorCallback)
641 return "deliverTransactionErrorCallback";
642 if (step == &SQLTransaction::deliverStatementCallback)
643 return "deliverStatementCallback";
644 if (step == &SQLTransaction::deliverQuotaIncreaseCallback)
645 return "deliverQuotaIncreaseCallback";
646 if (step == &SQLTransaction::deliverSuccessCallback)
647 return "deliverSuccessCallback";
648
649 ASSERT_NOT_REACHED();
650 return "UNKNOWN";
651}
652#endif
653
654} // namespace WebCore
655