1 /* 2 * Copyright (C) 2007, 2008, 2013 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "config.h" 30 #include "modules/webdatabase/Database.h" 31 32 #include "core/dom/CrossThreadTask.h" 33 #include "core/dom/Document.h" 34 #include "core/dom/ExecutionContext.h" 35 #include "core/html/VoidCallback.h" 36 #include "core/page/Page.h" 37 #include "platform/Logging.h" 38 #include "modules/webdatabase/sqlite/SQLiteStatement.h" 39 #include "modules/webdatabase/ChangeVersionData.h" 40 #include "modules/webdatabase/DatabaseCallback.h" 41 #include "modules/webdatabase/DatabaseContext.h" 42 #include "modules/webdatabase/DatabaseManager.h" 43 #include "modules/webdatabase/DatabaseTask.h" 44 #include "modules/webdatabase/DatabaseThread.h" 45 #include "modules/webdatabase/DatabaseTracker.h" 46 #include "modules/webdatabase/SQLError.h" 47 #include "modules/webdatabase/SQLTransaction.h" 48 #include "modules/webdatabase/SQLTransactionCallback.h" 49 #include "modules/webdatabase/SQLTransactionErrorCallback.h" 50 #include "platform/weborigin/SecurityOrigin.h" 51 #include "wtf/OwnPtr.h" 52 #include "wtf/PassOwnPtr.h" 53 #include "wtf/PassRefPtr.h" 54 #include "wtf/RefPtr.h" 55 #include "wtf/StdLibExtras.h" 56 #include "wtf/text/CString.h" 57 58 namespace WebCore { 59 60 PassRefPtr<Database> Database::create(ExecutionContext*, PassRefPtr<DatabaseBackendBase> backend) 61 { 62 // FIXME: Currently, we're only simulating the backend by return the 63 // frontend database as its own the backend. When we split the 2 apart, 64 // this create() function should be changed to be a factory method for 65 // instantiating the backend. 66 return static_cast<Database*>(backend.get()); 67 } 68 69 Database::Database(PassRefPtr<DatabaseContext> databaseContext, 70 const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize) 71 : DatabaseBase(databaseContext->executionContext()) 72 , DatabaseBackend(databaseContext, name, expectedVersion, displayName, estimatedSize) 73 , m_databaseContext(DatabaseBackend::databaseContext()) 74 { 75 ScriptWrappable::init(this); 76 m_databaseThreadSecurityOrigin = m_contextThreadSecurityOrigin->isolatedCopy(); 77 setFrontend(this); 78 79 ASSERT(m_databaseContext->databaseThread()); 80 } 81 82 class DerefContextTask : public ExecutionContextTask { 83 public: 84 static PassOwnPtr<DerefContextTask> create(PassRefPtr<ExecutionContext> context) 85 { 86 return adoptPtr(new DerefContextTask(context)); 87 } 88 89 virtual void performTask(ExecutionContext* context) 90 { 91 ASSERT_UNUSED(context, context == m_context); 92 m_context.clear(); 93 } 94 95 virtual bool isCleanupTask() const { return true; } 96 97 private: 98 DerefContextTask(PassRefPtr<ExecutionContext> context) 99 : m_context(context) 100 { 101 } 102 103 RefPtr<ExecutionContext> m_context; 104 }; 105 106 Database::~Database() 107 { 108 // The reference to the ExecutionContext needs to be cleared on the JavaScript thread. If we're on that thread already, we can just let the RefPtr's destruction do the dereffing. 109 if (!m_executionContext->isContextThread()) { 110 // Grab a pointer to the script execution here because we're releasing it when we pass it to 111 // DerefContextTask::create. 112 ExecutionContext* executionContext = m_executionContext.get(); 113 114 executionContext->postTask(DerefContextTask::create(m_executionContext.release())); 115 } 116 } 117 118 Database* Database::from(DatabaseBackend* backend) 119 { 120 return static_cast<Database*>(backend->m_frontend); 121 } 122 123 PassRefPtr<DatabaseBackend> Database::backend() 124 { 125 return this; 126 } 127 128 String Database::version() const 129 { 130 return DatabaseBackendBase::version(); 131 } 132 133 void Database::closeImmediately() 134 { 135 ASSERT(m_executionContext->isContextThread()); 136 DatabaseThread* databaseThread = databaseContext()->databaseThread(); 137 if (databaseThread && !databaseThread->terminationRequested() && opened()) { 138 logErrorMessage("forcibly closing database"); 139 databaseThread->scheduleTask(DatabaseCloseTask::create(this, 0)); 140 } 141 } 142 143 void Database::changeVersion(const String& oldVersion, const String& newVersion, PassOwnPtr<SQLTransactionCallback> callback, PassOwnPtr<SQLTransactionErrorCallback> errorCallback, PassOwnPtr<VoidCallback> successCallback) 144 { 145 ChangeVersionData data(oldVersion, newVersion); 146 runTransaction(callback, errorCallback, successCallback, false, &data); 147 } 148 149 void Database::transaction(PassOwnPtr<SQLTransactionCallback> callback, PassOwnPtr<SQLTransactionErrorCallback> errorCallback, PassOwnPtr<VoidCallback> successCallback) 150 { 151 runTransaction(callback, errorCallback, successCallback, false); 152 } 153 154 void Database::readTransaction(PassOwnPtr<SQLTransactionCallback> callback, PassOwnPtr<SQLTransactionErrorCallback> errorCallback, PassOwnPtr<VoidCallback> successCallback) 155 { 156 runTransaction(callback, errorCallback, successCallback, true); 157 } 158 159 static void callTransactionErrorCallback(ExecutionContext*, PassOwnPtr<SQLTransactionErrorCallback> callback, PassRefPtr<SQLError> error) 160 { 161 callback->handleEvent(error.get()); 162 } 163 164 void Database::runTransaction(PassOwnPtr<SQLTransactionCallback> callback, PassOwnPtr<SQLTransactionErrorCallback> errorCallback, 165 PassOwnPtr<VoidCallback> successCallback, bool readOnly, const ChangeVersionData* changeVersionData) 166 { 167 // FIXME: Rather than passing errorCallback to SQLTransaction and then sometimes firing it ourselves, 168 // this code should probably be pushed down into DatabaseBackend so that we only create the SQLTransaction 169 // if we're actually going to run it. 170 #if !ASSERT_DISABLED 171 SQLTransactionErrorCallback* originalErrorCallback = errorCallback.get(); 172 #endif 173 RefPtr<SQLTransaction> transaction = SQLTransaction::create(this, callback, successCallback, errorCallback, readOnly); 174 RefPtr<SQLTransactionBackend> transactionBackend = backend()->runTransaction(transaction, readOnly, changeVersionData); 175 if (!transactionBackend) { 176 OwnPtr<SQLTransactionErrorCallback> callback = transaction->releaseErrorCallback(); 177 ASSERT(callback == originalErrorCallback); 178 if (callback) { 179 RefPtr<SQLError> error = SQLError::create(SQLError::UNKNOWN_ERR, "database has been closed"); 180 executionContext()->postTask(createCallbackTask(&callTransactionErrorCallback, callback.release(), error.release())); 181 } 182 } 183 } 184 185 class DeliverPendingCallbackTask : public ExecutionContextTask { 186 public: 187 static PassOwnPtr<DeliverPendingCallbackTask> create(PassRefPtr<SQLTransaction> transaction) 188 { 189 return adoptPtr(new DeliverPendingCallbackTask(transaction)); 190 } 191 192 virtual void performTask(ExecutionContext*) 193 { 194 m_transaction->performPendingCallback(); 195 } 196 197 private: 198 DeliverPendingCallbackTask(PassRefPtr<SQLTransaction> transaction) 199 : m_transaction(transaction) 200 { 201 } 202 203 RefPtr<SQLTransaction> m_transaction; 204 }; 205 206 void Database::scheduleTransactionCallback(SQLTransaction* transaction) 207 { 208 m_executionContext->postTask(DeliverPendingCallbackTask::create(transaction)); 209 } 210 211 Vector<String> Database::performGetTableNames() 212 { 213 disableAuthorizer(); 214 215 SQLiteStatement statement(sqliteDatabase(), "SELECT name FROM sqlite_master WHERE type='table';"); 216 if (statement.prepare() != SQLResultOk) { 217 WTF_LOG_ERROR("Unable to retrieve list of tables for database %s", databaseDebugName().ascii().data()); 218 enableAuthorizer(); 219 return Vector<String>(); 220 } 221 222 Vector<String> tableNames; 223 int result; 224 while ((result = statement.step()) == SQLResultRow) { 225 String name = statement.getColumnText(0); 226 if (name != databaseInfoTableName()) 227 tableNames.append(name); 228 } 229 230 enableAuthorizer(); 231 232 if (result != SQLResultDone) { 233 WTF_LOG_ERROR("Error getting tables for database %s", databaseDebugName().ascii().data()); 234 return Vector<String>(); 235 } 236 237 return tableNames; 238 } 239 240 Vector<String> Database::tableNames() 241 { 242 // FIXME: Not using isolatedCopy on these strings looks ok since threads take strict turns 243 // in dealing with them. However, if the code changes, this may not be true anymore. 244 Vector<String> result; 245 DatabaseTaskSynchronizer synchronizer; 246 if (!databaseContext()->databaseThread() || databaseContext()->databaseThread()->terminationRequested(&synchronizer)) 247 return result; 248 249 OwnPtr<DatabaseTableNamesTask> task = DatabaseTableNamesTask::create(this, &synchronizer, result); 250 databaseContext()->databaseThread()->scheduleTask(task.release()); 251 synchronizer.waitForTaskCompletion(); 252 253 return result; 254 } 255 256 SecurityOrigin* Database::securityOrigin() const 257 { 258 if (m_executionContext->isContextThread()) 259 return m_contextThreadSecurityOrigin.get(); 260 if (databaseContext()->databaseThread()->isDatabaseThread()) 261 return m_databaseThreadSecurityOrigin.get(); 262 return 0; 263 } 264 265 void Database::reportStartTransactionResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode) 266 { 267 backend()->reportStartTransactionResult(errorSite, webSqlErrorCode, sqliteErrorCode); 268 } 269 270 void Database::reportCommitTransactionResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode) 271 { 272 backend()->reportCommitTransactionResult(errorSite, webSqlErrorCode, sqliteErrorCode); 273 } 274 275 276 } // namespace WebCore 277