Move basic IDBBackingStoreTransaction operations to IDBServerConnection
[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 "IDBIndexWriter.h"
32 #include "IDBKeyRange.h"
33 #include "IDBRecordIdentifier.h"
34 #include "Logging.h"
35 #include <wtf/text/CString.h>
36
37 #if ENABLE(INDEXED_DATABASE)
38
39 namespace WebCore {
40
41 class CallOnDestruct {
42 public:
43     CallOnDestruct(std::function<void()> callback)
44         : m_callback(callback)
45     { }
46
47     ~CallOnDestruct()
48     {
49         m_callback();
50     }
51
52 private:
53     std::function<void()> m_callback;
54 };
55
56 void CreateObjectStoreOperation::perform(std::function<void()> completionCallback)
57 {
58     CallOnDestruct callOnDestruct(completionCallback);
59
60     LOG(StorageAPI, "CreateObjectStoreOperation");
61     if (!m_transaction->database().serverConnection().deprecatedBackingStore()->createObjectStore(m_transaction->deprecatedBackingStoreTransaction(), m_transaction->database().id(), m_objectStoreMetadata.id, m_objectStoreMetadata.name, m_objectStoreMetadata.keyPath, m_objectStoreMetadata.autoIncrement)) {
62         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error creating object store '%s'.", m_objectStoreMetadata.name.utf8().data()));
63         m_transaction->abort(error.release());
64         return;
65     }
66 }
67
68 void CreateIndexOperation::perform(std::function<void()> completionCallback)
69 {
70     CallOnDestruct callOnDestruct(completionCallback);
71
72     LOG(StorageAPI, "CreateIndexOperation");
73     if (!m_transaction->database().serverConnection().deprecatedBackingStore()->createIndex(m_transaction->deprecatedBackingStoreTransaction(), m_transaction->database().id(), m_objectStoreId, m_indexMetadata.id, m_indexMetadata.name, m_indexMetadata.keyPath, m_indexMetadata.unique, m_indexMetadata.multiEntry)) {
74         m_transaction->abort(IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error when trying to create index '%s'.", m_indexMetadata.name.utf8().data())));
75         return;
76     }
77 }
78
79 void CreateIndexAbortOperation::perform()
80 {
81     LOG(StorageAPI, "CreateIndexAbortOperation");
82     m_transaction->database().removeIndex(m_objectStoreId, m_indexId);
83 }
84
85 void DeleteIndexOperation::perform(std::function<void()> completionCallback)
86 {
87     CallOnDestruct callOnDestruct(completionCallback);
88
89     LOG(StorageAPI, "DeleteIndexOperation");
90     bool ok = m_transaction->database().serverConnection().deprecatedBackingStore()->deleteIndex(m_transaction->deprecatedBackingStoreTransaction(), m_transaction->database().id(), m_objectStoreId, m_indexMetadata.id);
91     if (!ok) {
92         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error deleting index '%s'.", m_indexMetadata.name.utf8().data()));
93         m_transaction->abort(error);
94     }
95 }
96
97 void DeleteIndexAbortOperation::perform()
98 {
99     LOG(StorageAPI, "DeleteIndexAbortOperation");
100     m_transaction->database().addIndex(m_objectStoreId, m_indexMetadata, IDBIndexMetadata::InvalidId);
101 }
102
103 void GetOperation::perform(std::function<void()> completionCallback)
104 {
105     CallOnDestruct callOnDestruct(completionCallback);
106
107     LOG(StorageAPI, "GetOperation");
108
109     RefPtr<IDBKey> key;
110
111     if (m_keyRange->isOnlyKey())
112         key = m_keyRange->lower();
113     else {
114         RefPtr<IDBBackingStoreCursorInterface> backingStoreCursor;
115         if (m_indexId == IDBIndexMetadata::InvalidId) {
116             ASSERT(m_cursorType != IndexedDB::CursorKeyOnly);
117             // ObjectStore Retrieval Operation
118             backingStoreCursor = m_transaction->database().serverConnection().deprecatedBackingStore()->openObjectStoreCursor(m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), IndexedDB::CursorNext);
119         } else {
120             if (m_cursorType == IndexedDB::CursorKeyOnly) {
121                 // Index Value Retrieval Operation
122                 backingStoreCursor = m_transaction->database().serverConnection().deprecatedBackingStore()->openIndexKeyCursor(m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IndexedDB::CursorNext);
123             } else {
124                 // Index Referenced Value Retrieval Operation
125                 backingStoreCursor = m_transaction->database().serverConnection().deprecatedBackingStore()->openIndexCursor(m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IndexedDB::CursorNext);
126             }
127         }
128
129         if (!backingStoreCursor) {
130             m_callbacks->onSuccess();
131             return;
132         }
133
134         key = backingStoreCursor->key();
135     }
136
137     RefPtr<IDBKey> primaryKey;
138     bool ok;
139     if (m_indexId == IDBIndexMetadata::InvalidId) {
140         // Object Store Retrieval Operation
141         Vector<char> value;
142         ok = m_transaction->database().serverConnection().deprecatedBackingStore()->getRecord(m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStoreId, *key, value);
143         if (!ok) {
144             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getRecord."));
145             return;
146         }
147
148         if (value.isEmpty()) {
149             m_callbacks->onSuccess();
150             return;
151         }
152
153         if (m_autoIncrement && !m_keyPath.isNull()) {
154             m_callbacks->onSuccess(SharedBuffer::adoptVector(value), key, m_keyPath);
155             return;
156         }
157
158         m_callbacks->onSuccess(SharedBuffer::adoptVector(value));
159         return;
160
161     }
162
163     // From here we are dealing only with indexes.
164     ok = m_transaction->database().serverConnection().deprecatedBackingStore()->getPrimaryKeyViaIndex(m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, *key, primaryKey);
165     if (!ok) {
166         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getPrimaryKeyViaIndex."));
167         return;
168     }
169     if (!primaryKey) {
170         m_callbacks->onSuccess();
171         return;
172     }
173     if (m_cursorType == IndexedDB::CursorKeyOnly) {
174         // Index Value Retrieval Operation
175         m_callbacks->onSuccess(primaryKey.get());
176         return;
177     }
178
179     // Index Referenced Value Retrieval Operation
180     Vector<char> value;
181     ok = m_transaction->database().serverConnection().deprecatedBackingStore()->getRecord(m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStoreId, *primaryKey, value);
182     if (!ok) {
183         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getRecord."));
184         return;
185     }
186
187     if (value.isEmpty()) {
188         m_callbacks->onSuccess();
189         return;
190     }
191     if (m_autoIncrement && !m_keyPath.isNull()) {
192         m_callbacks->onSuccess(SharedBuffer::adoptVector(value), primaryKey, m_keyPath);
193         return;
194     }
195     m_callbacks->onSuccess(SharedBuffer::adoptVector(value));
196 }
197
198 void PutOperation::perform(std::function<void()> completionCallback)
199 {
200     CallOnDestruct callOnDestruct(completionCallback);
201
202     LOG(StorageAPI, "PutOperation");
203     ASSERT(m_transaction->mode() != IndexedDB::TransactionReadOnly);
204     ASSERT(m_indexIds.size() == m_indexKeys.size());
205     bool keyWasGenerated = false;
206
207     RefPtr<IDBKey> key;
208     if (m_putMode != IDBDatabaseBackend::CursorUpdate && m_objectStore.autoIncrement && !m_key) {
209         RefPtr<IDBKey> autoIncKey = m_transaction->database().serverConnection().deprecatedBackingStore()->generateKey(*m_transaction, m_databaseId, m_objectStore.id);
210         keyWasGenerated = true;
211         if (!autoIncKey->isValid()) {
212             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Maximum key generator value reached."));
213             return;
214         }
215         key = autoIncKey;
216     } else
217         key = m_key;
218
219     ASSERT(key);
220     ASSERT(key->isValid());
221
222     RefPtr<IDBRecordIdentifier> recordIdentifier;
223     if (m_putMode == IDBDatabaseBackend::AddOnly) {
224         bool ok = m_transaction->database().serverConnection().deprecatedBackingStore()->keyExistsInObjectStore(m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStore.id, *key, recordIdentifier);
225         if (!ok) {
226             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error checking key existence."));
227             return;
228         }
229         if (recordIdentifier) {
230             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Key already exists in the object store."));
231             return;
232         }
233     }
234
235     Vector<RefPtr<IDBIndexWriter>> indexWriters;
236     String errorMessage;
237     bool obeysConstraints = false;
238     bool backingStoreSuccess = m_transaction->database().serverConnection().deprecatedBackingStore()->makeIndexWriters(*m_transaction, m_databaseId, m_objectStore, *key, keyWasGenerated, m_indexIds, m_indexKeys, indexWriters, &errorMessage, obeysConstraints);
239     if (!backingStoreSuccess) {
240         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error updating index keys."));
241         return;
242     }
243     if (!obeysConstraints) {
244         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, errorMessage));
245         return;
246     }
247
248     // Before this point, don't do any mutation. After this point, rollback the transaction in case of error.
249     backingStoreSuccess = m_transaction->database().serverConnection().deprecatedBackingStore()->putRecord(m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStore.id, *key, m_value, recordIdentifier.get());
250     if (!backingStoreSuccess) {
251         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error performing put/add."));
252         return;
253     }
254
255     for (size_t i = 0; i < indexWriters.size(); ++i) {
256         IDBIndexWriter* indexWriter = indexWriters[i].get();
257         indexWriter->writeIndexKeys(recordIdentifier.get(), *m_transaction->database().serverConnection().deprecatedBackingStore(), m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStore.id);
258     }
259
260     if (m_objectStore.autoIncrement && m_putMode != IDBDatabaseBackend::CursorUpdate && key->type() == IDBKey::NumberType) {
261         bool ok = m_transaction->database().serverConnection().deprecatedBackingStore()->updateKeyGenerator(*m_transaction, m_databaseId, m_objectStore.id, *key, !keyWasGenerated);
262         if (!ok) {
263             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error updating key generator."));
264             return;
265         }
266     }
267
268     m_callbacks->onSuccess(key.release());
269 }
270
271 void SetIndexesReadyOperation::perform(std::function<void()> completionCallback)
272 {
273     CallOnDestruct callOnDestruct(completionCallback);
274
275     LOG(StorageAPI, "SetIndexesReadyOperation");
276     for (size_t i = 0; i < m_indexCount; ++i)
277         m_transaction->didCompletePreemptiveEvent();
278 }
279
280 void OpenCursorOperation::perform(std::function<void()> completionCallback)
281 {
282     CallOnDestruct callOnDestruct(completionCallback);
283
284     LOG(StorageAPI, "OpenCursorOperation");
285
286     // The frontend has begun indexing, so this pauses the transaction
287     // until the indexing is complete. This can't happen any earlier
288     // because we don't want to switch to early mode in case multiple
289     // indexes are being created in a row, with put()'s in between.
290     if (m_taskType == IDBDatabaseBackend::PreemptiveTask)
291         m_transaction->addPreemptiveEvent();
292
293     RefPtr<IDBBackingStoreCursorInterface> backingStoreCursor;
294     if (m_indexId == IDBIndexMetadata::InvalidId) {
295         ASSERT(m_cursorType != IndexedDB::CursorKeyOnly);
296         backingStoreCursor = m_transaction->database().serverConnection().deprecatedBackingStore()->openObjectStoreCursor(m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), m_direction);
297     } else {
298         ASSERT(m_taskType == IDBDatabaseBackend::NormalTask);
299         if (m_cursorType == IndexedDB::CursorKeyOnly)
300             backingStoreCursor = m_transaction->database().serverConnection().deprecatedBackingStore()->openIndexKeyCursor(m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), m_direction);
301         else
302             backingStoreCursor = m_transaction->database().serverConnection().deprecatedBackingStore()->openIndexCursor(m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), m_direction);
303     }
304
305     if (!backingStoreCursor) {
306         m_callbacks->onSuccess(static_cast<SharedBuffer*>(0));
307         return;
308     }
309
310     IDBDatabaseBackend::TaskType taskType(static_cast<IDBDatabaseBackend::TaskType>(m_taskType));
311
312     RefPtr<IDBCursorBackend> cursor = m_transaction->createCursorBackend(*backingStoreCursor, m_cursorType, taskType, m_objectStoreId);
313     m_callbacks->onSuccess(cursor, cursor->key(), cursor->primaryKey(), cursor->value());
314 }
315
316 void CountOperation::perform(std::function<void()> completionCallback)
317 {
318     CallOnDestruct callOnDestruct(completionCallback);
319
320     LOG(StorageAPI, "CountOperation");
321     uint32_t count = 0;
322     RefPtr<IDBBackingStoreCursorInterface> backingStoreCursor;
323
324     if (m_indexId == IDBIndexMetadata::InvalidId)
325         backingStoreCursor = m_transaction->database().serverConnection().deprecatedBackingStore()->openObjectStoreKeyCursor(m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), IndexedDB::CursorNext);
326     else
327         backingStoreCursor = m_transaction->database().serverConnection().deprecatedBackingStore()->openIndexKeyCursor(m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IndexedDB::CursorNext);
328     if (!backingStoreCursor) {
329         m_callbacks->onSuccess(count);
330         return;
331     }
332
333     do {
334         ++count;
335     } while (backingStoreCursor->continueFunction(0));
336
337     m_callbacks->onSuccess(count);
338 }
339
340 void DeleteRangeOperation::perform(std::function<void()> completionCallback)
341 {
342     CallOnDestruct callOnDestruct(completionCallback);
343
344     LOG(StorageAPI, "DeleteRangeOperation");
345     RefPtr<IDBBackingStoreCursorInterface> backingStoreCursor = m_transaction->database().serverConnection().deprecatedBackingStore()->openObjectStoreCursor(m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), IndexedDB::CursorNext);
346     if (backingStoreCursor) {
347         do {
348             if (!m_transaction->database().serverConnection().deprecatedBackingStore()->deleteRecord(m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStoreId, backingStoreCursor->recordIdentifier())) {
349                 m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error deleting data in range"));
350                 return;
351             }
352         } while (backingStoreCursor->continueFunction(0));
353     }
354
355     m_callbacks->onSuccess();
356 }
357
358 void ClearOperation::perform(std::function<void()> completionCallback)
359 {
360     CallOnDestruct callOnDestruct(completionCallback);
361
362     LOG(StorageAPI, "ObjectStoreClearOperation");
363     if (!m_transaction->database().serverConnection().deprecatedBackingStore()->clearObjectStore(m_transaction->deprecatedBackingStoreTransaction(), m_databaseId, m_objectStoreId)) {
364         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error clearing object store"));
365         return;
366     }
367     m_callbacks->onSuccess();
368 }
369
370 void DeleteObjectStoreOperation::perform(std::function<void()> completionCallback)
371 {
372     CallOnDestruct callOnDestruct(completionCallback);
373
374     LOG(StorageAPI, "DeleteObjectStoreOperation");
375     bool ok = m_transaction->database().serverConnection().deprecatedBackingStore()->deleteObjectStore(m_transaction->deprecatedBackingStoreTransaction(), m_transaction->database().id(), m_objectStoreMetadata.id);
376     if (!ok) {
377         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error deleting object store '%s'.", m_objectStoreMetadata.name.utf8().data()));
378         m_transaction->abort(error);
379     }
380 }
381
382 void IDBDatabaseBackend::VersionChangeOperation::perform(std::function<void()> completionCallback)
383 {
384     CallOnDestruct callOnDestruct(completionCallback);
385
386     LOG(StorageAPI, "VersionChangeOperation");
387     IDBDatabaseBackend& database = m_transaction->database();
388     int64_t databaseId = database.id();
389     uint64_t oldVersion = database.metadata().version;
390
391     // FIXME: Database versions are now of type uint64_t, but this code expected int64_t.
392     ASSERT(m_version > (int64_t)oldVersion);
393     database.setCurrentVersion(m_version);
394     if (!database.serverConnection().deprecatedBackingStore()->updateIDBDatabaseVersion(m_transaction->deprecatedBackingStoreTransaction(), databaseId, database.metadata().version)) {
395         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error writing data to stable storage when updating version.");
396         m_callbacks->onError(error);
397         m_transaction->abort(error);
398         return;
399     }
400     ASSERT(!database.hasPendingSecondHalfOpen());
401     database.setPendingSecondHalfOpen(IDBPendingOpenCall::create(*m_callbacks, *m_databaseCallbacks, m_transactionId, m_version));
402     m_callbacks->onUpgradeNeeded(oldVersion, &database, database.metadata());
403 }
404
405 void CreateObjectStoreAbortOperation::perform()
406 {
407     LOG(StorageAPI, "CreateObjectStoreAbortOperation");
408     m_transaction->database().removeObjectStore(m_objectStoreId);
409 }
410
411 void DeleteObjectStoreAbortOperation::perform()
412 {
413     LOG(StorageAPI, "DeleteObjectStoreAbortOperation");
414     m_transaction->database().addObjectStore(m_objectStoreMetadata, IDBObjectStoreMetadata::InvalidId);
415 }
416
417 void IDBDatabaseBackend::VersionChangeAbortOperation::perform()
418 {
419     LOG(StorageAPI, "VersionChangeAbortOperation");
420     m_transaction->database().setCurrentVersion(m_previousIntVersion);
421 }
422
423 } // namespace WebCore
424
425 #endif // ENABLE(INDEXED_DATABASE)