1/* 2 * Copyright (C) 2010 Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "DatabaseSync.h" 33 34#if ENABLE(DATABASE) 35#include "DatabaseCallback.h" 36#include "DatabaseTracker.h" 37#include "Logging.h" 38#include "SQLException.h" 39#include "SQLTransactionSync.h" 40#include "SQLTransactionSyncCallback.h" 41#include "ScriptExecutionContext.h" 42#include "SecurityOrigin.h" 43#include <wtf/PassRefPtr.h> 44#include <wtf/RefPtr.h> 45#include <wtf/text/CString.h> 46 47namespace WebCore { 48 49PassRefPtr<DatabaseSync> DatabaseSync::openDatabaseSync(ScriptExecutionContext* context, const String& name, const String& expectedVersion, const String& displayName, 50 unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback, ExceptionCode& ec) 51{ 52 ASSERT(context->isContextThread()); 53 54 if (!DatabaseTracker::tracker().canEstablishDatabase(context, name, displayName, estimatedSize)) { 55 LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), context->securityOrigin()->toString().ascii().data()); 56 return 0; 57 } 58 59 RefPtr<DatabaseSync> database = adoptRef(new DatabaseSync(context, name, expectedVersion, displayName, estimatedSize)); 60 61 if (!database->performOpenAndVerify(!creationCallback, ec)) { 62 LOG(StorageAPI, "Failed to open and verify version (expected %s) of database %s", expectedVersion.ascii().data(), database->databaseDebugName().ascii().data()); 63 DatabaseTracker::tracker().removeOpenDatabase(database.get()); 64 return 0; 65 } 66 67 DatabaseTracker::tracker().setDatabaseDetails(context->securityOrigin(), name, displayName, estimatedSize); 68 69 if (database->isNew() && creationCallback.get()) { 70 database->m_expectedVersion = ""; 71 LOG(StorageAPI, "Invoking the creation callback for database %p\n", database.get()); 72 creationCallback->handleEvent(database.get()); 73 } 74 75 return database; 76} 77 78DatabaseSync::DatabaseSync(ScriptExecutionContext* context, const String& name, const String& expectedVersion, 79 const String& displayName, unsigned long estimatedSize) 80 : AbstractDatabase(context, name, expectedVersion, displayName, estimatedSize) 81{ 82} 83 84DatabaseSync::~DatabaseSync() 85{ 86 ASSERT(m_scriptExecutionContext->isContextThread()); 87 88 if (opened()) { 89 DatabaseTracker::tracker().removeOpenDatabase(this); 90 closeDatabase(); 91 } 92} 93 94void DatabaseSync::changeVersion(const String& oldVersion, const String& newVersion, PassRefPtr<SQLTransactionSyncCallback> changeVersionCallback, ExceptionCode& ec) 95{ 96 ASSERT(m_scriptExecutionContext->isContextThread()); 97 98 if (sqliteDatabase().transactionInProgress()) { 99 ec = SQLException::DATABASE_ERR; 100 return; 101 } 102 103 RefPtr<SQLTransactionSync> transaction = SQLTransactionSync::create(this, changeVersionCallback, false); 104 if ((ec = transaction->begin())) 105 return; 106 107 String actualVersion; 108 if (!getVersionFromDatabase(actualVersion)) { 109 ec = SQLException::UNKNOWN_ERR; 110 return; 111 } 112 113 if (actualVersion != oldVersion) { 114 ec = SQLException::VERSION_ERR; 115 return; 116 } 117 118 if ((ec = transaction->execute())) 119 return; 120 121 if (!setVersionInDatabase(newVersion)) { 122 ec = SQLException::UNKNOWN_ERR; 123 return; 124 } 125 126 if ((ec = transaction->commit())) 127 return; 128 129 setExpectedVersion(newVersion); 130} 131 132void DatabaseSync::transaction(PassRefPtr<SQLTransactionSyncCallback> callback, ExceptionCode& ec) 133{ 134 runTransaction(callback, false, ec); 135} 136 137void DatabaseSync::readTransaction(PassRefPtr<SQLTransactionSyncCallback> callback, ExceptionCode& ec) 138{ 139 runTransaction(callback, true, ec); 140} 141 142void DatabaseSync::runTransaction(PassRefPtr<SQLTransactionSyncCallback> callback, bool readOnly, ExceptionCode& ec) 143{ 144 ASSERT(m_scriptExecutionContext->isContextThread()); 145 146 if (sqliteDatabase().transactionInProgress()) { 147 ec = SQLException::DATABASE_ERR; 148 return; 149 } 150 151 RefPtr<SQLTransactionSync> transaction = SQLTransactionSync::create(this, callback, readOnly); 152 if ((ec = transaction->begin()) || (ec = transaction->execute()) || (ec = transaction->commit())) 153 transaction->rollback(); 154} 155 156void DatabaseSync::markAsDeletedAndClose() 157{ 158 // FIXME: need to do something similar to closeImmediately(), but in a sync way 159} 160 161class CloseSyncDatabaseOnContextThreadTask : public ScriptExecutionContext::Task { 162public: 163 static PassOwnPtr<CloseSyncDatabaseOnContextThreadTask> create(PassRefPtr<DatabaseSync> database) 164 { 165 return adoptPtr(new CloseSyncDatabaseOnContextThreadTask(database)); 166 } 167 168 virtual void performTask(ScriptExecutionContext*) 169 { 170 m_database->closeImmediately(); 171 } 172 173private: 174 CloseSyncDatabaseOnContextThreadTask(PassRefPtr<DatabaseSync> database) 175 : m_database(database) 176 { 177 } 178 179 RefPtr<DatabaseSync> m_database; 180}; 181 182void DatabaseSync::closeImmediately() 183{ 184 if (!m_scriptExecutionContext->isContextThread()) { 185 m_scriptExecutionContext->postTask(CloseSyncDatabaseOnContextThreadTask::create(this)); 186 return; 187 } 188 189 if (!opened()) 190 return; 191 192 DatabaseTracker::tracker().removeOpenDatabase(this); 193 194 closeDatabase(); 195} 196 197} // namespace WebCore 198 199#endif // ENABLE(DATABASE) 200