d4f687ad592b124af45f79db0dc41cc6fe45ddd0
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / legacy / IDBTransactionBackendOperations.cpp
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
46 namespace WebCore {
47
48 void 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
58 void 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
68 void CreateIndexAbortOperation::perform()
69 {
70     LOG(StorageAPI, "CreateIndexAbortOperation");
71     m_transaction->database().removeIndex(m_objectStoreID, m_indexID);
72 }
73
74 void 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
84 void DeleteIndexAbortOperation::perform()
85 {
86     LOG(StorageAPI, "DeleteIndexAbortOperation");
87     m_transaction->database().addIndex(m_objectStoreID, m_indexMetadata, IDBIndexMetadata::InvalidId);
88 }
89
90 void 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
120 void 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
139 void 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
149 void 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*>(nullptr));
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
172 void 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
188 void 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
205 void 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
226 void 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
236 void IDBDatabaseBackend::VersionChangeOperation::perform(std::function<void()> completionCallback)
237 {
238     LOG(StorageAPI, "VersionChangeOperation");
239
240     uint64_t oldVersion = m_transaction->database().metadata().version;
241     if (oldVersion == IDBDatabaseMetadata::NoIntVersion)
242         oldVersion = 0;
243
244     RefPtr<IDBDatabaseBackend::VersionChangeOperation> operation(this);
245     ASSERT(static_cast<uint64_t>(m_version) > oldVersion);
246
247     std::function<void(PassRefPtr<IDBDatabaseError>)> operationCallback = [oldVersion, operation, this, completionCallback](PassRefPtr<IDBDatabaseError> prpError) {
248         RefPtr<IDBDatabaseError> error = prpError;
249         if (error) {
250             m_callbacks->onError(error);
251             m_transaction->abort(error);
252         } else {
253             ASSERT(!m_transaction->database().hasPendingSecondHalfOpen());
254             m_transaction->database().setCurrentVersion(m_version);
255             m_transaction->database().setPendingSecondHalfOpen(std::make_unique<IDBPendingOpenCall>(*m_callbacks, *m_databaseCallbacks, m_transaction->id(), m_version));
256             m_callbacks->onUpgradeNeeded(oldVersion, &m_transaction->database(), m_transaction->database().metadata());
257         }
258         completionCallback();
259     };
260
261     m_transaction->database().serverConnection().changeDatabaseVersion(*m_transaction, *this, operationCallback);
262 }
263
264 void CreateObjectStoreAbortOperation::perform()
265 {
266     LOG(StorageAPI, "CreateObjectStoreAbortOperation");
267     m_transaction->database().removeObjectStore(m_objectStoreID);
268 }
269
270 void DeleteObjectStoreAbortOperation::perform()
271 {
272     LOG(StorageAPI, "DeleteObjectStoreAbortOperation");
273     m_transaction->database().addObjectStore(m_objectStoreMetadata, IDBObjectStoreMetadata::InvalidId);
274 }
275
276 void IDBDatabaseBackend::VersionChangeAbortOperation::perform()
277 {
278     LOG(StorageAPI, "VersionChangeAbortOperation");
279     m_transaction->database().setCurrentVersion(m_previousIntVersion);
280 }
281
282 } // namespace WebCore
283
284 #endif // ENABLE(INDEXED_DATABASE)