Unreviewed, roll out http://trac.webkit.org/changeset/187972.
[WebKit-https.git] / Source / WebCore / Modules / webdatabase / Database.cpp
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 "Database.h"
31
32 #include "ChangeVersionData.h"
33 #include "ChangeVersionWrapper.h"
34 #include "DatabaseAuthorizer.h"
35 #include "DatabaseCallback.h"
36 #include "DatabaseContext.h"
37 #include "DatabaseManager.h"
38 #include "DatabaseTask.h"
39 #include "DatabaseThread.h"
40 #include "DatabaseTracker.h"
41 #include "Document.h"
42 #include "JSDOMWindow.h"
43 #include "Logging.h"
44 #include "Page.h"
45 #include "SQLError.h"
46 #include "SQLTransaction.h"
47 #include "SQLTransactionCallback.h"
48 #include "SQLTransactionErrorCallback.h"
49 #include "SQLiteDatabaseTracker.h"
50 #include "SQLiteStatement.h"
51 #include "SQLiteTransaction.h"
52 #include "ScriptExecutionContext.h"
53 #include "SecurityOrigin.h"
54 #include "VoidCallback.h"
55 #include <wtf/NeverDestroyed.h>
56 #include <wtf/PassRefPtr.h>
57 #include <wtf/RefPtr.h>
58 #include <wtf/StdLibExtras.h>
59 #include <wtf/text/CString.h>
60
61 namespace WebCore {
62
63 static const char versionKey[] = "WebKitDatabaseVersionKey";
64 static const char unqualifiedInfoTableName[] = "__WebKitDatabaseInfoTable__";
65
66 static const char* fullyQualifiedInfoTableName()
67 {
68     static const char qualifier[] = "main.";
69     static char qualifiedName[sizeof(qualifier) + sizeof(unqualifiedInfoTableName) - 1];
70
71     static std::once_flag onceFlag;
72     std::call_once(onceFlag, [] {
73         strcpy(qualifiedName, qualifier);
74         strcpy(qualifiedName + sizeof(qualifier) - 1, unqualifiedInfoTableName);
75     });
76
77     return qualifiedName;
78 }
79
80 static String formatErrorMessage(const char* message, int sqliteErrorCode, const char* sqliteErrorMessage)
81 {
82     return String::format("%s (%d %s)", message, sqliteErrorCode, sqliteErrorMessage);
83 }
84
85 static bool setTextValueInDatabase(SQLiteDatabase& db, const String& query, const String& value)
86 {
87     SQLiteStatement statement(db, query);
88     int result = statement.prepare();
89
90     if (result != SQLITE_OK) {
91         LOG_ERROR("Failed to prepare statement to set value in database (%s)", query.ascii().data());
92         return false;
93     }
94
95     statement.bindText(1, value);
96
97     result = statement.step();
98     if (result != SQLITE_DONE) {
99         LOG_ERROR("Failed to step statement to set value in database (%s)", query.ascii().data());
100         return false;
101     }
102
103     return true;
104 }
105
106 static bool retrieveTextResultFromDatabase(SQLiteDatabase& db, const String& query, String& resultString)
107 {
108     SQLiteStatement statement(db, query);
109     int result = statement.prepare();
110
111     if (result != SQLITE_OK) {
112         LOG_ERROR("Error (%i) preparing statement to read text result from database (%s)", result, query.ascii().data());
113         return false;
114     }
115
116     result = statement.step();
117     if (result == SQLITE_ROW) {
118         resultString = statement.getColumnText(0);
119         return true;
120     }
121     if (result == SQLITE_DONE) {
122         resultString = String();
123         return true;
124     }
125
126     LOG_ERROR("Error (%i) reading text result from database (%s)", result, query.ascii().data());
127     return false;
128 }
129
130 // FIXME: move all guid-related functions to a DatabaseVersionTracker class.
131 static std::mutex& guidMutex()
132 {
133     static std::once_flag onceFlag;
134     static LazyNeverDestroyed<std::mutex> mutex;
135
136     std::call_once(onceFlag, [] {
137         mutex.construct();
138     });
139
140     return mutex;
141 }
142
143 typedef HashMap<DatabaseGuid, String> GuidVersionMap;
144 static GuidVersionMap& guidToVersionMap()
145 {
146     static NeverDestroyed<GuidVersionMap> map;
147     return map;
148 }
149
150 // NOTE: Caller must lock guidMutex().
151 static inline void updateGuidVersionMap(DatabaseGuid guid, String newVersion)
152 {
153     // Note: It is not safe to put an empty string into the guidToVersionMap() map.
154     // That's because the map is cross-thread, but empty strings are per-thread.
155     // The copy() function makes a version of the string you can use on the current
156     // thread, but we need a string we can keep in a cross-thread data structure.
157     // FIXME: This is a quite-awkward restriction to have to program with.
158
159     // Map null string to empty string (see comment above).
160     guidToVersionMap().set(guid, newVersion.isEmpty() ? String() : newVersion.isolatedCopy());
161 }
162
163 typedef HashMap<DatabaseGuid, std::unique_ptr<HashSet<DatabaseBackendBase*>>> GuidDatabaseMap;
164
165 static GuidDatabaseMap& guidToDatabaseMap()
166 {
167     static NeverDestroyed<GuidDatabaseMap> map;
168     return map;
169 }
170
171 static DatabaseGuid guidForOriginAndName(const String& origin, const String& name)
172 {
173     String stringID = origin + "/" + name;
174
175     static NeverDestroyed<HashMap<String, int>> map;
176     DatabaseGuid guid = map.get().get(stringID);
177     if (!guid) {
178         static int currentNewGUID = 1;
179         guid = currentNewGUID++;
180         map.get().set(stringID, guid);
181     }
182
183     return guid;
184 }
185
186 Database::Database(PassRefPtr<DatabaseContext> databaseContext, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
187     : DatabaseBackendBase(databaseContext.get(), name, expectedVersion, displayName, estimatedSize)
188     , m_transactionInProgress(false)
189     , m_isTransactionQueueEnabled(true)
190     , m_scriptExecutionContext(databaseContext->scriptExecutionContext())
191     , m_databaseContext(databaseContext)
192     , m_deleted(false)
193 {
194     m_contextThreadSecurityOrigin = m_databaseContext->securityOrigin()->isolatedCopy();
195
196     m_databaseAuthorizer = DatabaseAuthorizer::create(unqualifiedInfoTableName);
197
198     if (m_name.isNull())
199         m_name = emptyString();
200
201     {
202         std::lock_guard<std::mutex> locker(guidMutex());
203
204         m_guid = guidForOriginAndName(securityOrigin()->toString(), name);
205         std::unique_ptr<HashSet<DatabaseBackendBase*>>& hashSet = guidToDatabaseMap().add(m_guid, nullptr).iterator->value;
206         if (!hashSet)
207             hashSet = std::make_unique<HashSet<DatabaseBackendBase*>>();
208         hashSet->add(this);
209     }
210
211     m_filename = DatabaseManager::singleton().fullPathForDatabase(securityOrigin(), m_name);
212
213     m_databaseThreadSecurityOrigin = m_contextThreadSecurityOrigin->isolatedCopy();
214     setFrontend(this);
215
216     ASSERT(m_databaseContext->databaseThread());
217 }
218
219 Database::~Database()
220 {
221     // The reference to the ScriptExecutionContext needs to be cleared on the JavaScript thread.  If we're on that thread already, we can just let the RefPtr's destruction do the dereffing.
222     if (!m_scriptExecutionContext->isContextThread()) {
223         // Grab a pointer to the script execution here because we're releasing it when we pass it to
224         // DerefContextTask::create.
225         PassRefPtr<ScriptExecutionContext> passedContext = m_scriptExecutionContext.release();
226         passedContext->postTask({ScriptExecutionContext::Task::CleanupTask, [passedContext] (ScriptExecutionContext& context) {
227             ASSERT_UNUSED(context, &context == passedContext);
228             RefPtr<ScriptExecutionContext> scriptExecutionContext(passedContext);
229         }});
230     }
231 }
232
233 bool Database::openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage)
234 {
235     DatabaseTaskSynchronizer synchronizer;
236     if (!databaseContext()->databaseThread() || databaseContext()->databaseThread()->terminationRequested(&synchronizer))
237         return false;
238
239     bool success = false;
240     auto task = std::make_unique<DatabaseOpenTask>(*this, setVersionInNewDatabase, synchronizer, error, errorMessage, success);
241     databaseContext()->databaseThread()->scheduleImmediateTask(WTF::move(task));
242     synchronizer.waitForTaskCompletion();
243
244     return success;
245 }
246
247 void Database::close()
248 {
249     ASSERT(databaseContext()->databaseThread());
250     ASSERT(currentThread() == databaseContext()->databaseThread()->getThreadID());
251
252     {
253         MutexLocker locker(m_transactionInProgressMutex);
254
255         // Clean up transactions that have not been scheduled yet:
256         // Transaction phase 1 cleanup. See comment on "What happens if a
257         // transaction is interrupted?" at the top of SQLTransactionBackend.cpp.
258         RefPtr<SQLTransactionBackend> transaction;
259         while (!m_transactionQueue.isEmpty()) {
260             transaction = m_transactionQueue.takeFirst();
261             transaction->notifyDatabaseThreadIsShuttingDown();
262         }
263
264         m_isTransactionQueueEnabled = false;
265         m_transactionInProgress = false;
266     }
267
268     closeDatabase();
269
270     // DatabaseThread keeps databases alive by referencing them in its
271     // m_openDatabaseSet. DatabaseThread::recordDatabaseClose() will remove
272     // this database from that set (which effectively deref's it). We hold on
273     // to it with a local pointer here for a liitle longer, so that we can
274     // unschedule any DatabaseTasks that refer to it before the database gets
275     // deleted.
276     Ref<Database> protect(*this);
277     databaseContext()->databaseThread()->recordDatabaseClosed(this);
278     databaseContext()->databaseThread()->unscheduleDatabaseTasks(this);
279 }
280
281 class DoneCreatingDatabaseOnExitCaller {
282 public:
283     DoneCreatingDatabaseOnExitCaller(DatabaseBackendBase* database)
284         : m_database(database)
285         , m_openSucceeded(false)
286     {
287     }
288     ~DoneCreatingDatabaseOnExitCaller()
289     {
290         DatabaseTracker::tracker().doneCreatingDatabase(static_cast<Database*>(m_database));
291     }
292
293     void setOpenSucceeded() { m_openSucceeded = true; }
294
295 private:
296     DatabaseBackendBase* m_database;
297     bool m_openSucceeded;
298 };
299
300 bool Database::performOpenAndVerify(bool shouldSetVersionInNewDatabase, DatabaseError& error, String& errorMessage)
301 {
302     DoneCreatingDatabaseOnExitCaller onExitCaller(this);
303     ASSERT(errorMessage.isEmpty());
304     ASSERT(error == DatabaseError::None); // Better not have any errors already.
305     error = DatabaseError::InvalidDatabaseState; // Presumed failure. We'll clear it if we succeed below.
306
307     const int maxSqliteBusyWaitTime = 30000;
308
309 #if PLATFORM(IOS)
310     {
311         // Make sure we wait till the background removal of the empty database files finished before trying to open any database.
312         DeprecatedMutexLocker locker(DatabaseTracker::openDatabaseMutex());
313     }
314 #endif
315
316     SQLiteTransactionInProgressAutoCounter transactionCounter;
317
318     if (!m_sqliteDatabase.open(m_filename, true)) {
319         errorMessage = formatErrorMessage("unable to open database", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
320         return false;
321     }
322     if (!m_sqliteDatabase.turnOnIncrementalAutoVacuum())
323         LOG_ERROR("Unable to turn on incremental auto-vacuum (%d %s)", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
324
325     m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime);
326
327     String currentVersion;
328     {
329         std::lock_guard<std::mutex> locker(guidMutex());
330
331         auto entry = guidToVersionMap().find(m_guid);
332         if (entry != guidToVersionMap().end()) {
333             // Map null string to empty string (see updateGuidVersionMap()).
334             currentVersion = entry->value.isNull() ? emptyString() : entry->value.isolatedCopy();
335             LOG(StorageAPI, "Current cached version for guid %i is %s", m_guid, currentVersion.ascii().data());
336         } else {
337             LOG(StorageAPI, "No cached version for guid %i", m_guid);
338
339             SQLiteTransaction transaction(m_sqliteDatabase);
340             transaction.begin();
341             if (!transaction.inProgress()) {
342                 errorMessage = formatErrorMessage("unable to open database, failed to start transaction", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
343                 m_sqliteDatabase.close();
344                 return false;
345             }
346
347             String tableName(unqualifiedInfoTableName);
348             if (!m_sqliteDatabase.tableExists(tableName)) {
349                 m_new = true;
350
351                 if (!m_sqliteDatabase.executeCommand("CREATE TABLE " + tableName + " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,value TEXT NOT NULL ON CONFLICT FAIL);")) {
352                     errorMessage = formatErrorMessage("unable to open database, failed to create 'info' table", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
353                     transaction.rollback();
354                     m_sqliteDatabase.close();
355                     return false;
356                 }
357             } else if (!m_frontend->getVersionFromDatabase(currentVersion, false)) {
358                 errorMessage = formatErrorMessage("unable to open database, failed to read current version", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
359                 transaction.rollback();
360                 m_sqliteDatabase.close();
361                 return false;
362             }
363
364             if (currentVersion.length()) {
365                 LOG(StorageAPI, "Retrieved current version %s from database %s", currentVersion.ascii().data(), databaseDebugName().ascii().data());
366             } else if (!m_new || shouldSetVersionInNewDatabase) {
367                 LOG(StorageAPI, "Setting version %s in database %s that was just created", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data());
368                 if (!m_frontend->setVersionInDatabase(m_expectedVersion, false)) {
369                     errorMessage = formatErrorMessage("unable to open database, failed to write current version", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
370                     transaction.rollback();
371                     m_sqliteDatabase.close();
372                     return false;
373                 }
374                 currentVersion = m_expectedVersion;
375             }
376             updateGuidVersionMap(m_guid, currentVersion);
377             transaction.commit();
378         }
379     }
380
381     if (currentVersion.isNull()) {
382         LOG(StorageAPI, "Database %s does not have its version set", databaseDebugName().ascii().data());
383         currentVersion = "";
384     }
385
386     // If the expected version isn't the empty string, ensure that the current database version we have matches that version. Otherwise, set an exception.
387     // If the expected version is the empty string, then we always return with whatever version of the database we have.
388     if ((!m_new || shouldSetVersionInNewDatabase) && m_expectedVersion.length() && m_expectedVersion != currentVersion) {
389         errorMessage = "unable to open database, version mismatch, '" + m_expectedVersion + "' does not match the currentVersion of '" + currentVersion + "'";
390         m_sqliteDatabase.close();
391         return false;
392     }
393
394     ASSERT(m_databaseAuthorizer);
395     m_sqliteDatabase.setAuthorizer(m_databaseAuthorizer);
396
397     // See comment at the top this file regarding calling addOpenDatabase().
398     DatabaseTracker::tracker().addOpenDatabase(static_cast<Database*>(this));
399     m_opened = true;
400
401     // Declare success:
402     error = DatabaseError::None; // Clear the presumed error from above.
403     onExitCaller.setOpenSucceeded();
404
405     if (m_new && !shouldSetVersionInNewDatabase)
406         m_expectedVersion = ""; // The caller provided a creationCallback which will set the expected version.
407
408     if (databaseContext()->databaseThread())
409         databaseContext()->databaseThread()->recordDatabaseOpen(this);
410
411     return true;
412 }
413
414 void Database::closeDatabase()
415 {
416     if (!m_opened)
417         return;
418
419     m_sqliteDatabase.close();
420     m_opened = false;
421     // See comment at the top this file regarding calling removeOpenDatabase().
422     DatabaseTracker::tracker().removeOpenDatabase(this);
423     {
424         std::lock_guard<std::mutex> locker(guidMutex());
425
426         auto it = guidToDatabaseMap().find(m_guid);
427         ASSERT(it != guidToDatabaseMap().end());
428         ASSERT(it->value);
429         ASSERT(it->value->contains(this));
430         it->value->remove(this);
431         if (it->value->isEmpty()) {
432             guidToDatabaseMap().remove(it);
433             guidToVersionMap().remove(m_guid);
434         }
435     }
436 }
437
438 bool Database::getVersionFromDatabase(String& version, bool shouldCacheVersion)
439 {
440     String query(String("SELECT value FROM ") + fullyQualifiedInfoTableName() +  " WHERE key = '" + versionKey + "';");
441
442     m_databaseAuthorizer->disable();
443
444     bool result = retrieveTextResultFromDatabase(m_sqliteDatabase, query, version);
445     if (result) {
446         if (shouldCacheVersion)
447             setCachedVersion(version);
448     } else
449         LOG_ERROR("Failed to retrieve version from database %s", databaseDebugName().ascii().data());
450
451     m_databaseAuthorizer->enable();
452
453     return result;
454 }
455
456 bool Database::setVersionInDatabase(const String& version, bool shouldCacheVersion)
457 {
458     // The INSERT will replace an existing entry for the database with the new version number, due to the UNIQUE ON CONFLICT REPLACE
459     // clause in the CREATE statement (see Database::performOpenAndVerify()).
460     String query(String("INSERT INTO ") + fullyQualifiedInfoTableName() +  " (key, value) VALUES ('" + versionKey + "', ?);");
461
462     m_databaseAuthorizer->disable();
463
464     bool result = setTextValueInDatabase(m_sqliteDatabase, query, version);
465     if (result) {
466         if (shouldCacheVersion)
467             setCachedVersion(version);
468     } else
469         LOG_ERROR("Failed to set version %s in database (%s)", version.ascii().data(), query.ascii().data());
470
471     m_databaseAuthorizer->enable();
472
473     return result;
474 }
475
476 String Database::getCachedVersion() const
477 {
478     std::lock_guard<std::mutex> locker(guidMutex());
479
480     return guidToVersionMap().get(m_guid).isolatedCopy();
481 }
482
483 void Database::setCachedVersion(const String& actualVersion)
484 {
485     // Update the in memory database version map.
486     std::lock_guard<std::mutex> locker(guidMutex());
487
488     updateGuidVersionMap(m_guid, actualVersion);
489 }
490
491 void Database::scheduleTransaction()
492 {
493     ASSERT(!m_transactionInProgressMutex.tryLock()); // Locked by caller.
494     RefPtr<SQLTransactionBackend> transaction;
495
496     if (m_isTransactionQueueEnabled && !m_transactionQueue.isEmpty())
497         transaction = m_transactionQueue.takeFirst();
498
499     if (transaction && databaseContext()->databaseThread()) {
500         auto task = std::make_unique<DatabaseTransactionTask>(transaction);
501         LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for transaction %p\n", task.get(), task->transaction());
502         m_transactionInProgress = true;
503         databaseContext()->databaseThread()->scheduleTask(WTF::move(task));
504     } else
505         m_transactionInProgress = false;
506 }
507
508 PassRefPtr<SQLTransactionBackend> Database::runTransaction(PassRefPtr<SQLTransaction> transaction, bool readOnly, const ChangeVersionData* data)
509 {
510     MutexLocker locker(m_transactionInProgressMutex);
511     if (!m_isTransactionQueueEnabled)
512         return 0;
513
514     RefPtr<SQLTransactionWrapper> wrapper;
515     if (data)
516         wrapper = ChangeVersionWrapper::create(data->oldVersion(), data->newVersion());
517
518     RefPtr<SQLTransactionBackend> transactionBackend = SQLTransactionBackend::create(this, transaction, wrapper, readOnly);
519     m_transactionQueue.append(transactionBackend);
520     if (!m_transactionInProgress)
521         scheduleTransaction();
522
523     return transactionBackend;
524 }
525
526 void Database::scheduleTransactionStep(SQLTransactionBackend* transaction)
527 {
528     if (!databaseContext()->databaseThread())
529         return;
530
531     auto task = std::make_unique<DatabaseTransactionTask>(transaction);
532     LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for the transaction step\n", task.get());
533     databaseContext()->databaseThread()->scheduleTask(WTF::move(task));
534 }
535
536 void Database::inProgressTransactionCompleted()
537 {
538     MutexLocker locker(m_transactionInProgressMutex);
539     m_transactionInProgress = false;
540     scheduleTransaction();
541 }
542
543 bool Database::hasPendingTransaction()
544 {
545     MutexLocker locker(m_transactionInProgressMutex);
546     return m_transactionInProgress || !m_transactionQueue.isEmpty();
547 }
548
549 SQLTransactionClient* Database::transactionClient() const
550 {
551     return databaseContext()->databaseThread()->transactionClient();
552 }
553
554 SQLTransactionCoordinator* Database::transactionCoordinator() const
555 {
556     return databaseContext()->databaseThread()->transactionCoordinator();
557 }
558
559 String Database::version() const
560 {
561     if (m_deleted)
562         return String();
563     return DatabaseBackendBase::version();
564 }
565
566 void Database::markAsDeletedAndClose()
567 {
568     if (m_deleted || !databaseContext()->databaseThread())
569         return;
570
571     LOG(StorageAPI, "Marking %s (%p) as deleted", stringIdentifier().ascii().data(), this);
572     m_deleted = true;
573
574     DatabaseTaskSynchronizer synchronizer;
575     if (databaseContext()->databaseThread()->terminationRequested(&synchronizer)) {
576         LOG(StorageAPI, "Database handle %p is on a terminated DatabaseThread, cannot be marked for normal closure\n", this);
577         return;
578     }
579
580     auto task = std::make_unique<DatabaseCloseTask>(*this, synchronizer);
581     databaseContext()->databaseThread()->scheduleImmediateTask(WTF::move(task));
582     synchronizer.waitForTaskCompletion();
583 }
584
585 void Database::changeVersion(const String& oldVersion, const String& newVersion,
586                              PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
587                              PassRefPtr<VoidCallback> successCallback)
588 {
589     ChangeVersionData data(oldVersion, newVersion);
590     runTransaction(callback, errorCallback, successCallback, false, &data);
591 }
592
593 void Database::transaction(PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, PassRefPtr<VoidCallback> successCallback)
594 {
595     runTransaction(callback, errorCallback, successCallback, false);
596 }
597
598 void Database::readTransaction(PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, PassRefPtr<VoidCallback> successCallback)
599 {
600     runTransaction(callback, errorCallback, successCallback, true);
601 }
602
603 void Database::disableAuthorizer()
604 {
605     ASSERT(m_databaseAuthorizer);
606     m_databaseAuthorizer->disable();
607 }
608
609 void Database::enableAuthorizer()
610 {
611     ASSERT(m_databaseAuthorizer);
612     m_databaseAuthorizer->enable();
613 }
614
615 void Database::setAuthorizerPermissions(int permissions)
616 {
617     ASSERT(m_databaseAuthorizer);
618     m_databaseAuthorizer->setPermissions(permissions);
619 }
620
621 bool Database::lastActionChangedDatabase()
622 {
623     ASSERT(m_databaseAuthorizer);
624     return m_databaseAuthorizer->lastActionChangedDatabase();
625 }
626
627 bool Database::lastActionWasInsert()
628 {
629     ASSERT(m_databaseAuthorizer);
630     return m_databaseAuthorizer->lastActionWasInsert();
631 }
632
633 void Database::resetDeletes()
634 {
635     ASSERT(m_databaseAuthorizer);
636     m_databaseAuthorizer->resetDeletes();
637 }
638
639 bool Database::hadDeletes()
640 {
641     ASSERT(m_databaseAuthorizer);
642     return m_databaseAuthorizer->hadDeletes();
643 }
644
645 void Database::resetAuthorizer()
646 {
647     if (m_databaseAuthorizer)
648         m_databaseAuthorizer->reset();
649 }
650
651 void Database::runTransaction(RefPtr<SQLTransactionCallback>&& callback, RefPtr<SQLTransactionErrorCallback>&& errorCallback, RefPtr<VoidCallback>&& successCallback, bool readOnly, const ChangeVersionData* changeVersionData)
652 {
653     RefPtr<SQLTransaction> transaction = SQLTransaction::create(*this, WTF::move(callback), WTF::move(successCallback), errorCallback.copyRef(), readOnly);
654
655     RefPtr<SQLTransactionBackend> transactionBackend = runTransaction(transaction.release(), readOnly, changeVersionData);
656     if (!transactionBackend && errorCallback) {
657         WTF::RefPtr<SQLTransactionErrorCallback> errorCallbackProtector = WTF::move(errorCallback);
658         m_scriptExecutionContext->postTask([errorCallbackProtector](ScriptExecutionContext&) {
659             errorCallbackProtector->handleEvent(SQLError::create(SQLError::UNKNOWN_ERR, "database has been closed").ptr());
660         });
661     }
662 }
663
664 void Database::scheduleTransactionCallback(SQLTransaction* transaction)
665 {
666     RefPtr<SQLTransaction> transactionProtector(transaction);
667     m_scriptExecutionContext->postTask([transactionProtector] (ScriptExecutionContext&) {
668         transactionProtector->performPendingCallback();
669     });
670 }
671
672 Vector<String> Database::performGetTableNames()
673 {
674     disableAuthorizer();
675
676     SQLiteStatement statement(sqliteDatabase(), "SELECT name FROM sqlite_master WHERE type='table';");
677     if (statement.prepare() != SQLITE_OK) {
678         LOG_ERROR("Unable to retrieve list of tables for database %s", databaseDebugName().ascii().data());
679         enableAuthorizer();
680         return Vector<String>();
681     }
682
683     Vector<String> tableNames;
684     int result;
685     while ((result = statement.step()) == SQLITE_ROW) {
686         String name = statement.getColumnText(0);
687         if (name != unqualifiedInfoTableName)
688             tableNames.append(name);
689     }
690
691     enableAuthorizer();
692
693     if (result != SQLITE_DONE) {
694         LOG_ERROR("Error getting tables for database %s", databaseDebugName().ascii().data());
695         return Vector<String>();
696     }
697
698     return tableNames;
699 }
700
701 void Database::incrementalVacuumIfNeeded()
702 {
703     SQLiteTransactionInProgressAutoCounter transactionCounter;
704
705     int64_t freeSpaceSize = m_sqliteDatabase.freeSpaceSize();
706     int64_t totalSize = m_sqliteDatabase.totalSize();
707     if (totalSize <= 10 * freeSpaceSize) {
708         int result = m_sqliteDatabase.runIncrementalVacuumCommand();
709         if (result != SQLITE_OK)
710             logErrorMessage(formatErrorMessage("error vacuuming database", result, m_sqliteDatabase.lastErrorMsg()));
711     }
712 }
713
714 void Database::logErrorMessage(const String& message)
715 {
716     m_scriptExecutionContext->addConsoleMessage(MessageSource::Storage, MessageLevel::Error, message);
717 }
718
719 Vector<String> Database::tableNames()
720 {
721     // FIXME: Not using isolatedCopy on these strings looks ok since threads take strict turns
722     // in dealing with them. However, if the code changes, this may not be true anymore.
723     Vector<String> result;
724     DatabaseTaskSynchronizer synchronizer;
725     if (!databaseContext()->databaseThread() || databaseContext()->databaseThread()->terminationRequested(&synchronizer))
726         return result;
727
728     auto task = std::make_unique<DatabaseTableNamesTask>(*this, synchronizer, result);
729     databaseContext()->databaseThread()->scheduleImmediateTask(WTF::move(task));
730     synchronizer.waitForTaskCompletion();
731
732     return result;
733 }
734
735 SecurityOrigin* Database::securityOrigin() const
736 {
737     if (m_scriptExecutionContext->isContextThread())
738         return m_contextThreadSecurityOrigin.get();
739     if (currentThread() == databaseContext()->databaseThread()->getThreadID())
740         return m_databaseThreadSecurityOrigin.get();
741     return 0;
742 }
743
744 } // namespace WebCore