IDB: indexeddb/mozilla/add-twice-failure.html fails
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / 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<IDBKey> valueKey, PassRefPtr<IDBDatabaseError>) {
155         // FIXME: When the LevelDB port fails to open a backing store cursor it calls onSuccess(nullptr);
156         // This seems nonsensical and might have to change soon, breaking them.
157         if (!cursorID)
158             m_callbacks->onSuccess(static_cast<SharedBuffer*>(0));
159         else {
160             RefPtr<IDBCursorBackend> cursor = IDBCursorBackend::create(cursorID, m_cursorType, m_taskType, *m_transaction, m_objectStoreID);
161             if (key || primaryKey || valueBuffer || valueKey)
162                 cursor->updateCursorData(key.get(), primaryKey.get(), valueBuffer.get(), valueKey.get());
163
164             m_callbacks->onSuccess(cursor.release());
165         }
166
167         completionCallback();
168     };
169
170     m_transaction->database().serverConnection().openCursor(*m_transaction, *this, callback);
171 }
172
173 void CountOperation::perform(std::function<void()> completionCallback)
174 {
175     LOG(StorageAPI, "CountOperation");
176
177     RefPtr<CountOperation> operation(this);
178     auto callback = [this, operation, completionCallback](int64_t count, PassRefPtr<IDBDatabaseError>) {
179         // FIXME: The LevelDB port never had an error condition for the count operation.
180         // We probably need to support an error for the count operation, breaking the LevelDB port.
181         m_callbacks->onSuccess(count);
182
183         completionCallback();
184     };
185
186     m_transaction->database().serverConnection().count(*m_transaction, *this, callback);
187 }
188
189 void DeleteRangeOperation::perform(std::function<void()> completionCallback)
190 {
191     LOG(StorageAPI, "DeleteRangeOperation");
192
193     RefPtr<DeleteRangeOperation> operation(this);
194     auto callback = [this, operation, completionCallback](PassRefPtr<IDBDatabaseError> error) {
195         if (error)
196             m_callbacks->onError(error);
197         else
198             m_callbacks->onSuccess();
199
200         completionCallback();
201     };
202
203     m_transaction->database().serverConnection().deleteRange(*m_transaction, *this, callback);
204 }
205
206 void ClearObjectStoreOperation::perform(std::function<void()> completionCallback)
207 {
208     LOG(StorageAPI, "ClearObjectStoreOperation");
209
210     RefPtr<ClearObjectStoreOperation> operation(this);
211
212     auto clearCallback = [this, operation, completionCallback](PassRefPtr<IDBDatabaseError> prpError) {
213         RefPtr<IDBDatabaseError> error = prpError;
214
215         if (error) {
216             m_callbacks->onError(error);
217             m_transaction->abort(error.release());
218         } else
219             m_callbacks->onSuccess();
220
221         completionCallback();
222     };
223
224     m_transaction->database().serverConnection().clearObjectStore(*m_transaction, *this, clearCallback);
225 }
226
227 void DeleteObjectStoreOperation::perform(std::function<void()> completionCallback)
228 {
229     LOG(StorageAPI, "DeleteObjectStoreOperation");
230
231     RefPtr<DeleteObjectStoreOperation> operation(this);
232     STANDARD_DATABASE_ERROR_CALLBACK;
233
234     m_transaction->database().serverConnection().deleteObjectStore(*m_transaction, *this, operationCallback);
235 }
236
237 void IDBDatabaseBackend::VersionChangeOperation::perform(std::function<void()> completionCallback)
238 {
239     LOG(StorageAPI, "VersionChangeOperation");
240
241     uint64_t oldVersion = m_transaction->database().metadata().version;
242     RefPtr<IDBDatabaseBackend::VersionChangeOperation> operation(this);
243     ASSERT(static_cast<uint64_t>(m_version) > oldVersion || oldVersion == IDBDatabaseMetadata::NoIntVersion);
244
245     std::function<void(PassRefPtr<IDBDatabaseError>)> operationCallback = [oldVersion, operation, this, completionCallback](PassRefPtr<IDBDatabaseError> prpError) {
246         RefPtr<IDBDatabaseError> error = prpError;
247         if (error) {
248             m_callbacks->onError(error);
249             m_transaction->abort(error);
250         } else {
251             ASSERT(!m_transaction->database().hasPendingSecondHalfOpen());
252             m_transaction->database().setCurrentVersion(m_version);
253             m_transaction->database().setPendingSecondHalfOpen(IDBPendingOpenCall::create(*m_callbacks, *m_databaseCallbacks, m_transaction->id(), m_version));
254             m_callbacks->onUpgradeNeeded(oldVersion, &m_transaction->database(), m_transaction->database().metadata());
255         }
256         completionCallback();
257     };
258
259     m_transaction->database().serverConnection().changeDatabaseVersion(*m_transaction, *this, operationCallback);
260 }
261
262 void CreateObjectStoreAbortOperation::perform()
263 {
264     LOG(StorageAPI, "CreateObjectStoreAbortOperation");
265     m_transaction->database().removeObjectStore(m_objectStoreID);
266 }
267
268 void DeleteObjectStoreAbortOperation::perform()
269 {
270     LOG(StorageAPI, "DeleteObjectStoreAbortOperation");
271     m_transaction->database().addObjectStore(m_objectStoreMetadata, IDBObjectStoreMetadata::InvalidId);
272 }
273
274 void IDBDatabaseBackend::VersionChangeAbortOperation::perform()
275 {
276     LOG(StorageAPI, "VersionChangeAbortOperation");
277     m_transaction->database().setCurrentVersion(m_previousIntVersion);
278 }
279
280 } // namespace WebCore
281
282 #endif // ENABLE(INDEXED_DATABASE)