IndexedDB: simplify RecordIdentifier
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / IDBObjectStoreBackendImpl.cpp
1 /*
2  * Copyright (C) 2011 Google 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  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "IDBObjectStoreBackendImpl.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "CrossThreadTask.h"
32 #include "IDBBackingStore.h"
33 #include "IDBBindingUtilities.h"
34 #include "IDBCallbacks.h"
35 #include "IDBCursorBackendImpl.h"
36 #include "IDBDatabaseBackendImpl.h"
37 #include "IDBDatabaseException.h"
38 #include "IDBIndexBackendImpl.h"
39 #include "IDBKey.h"
40 #include "IDBKeyPath.h"
41 #include "IDBKeyRange.h"
42 #include "IDBTracing.h"
43 #include "IDBTransactionBackendImpl.h"
44 #include <wtf/MathExtras.h>
45
46 namespace WebCore {
47
48 IDBObjectStoreBackendImpl::~IDBObjectStoreBackendImpl()
49 {
50 }
51
52 IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(const IDBDatabaseBackendImpl* database, const IDBObjectStoreMetadata& metadata)
53     : m_database(database)
54     , m_metadata(metadata)
55 {
56     loadIndexes();
57 }
58
59 IDBObjectStoreMetadata IDBObjectStoreBackendImpl::metadata() const
60 {
61     IDBObjectStoreMetadata metadata(m_metadata);
62     for (IndexMap::const_iterator it = m_indexes.begin(); it != m_indexes.end(); ++it)
63         metadata.indexes.set(it->key, it->value->metadata());
64     return metadata;
65 }
66
67 void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
68 {
69     IDB_TRACE("IDBObjectStoreBackendImpl::get");
70     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
71     RefPtr<IDBKeyRange> keyRange = prpKeyRange;
72     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
73     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
74     if (!transaction->scheduleTask(
75             createCallbackTask(&IDBObjectStoreBackendImpl::getInternal, objectStore, keyRange, callbacks, transaction)))
76         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
77 }
78
79 void IDBObjectStoreBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
80 {
81     IDB_TRACE("IDBObjectStoreBackendImpl::getInternal");
82     RefPtr<IDBKey> key;
83     if (keyRange->isOnlyKey())
84         key = keyRange->lower();
85     else {
86         RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), keyRange.get(), IDBCursor::NEXT);
87         if (!backingStoreCursor) {
88             callbacks->onSuccess();
89             return;
90         }
91         key = backingStoreCursor->key();
92     }
93
94     String wireData = objectStore->backingStore()->getRecord(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), *key);
95     if (wireData.isNull()) {
96         callbacks->onSuccess();
97         return;
98     }
99
100     if (objectStore->autoIncrement() && !objectStore->keyPath().isNull()) {
101         callbacks->onSuccess(SerializedScriptValue::createFromWire(wireData),
102                              key, objectStore->keyPath());
103         return;
104     }
105     callbacks->onSuccess(SerializedScriptValue::createFromWire(wireData));
106 }
107
108 void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, const Vector<int64_t>& indexIds, const Vector<IndexKeys>& indexKeys)
109 {
110     IDB_TRACE("IDBObjectStoreBackendImpl::put");
111
112     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
113     RefPtr<SerializedScriptValue> value = prpValue;
114     RefPtr<IDBKey> key = prpKey;
115     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
116     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
117     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
118
119     OwnPtr<Vector<int64_t> > newIndexIds = adoptPtr(new Vector<int64_t>(indexIds));
120     OwnPtr<Vector<IndexKeys> > newIndexKeys = adoptPtr(new Vector<IndexKeys>(indexKeys));
121
122     ASSERT(autoIncrement() || key);
123
124     if (!transaction->scheduleTask(
125         createCallbackTask(&IDBObjectStoreBackendImpl::putInternal, objectStore, value, key, putMode, callbacks, transaction, newIndexIds.release(), newIndexKeys.release())))
126         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
127 }
128
129 namespace {
130 class IndexWriter {
131 public:
132     explicit IndexWriter(const IDBIndexMetadata& indexMetadata)
133         : m_indexMetadata(indexMetadata)
134     { }
135
136     IndexWriter(const IDBIndexMetadata& indexMetadata,
137                 const IDBObjectStoreBackendInterface::IndexKeys& indexKeys)
138         : m_indexMetadata(indexMetadata)
139         , m_indexKeys(indexKeys)
140     { }
141
142     bool verifyIndexKeys(IDBBackingStore& backingStore, IDBBackingStore::Transaction* transaction,
143                          int64_t databaseId, int64_t objectStoreId, int64_t indexId,
144                          const IDBKey* primaryKey = 0, String* errorMessage = 0)
145     {
146         for (size_t i = 0; i < m_indexKeys.size(); ++i) {
147             if (!addingKeyAllowed(backingStore, transaction, databaseId, objectStoreId, indexId,
148                                   (m_indexKeys)[i].get(), primaryKey)) {
149                 if (errorMessage)
150                     *errorMessage = String::format("Unable to add key to index '%s': at least one key does not satisfy the uniqueness requirements.",
151                                                    m_indexMetadata.name.utf8().data());
152                 return false;
153             }
154         }
155         return true;
156     }
157
158     void writeIndexKeys(const IDBBackingStore::RecordIdentifier& recordIdentifier, IDBBackingStore& backingStore, IDBBackingStore::Transaction* transaction, int64_t databaseId, int64_t objectStoreId) const
159     {
160         int64_t indexId = m_indexMetadata.id;
161         for (size_t i = 0; i < m_indexKeys.size(); ++i) {
162             backingStore.putIndexDataForRecord(transaction, databaseId, objectStoreId, indexId, *(m_indexKeys)[i].get(), recordIdentifier);
163         }
164     }
165
166 private:
167
168     bool addingKeyAllowed(IDBBackingStore& backingStore, IDBBackingStore::Transaction* transaction,
169                           int64_t databaseId, int64_t objectStoreId, int64_t indexId,
170                           const IDBKey* indexKey, const IDBKey* primaryKey) const
171     {
172         if (!m_indexMetadata.unique)
173             return true;
174
175         RefPtr<IDBKey> foundPrimaryKey;
176         bool found = backingStore.keyExistsInIndex(transaction, databaseId, objectStoreId, indexId, *indexKey, foundPrimaryKey);
177         if (!found)
178             return true;
179         if (primaryKey && foundPrimaryKey->isEqual(primaryKey))
180             return true;
181         return false;
182     }
183
184     const IDBIndexMetadata m_indexMetadata;
185     IDBObjectStoreBackendInterface::IndexKeys m_indexKeys;
186 };
187 }
188
189 static bool makeIndexWriters(PassRefPtr<IDBTransactionBackendImpl> transaction, IDBObjectStoreBackendImpl* objectStore, PassRefPtr<IDBKey> primaryKey, bool keyWasGenerated, const Vector<int64_t>& indexIds, const Vector<IDBObjectStoreBackendInterface::IndexKeys>& indexKeys, Vector<OwnPtr<IndexWriter> >* indexWriters, String* errorMessage)
190 {
191     ASSERT(indexIds.size() == indexKeys.size());
192
193     HashMap<int64_t, IDBObjectStoreBackendInterface::IndexKeys> indexKeyMap;
194     for (size_t i = 0; i < indexIds.size(); ++i)
195         indexKeyMap.add(indexIds[i], indexKeys[i]);
196
197     for (IDBObjectStoreBackendImpl::IndexMap::iterator it = objectStore->iterIndexesBegin(); it != objectStore->iterIndexesEnd(); ++it) {
198
199         const RefPtr<IDBIndexBackendImpl>& index = it->value;
200
201         IDBObjectStoreBackendInterface::IndexKeys keys = indexKeyMap.get(it->key);
202         // If the objectStore is using autoIncrement, then any indexes with an identical keyPath need to also use the primary (generated) key as a key.
203         if (keyWasGenerated) {
204             const IDBKeyPath& indexKeyPath = index->keyPath();
205             if (indexKeyPath == objectStore->keyPath())
206                 keys.append(primaryKey);
207         }
208
209         OwnPtr<IndexWriter> indexWriter(adoptPtr(new IndexWriter(index->metadata(), keys)));
210         if (!indexWriter->verifyIndexKeys(*objectStore->backingStore(),
211                                           transaction->backingStoreTransaction(),
212                                           objectStore->databaseId(),
213                                           objectStore->id(),
214                                           index->id(), primaryKey.get(), errorMessage)) {
215             return false;
216         }
217
218         indexWriters->append(indexWriter.release());
219     }
220
221     return true;
222 }
223
224 void IDBObjectStoreBackendImpl::setIndexKeys(PassRefPtr<IDBKey> prpPrimaryKey, const Vector<int64_t>& indexIds, const Vector<IndexKeys>& indexKeys, IDBTransactionBackendInterface* transactionPtr)
225 {
226     IDB_TRACE("IDBObjectStoreBackendImpl::setIndexKeys");
227     RefPtr<IDBKey> primaryKey = prpPrimaryKey;
228     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
229
230     // FIXME: This method could be asynchronous, but we need to evaluate if it's worth the extra complexity.
231     IDBBackingStore::RecordIdentifier recordIdentifier;
232     if (!backingStore()->keyExistsInObjectStore(transaction->backingStoreTransaction(), databaseId(), id(), *primaryKey, &recordIdentifier)) {
233         transaction->abort();
234         return;
235     }
236
237     Vector<OwnPtr<IndexWriter> > indexWriters;
238     String errorMessage;
239     if (!makeIndexWriters(transaction, this, primaryKey, false, indexIds, indexKeys, &indexWriters, &errorMessage)) {
240         // FIXME: Need to deal with errorMessage here. makeIndexWriters only fails on uniqueness constraint errors.
241         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Duplicate index keys exist in the object store."));
242         return;
243     }
244
245     for (size_t i = 0; i < indexWriters.size(); ++i) {
246         IndexWriter* indexWriter = indexWriters[i].get();
247         indexWriter->writeIndexKeys(recordIdentifier, *backingStore(), transaction->backingStoreTransaction(), databaseId(), m_metadata.id);
248     }
249 }
250
251 void IDBObjectStoreBackendImpl::setIndexesReady(const Vector<int64_t>& indexIds, IDBTransactionBackendInterface* transactionInterface)
252 {
253     IDB_TRACE("IDBObjectStoreBackendImpl::setIndexesReady");
254     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
255
256     OwnPtr<Vector<int64_t> > newIndexIds = adoptPtr(new Vector<int64_t>(indexIds));
257     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionInterface);
258
259     if (!transaction->scheduleTask(
260             IDBTransactionBackendInterface::PreemptiveTask,
261             createCallbackTask(&IDBObjectStoreBackendImpl::setIndexesReadyInternal, objectStore, newIndexIds.release(), transaction)))
262         ASSERT_NOT_REACHED();
263 }
264
265 void IDBObjectStoreBackendImpl::setIndexesReadyInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassOwnPtr<Vector<int64_t> > popIndexIds, PassRefPtr<IDBTransactionBackendImpl> transaction)
266 {
267     IDB_TRACE("IDBObjectStoreBackendImpl::setIndexesReadyInternal");
268     OwnPtr<Vector<int64_t> > indexIds = popIndexIds;
269     for (size_t i = 0; i < indexIds->size(); ++i)
270         transaction->didCompletePreemptiveEvent();
271     transaction->didCompleteTaskEvents();
272 }
273
274 void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> prpTransaction, PassOwnPtr<Vector<int64_t> > popIndexIds, PassOwnPtr<Vector<IndexKeys> > popIndexKeys)
275 {
276     IDB_TRACE("IDBObjectStoreBackendImpl::putInternal");
277     RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
278     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
279     RefPtr<SerializedScriptValue> value = prpValue;
280     RefPtr<IDBKey> key = prpKey;
281     OwnPtr<Vector<int64_t> > indexIds = popIndexIds;
282     OwnPtr<Vector<IndexKeys> > indexKeys = popIndexKeys;
283     ASSERT(indexIds && indexKeys && indexIds->size() == indexKeys->size());
284     const bool autoIncrement = objectStore->autoIncrement();
285     bool keyWasGenerated = false;
286
287     if (putMode != CursorUpdate && autoIncrement && !key) {
288         RefPtr<IDBKey> autoIncKey = objectStore->generateKey(transaction);
289         keyWasGenerated = true;
290         if (!autoIncKey->isValid()) {
291             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Maximum key generator value reached."));
292             return;
293         }
294         key = autoIncKey;
295     }
296
297     ASSERT(key && key->isValid());
298
299     IDBBackingStore::RecordIdentifier recordIdentifier;
300     if (putMode == AddOnly && objectStore->backingStore()->keyExistsInObjectStore(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), *key, &recordIdentifier)) {
301         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
302         return;
303     }
304
305     Vector<OwnPtr<IndexWriter> > indexWriters;
306     String errorMessage;
307     if (!makeIndexWriters(transaction, objectStore.get(), key, keyWasGenerated, *indexIds, *indexKeys, &indexWriters, &errorMessage)) {
308         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, errorMessage));
309         return;
310     }
311
312     // Before this point, don't do any mutation.  After this point, rollback the transaction in case of error.
313
314     objectStore->backingStore()->putRecord(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), *key, value->toWireString(), &recordIdentifier);
315
316     for (size_t i = 0; i < indexWriters.size(); ++i) {
317         IndexWriter* indexWriter = indexWriters[i].get();
318         indexWriter->writeIndexKeys(recordIdentifier, *objectStore->backingStore(), transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->m_metadata.id);
319     }
320
321     if (autoIncrement && putMode != CursorUpdate && key->type() == IDBKey::NumberType)
322         objectStore->updateKeyGenerator(transaction, key.get(), !keyWasGenerated);
323
324     callbacks->onSuccess(key.release());
325 }
326
327 void IDBObjectStoreBackendImpl::deleteFunction(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
328 {
329     IDB_TRACE("IDBObjectStoreBackendImpl::delete");
330
331     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
332     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
333
334     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
335     RefPtr<IDBKeyRange> keyRange = prpKeyRange;
336     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
337
338     if (!transaction->scheduleTask(
339             createCallbackTask(&IDBObjectStoreBackendImpl::deleteInternal, objectStore, keyRange, callbacks, transaction)))
340         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
341 }
342
343 void IDBObjectStoreBackendImpl::deleteInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
344 {
345     IDB_TRACE("IDBObjectStoreBackendImpl::deleteInternal");
346
347     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), keyRange.get(), IDBCursor::NEXT);
348     if (backingStoreCursor) {
349
350         do {
351             objectStore->backingStore()->deleteRecord(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), backingStoreCursor->recordIdentifier());
352
353         } while (backingStoreCursor->continueFunction(0));
354     }
355
356     callbacks->onSuccess();
357 }
358
359 void IDBObjectStoreBackendImpl::clear(PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
360 {
361     IDB_TRACE("IDBObjectStoreBackendImpl::clear");
362
363     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
364     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
365
366     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
367     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
368
369     if (!transaction->scheduleTask(
370             createCallbackTask(&IDBObjectStoreBackendImpl::clearInternal, objectStore, callbacks, transaction)))
371         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
372 }
373
374 void IDBObjectStoreBackendImpl::clearInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
375 {
376     objectStore->backingStore()->clearObjectStore(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id());
377     callbacks->onSuccess();
378 }
379
380 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::createIndex(int64_t id, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
381 {
382     ASSERT_WITH_MESSAGE(!m_indexes.contains(id), "Indexes already contain %s", name.utf8().data());
383
384     RefPtr<IDBIndexBackendImpl> index = IDBIndexBackendImpl::create(m_database, this, IDBIndexMetadata(name, id, keyPath, unique, multiEntry));
385     ASSERT(index->name() == name);
386
387     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
388     ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
389     ASSERT(id > m_metadata.maxIndexId);
390     m_metadata.maxIndexId = id;
391
392     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
393     if (!transaction->scheduleTask(
394               createCallbackTask(&IDBObjectStoreBackendImpl::createIndexInternal, objectStore, index, transaction),
395               createCallbackTask(&IDBObjectStoreBackendImpl::removeIndexFromMap, objectStore, index))) {
396         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
397         return 0;
398     }
399
400     m_indexes.set(id, index);
401     return index.release();
402 }
403
404 void IDBObjectStoreBackendImpl::createIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendImpl> transaction)
405 {
406     if (!objectStore->backingStore()->createIndex(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), index->id(), index->name(), index->keyPath(), index->unique(), index->multiEntry())) {
407         transaction->abort();
408         return;
409     }
410
411     transaction->didCompleteTaskEvents();
412 }
413
414 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::index(int64_t indexId)
415 {
416     RefPtr<IDBIndexBackendInterface> index = m_indexes.get(indexId);
417     ASSERT(index);
418     return index.release();
419 }
420
421 void IDBObjectStoreBackendImpl::deleteIndex(int64_t indexId, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
422 {
423     ASSERT(m_indexes.contains(indexId));
424
425     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
426     RefPtr<IDBIndexBackendImpl> index = m_indexes.get(indexId);
427     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
428     ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
429
430     if (!transaction->scheduleTask(
431               createCallbackTask(&IDBObjectStoreBackendImpl::deleteIndexInternal, objectStore, index, transaction),
432               createCallbackTask(&IDBObjectStoreBackendImpl::addIndexToMap, objectStore, index))) {
433         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
434         return;
435     }
436     m_indexes.remove(indexId);
437 }
438
439 void IDBObjectStoreBackendImpl::deleteIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendImpl> transaction)
440 {
441     objectStore->backingStore()->deleteIndex(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), index->id());
442     transaction->didCompleteTaskEvents();
443 }
444
445 void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, IDBCursor::Direction direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface::TaskType taskType, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
446 {
447     IDB_TRACE("IDBObjectStoreBackendImpl::openCursor");
448     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
449     RefPtr<IDBKeyRange> range = prpRange;
450     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
451     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
452     if (!transaction->scheduleTask(
453             createCallbackTask(&IDBObjectStoreBackendImpl::openCursorInternal, objectStore, range, direction, callbacks, taskType, transaction))) {
454         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
455     }
456 }
457
458 void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, IDBCursor::Direction direction, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface::TaskType taskType, PassRefPtr<IDBTransactionBackendImpl> transaction)
459 {
460     IDB_TRACE("IDBObjectStoreBackendImpl::openCursorInternal");
461
462     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), range.get(), direction);
463     // The frontend has begun indexing, so this pauses the transaction
464     // until the indexing is complete. This can't happen any earlier
465     // because we don't want to switch to early mode in case multiple
466     // indexes are being created in a row, with put()'s in between.
467     if (taskType == IDBTransactionBackendInterface::PreemptiveTask)
468         transaction->addPreemptiveEvent();
469     if (!backingStoreCursor) {
470         callbacks->onSuccess(static_cast<SerializedScriptValue*>(0));
471         return;
472     }
473
474     RefPtr<IDBCursorBackendImpl> cursor = IDBCursorBackendImpl::create(backingStoreCursor.release(), IDBCursorBackendInterface::ObjectStoreCursor, taskType, transaction.get(), objectStore.get());
475     callbacks->onSuccess(cursor, cursor->key(), cursor->primaryKey(), cursor->value());
476 }
477
478 void IDBObjectStoreBackendImpl::count(PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
479 {
480     IDB_TRACE("IDBObjectStoreBackendImpl::count");
481     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
482     if (!transaction->scheduleTask(
483             createCallbackTask(&IDBObjectStoreBackendImpl::countInternal, this, range, callbacks, transaction)))
484         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
485 }
486
487 void IDBObjectStoreBackendImpl::countInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
488 {
489     IDB_TRACE("IDBObjectStoreBackendImpl::countInternal");
490     uint32_t count = 0;
491     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreKeyCursor(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), range.get(), IDBCursor::NEXT);
492     if (!backingStoreCursor) {
493         callbacks->onSuccess(count);
494         return;
495     }
496
497     do {
498         ++count;
499     } while (backingStoreCursor->continueFunction(0));
500
501     callbacks->onSuccess(count);
502 }
503
504 void IDBObjectStoreBackendImpl::loadIndexes()
505 {
506     Vector<IDBIndexMetadata> indexes = backingStore()->getIndexes(databaseId(), m_metadata.id);
507
508     for (size_t i = 0; i < indexes.size(); ++i)
509         m_indexes.set(indexes[i].id, IDBIndexBackendImpl::create(m_database, this, indexes[i]));
510 }
511
512 void IDBObjectStoreBackendImpl::removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
513 {
514     ASSERT(objectStore->m_indexes.contains(index->id()));
515     objectStore->m_indexes.remove(index->id());
516 }
517
518 void IDBObjectStoreBackendImpl::addIndexToMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
519 {
520     RefPtr<IDBIndexBackendImpl> indexPtr = index;
521     ASSERT(!objectStore->m_indexes.contains(indexPtr->id()));
522     objectStore->m_indexes.set(indexPtr->id(), indexPtr);
523 }
524
525 PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::generateKey(PassRefPtr<IDBTransactionBackendImpl> transaction)
526 {
527     const int64_t maxGeneratorValue = 9007199254740992LL; // Maximum integer storable as ECMAScript number.
528     int64_t currentNumber = backingStore()->getKeyGeneratorCurrentNumber(transaction->backingStoreTransaction(), databaseId(), id());
529     if (currentNumber < 0 || currentNumber > maxGeneratorValue)
530         return IDBKey::createInvalid();
531
532     return IDBKey::createNumber(currentNumber);
533 }
534
535 void IDBObjectStoreBackendImpl::updateKeyGenerator(PassRefPtr<IDBTransactionBackendImpl> transaction, const IDBKey* key, bool checkCurrent)
536 {
537     ASSERT(key && key->type() == IDBKey::NumberType);
538     backingStore()->maybeUpdateKeyGeneratorCurrentNumber(transaction->backingStoreTransaction(), databaseId(), id(), static_cast<int64_t>(floor(key->number())) + 1, checkCurrent);
539 }
540
541 } // namespace WebCore
542
543 #endif