1/*
2 * Copyright (C) 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 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "modules/webdatabase/Database.h"
28
29#include "core/dom/CrossThreadTask.h"
30#include "core/dom/ExceptionCode.h"
31#include "core/html/VoidCallback.h"
32#include "modules/webdatabase/ChangeVersionData.h"
33#include "modules/webdatabase/ChangeVersionWrapper.h"
34#include "modules/webdatabase/DatabaseAuthorizer.h"
35#include "modules/webdatabase/DatabaseContext.h"
36#include "modules/webdatabase/DatabaseManager.h"
37#include "modules/webdatabase/DatabaseTask.h"
38#include "modules/webdatabase/DatabaseThread.h"
39#include "modules/webdatabase/DatabaseTracker.h"
40#include "modules/webdatabase/SQLError.h"
41#include "modules/webdatabase/SQLTransaction.h"
42#include "modules/webdatabase/SQLTransactionBackend.h"
43#include "modules/webdatabase/SQLTransactionCallback.h"
44#include "modules/webdatabase/SQLTransactionClient.h"
45#include "modules/webdatabase/SQLTransactionCoordinator.h"
46#include "modules/webdatabase/SQLTransactionErrorCallback.h"
47#include "modules/webdatabase/sqlite/SQLiteStatement.h"
48#include "modules/webdatabase/sqlite/SQLiteTransaction.h"
49#include "platform/Logging.h"
50#include "platform/weborigin/DatabaseIdentifier.h"
51#include "public/platform/Platform.h"
52#include "public/platform/WebDatabaseObserver.h"
53
54// Registering "opened" databases with the DatabaseTracker
55// =======================================================
56// The DatabaseTracker maintains a list of databases that have been
57// "opened" so that the client can call interrupt or delete on every database
58// associated with a DatabaseContext.
59//
60// We will only call DatabaseTracker::addOpenDatabase() to add the database
61// to the tracker as opened when we've succeeded in opening the database,
62// and will set m_opened to true. Similarly, we only call
63// DatabaseTracker::removeOpenDatabase() to remove the database from the
64// tracker when we set m_opened to false in closeDatabase(). This sets up
65// a simple symmetry between open and close operations, and a direct
66// correlation to adding and removing databases from the tracker's list,
67// thus ensuring that we have a correct list for the interrupt and
68// delete operations to work on.
69//
70// The only databases instances not tracked by the tracker's open database
71// list are the ones that have not been added yet, or the ones that we
72// attempted an open on but failed to. Such instances only exist in the
73// DatabaseServer's factory methods for creating database backends.
74//
75// The factory methods will either call openAndVerifyVersion() or
76// performOpenAndVerify(). These methods will add the newly instantiated
77// database backend if they succeed in opening the requested database.
78// In the case of failure to open the database, the factory methods will
79// simply discard the newly instantiated database backend when they return.
80// The ref counting mechanims will automatically destruct the un-added
81// (and un-returned) databases instances.
82
83namespace blink {
84
85static const char versionKey[] = "WebKitDatabaseVersionKey";
86static const char infoTableName[] = "__WebKitDatabaseInfoTable__";
87
88static String formatErrorMessage(const char* message, int sqliteErrorCode, const char* sqliteErrorMessage)
89{
90    return String::format("%s (%d %s)", message, sqliteErrorCode, sqliteErrorMessage);
91}
92
93static bool retrieveTextResultFromDatabase(SQLiteDatabase& db, const String& query, String& resultString)
94{
95    SQLiteStatement statement(db, query);
96    int result = statement.prepare();
97
98    if (result != SQLResultOk) {
99        WTF_LOG_ERROR("Error (%i) preparing statement to read text result from database (%s)", result, query.ascii().data());
100        return false;
101    }
102
103    result = statement.step();
104    if (result == SQLResultRow) {
105        resultString = statement.getColumnText(0);
106        return true;
107    }
108    if (result == SQLResultDone) {
109        resultString = String();
110        return true;
111    }
112
113    WTF_LOG_ERROR("Error (%i) reading text result from database (%s)", result, query.ascii().data());
114    return false;
115}
116
117static bool setTextValueInDatabase(SQLiteDatabase& db, const String& query, const String& value)
118{
119    SQLiteStatement statement(db, query);
120    int result = statement.prepare();
121
122    if (result != SQLResultOk) {
123        WTF_LOG_ERROR("Failed to prepare statement to set value in database (%s)", query.ascii().data());
124        return false;
125    }
126
127    statement.bindText(1, value);
128
129    result = statement.step();
130    if (result != SQLResultDone) {
131        WTF_LOG_ERROR("Failed to step statement to set value in database (%s)", query.ascii().data());
132        return false;
133    }
134
135    return true;
136}
137
138// FIXME: move all guid-related functions to a DatabaseVersionTracker class.
139static RecursiveMutex& guidMutex()
140{
141    AtomicallyInitializedStatic(RecursiveMutex&, mutex = *new RecursiveMutex);
142    return mutex;
143}
144
145typedef HashMap<DatabaseGuid, String> GuidVersionMap;
146static GuidVersionMap& guidToVersionMap()
147{
148    // Ensure the the mutex is locked.
149    ASSERT(guidMutex().locked());
150    DEFINE_STATIC_LOCAL(GuidVersionMap, map, ());
151    return map;
152}
153
154// NOTE: Caller must lock guidMutex().
155static inline void updateGuidVersionMap(DatabaseGuid guid, String newVersion)
156{
157    // Ensure the the mutex is locked.
158    ASSERT(guidMutex().locked());
159
160    // Note: It is not safe to put an empty string into the guidToVersionMap()
161    // map. That's because the map is cross-thread, but empty strings are
162    // per-thread. The copy() function makes a version of the string you can
163    // use on the current thread, but we need a string we can keep in a
164    // cross-thread data structure.
165    // FIXME: This is a quite-awkward restriction to have to program with.
166
167    // Map null string to empty string (see comment above).
168    guidToVersionMap().set(guid, newVersion.isEmpty() ? String() : newVersion.isolatedCopy());
169}
170
171typedef HashMap<DatabaseGuid, HashSet<Database*>*> GuidDatabaseMap;
172static GuidDatabaseMap& guidToDatabaseMap()
173{
174    // Ensure the the mutex is locked.
175    ASSERT(guidMutex().locked());
176    DEFINE_STATIC_LOCAL(GuidDatabaseMap, map, ());
177    return map;
178}
179
180static DatabaseGuid guidForOriginAndName(const String& origin, const String& name)
181{
182    // Ensure the the mutex is locked.
183    ASSERT(guidMutex().locked());
184
185    String stringID = origin + "/" + name;
186
187    typedef HashMap<String, int> IDGuidMap;
188    DEFINE_STATIC_LOCAL(IDGuidMap, stringIdentifierToGUIDMap, ());
189    DatabaseGuid guid = stringIdentifierToGUIDMap.get(stringID);
190    if (!guid) {
191        static int currentNewGUID = 1;
192        guid = currentNewGUID++;
193        stringIdentifierToGUIDMap.set(stringID, guid);
194    }
195
196    return guid;
197}
198
199Database::Database(DatabaseContext* databaseContext, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
200    : m_databaseContext(databaseContext)
201    , m_name(name.isolatedCopy())
202    , m_expectedVersion(expectedVersion.isolatedCopy())
203    , m_displayName(displayName.isolatedCopy())
204    , m_estimatedSize(estimatedSize)
205    , m_guid(0)
206    , m_opened(false)
207    , m_new(false)
208    , m_transactionInProgress(false)
209    , m_isTransactionQueueEnabled(true)
210{
211    m_contextThreadSecurityOrigin = m_databaseContext->securityOrigin()->isolatedCopy();
212
213    m_databaseAuthorizer = DatabaseAuthorizer::create(infoTableName);
214
215    if (m_name.isNull())
216        m_name = "";
217
218    {
219        SafePointAwareMutexLocker locker(guidMutex());
220        m_guid = guidForOriginAndName(securityOrigin()->toString(), name);
221        HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid);
222        if (!hashSet) {
223            hashSet = new HashSet<Database*>;
224            guidToDatabaseMap().set(m_guid, hashSet);
225        }
226
227        hashSet->add(this);
228    }
229
230    m_filename = DatabaseManager::manager().fullPathForDatabase(securityOrigin(), m_name);
231
232    m_databaseThreadSecurityOrigin = m_contextThreadSecurityOrigin->isolatedCopy();
233    ASSERT(m_databaseContext->databaseThread());
234    ASSERT(m_databaseContext->isContextThread());
235}
236
237Database::~Database()
238{
239    // SQLite is "multi-thread safe", but each database handle can only be used
240    // on a single thread at a time.
241    //
242    // For Database, we open the SQLite database on the DatabaseThread, and
243    // hence we should also close it on that same thread. This means that the
244    // SQLite database need to be closed by another mechanism (see
245    // DatabaseContext::stopDatabases()). By the time we get here, the SQLite
246    // database should have already been closed.
247
248    ASSERT(!m_opened);
249}
250
251void Database::trace(Visitor* visitor)
252{
253    visitor->trace(m_databaseContext);
254    visitor->trace(m_sqliteDatabase);
255    visitor->trace(m_databaseAuthorizer);
256    visitor->trace(m_transactionQueue);
257}
258
259bool Database::openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage)
260{
261    TaskSynchronizer synchronizer;
262    if (!databaseContext()->databaseThreadAvailable())
263        return false;
264
265    DatabaseTracker::tracker().prepareToOpenDatabase(this);
266    bool success = false;
267    OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, setVersionInNewDatabase, &synchronizer, error, errorMessage, success);
268    databaseContext()->databaseThread()->scheduleTask(task.release());
269    synchronizer.waitForTaskCompletion();
270
271    return success;
272}
273
274void Database::close()
275{
276    ASSERT(databaseContext()->databaseThread());
277    ASSERT(databaseContext()->databaseThread()->isDatabaseThread());
278
279    {
280        MutexLocker locker(m_transactionInProgressMutex);
281
282        // Clean up transactions that have not been scheduled yet:
283        // Transaction phase 1 cleanup. See comment on "What happens if a
284        // transaction is interrupted?" at the top of SQLTransactionBackend.cpp.
285        RefPtrWillBeRawPtr<SQLTransactionBackend> transaction = nullptr;
286        while (!m_transactionQueue.isEmpty()) {
287            transaction = m_transactionQueue.takeFirst();
288            transaction->notifyDatabaseThreadIsShuttingDown();
289        }
290
291        m_isTransactionQueueEnabled = false;
292        m_transactionInProgress = false;
293    }
294
295    closeDatabase();
296    databaseContext()->databaseThread()->recordDatabaseClosed(this);
297}
298
299PassRefPtrWillBeRawPtr<SQLTransactionBackend> Database::runTransaction(PassRefPtrWillBeRawPtr<SQLTransaction> transaction,
300    bool readOnly, const ChangeVersionData* data)
301{
302    MutexLocker locker(m_transactionInProgressMutex);
303    if (!m_isTransactionQueueEnabled)
304        return nullptr;
305
306    RefPtrWillBeRawPtr<SQLTransactionWrapper> wrapper = nullptr;
307    if (data)
308        wrapper = ChangeVersionWrapper::create(data->oldVersion(), data->newVersion());
309
310    RefPtrWillBeRawPtr<SQLTransactionBackend> transactionBackend = SQLTransactionBackend::create(this, transaction, wrapper.release(), readOnly);
311    m_transactionQueue.append(transactionBackend);
312    if (!m_transactionInProgress)
313        scheduleTransaction();
314
315    return transactionBackend;
316}
317
318void Database::inProgressTransactionCompleted()
319{
320    MutexLocker locker(m_transactionInProgressMutex);
321    m_transactionInProgress = false;
322    scheduleTransaction();
323}
324
325void Database::scheduleTransaction()
326{
327    ASSERT(!m_transactionInProgressMutex.tryLock()); // Locked by caller.
328    RefPtrWillBeRawPtr<SQLTransactionBackend> transaction = nullptr;
329
330    if (m_isTransactionQueueEnabled && !m_transactionQueue.isEmpty())
331        transaction = m_transactionQueue.takeFirst();
332
333    if (transaction && databaseContext()->databaseThreadAvailable()) {
334        OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
335        WTF_LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for transaction %p\n", task.get(), task->transaction());
336        m_transactionInProgress = true;
337        databaseContext()->databaseThread()->scheduleTask(task.release());
338    } else {
339        m_transactionInProgress = false;
340    }
341}
342
343void Database::scheduleTransactionStep(SQLTransactionBackend* transaction)
344{
345    if (!databaseContext()->databaseThreadAvailable())
346        return;
347
348    OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
349    WTF_LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for the transaction step\n", task.get());
350    databaseContext()->databaseThread()->scheduleTask(task.release());
351}
352
353SQLTransactionClient* Database::transactionClient() const
354{
355    return databaseContext()->databaseThread()->transactionClient();
356}
357
358SQLTransactionCoordinator* Database::transactionCoordinator() const
359{
360    return databaseContext()->databaseThread()->transactionCoordinator();
361}
362
363// static
364const char* Database::databaseInfoTableName()
365{
366    return infoTableName;
367}
368
369void Database::closeDatabase()
370{
371    if (!m_opened)
372        return;
373
374    m_sqliteDatabase.close();
375    m_opened = false;
376    // See comment at the top this file regarding calling removeOpenDatabase().
377    DatabaseTracker::tracker().removeOpenDatabase(this);
378    {
379        SafePointAwareMutexLocker locker(guidMutex());
380
381        HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid);
382        ASSERT(hashSet);
383        ASSERT(hashSet->contains(this));
384        hashSet->remove(this);
385        if (hashSet->isEmpty()) {
386            guidToDatabaseMap().remove(m_guid);
387            delete hashSet;
388            guidToVersionMap().remove(m_guid);
389        }
390    }
391}
392
393String Database::version() const
394{
395    // Note: In multi-process browsers the cached value may be accurate, but we
396    // cannot read the actual version from the database without potentially
397    // inducing a deadlock.
398    // FIXME: Add an async version getter to the DatabaseAPI.
399    return getCachedVersion();
400}
401
402class DoneCreatingDatabaseOnExitCaller {
403public:
404    DoneCreatingDatabaseOnExitCaller(Database* database)
405        : m_database(database)
406        , m_openSucceeded(false)
407    {
408    }
409    ~DoneCreatingDatabaseOnExitCaller()
410    {
411        if (!m_openSucceeded)
412            DatabaseTracker::tracker().failedToOpenDatabase(m_database);
413    }
414
415    void setOpenSucceeded() { m_openSucceeded = true; }
416
417private:
418    Database* m_database;
419    bool m_openSucceeded;
420};
421
422bool Database::performOpenAndVerify(bool shouldSetVersionInNewDatabase, DatabaseError& error, String& errorMessage)
423{
424    DoneCreatingDatabaseOnExitCaller onExitCaller(this);
425    ASSERT(errorMessage.isEmpty());
426    ASSERT(error == DatabaseError::None); // Better not have any errors already.
427    // Presumed failure. We'll clear it if we succeed below.
428    error = DatabaseError::InvalidDatabaseState;
429
430    const int maxSqliteBusyWaitTime = 30000;
431
432    if (!m_sqliteDatabase.open(m_filename, true)) {
433        reportOpenDatabaseResult(1, InvalidStateError, m_sqliteDatabase.lastError());
434        errorMessage = formatErrorMessage("unable to open database", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
435        return false;
436    }
437    if (!m_sqliteDatabase.turnOnIncrementalAutoVacuum())
438        WTF_LOG_ERROR("Unable to turn on incremental auto-vacuum (%d %s)", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
439
440    m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime);
441
442    String currentVersion;
443    {
444        SafePointAwareMutexLocker locker(guidMutex());
445
446        GuidVersionMap::iterator entry = guidToVersionMap().find(m_guid);
447        if (entry != guidToVersionMap().end()) {
448            // Map null string to empty string (see updateGuidVersionMap()).
449            currentVersion = entry->value.isNull() ? emptyString() : entry->value.isolatedCopy();
450            WTF_LOG(StorageAPI, "Current cached version for guid %i is %s", m_guid, currentVersion.ascii().data());
451
452            // Note: In multi-process browsers the cached value may be
453            // inaccurate, but we cannot read the actual version from the
454            // database without potentially inducing a form of deadlock, a
455            // busytimeout error when trying to access the database. So we'll
456            // use the cached value if we're unable to read the value from the
457            // database file without waiting.
458            // FIXME: Add an async openDatabase method to the DatabaseAPI.
459            const int noSqliteBusyWaitTime = 0;
460            m_sqliteDatabase.setBusyTimeout(noSqliteBusyWaitTime);
461            String versionFromDatabase;
462            if (getVersionFromDatabase(versionFromDatabase, false)) {
463                currentVersion = versionFromDatabase;
464                updateGuidVersionMap(m_guid, currentVersion);
465            }
466            m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime);
467        } else {
468            WTF_LOG(StorageAPI, "No cached version for guid %i", m_guid);
469
470            SQLiteTransaction transaction(m_sqliteDatabase);
471            transaction.begin();
472            if (!transaction.inProgress()) {
473                reportOpenDatabaseResult(2, InvalidStateError, m_sqliteDatabase.lastError());
474                errorMessage = formatErrorMessage("unable to open database, failed to start transaction", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
475                m_sqliteDatabase.close();
476                return false;
477            }
478
479            String tableName(infoTableName);
480            if (!m_sqliteDatabase.tableExists(tableName)) {
481                m_new = true;
482
483                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);")) {
484                    reportOpenDatabaseResult(3, InvalidStateError, m_sqliteDatabase.lastError());
485                    errorMessage = formatErrorMessage("unable to open database, failed to create 'info' table", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
486                    transaction.rollback();
487                    m_sqliteDatabase.close();
488                    return false;
489                }
490            } else if (!getVersionFromDatabase(currentVersion, false)) {
491                reportOpenDatabaseResult(4, InvalidStateError, m_sqliteDatabase.lastError());
492                errorMessage = formatErrorMessage("unable to open database, failed to read current version", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
493                transaction.rollback();
494                m_sqliteDatabase.close();
495                return false;
496            }
497
498            if (currentVersion.length()) {
499                WTF_LOG(StorageAPI, "Retrieved current version %s from database %s", currentVersion.ascii().data(), databaseDebugName().ascii().data());
500            } else if (!m_new || shouldSetVersionInNewDatabase) {
501                WTF_LOG(StorageAPI, "Setting version %s in database %s that was just created", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data());
502                if (!setVersionInDatabase(m_expectedVersion, false)) {
503                    reportOpenDatabaseResult(5, InvalidStateError, m_sqliteDatabase.lastError());
504                    errorMessage = formatErrorMessage("unable to open database, failed to write current version", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
505                    transaction.rollback();
506                    m_sqliteDatabase.close();
507                    return false;
508                }
509                currentVersion = m_expectedVersion;
510            }
511            updateGuidVersionMap(m_guid, currentVersion);
512            transaction.commit();
513        }
514    }
515
516    if (currentVersion.isNull()) {
517        WTF_LOG(StorageAPI, "Database %s does not have its version set", databaseDebugName().ascii().data());
518        currentVersion = "";
519    }
520
521    // If the expected version isn't the empty string, ensure that the current
522    // database version we have matches that version. Otherwise, set an
523    // exception.
524    // If the expected version is the empty string, then we always return with
525    // whatever version of the database we have.
526    if ((!m_new || shouldSetVersionInNewDatabase) && m_expectedVersion.length() && m_expectedVersion != currentVersion) {
527        reportOpenDatabaseResult(6, InvalidStateError, 0);
528        errorMessage = "unable to open database, version mismatch, '" + m_expectedVersion + "' does not match the currentVersion of '" + currentVersion + "'";
529        m_sqliteDatabase.close();
530        return false;
531    }
532
533    ASSERT(m_databaseAuthorizer);
534    m_sqliteDatabase.setAuthorizer(m_databaseAuthorizer.get());
535
536    // See comment at the top this file regarding calling addOpenDatabase().
537    DatabaseTracker::tracker().addOpenDatabase(this);
538    m_opened = true;
539
540    // Declare success:
541    error = DatabaseError::None; // Clear the presumed error from above.
542    onExitCaller.setOpenSucceeded();
543
544    if (m_new && !shouldSetVersionInNewDatabase) {
545        // The caller provided a creationCallback which will set the expected
546        // version.
547        m_expectedVersion = "";
548    }
549
550    reportOpenDatabaseResult(0, -1, 0); // OK
551
552    if (databaseContext()->databaseThread())
553        databaseContext()->databaseThread()->recordDatabaseOpen(this);
554    return true;
555}
556
557String Database::stringIdentifier() const
558{
559    // Return a deep copy for ref counting thread safety
560    return m_name.isolatedCopy();
561}
562
563String Database::displayName() const
564{
565    // Return a deep copy for ref counting thread safety
566    return m_displayName.isolatedCopy();
567}
568
569unsigned long Database::estimatedSize() const
570{
571    return m_estimatedSize;
572}
573
574String Database::fileName() const
575{
576    // Return a deep copy for ref counting thread safety
577    return m_filename.isolatedCopy();
578}
579
580bool Database::getVersionFromDatabase(String& version, bool shouldCacheVersion)
581{
582    String query(String("SELECT value FROM ") + infoTableName +  " WHERE key = '" + versionKey + "';");
583
584    m_databaseAuthorizer->disable();
585
586    bool result = retrieveTextResultFromDatabase(m_sqliteDatabase, query, version);
587    if (result) {
588        if (shouldCacheVersion)
589            setCachedVersion(version);
590    } else {
591        WTF_LOG_ERROR("Failed to retrieve version from database %s", databaseDebugName().ascii().data());
592    }
593
594    m_databaseAuthorizer->enable();
595
596    return result;
597}
598
599bool Database::setVersionInDatabase(const String& version, bool shouldCacheVersion)
600{
601    // The INSERT will replace an existing entry for the database with the new
602    // version number, due to the UNIQUE ON CONFLICT REPLACE clause in the
603    // CREATE statement (see Database::performOpenAndVerify()).
604    String query(String("INSERT INTO ") + infoTableName +  " (key, value) VALUES ('" + versionKey + "', ?);");
605
606    m_databaseAuthorizer->disable();
607
608    bool result = setTextValueInDatabase(m_sqliteDatabase, query, version);
609    if (result) {
610        if (shouldCacheVersion)
611            setCachedVersion(version);
612    } else {
613        WTF_LOG_ERROR("Failed to set version %s in database (%s)", version.ascii().data(), query.ascii().data());
614    }
615
616    m_databaseAuthorizer->enable();
617
618    return result;
619}
620
621void Database::setExpectedVersion(const String& version)
622{
623    m_expectedVersion = version.isolatedCopy();
624}
625
626String Database::getCachedVersion() const
627{
628    SafePointAwareMutexLocker locker(guidMutex());
629    return guidToVersionMap().get(m_guid).isolatedCopy();
630}
631
632void Database::setCachedVersion(const String& actualVersion)
633{
634    // Update the in memory database version map.
635    SafePointAwareMutexLocker locker(guidMutex());
636    updateGuidVersionMap(m_guid, actualVersion);
637}
638
639bool Database::getActualVersionForTransaction(String& actualVersion)
640{
641    ASSERT(m_sqliteDatabase.transactionInProgress());
642    // Note: In multi-process browsers the cached value may be inaccurate. So we
643    // retrieve the value from the database and update the cached value here.
644    return getVersionFromDatabase(actualVersion, true);
645}
646
647void Database::disableAuthorizer()
648{
649    ASSERT(m_databaseAuthorizer);
650    m_databaseAuthorizer->disable();
651}
652
653void Database::enableAuthorizer()
654{
655    ASSERT(m_databaseAuthorizer);
656    m_databaseAuthorizer->enable();
657}
658
659void Database::setAuthorizerPermissions(int permissions)
660{
661    ASSERT(m_databaseAuthorizer);
662    m_databaseAuthorizer->setPermissions(permissions);
663}
664
665bool Database::lastActionChangedDatabase()
666{
667    ASSERT(m_databaseAuthorizer);
668    return m_databaseAuthorizer->lastActionChangedDatabase();
669}
670
671bool Database::lastActionWasInsert()
672{
673    ASSERT(m_databaseAuthorizer);
674    return m_databaseAuthorizer->lastActionWasInsert();
675}
676
677void Database::resetDeletes()
678{
679    ASSERT(m_databaseAuthorizer);
680    m_databaseAuthorizer->resetDeletes();
681}
682
683bool Database::hadDeletes()
684{
685    ASSERT(m_databaseAuthorizer);
686    return m_databaseAuthorizer->hadDeletes();
687}
688
689void Database::resetAuthorizer()
690{
691    if (m_databaseAuthorizer)
692        m_databaseAuthorizer->reset();
693}
694
695unsigned long long Database::maximumSize() const
696{
697    return DatabaseTracker::tracker().getMaxSizeForDatabase(this);
698}
699
700void Database::incrementalVacuumIfNeeded()
701{
702    int64_t freeSpaceSize = m_sqliteDatabase.freeSpaceSize();
703    int64_t totalSize = m_sqliteDatabase.totalSize();
704    if (totalSize <= 10 * freeSpaceSize) {
705        int result = m_sqliteDatabase.runIncrementalVacuumCommand();
706        reportVacuumDatabaseResult(result);
707        if (result != SQLResultOk)
708            logErrorMessage(formatErrorMessage("error vacuuming database", result, m_sqliteDatabase.lastErrorMsg()));
709    }
710}
711
712// These are used to generate histograms of errors seen with websql.
713// See about:histograms in chromium.
714void Database::reportOpenDatabaseResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode)
715{
716    if (Platform::current()->databaseObserver()) {
717        Platform::current()->databaseObserver()->reportOpenDatabaseResult(
718            createDatabaseIdentifierFromSecurityOrigin(securityOrigin()),
719            stringIdentifier(), false,
720            errorSite, webSqlErrorCode, sqliteErrorCode);
721    }
722}
723
724void Database::reportChangeVersionResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode)
725{
726    if (Platform::current()->databaseObserver()) {
727        Platform::current()->databaseObserver()->reportChangeVersionResult(
728            createDatabaseIdentifierFromSecurityOrigin(securityOrigin()),
729            stringIdentifier(), false,
730            errorSite, webSqlErrorCode, sqliteErrorCode);
731    }
732}
733
734void Database::reportStartTransactionResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode)
735{
736    if (Platform::current()->databaseObserver()) {
737        Platform::current()->databaseObserver()->reportStartTransactionResult(
738            createDatabaseIdentifierFromSecurityOrigin(securityOrigin()),
739            stringIdentifier(), false,
740            errorSite, webSqlErrorCode, sqliteErrorCode);
741    }
742}
743
744void Database::reportCommitTransactionResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode)
745{
746    if (Platform::current()->databaseObserver()) {
747        Platform::current()->databaseObserver()->reportCommitTransactionResult(
748            createDatabaseIdentifierFromSecurityOrigin(securityOrigin()),
749            stringIdentifier(), false,
750            errorSite, webSqlErrorCode, sqliteErrorCode);
751    }
752}
753
754void Database::reportExecuteStatementResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode)
755{
756    if (Platform::current()->databaseObserver()) {
757        Platform::current()->databaseObserver()->reportExecuteStatementResult(
758            createDatabaseIdentifierFromSecurityOrigin(securityOrigin()),
759            stringIdentifier(), false,
760            errorSite, webSqlErrorCode, sqliteErrorCode);
761    }
762}
763
764void Database::reportVacuumDatabaseResult(int sqliteErrorCode)
765{
766    if (Platform::current()->databaseObserver()) {
767        Platform::current()->databaseObserver()->reportVacuumDatabaseResult(
768            createDatabaseIdentifierFromSecurityOrigin(securityOrigin()),
769            stringIdentifier(), false, sqliteErrorCode);
770    }
771}
772
773void Database::logErrorMessage(const String& message)
774{
775    executionContext()->addConsoleMessage(ConsoleMessage::create(StorageMessageSource, ErrorMessageLevel, message));
776}
777
778ExecutionContext* Database::executionContext() const
779{
780    return databaseContext()->executionContext();
781}
782
783void Database::closeImmediately()
784{
785    ASSERT(executionContext()->isContextThread());
786    if (databaseContext()->databaseThreadAvailable() && opened()) {
787        logErrorMessage("forcibly closing database");
788        databaseContext()->databaseThread()->scheduleTask(DatabaseCloseTask::create(this, 0));
789    }
790}
791
792void Database::changeVersion(
793    const String& oldVersion,
794    const String& newVersion,
795    SQLTransactionCallback* callback,
796    SQLTransactionErrorCallback* errorCallback,
797    VoidCallback* successCallback)
798{
799    ChangeVersionData data(oldVersion, newVersion);
800    runTransaction(callback, errorCallback, successCallback, false, &data);
801}
802
803void Database::transaction(
804    SQLTransactionCallback* callback,
805    SQLTransactionErrorCallback* errorCallback,
806    VoidCallback* successCallback)
807{
808    runTransaction(callback, errorCallback, successCallback, false);
809}
810
811void Database::readTransaction(
812    SQLTransactionCallback* callback,
813    SQLTransactionErrorCallback* errorCallback,
814    VoidCallback* successCallback)
815{
816    runTransaction(callback, errorCallback, successCallback, true);
817}
818
819static void callTransactionErrorCallback(ExecutionContext*, SQLTransactionErrorCallback* callback, PassOwnPtr<SQLErrorData> errorData)
820{
821    RefPtrWillBeRawPtr<SQLError> error = SQLError::create(*errorData);
822    callback->handleEvent(error.get());
823}
824
825void Database::runTransaction(
826    SQLTransactionCallback* callback,
827    SQLTransactionErrorCallback* errorCallback,
828    VoidCallback* successCallback,
829    bool readOnly,
830    const ChangeVersionData* changeVersionData)
831{
832    // FIXME: Rather than passing errorCallback to SQLTransaction and then
833    // sometimes firing it ourselves, this code should probably be pushed down
834    // into Database so that we only create the SQLTransaction if we're
835    // actually going to run it.
836#if ENABLE(ASSERT)
837    SQLTransactionErrorCallback* originalErrorCallback = errorCallback;
838#endif
839    RefPtrWillBeRawPtr<SQLTransaction> transaction = SQLTransaction::create(this, callback, successCallback, errorCallback, readOnly);
840    RefPtrWillBeRawPtr<SQLTransactionBackend> transactionBackend = runTransaction(transaction, readOnly, changeVersionData);
841    if (!transactionBackend) {
842        SQLTransactionErrorCallback* callback = transaction->releaseErrorCallback();
843        ASSERT(callback == originalErrorCallback);
844        if (callback) {
845            OwnPtr<SQLErrorData> error = SQLErrorData::create(SQLError::UNKNOWN_ERR, "database has been closed");
846            executionContext()->postTask(createCrossThreadTask(&callTransactionErrorCallback, callback, error.release()));
847        }
848    }
849}
850
851// This object is constructed in a database thread, and destructed in the
852// context thread.
853class DeliverPendingCallbackTask FINAL : public ExecutionContextTask {
854public:
855    static PassOwnPtr<DeliverPendingCallbackTask> create(PassRefPtrWillBeRawPtr<SQLTransaction> transaction)
856    {
857        return adoptPtr(new DeliverPendingCallbackTask(transaction));
858    }
859
860    virtual void performTask(ExecutionContext*) OVERRIDE
861    {
862        m_transaction->performPendingCallback();
863    }
864
865private:
866    DeliverPendingCallbackTask(PassRefPtrWillBeRawPtr<SQLTransaction> transaction)
867        : m_transaction(transaction)
868    {
869    }
870
871    RefPtrWillBeCrossThreadPersistent<SQLTransaction> m_transaction;
872};
873
874void Database::scheduleTransactionCallback(SQLTransaction* transaction)
875{
876    executionContext()->postTask(DeliverPendingCallbackTask::create(transaction));
877}
878
879Vector<String> Database::performGetTableNames()
880{
881    disableAuthorizer();
882
883    SQLiteStatement statement(sqliteDatabase(), "SELECT name FROM sqlite_master WHERE type='table';");
884    if (statement.prepare() != SQLResultOk) {
885        WTF_LOG_ERROR("Unable to retrieve list of tables for database %s", databaseDebugName().ascii().data());
886        enableAuthorizer();
887        return Vector<String>();
888    }
889
890    Vector<String> tableNames;
891    int result;
892    while ((result = statement.step()) == SQLResultRow) {
893        String name = statement.getColumnText(0);
894        if (name != databaseInfoTableName())
895            tableNames.append(name);
896    }
897
898    enableAuthorizer();
899
900    if (result != SQLResultDone) {
901        WTF_LOG_ERROR("Error getting tables for database %s", databaseDebugName().ascii().data());
902        return Vector<String>();
903    }
904
905    return tableNames;
906}
907
908Vector<String> Database::tableNames()
909{
910    // FIXME: Not using isolatedCopy on these strings looks ok since threads
911    // take strict turns in dealing with them. However, if the code changes,
912    // this may not be true anymore.
913    Vector<String> result;
914    TaskSynchronizer synchronizer;
915    if (!databaseContext()->databaseThreadAvailable())
916        return result;
917
918    OwnPtr<DatabaseTableNamesTask> task = DatabaseTableNamesTask::create(this, &synchronizer, result);
919    databaseContext()->databaseThread()->scheduleTask(task.release());
920    synchronizer.waitForTaskCompletion();
921
922    return result;
923}
924
925SecurityOrigin* Database::securityOrigin() const
926{
927    if (executionContext()->isContextThread())
928        return m_contextThreadSecurityOrigin.get();
929    if (databaseContext()->databaseThread()->isDatabaseThread())
930        return m_databaseThreadSecurityOrigin.get();
931    return 0;
932}
933
934} // namespace blink
935