Home | History | Annotate | Download | only in webdatabase
      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 
     83 namespace blink {
     84 
     85 static const char versionKey[] = "WebKitDatabaseVersionKey";
     86 static const char infoTableName[] = "__WebKitDatabaseInfoTable__";
     87 
     88 static String formatErrorMessage(const char* message, int sqliteErrorCode, const char* sqliteErrorMessage)
     89 {
     90     return String::format("%s (%d %s)", message, sqliteErrorCode, sqliteErrorMessage);
     91 }
     92 
     93 static 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 
    117 static 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.
    139 static RecursiveMutex& guidMutex()
    140 {
    141     AtomicallyInitializedStatic(RecursiveMutex&, mutex = *new RecursiveMutex);
    142     return mutex;
    143 }
    144 
    145 typedef HashMap<DatabaseGuid, String> GuidVersionMap;
    146 static 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().
    155 static 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 
    171 typedef HashMap<DatabaseGuid, HashSet<Database*>*> GuidDatabaseMap;
    172 static 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 
    180 static 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 
    199 Database::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 
    237 Database::~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 
    251 void 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 
    259 bool 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 
    274 void 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 
    299 PassRefPtrWillBeRawPtr<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 
    318 void Database::inProgressTransactionCompleted()
    319 {
    320     MutexLocker locker(m_transactionInProgressMutex);
    321     m_transactionInProgress = false;
    322     scheduleTransaction();
    323 }
    324 
    325 void 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 
    343 void 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 
    353 SQLTransactionClient* Database::transactionClient() const
    354 {
    355     return databaseContext()->databaseThread()->transactionClient();
    356 }
    357 
    358 SQLTransactionCoordinator* Database::transactionCoordinator() const
    359 {
    360     return databaseContext()->databaseThread()->transactionCoordinator();
    361 }
    362 
    363 // static
    364 const char* Database::databaseInfoTableName()
    365 {
    366     return infoTableName;
    367 }
    368 
    369 void 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 
    393 String 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 
    402 class DoneCreatingDatabaseOnExitCaller {
    403 public:
    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 
    417 private:
    418     Database* m_database;
    419     bool m_openSucceeded;
    420 };
    421 
    422 bool 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 
    557 String Database::stringIdentifier() const
    558 {
    559     // Return a deep copy for ref counting thread safety
    560     return m_name.isolatedCopy();
    561 }
    562 
    563 String Database::displayName() const
    564 {
    565     // Return a deep copy for ref counting thread safety
    566     return m_displayName.isolatedCopy();
    567 }
    568 
    569 unsigned long Database::estimatedSize() const
    570 {
    571     return m_estimatedSize;
    572 }
    573 
    574 String Database::fileName() const
    575 {
    576     // Return a deep copy for ref counting thread safety
    577     return m_filename.isolatedCopy();
    578 }
    579 
    580 bool 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 
    599 bool 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 
    621 void Database::setExpectedVersion(const String& version)
    622 {
    623     m_expectedVersion = version.isolatedCopy();
    624 }
    625 
    626 String Database::getCachedVersion() const
    627 {
    628     SafePointAwareMutexLocker locker(guidMutex());
    629     return guidToVersionMap().get(m_guid).isolatedCopy();
    630 }
    631 
    632 void 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 
    639 bool 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 
    647 void Database::disableAuthorizer()
    648 {
    649     ASSERT(m_databaseAuthorizer);
    650     m_databaseAuthorizer->disable();
    651 }
    652 
    653 void Database::enableAuthorizer()
    654 {
    655     ASSERT(m_databaseAuthorizer);
    656     m_databaseAuthorizer->enable();
    657 }
    658 
    659 void Database::setAuthorizerPermissions(int permissions)
    660 {
    661     ASSERT(m_databaseAuthorizer);
    662     m_databaseAuthorizer->setPermissions(permissions);
    663 }
    664 
    665 bool Database::lastActionChangedDatabase()
    666 {
    667     ASSERT(m_databaseAuthorizer);
    668     return m_databaseAuthorizer->lastActionChangedDatabase();
    669 }
    670 
    671 bool Database::lastActionWasInsert()
    672 {
    673     ASSERT(m_databaseAuthorizer);
    674     return m_databaseAuthorizer->lastActionWasInsert();
    675 }
    676 
    677 void Database::resetDeletes()
    678 {
    679     ASSERT(m_databaseAuthorizer);
    680     m_databaseAuthorizer->resetDeletes();
    681 }
    682 
    683 bool Database::hadDeletes()
    684 {
    685     ASSERT(m_databaseAuthorizer);
    686     return m_databaseAuthorizer->hadDeletes();
    687 }
    688 
    689 void Database::resetAuthorizer()
    690 {
    691     if (m_databaseAuthorizer)
    692         m_databaseAuthorizer->reset();
    693 }
    694 
    695 unsigned long long Database::maximumSize() const
    696 {
    697     return DatabaseTracker::tracker().getMaxSizeForDatabase(this);
    698 }
    699 
    700 void 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.
    714 void 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 
    724 void 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 
    734 void 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 
    744 void 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 
    754 void 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 
    764 void 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 
    773 void Database::logErrorMessage(const String& message)
    774 {
    775     executionContext()->addConsoleMessage(ConsoleMessage::create(StorageMessageSource, ErrorMessageLevel, message));
    776 }
    777 
    778 ExecutionContext* Database::executionContext() const
    779 {
    780     return databaseContext()->executionContext();
    781 }
    782 
    783 void 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 
    792 void 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 
    803 void Database::transaction(
    804     SQLTransactionCallback* callback,
    805     SQLTransactionErrorCallback* errorCallback,
    806     VoidCallback* successCallback)
    807 {
    808     runTransaction(callback, errorCallback, successCallback, false);
    809 }
    810 
    811 void Database::readTransaction(
    812     SQLTransactionCallback* callback,
    813     SQLTransactionErrorCallback* errorCallback,
    814     VoidCallback* successCallback)
    815 {
    816     runTransaction(callback, errorCallback, successCallback, true);
    817 }
    818 
    819 static void callTransactionErrorCallback(ExecutionContext*, SQLTransactionErrorCallback* callback, PassOwnPtr<SQLErrorData> errorData)
    820 {
    821     RefPtrWillBeRawPtr<SQLError> error = SQLError::create(*errorData);
    822     callback->handleEvent(error.get());
    823 }
    824 
    825 void 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.
    853 class DeliverPendingCallbackTask FINAL : public ExecutionContextTask {
    854 public:
    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 
    865 private:
    866     DeliverPendingCallbackTask(PassRefPtrWillBeRawPtr<SQLTransaction> transaction)
    867         : m_transaction(transaction)
    868     {
    869     }
    870 
    871     RefPtrWillBeCrossThreadPersistent<SQLTransaction> m_transaction;
    872 };
    873 
    874 void Database::scheduleTransactionCallback(SQLTransaction* transaction)
    875 {
    876     executionContext()->postTask(DeliverPendingCallbackTask::create(transaction));
    877 }
    878 
    879 Vector<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 
    908 Vector<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 
    925 SecurityOrigin* 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