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. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "IDBTransactionBackendOperations.h" 28 29#include "IDBCursorBackend.h" 30#include "IDBDatabaseCallbacks.h" 31#include "IDBKeyRange.h" 32#include "IDBRecordIdentifier.h" 33#include "IDBServerConnection.h" 34#include "Logging.h" 35#include <wtf/text/CString.h> 36 37#if ENABLE(INDEXED_DATABASE) 38 39#define STANDARD_DATABASE_ERROR_CALLBACK std::function<void(PassRefPtr<IDBDatabaseError>)> operationCallback = \ 40 [operation, completionCallback](PassRefPtr<IDBDatabaseError> error) { \ 41 if (error) \ 42 operation->m_transaction->abort(error); \ 43 completionCallback(); \ 44 }; 45 46namespace WebCore { 47 48void CreateObjectStoreOperation::perform(std::function<void()> completionCallback) 49{ 50 LOG(StorageAPI, "CreateObjectStoreOperation"); 51 52 RefPtr<CreateObjectStoreOperation> operation(this); 53 STANDARD_DATABASE_ERROR_CALLBACK; 54 55 m_transaction->database().serverConnection().createObjectStore(*m_transaction, *this, operationCallback); 56} 57 58void CreateIndexOperation::perform(std::function<void()> completionCallback) 59{ 60 LOG(StorageAPI, "CreateIndexOperation"); 61 62 RefPtr<CreateIndexOperation> operation(this); 63 STANDARD_DATABASE_ERROR_CALLBACK; 64 65 m_transaction->database().serverConnection().createIndex(*m_transaction, *this, operationCallback); 66} 67 68void CreateIndexAbortOperation::perform() 69{ 70 LOG(StorageAPI, "CreateIndexAbortOperation"); 71 m_transaction->database().removeIndex(m_objectStoreID, m_indexID); 72} 73 74void DeleteIndexOperation::perform(std::function<void()> completionCallback) 75{ 76 LOG(StorageAPI, "DeleteIndexOperation"); 77 78 RefPtr<DeleteIndexOperation> operation(this); 79 STANDARD_DATABASE_ERROR_CALLBACK; 80 81 m_transaction->database().serverConnection().deleteIndex(*m_transaction, *this, operationCallback); 82} 83 84void DeleteIndexAbortOperation::perform() 85{ 86 LOG(StorageAPI, "DeleteIndexAbortOperation"); 87 m_transaction->database().addIndex(m_objectStoreID, m_indexMetadata, IDBIndexMetadata::InvalidId); 88} 89 90void GetOperation::perform(std::function<void()> completionCallback) 91{ 92 LOG(StorageAPI, "GetOperation"); 93 94 RefPtr<GetOperation> operation(this); 95 STANDARD_DATABASE_ERROR_CALLBACK; 96 97 m_transaction->database().serverConnection().get(*m_transaction, *this, [this, operation, operationCallback](const IDBGetResult& result, PassRefPtr<IDBDatabaseError> prpError) { 98 RefPtr<IDBDatabaseError> error = prpError; 99 100 if (error) 101 m_callbacks->onError(error); 102 else { 103 if (!result.valueBuffer) { 104 if (result.keyData.isNull) 105 m_callbacks->onSuccess(); 106 else 107 m_callbacks->onSuccess(result.keyData.maybeCreateIDBKey()); 108 } else { 109 if (!result.keyData.isNull) 110 m_callbacks->onSuccess(result.valueBuffer, result.keyData.maybeCreateIDBKey(), result.keyPath); 111 else 112 m_callbacks->onSuccess(result.valueBuffer.get()); 113 } 114 } 115 116 operationCallback(error.release()); 117 }); 118} 119 120void PutOperation::perform(std::function<void()> completionCallback) 121{ 122 LOG(StorageAPI, "PutOperation"); 123 ASSERT(m_transaction->mode() != IndexedDB::TransactionMode::ReadOnly); 124 ASSERT(m_indexIDs.size() == m_indexKeys.size()); 125 126 m_transaction->database().serverConnection().put(*m_transaction, *this, [this, completionCallback](PassRefPtr<IDBKey> key, PassRefPtr<IDBDatabaseError> prpError) { 127 RefPtr<IDBDatabaseError> error = prpError; 128 if (key) { 129 ASSERT(!error); 130 m_callbacks->onSuccess(key); 131 } else { 132 ASSERT(error); 133 m_callbacks->onError(error); 134 } 135 completionCallback(); 136 }); 137} 138 139void SetIndexesReadyOperation::perform(std::function<void()> completionCallback) 140{ 141 LOG(StorageAPI, "SetIndexesReadyOperation"); 142 143 for (size_t i = 0; i < m_indexCount; ++i) 144 m_transaction->didCompletePreemptiveEvent(); 145 146 callOnMainThread(completionCallback); 147} 148 149void OpenCursorOperation::perform(std::function<void()> completionCallback) 150{ 151 LOG(StorageAPI, "OpenCursorOperation"); 152 153 RefPtr<OpenCursorOperation> operation(this); 154 auto callback = [this, operation, completionCallback](int64_t cursorID, PassRefPtr<IDBKey> key, PassRefPtr<IDBKey> primaryKey, PassRefPtr<SharedBuffer> valueBuffer, PassRefPtr<IDBDatabaseError> error) { 155 if (error) { 156 m_callbacks->onError(error); 157 } else if (!key) { 158 // If there's no error but also no key, then the cursor had no records. 159 m_callbacks->onSuccess(static_cast<SharedBuffer*>(0)); 160 } else { 161 RefPtr<IDBCursorBackend> cursor = IDBCursorBackend::create(cursorID, m_cursorType, m_taskType, *m_transaction, m_objectStoreID); 162 cursor->updateCursorData(key.get(), primaryKey.get(), valueBuffer.get()); 163 m_callbacks->onSuccess(cursor.release()); 164 } 165 166 completionCallback(); 167 }; 168 169 m_transaction->database().serverConnection().openCursor(*m_transaction, *this, callback); 170} 171 172void CountOperation::perform(std::function<void()> completionCallback) 173{ 174 LOG(StorageAPI, "CountOperation"); 175 176 RefPtr<CountOperation> operation(this); 177 auto callback = [this, operation, completionCallback](int64_t count, PassRefPtr<IDBDatabaseError>) { 178 // FIXME: The LevelDB port never had an error condition for the count operation. 179 // We probably need to support an error for the count operation, breaking the LevelDB port. 180 m_callbacks->onSuccess(count); 181 182 completionCallback(); 183 }; 184 185 m_transaction->database().serverConnection().count(*m_transaction, *this, callback); 186} 187 188void DeleteRangeOperation::perform(std::function<void()> completionCallback) 189{ 190 LOG(StorageAPI, "DeleteRangeOperation"); 191 192 RefPtr<DeleteRangeOperation> operation(this); 193 auto callback = [this, operation, completionCallback](PassRefPtr<IDBDatabaseError> error) { 194 if (error) 195 m_callbacks->onError(error); 196 else 197 m_callbacks->onSuccess(); 198 199 completionCallback(); 200 }; 201 202 m_transaction->database().serverConnection().deleteRange(*m_transaction, *this, callback); 203} 204 205void ClearObjectStoreOperation::perform(std::function<void()> completionCallback) 206{ 207 LOG(StorageAPI, "ClearObjectStoreOperation"); 208 209 RefPtr<ClearObjectStoreOperation> operation(this); 210 211 auto clearCallback = [this, operation, completionCallback](PassRefPtr<IDBDatabaseError> prpError) { 212 RefPtr<IDBDatabaseError> error = prpError; 213 214 if (error) { 215 m_callbacks->onError(error); 216 m_transaction->abort(error.release()); 217 } else 218 m_callbacks->onSuccess(); 219 220 completionCallback(); 221 }; 222 223 m_transaction->database().serverConnection().clearObjectStore(*m_transaction, *this, clearCallback); 224} 225 226void DeleteObjectStoreOperation::perform(std::function<void()> completionCallback) 227{ 228 LOG(StorageAPI, "DeleteObjectStoreOperation"); 229 230 RefPtr<DeleteObjectStoreOperation> operation(this); 231 STANDARD_DATABASE_ERROR_CALLBACK; 232 233 m_transaction->database().serverConnection().deleteObjectStore(*m_transaction, *this, operationCallback); 234} 235 236void IDBDatabaseBackend::VersionChangeOperation::perform(std::function<void()> completionCallback) 237{ 238 LOG(StorageAPI, "VersionChangeOperation"); 239 240 uint64_t oldVersion = m_transaction->database().metadata().version; 241 RefPtr<IDBDatabaseBackend::VersionChangeOperation> operation(this); 242 ASSERT(static_cast<uint64_t>(m_version) > oldVersion || oldVersion == IDBDatabaseMetadata::NoIntVersion); 243 244 std::function<void(PassRefPtr<IDBDatabaseError>)> operationCallback = [oldVersion, operation, this, completionCallback](PassRefPtr<IDBDatabaseError> prpError) { 245 RefPtr<IDBDatabaseError> error = prpError; 246 if (error) { 247 m_callbacks->onError(error); 248 m_transaction->abort(error); 249 } else { 250 ASSERT(!m_transaction->database().hasPendingSecondHalfOpen()); 251 m_transaction->database().setCurrentVersion(m_version); 252 m_transaction->database().setPendingSecondHalfOpen(std::make_unique<IDBPendingOpenCall>(*m_callbacks, *m_databaseCallbacks, m_transaction->id(), m_version)); 253 m_callbacks->onUpgradeNeeded(oldVersion, &m_transaction->database(), m_transaction->database().metadata()); 254 } 255 completionCallback(); 256 }; 257 258 m_transaction->database().serverConnection().changeDatabaseVersion(*m_transaction, *this, operationCallback); 259} 260 261void CreateObjectStoreAbortOperation::perform() 262{ 263 LOG(StorageAPI, "CreateObjectStoreAbortOperation"); 264 m_transaction->database().removeObjectStore(m_objectStoreID); 265} 266 267void DeleteObjectStoreAbortOperation::perform() 268{ 269 LOG(StorageAPI, "DeleteObjectStoreAbortOperation"); 270 m_transaction->database().addObjectStore(m_objectStoreMetadata, IDBObjectStoreMetadata::InvalidId); 271} 272 273void IDBDatabaseBackend::VersionChangeAbortOperation::perform() 274{ 275 LOG(StorageAPI, "VersionChangeAbortOperation"); 276 m_transaction->database().setCurrentVersion(m_previousIntVersion); 277} 278 279} // namespace WebCore 280 281#endif // ENABLE(INDEXED_DATABASE) 282