dd75a3d4d5a907440069126046f746f1dc770f00
[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 "DOMWindow.h"
35 #include "DatabaseAuthorizer.h"
36 #include "DatabaseCallback.h"
37 #include "DatabaseContext.h"
38 #include "DatabaseManager.h"
39 #include "DatabaseTask.h"
40 #include "DatabaseThread.h"
41 #include "DatabaseTracker.h"
42 #include "Document.h"
43 #include "JSDOMWindow.h"
44 #include "Logging.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/RefPtr.h>
57 #include <wtf/StdLibExtras.h>
58 #include <wtf/text/CString.h>
59
60 namespace WebCore {
61
62 // Registering "opened" databases with the DatabaseTracker
63 // =======================================================
64 // The DatabaseTracker maintains a list of databases that have been
65 // "opened" so that the client can call interrupt or delete on every database
66 // associated with a DatabaseContext.
67 //
68 // We will only call DatabaseTracker::addOpenDatabase() to add the database
69 // to the tracker as opened when we've succeeded in opening the database,
70 // and will set m_opened to true. Similarly, we only call
71 // DatabaseTracker::removeOpenDatabase() to remove the database from the
72 // tracker when we set m_opened to false in closeDatabase(). This sets up
73 // a simple symmetry between open and close operations, and a direct
74 // correlation to adding and removing databases from the tracker's list,
75 // thus ensuring that we have a correct list for the interrupt and
76 // delete operations to work on.
77 //
78 // The only databases instances not tracked by the tracker's open database
79 // list are the ones that have not been added yet, or the ones that we
80 // attempted an open on but failed to. Such instances only exist in the
81 // factory functions for creating database backends.
82 //
83 // The factory functions will either call openAndVerifyVersion() or
84 // performOpenAndVerify(). These methods will add the newly instantiated
85 // database backend if they succeed in opening the requested database.
86 // In the case of failure to open the database, the factory methods will
87 // simply discard the newly instantiated database backend when they return.
88 // The ref counting mechanims will automatically destruct the un-added
89 // (and un-returned) databases instances.
90
91 static const char versionKey[] = "WebKitDatabaseVersionKey";
92 static const char unqualifiedInfoTableName[] = "__WebKitDatabaseInfoTable__";
93
94 static const char* fullyQualifiedInfoTableName()
95 {
96     static const char qualifier[] = "main.";
97     static char qualifiedName[sizeof(qualifier) + sizeof(unqualifiedInfoTableName) - 1];
98
99     static std::once_flag onceFlag;
100     std::call_once(onceFlag, [] {
101         snprintf(qualifiedName, sizeof(qualifiedName), "%s%s", qualifier, unqualifiedInfoTableName);
102     });
103
104     return qualifiedName;
105 }
106
107 static String formatErrorMessage(const char* message, int sqliteErrorCode, const char* sqliteErrorMessage)
108 {
109     return String::format("%s (%d %s)", message, sqliteErrorCode, sqliteErrorMessage);
110 }
111
112 static bool setTextValueInDatabase(SQLiteDatabase& db, const String& query, const String& value)
113 {
114     SQLiteStatement statement(db, query);
115     int result = statement.prepare();
116
117     if (result != SQLITE_OK) {
118         LOG_ERROR("Failed to prepare statement to set value in database (%s)", query.ascii().data());
119         return false;
120     }
121
122     statement.bindText(1, value);
123
124     result = statement.step();
125     if (result != SQLITE_DONE) {
126         LOG_ERROR("Failed to step statement to set value in database (%s)", query.ascii().data());
127         return false;
128     }
129
130     return true;
131 }
132
133 static bool retrieveTextResultFromDatabase(SQLiteDatabase& db, const String& query, String& resultString)
134 {
135     SQLiteStatement statement(db, query);
136     int result = statement.prepare();
137
138     if (result != SQLITE_OK) {
139         LOG_ERROR("Error (%i) preparing statement to read text result from database (%s)", result, query.ascii().data());
140         return false;
141     }
142
143     result = statement.step();
144     if (result == SQLITE_ROW) {
145         resultString = statement.getColumnText(0);
146         return true;
147     }
148     if (result == SQLITE_DONE) {
149         resultString = String();
150         return true;
151     }
152
153     LOG_ERROR("Error (%i) reading text result from database (%s)", result, query.ascii().data());
154     return false;
155 }
156
157 // FIXME: move all guid-related functions to a DatabaseVersionTracker class.
158 static StaticLock guidMutex;
159
160 static HashMap<DatabaseGUID, String>& guidToVersionMap()
161 {
162     static NeverDestroyed<HashMap<DatabaseGUID, String>> map;
163     return map;
164 }
165
166 // NOTE: Caller must lock guidMutex().
167 static inline void updateGUIDVersionMap(DatabaseGUID guid, const String& newVersion)
168 {
169     // Note: It is not safe to put an empty string into the guidToVersionMap() map.
170     // That's because the map is cross-thread, but empty strings are per-thread.
171     // The copy() function makes a version of the string you can use on the current
172     // thread, but we need a string we can keep in a cross-thread data structure.
173     // FIXME: This is a quite-awkward restriction to have to program with.
174
175     // Map empty string to null string (see comment above).
176     guidToVersionMap().set(guid, newVersion.isEmpty() ? String() : newVersion.isolatedCopy());
177 }
178
179 static HashMap<DatabaseGUID, HashSet<Database*>>& guidToDatabaseMap()
180 {
181     static NeverDestroyed<HashMap<DatabaseGUID, HashSet<Database*>>> map;
182     return map;
183 }
184
185 static inline DatabaseGUID guidForOriginAndName(const String& origin, const String& name)
186 {
187     static NeverDestroyed<HashMap<String, DatabaseGUID>> map;
188     return map.get().ensure(makeString(origin, '/', name), [] {
189         static DatabaseGUID lastUsedGUID;
190         return ++lastUsedGUID;
191     }).iterator->value;
192 }
193
194 Database::Database(DatabaseContext& context, const String& name, const String& expectedVersion, const String& displayName, unsigned estimatedSize)
195     : m_scriptExecutionContext(*context.scriptExecutionContext())
196     , m_contextThreadSecurityOrigin(m_scriptExecutionContext->securityOrigin()->isolatedCopy())
197     , m_databaseThreadSecurityOrigin(m_scriptExecutionContext->securityOrigin()->isolatedCopy())
198     , m_databaseContext(context)
199     , m_name((name.isNull() ? emptyString() : name).isolatedCopy())
200     , m_expectedVersion(expectedVersion.isolatedCopy())
201     , m_displayName(displayName.isolatedCopy())
202     , m_estimatedSize(estimatedSize)
203     , m_filename(DatabaseManager::singleton().fullPathForDatabase(*m_scriptExecutionContext->securityOrigin(), m_name))
204     , m_databaseAuthorizer(DatabaseAuthorizer::create(unqualifiedInfoTableName))
205 {
206     {
207         std::lock_guard<StaticLock> locker(guidMutex);
208
209         m_guid = guidForOriginAndName(securityOrigin().securityOrigin()->toString(), name);
210         guidToDatabaseMap().ensure(m_guid, [] {
211             return HashSet<Database*>();
212         }).iterator->value.add(this);
213     }
214
215     m_databaseContext->databaseThread();
216
217     ASSERT(m_databaseContext->existingDatabaseThread());
218 }
219
220 DatabaseThread& Database::databaseThread()
221 {
222     ASSERT(m_databaseContext->existingDatabaseThread());
223     return *m_databaseContext->existingDatabaseThread();
224 }
225
226 Database::~Database()
227 {
228     // 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.
229     if (!m_scriptExecutionContext->isContextThread()) {
230         auto passedContext = WTFMove(m_scriptExecutionContext);
231         auto& contextRef = passedContext.get();
232         contextRef.postTask({ScriptExecutionContext::Task::CleanupTask, [passedContext = WTFMove(passedContext), databaseContext = WTFMove(m_databaseContext)] (ScriptExecutionContext& context) {
233             ASSERT_UNUSED(context, &context == passedContext.ptr());
234         }});
235     }
236
237     // SQLite is "multi-thread safe", but each database handle can only be used
238     // on a single thread at a time.
239     //
240     // For DatabaseBackend, we open the SQLite database on the DatabaseThread,
241     // and hence we should also close it on that same thread. This means that the
242     // SQLite database need to be closed by another mechanism (see
243     // DatabaseContext::stopDatabases()). By the time we get here, the SQLite
244     // database should have already been closed.
245
246     ASSERT(!m_opened);
247 }
248
249 ExceptionOr<void> Database::openAndVerifyVersion(bool setVersionInNewDatabase)
250 {
251     DatabaseTaskSynchronizer synchronizer;
252     auto& thread = databaseThread();
253     if (thread.terminationRequested(&synchronizer))
254         return Exception { InvalidStateError };
255
256     ExceptionOr<void> result;
257     auto task = std::make_unique<DatabaseOpenTask>(*this, setVersionInNewDatabase, synchronizer, result);
258     thread.scheduleImmediateTask(WTFMove(task));
259     synchronizer.waitForTaskCompletion();
260
261     return result;
262 }
263
264 void Database::interrupt()
265 {
266     // It is safe to call this from any thread for an opened or closed database.
267     m_sqliteDatabase.interrupt();
268 }
269
270 void Database::close()
271 {
272     auto& thread = databaseThread();
273
274     DatabaseTaskSynchronizer synchronizer;
275     if (thread.terminationRequested(&synchronizer)) {
276         LOG(StorageAPI, "Database handle %p is on a terminated DatabaseThread, cannot be marked for normal closure\n", this);
277         return;
278     }
279
280     thread.scheduleImmediateTask(std::make_unique<DatabaseCloseTask>(*this, synchronizer));
281
282     // FIXME: iOS depends on this function blocking until the database is closed as part
283     // of closing all open databases from a process assertion expiration handler.
284     // See <https://bugs.webkit.org/show_bug.cgi?id=157184>.
285     synchronizer.waitForTaskCompletion();
286 }
287
288 void Database::performClose()
289 {
290     ASSERT(databaseThread().getThread() == &Thread::current());
291
292     {
293         LockHolder locker(m_transactionInProgressMutex);
294
295         // Clean up transactions that have not been scheduled yet:
296         // Transaction phase 1 cleanup. See comment on "What happens if a
297         // transaction is interrupted?" at the top of SQLTransactionBackend.cpp.
298         while (!m_transactionQueue.isEmpty())
299             m_transactionQueue.takeFirst()->notifyDatabaseThreadIsShuttingDown();
300
301         m_isTransactionQueueEnabled = false;
302         m_transactionInProgress = false;
303     }
304
305     closeDatabase();
306
307     // DatabaseThread keeps databases alive by referencing them in its
308     // m_openDatabaseSet. DatabaseThread::recordDatabaseClose() will remove
309     // this database from that set (which effectively deref's it). We hold on
310     // to it with a local pointer here for a liitle longer, so that we can
311     // unschedule any DatabaseTasks that refer to it before the database gets
312     // deleted.
313     Ref<Database> protectedThis(*this);
314     auto& thread = databaseThread();
315     thread.recordDatabaseClosed(*this);
316     thread.unscheduleDatabaseTasks(*this);
317 }
318
319 class DoneCreatingDatabaseOnExitCaller {
320 public:
321     DoneCreatingDatabaseOnExitCaller(Database& database)
322         : m_database(database)
323     {
324     }
325
326     ~DoneCreatingDatabaseOnExitCaller()
327     {
328         DatabaseTracker::singleton().doneCreatingDatabase(m_database);
329     }
330
331 private:
332     Database& m_database;
333 };
334
335 ExceptionOr<void> Database::performOpenAndVerify(bool shouldSetVersionInNewDatabase)
336 {
337     DoneCreatingDatabaseOnExitCaller onExitCaller(*this);
338
339     const int maxSqliteBusyWaitTime = 30000;
340
341 #if PLATFORM(IOS)
342     {
343         // Make sure we wait till the background removal of the empty database files finished before trying to open any database.
344         auto locker = holdLock(DatabaseTracker::openDatabaseMutex());
345     }
346 #endif
347
348     SQLiteTransactionInProgressAutoCounter transactionCounter;
349
350     if (!m_sqliteDatabase.open(m_filename, true))
351         return Exception { InvalidStateError, formatErrorMessage("unable to open database", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg()) };
352     if (!m_sqliteDatabase.turnOnIncrementalAutoVacuum())
353         LOG_ERROR("Unable to turn on incremental auto-vacuum (%d %s)", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
354
355     m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime);
356
357     String currentVersion;
358     {
359         std::lock_guard<StaticLock> locker(guidMutex);
360
361         auto entry = guidToVersionMap().find(m_guid);
362         if (entry != guidToVersionMap().end()) {
363             // Map null string to empty string (see updateGUIDVersionMap()).
364             currentVersion = entry->value.isNull() ? emptyString() : entry->value.isolatedCopy();
365             LOG(StorageAPI, "Current cached version for guid %i is %s", m_guid, currentVersion.ascii().data());
366         } else {
367             LOG(StorageAPI, "No cached version for guid %i", m_guid);
368
369             SQLiteTransaction transaction(m_sqliteDatabase);
370             transaction.begin();
371             if (!transaction.inProgress()) {
372                 String message = formatErrorMessage("unable to open database, failed to start transaction", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
373                 m_sqliteDatabase.close();
374                 return Exception { InvalidStateError, WTFMove(message) };
375             }
376
377             String tableName(unqualifiedInfoTableName);
378             if (!m_sqliteDatabase.tableExists(tableName)) {
379                 m_new = true;
380
381                 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);")) {
382                     String message = formatErrorMessage("unable to open database, failed to create 'info' table", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
383                     transaction.rollback();
384                     m_sqliteDatabase.close();
385                 return Exception { InvalidStateError, WTFMove(message) };
386                 }
387             } else if (!getVersionFromDatabase(currentVersion, false)) {
388                 String message = formatErrorMessage("unable to open database, failed to read current version", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
389                 transaction.rollback();
390                 m_sqliteDatabase.close();
391                 return Exception { InvalidStateError, WTFMove(message) };
392             }
393
394             if (currentVersion.length()) {
395                 LOG(StorageAPI, "Retrieved current version %s from database %s", currentVersion.ascii().data(), databaseDebugName().ascii().data());
396             } else if (!m_new || shouldSetVersionInNewDatabase) {
397                 LOG(StorageAPI, "Setting version %s in database %s that was just created", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data());
398                 if (!setVersionInDatabase(m_expectedVersion, false)) {
399                     String message = formatErrorMessage("unable to open database, failed to write current version", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
400                     transaction.rollback();
401                     m_sqliteDatabase.close();
402                     return Exception { InvalidStateError, WTFMove(message) };
403                 }
404                 currentVersion = m_expectedVersion;
405             }
406             updateGUIDVersionMap(m_guid, currentVersion);
407             transaction.commit();
408         }
409     }
410
411     if (currentVersion.isNull()) {
412         LOG(StorageAPI, "Database %s does not have its version set", databaseDebugName().ascii().data());
413         currentVersion = emptyString();
414     }
415
416     // If the expected version isn't the empty string, ensure that the current database version we have matches that version. Otherwise, set an exception.
417     // If the expected version is the empty string, then we always return with whatever version of the database we have.
418     if ((!m_new || shouldSetVersionInNewDatabase) && m_expectedVersion.length() && m_expectedVersion != currentVersion) {
419         m_sqliteDatabase.close();
420         return Exception { InvalidStateError, "unable to open database, version mismatch, '" + m_expectedVersion + "' does not match the currentVersion of '" + currentVersion + "'" };
421     }
422
423     m_sqliteDatabase.setAuthorizer(m_databaseAuthorizer.get());
424
425     DatabaseTracker::singleton().addOpenDatabase(*this);
426     m_opened = true;
427
428     if (m_new && !shouldSetVersionInNewDatabase)
429         m_expectedVersion = emptyString(); // The caller provided a creationCallback which will set the expected version.
430
431     databaseThread().recordDatabaseOpen(*this);
432
433     return { };
434 }
435
436 void Database::closeDatabase()
437 {
438     if (!m_opened)
439         return;
440
441     m_sqliteDatabase.close();
442     m_opened = false;
443
444     // See comment at the top this file regarding calling removeOpenDatabase().
445     DatabaseTracker::singleton().removeOpenDatabase(*this);
446
447     {
448         std::lock_guard<StaticLock> locker(guidMutex);
449
450         auto it = guidToDatabaseMap().find(m_guid);
451         ASSERT(it != guidToDatabaseMap().end());
452         ASSERT(it->value.contains(this));
453         it->value.remove(this);
454         if (it->value.isEmpty()) {
455             guidToDatabaseMap().remove(it);
456             guidToVersionMap().remove(m_guid);
457         }
458     }
459 }
460
461 bool Database::getVersionFromDatabase(String& version, bool shouldCacheVersion)
462 {
463     String query(String("SELECT value FROM ") + fullyQualifiedInfoTableName() +  " WHERE key = '" + versionKey + "';");
464
465     m_databaseAuthorizer->disable();
466
467     bool result = retrieveTextResultFromDatabase(m_sqliteDatabase, query, version);
468     if (result) {
469         if (shouldCacheVersion)
470             setCachedVersion(version);
471     } else
472         LOG_ERROR("Failed to retrieve version from database %s", databaseDebugName().ascii().data());
473
474     m_databaseAuthorizer->enable();
475
476     return result;
477 }
478
479 bool Database::setVersionInDatabase(const String& version, bool shouldCacheVersion)
480 {
481     // The INSERT will replace an existing entry for the database with the new version number, due to the UNIQUE ON CONFLICT REPLACE
482     // clause in the CREATE statement (see Database::performOpenAndVerify()).
483     String query(String("INSERT INTO ") + fullyQualifiedInfoTableName() +  " (key, value) VALUES ('" + versionKey + "', ?);");
484
485     m_databaseAuthorizer->disable();
486
487     bool result = setTextValueInDatabase(m_sqliteDatabase, query, version);
488     if (result) {
489         if (shouldCacheVersion)
490             setCachedVersion(version);
491     } else
492         LOG_ERROR("Failed to set version %s in database (%s)", version.ascii().data(), query.ascii().data());
493
494     m_databaseAuthorizer->enable();
495
496     return result;
497 }
498
499 void Database::setExpectedVersion(const String& version)
500 {
501     m_expectedVersion = version.isolatedCopy();
502 }
503
504 String Database::getCachedVersion() const
505 {
506     std::lock_guard<StaticLock> locker(guidMutex);
507
508     return guidToVersionMap().get(m_guid).isolatedCopy();
509 }
510
511 void Database::setCachedVersion(const String& actualVersion)
512 {
513     std::lock_guard<StaticLock> locker(guidMutex);
514
515     updateGUIDVersionMap(m_guid, actualVersion);
516 }
517
518 bool Database::getActualVersionForTransaction(String &actualVersion)
519 {
520     ASSERT(m_sqliteDatabase.transactionInProgress());
521
522     // Note: In multi-process browsers the cached value may be inaccurate.
523     // So we retrieve the value from the database and update the cached value here.
524     return getVersionFromDatabase(actualVersion, true);
525 }
526
527 void Database::scheduleTransaction()
528 {
529     ASSERT(!m_transactionInProgressMutex.tryLock()); // Locked by caller.
530
531     if (!m_isTransactionQueueEnabled || m_transactionQueue.isEmpty()) {
532         m_transactionInProgress = false;
533         return;
534     }
535
536     m_transactionInProgress = true;
537
538     auto transaction = m_transactionQueue.takeFirst();
539     auto task = std::make_unique<DatabaseTransactionTask>(WTFMove(transaction));
540     LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for transaction %p\n", task.get(), task->transaction());
541     databaseThread().scheduleTask(WTFMove(task));
542 }
543
544 void Database::scheduleTransactionStep(SQLTransaction& transaction)
545 {
546     auto& thread = databaseThread();
547
548     auto task = std::make_unique<DatabaseTransactionTask>(&transaction);
549     LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for the transaction step\n", task.get());
550     thread.scheduleTask(WTFMove(task));
551 }
552
553 void Database::inProgressTransactionCompleted()
554 {
555     LockHolder locker(m_transactionInProgressMutex);
556     m_transactionInProgress = false;
557     scheduleTransaction();
558 }
559
560 bool Database::hasPendingTransaction()
561 {
562     LockHolder locker(m_transactionInProgressMutex);
563     return m_transactionInProgress || !m_transactionQueue.isEmpty();
564 }
565
566 SQLTransactionCoordinator* Database::transactionCoordinator()
567 {
568     return databaseThread().transactionCoordinator();
569 }
570
571 String Database::version() const
572 {
573     if (m_deleted)
574         return String();
575
576     // Note: In multi-process browsers the cached value may be accurate, but we cannot read the
577     // actual version from the database without potentially inducing a deadlock.
578     // FIXME: Add an async version getter to the DatabaseAPI.
579     return getCachedVersion();
580 }
581
582 void Database::markAsDeletedAndClose()
583 {
584     if (m_deleted)
585         return;
586
587     LOG(StorageAPI, "Marking %s (%p) as deleted", stringIdentifier().ascii().data(), this);
588     m_deleted = true;
589
590     close();
591 }
592
593 void Database::changeVersion(const String& oldVersion, const String& newVersion, RefPtr<SQLTransactionCallback>&& callback, RefPtr<SQLTransactionErrorCallback>&& errorCallback, RefPtr<VoidCallback>&& successCallback)
594 {
595     runTransaction(WTFMove(callback), WTFMove(errorCallback), WTFMove(successCallback), ChangeVersionWrapper::create(oldVersion, newVersion), false);
596 }
597
598 void Database::transaction(RefPtr<SQLTransactionCallback>&& callback, RefPtr<SQLTransactionErrorCallback>&& errorCallback, RefPtr<VoidCallback>&& successCallback)
599 {
600     runTransaction(WTFMove(callback), WTFMove(errorCallback), WTFMove(successCallback), nullptr, false);
601 }
602
603 void Database::readTransaction(RefPtr<SQLTransactionCallback>&& callback, RefPtr<SQLTransactionErrorCallback>&& errorCallback, RefPtr<VoidCallback>&& successCallback)
604 {
605     runTransaction(WTFMove(callback), WTFMove(errorCallback), WTFMove(successCallback), nullptr, true);
606 }
607
608 String Database::stringIdentifier() const
609 {
610     // Return a deep copy for ref counting thread safety
611     return m_name.isolatedCopy();
612 }
613
614 String Database::displayName() const
615 {
616     // Return a deep copy for ref counting thread safety
617     return m_displayName.isolatedCopy();
618 }
619
620 unsigned Database::estimatedSize() const
621 {
622     return m_estimatedSize;
623 }
624
625 String Database::fileName() const
626 {
627     // Return a deep copy for ref counting thread safety
628     return m_filename.isolatedCopy();
629 }
630
631 DatabaseDetails Database::details() const
632 {
633     // This code path is only used for database quota delegate calls, so file dates are irrelevant and left uninitialized.
634     return DatabaseDetails(stringIdentifier(), displayName(), estimatedSize(), 0, 0, 0);
635 }
636
637 void Database::disableAuthorizer()
638 {
639     m_databaseAuthorizer->disable();
640 }
641
642 void Database::enableAuthorizer()
643 {
644     m_databaseAuthorizer->enable();
645 }
646
647 void Database::setAuthorizerPermissions(int permissions)
648 {
649     m_databaseAuthorizer->setPermissions(permissions);
650 }
651
652 bool Database::lastActionChangedDatabase()
653 {
654     return m_databaseAuthorizer->lastActionChangedDatabase();
655 }
656
657 bool Database::lastActionWasInsert()
658 {
659     return m_databaseAuthorizer->lastActionWasInsert();
660 }
661
662 void Database::resetDeletes()
663 {
664     m_databaseAuthorizer->resetDeletes();
665 }
666
667 bool Database::hadDeletes()
668 {
669     return m_databaseAuthorizer->hadDeletes();
670 }
671
672 void Database::resetAuthorizer()
673 {
674     m_databaseAuthorizer->reset();
675 }
676
677 void Database::runTransaction(RefPtr<SQLTransactionCallback>&& callback, RefPtr<SQLTransactionErrorCallback>&& errorCallback, RefPtr<VoidCallback>&& successCallback, RefPtr<SQLTransactionWrapper>&& wrapper, bool readOnly)
678 {
679     LockHolder locker(m_transactionInProgressMutex);
680     if (!m_isTransactionQueueEnabled) {
681         if (errorCallback) {
682             RefPtr<SQLTransactionErrorCallback> errorCallbackProtector = WTFMove(errorCallback);
683             m_scriptExecutionContext->postTask([errorCallbackProtector](ScriptExecutionContext&) {
684                 errorCallbackProtector->handleEvent(SQLError::create(SQLError::UNKNOWN_ERR, "database has been closed"));
685             });
686         }
687         return;
688     }
689
690     m_transactionQueue.append(SQLTransaction::create(*this, WTFMove(callback), WTFMove(successCallback), errorCallback.copyRef(), WTFMove(wrapper), readOnly));
691     if (!m_transactionInProgress)
692         scheduleTransaction();
693 }
694
695 void Database::scheduleTransactionCallback(SQLTransaction* transaction)
696 {
697     RefPtr<SQLTransaction> transactionProtector(transaction);
698     m_scriptExecutionContext->postTask([transactionProtector] (ScriptExecutionContext&) {
699         transactionProtector->performPendingCallback();
700     });
701 }
702
703 Vector<String> Database::performGetTableNames()
704 {
705     disableAuthorizer();
706
707     SQLiteStatement statement(sqliteDatabase(), "SELECT name FROM sqlite_master WHERE type='table';");
708     if (statement.prepare() != SQLITE_OK) {
709         LOG_ERROR("Unable to retrieve list of tables for database %s", databaseDebugName().ascii().data());
710         enableAuthorizer();
711         return Vector<String>();
712     }
713
714     Vector<String> tableNames;
715     int result;
716     while ((result = statement.step()) == SQLITE_ROW) {
717         String name = statement.getColumnText(0);
718         if (name != unqualifiedInfoTableName)
719             tableNames.append(name);
720     }
721
722     enableAuthorizer();
723
724     if (result != SQLITE_DONE) {
725         LOG_ERROR("Error getting tables for database %s", databaseDebugName().ascii().data());
726         return Vector<String>();
727     }
728
729     return tableNames;
730 }
731
732 void Database::incrementalVacuumIfNeeded()
733 {
734     SQLiteTransactionInProgressAutoCounter transactionCounter;
735
736     int64_t freeSpaceSize = m_sqliteDatabase.freeSpaceSize();
737     int64_t totalSize = m_sqliteDatabase.totalSize();
738     if (totalSize <= 10 * freeSpaceSize) {
739         int result = m_sqliteDatabase.runIncrementalVacuumCommand();
740         if (result != SQLITE_OK)
741             logErrorMessage(formatErrorMessage("error vacuuming database", result, m_sqliteDatabase.lastErrorMsg()));
742     }
743 }
744
745 void Database::logErrorMessage(const String& message)
746 {
747     m_scriptExecutionContext->addConsoleMessage(MessageSource::Storage, MessageLevel::Error, message);
748 }
749
750 Vector<String> Database::tableNames()
751 {
752     // FIXME: Not using isolatedCopy on these strings looks ok since threads take strict turns
753     // in dealing with them. However, if the code changes, this may not be true anymore.
754     Vector<String> result;
755     DatabaseTaskSynchronizer synchronizer;
756     auto& thread = databaseThread();
757     if (thread.terminationRequested(&synchronizer))
758         return result;
759
760     auto task = std::make_unique<DatabaseTableNamesTask>(*this, synchronizer, result);
761     thread.scheduleImmediateTask(WTFMove(task));
762     synchronizer.waitForTaskCompletion();
763
764     return result;
765 }
766
767 SecurityOriginData Database::securityOrigin()
768 {
769     if (m_scriptExecutionContext->isContextThread())
770         return SecurityOriginData::fromSecurityOrigin(m_contextThreadSecurityOrigin.get());
771     if (databaseThread().getThread() == &Thread::current())
772         return SecurityOriginData::fromSecurityOrigin(m_databaseThreadSecurityOrigin.get());
773     RELEASE_ASSERT_NOT_REACHED();
774 }
775
776 unsigned long long Database::maximumSize()
777 {
778     return DatabaseTracker::singleton().maximumSize(*this);
779 }
780
781 void Database::didCommitWriteTransaction()
782 {
783     DatabaseTracker::singleton().scheduleNotifyDatabaseChanged(securityOrigin(), stringIdentifier());
784 }
785
786 bool Database::didExceedQuota()
787 {
788     ASSERT(databaseContext().scriptExecutionContext()->isContextThread());
789     auto& tracker = DatabaseTracker::singleton();
790     auto oldQuota = tracker.quota(securityOrigin());
791     databaseContext().databaseExceededQuota(stringIdentifier(), details());
792     return tracker.quota(securityOrigin()) > oldQuota;
793 }
794
795 #if !LOG_DISABLED || !ERROR_DISABLED
796
797 String Database::databaseDebugName() const
798 {
799     return m_contextThreadSecurityOrigin->toString() + "::" + m_name;
800 }
801
802 #endif
803
804 } // namespace WebCore