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 47 namespace WebCore { 48 49 PassRefPtr<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 78 DatabaseSync::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 84 DatabaseSync::~DatabaseSync() 85 { 86 ASSERT(m_scriptExecutionContext->isContextThread()); 87 88 if (opened()) { 89 DatabaseTracker::tracker().removeOpenDatabase(this); 90 closeDatabase(); 91 } 92 } 93 94 void 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 132 void DatabaseSync::transaction(PassRefPtr<SQLTransactionSyncCallback> callback, ExceptionCode& ec) 133 { 134 runTransaction(callback, false, ec); 135 } 136 137 void DatabaseSync::readTransaction(PassRefPtr<SQLTransactionSyncCallback> callback, ExceptionCode& ec) 138 { 139 runTransaction(callback, true, ec); 140 } 141 142 void 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 156 void DatabaseSync::markAsDeletedAndClose() 157 { 158 // FIXME: need to do something similar to closeImmediately(), but in a sync way 159 } 160 161 class CloseSyncDatabaseOnContextThreadTask : public ScriptExecutionContext::Task { 162 public: 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 173 private: 174 CloseSyncDatabaseOnContextThreadTask(PassRefPtr<DatabaseSync> database) 175 : m_database(database) 176 { 177 } 178 179 RefPtr<DatabaseSync> m_database; 180 }; 181 182 void 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