IndexedDB: Move method precondition checks to front end objects
[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 "DOMStringList.h"
33 #include "IDBBackingStore.h"
34 #include "IDBBindingUtilities.h"
35 #include "IDBCallbacks.h"
36 #include "IDBCursorBackendImpl.h"
37 #include "IDBDatabaseBackendImpl.h"
38 #include "IDBDatabaseException.h"
39 #include "IDBIndexBackendImpl.h"
40 #include "IDBKey.h"
41 #include "IDBKeyPath.h"
42 #include "IDBKeyPathBackendImpl.h"
43 #include "IDBKeyRange.h"
44 #include "IDBTracing.h"
45 #include "IDBTransactionBackendImpl.h"
46 #include "ScriptExecutionContext.h"
47
48 namespace WebCore {
49
50 IDBObjectStoreBackendImpl::~IDBObjectStoreBackendImpl()
51 {
52 }
53
54 IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(const IDBDatabaseBackendImpl* database, int64_t id, const String& name, const IDBKeyPath& keyPath, bool autoIncrement)
55     : m_database(database)
56     , m_id(id)
57     , m_name(name)
58     , m_keyPath(keyPath)
59     , m_autoIncrement(autoIncrement)
60     , m_autoIncrementNumber(-1)
61 {
62     loadIndexes();
63 }
64
65 IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(const IDBDatabaseBackendImpl* database, const String& name, const IDBKeyPath& keyPath, bool autoIncrement)
66     : m_database(database)
67     , m_id(InvalidId)
68     , m_name(name)
69     , m_keyPath(keyPath)
70     , m_autoIncrement(autoIncrement)
71     , m_autoIncrementNumber(-1)
72 {
73 }
74
75 IDBObjectStoreMetadata IDBObjectStoreBackendImpl::metadata() const
76 {
77     IDBObjectStoreMetadata metadata(m_name, m_keyPath, m_autoIncrement);
78     for (IndexMap::const_iterator it = m_indexes.begin(); it != m_indexes.end(); ++it)
79         metadata.indexes.set(it->first, it->second->metadata());
80     return metadata;
81 }
82
83 void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
84 {
85     IDB_TRACE("IDBObjectStoreBackendImpl::get");
86     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
87     RefPtr<IDBKeyRange> keyRange = prpKeyRange;
88     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
89     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::getInternal, objectStore, keyRange, callbacks)))
90         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
91 }
92
93 void IDBObjectStoreBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
94 {
95     IDB_TRACE("IDBObjectStoreBackendImpl::getInternal");
96     RefPtr<IDBKey> key;
97     if (keyRange->isOnlyKey())
98         key = keyRange->lower();
99     else {
100         RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), keyRange.get(), IDBCursor::NEXT);
101         if (!backingStoreCursor) {
102             callbacks->onSuccess(SerializedScriptValue::undefinedValue());
103             return;
104         }
105         key = backingStoreCursor->key();
106         backingStoreCursor->close();
107     }
108
109     String wireData = objectStore->backingStore()->getObjectStoreRecord(objectStore->databaseId(), objectStore->id(), *key);
110     if (wireData.isNull()) {
111         callbacks->onSuccess(SerializedScriptValue::undefinedValue());
112         return;
113     }
114
115     callbacks->onSuccess(SerializedScriptValue::createFromWire(wireData));
116 }
117
118 static PassRefPtr<IDBKey> fetchKeyFromKeyPath(SerializedScriptValue* value, const IDBKeyPath& keyPath)
119 {
120     IDB_TRACE("IDBObjectStoreBackendImpl::fetchKeyFromKeyPath");
121     ASSERT(!keyPath.isNull());
122
123     Vector<RefPtr<SerializedScriptValue> > values;
124     values.append(value);
125     Vector<RefPtr<IDBKey> > keys;
126     IDBKeyPathBackendImpl::createIDBKeysFromSerializedValuesAndKeyPath(values, keyPath, keys);
127     if (keys.isEmpty())
128         return 0;
129     ASSERT(keys.size() == 1);
130     return keys[0].release();
131 }
132
133 static PassRefPtr<SerializedScriptValue> injectKeyIntoKeyPath(PassRefPtr<IDBKey> key, PassRefPtr<SerializedScriptValue> value, const IDBKeyPath& keyPath)
134 {
135     IDB_TRACE("IDBObjectStoreBackendImpl::injectKeyIntoKeyPath");
136     return IDBKeyPathBackendImpl::injectIDBKeyIntoSerializedValue(key, value, keyPath);
137 }
138
139 void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
140 {
141     IDB_TRACE("IDBObjectStoreBackendImpl::put");
142
143     ASSERT(transactionPtr->mode() != IDBTransaction::READ_ONLY);
144
145     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
146     RefPtr<SerializedScriptValue> value = prpValue;
147     RefPtr<IDBKey> key = prpKey;
148     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
149     RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
150
151     if (!transaction->scheduleTask(
152             createCallbackTask(&IDBObjectStoreBackendImpl::putInternal, objectStore, value, key, putMode, callbacks, transaction),
153             // FIXME: One of these per put() is overkill, since it's simply a cache invalidation.
154             createCallbackTask(&IDBObjectStoreBackendImpl::revertAutoIncrementKeyCache, objectStore)))
155         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
156 }
157
158 void IDBObjectStoreBackendImpl::revertAutoIncrementKeyCache(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
159 {
160     objectStore->resetAutoIncrementKeyCache();
161 }
162
163 namespace {
164 class IndexWriter {
165 public:
166     explicit IndexWriter(PassRefPtr<IDBIndexBackendImpl> index)
167         : m_index(index)
168     {
169     }
170
171     bool loadIndexKeysForValue(SerializedScriptValue* objectValue, const IDBKey* primaryKey = 0, String* errorMessage = 0)
172     {
173         m_indexKeys.clear();
174
175         RefPtr<IDBKey> indexKey = fetchKeyFromKeyPath(objectValue, m_index->keyPath());
176
177         if (!indexKey)
178             return true;
179
180         if (!m_index->multiEntry() || indexKey->type() != IDBKey::ArrayType) {
181             if (!indexKey->isValid())
182                 return true;
183
184             if (!m_index->addingKeyAllowed(indexKey.get(), primaryKey)) {
185                 if (errorMessage)
186                     *errorMessage = String::format("Unable to add key to index '%s': the key does not satisfy its uniqueness requirements.",
187                                                    m_index->name().utf8().data());
188                 return false;
189             }
190             m_indexKeys.append(indexKey);
191         } else {
192             ASSERT(m_index->multiEntry());
193             ASSERT(indexKey->type() == IDBKey::ArrayType);
194             indexKey = IDBKey::createMultiEntryArray(indexKey->array());
195
196             for (size_t i = 0; i < indexKey->array().size(); ++i) {
197                 if (!m_index->addingKeyAllowed(indexKey->array()[i].get(), primaryKey)) {
198                     if (errorMessage)
199                         *errorMessage = String::format("Unable to add key to index '%s': at least one key does not satisfy the uniqueness requirements.",
200                                                        m_index->name().utf8().data());
201                     return false;
202                 }
203                 m_indexKeys.append(indexKey->array()[i]);
204             }
205         }
206         return true;
207     }
208
209     bool writeIndexKeys(const IDBBackingStore::ObjectStoreRecordIdentifier* recordIdentifier, IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, String* errorMessage = 0)
210     {
211         for (size_t i = 0; i < m_indexKeys.size(); ++i) {
212             if (!backingStore.deleteIndexDataForRecord(databaseId, objectStoreId, m_index->id(), recordIdentifier))
213                 return false;
214             if (!backingStore.putIndexDataForRecord(databaseId, objectStoreId, m_index->id(), *m_indexKeys[i].get(), recordIdentifier))
215                 return false;
216         }
217         return true;
218     }
219
220 private:
221     RefPtr<IDBIndexBackendImpl> m_index;
222     Vector<RefPtr<IDBKey> > m_indexKeys;
223 };
224 }
225
226 void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
227 {
228     IDB_TRACE("IDBObjectStoreBackendImpl::putInternal");
229     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
230     RefPtr<SerializedScriptValue> value = prpValue;
231     RefPtr<IDBKey> key = prpKey;
232
233     if (putMode != CursorUpdate) {
234         const bool autoIncrement = objectStore->autoIncrement();
235         const bool hasKeyPath = !objectStore->m_keyPath.isNull();
236         if (hasKeyPath) {
237             ASSERT(!key);
238             RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
239             if (keyPathKey)
240                 key = keyPathKey;
241         }
242         if (autoIncrement) {
243             if (!key) {
244                 RefPtr<IDBKey> autoIncKey = objectStore->genAutoIncrementKey();
245                 if (!autoIncKey->isValid()) {
246                     callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "Maximum key generator value reached."));
247                     return;
248                 }
249                 if (hasKeyPath) {
250                     RefPtr<SerializedScriptValue> valueAfterInjection = injectKeyIntoKeyPath(autoIncKey, value, objectStore->m_keyPath);
251                     ASSERT(valueAfterInjection);
252                     if (!valueAfterInjection) {
253                         objectStore->resetAutoIncrementKeyCache();
254                         // Checks in put() ensure this should only happen if I/O error occurs.
255                         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error inserting generated key into the object."));
256                         return;
257                     }
258                     value = valueAfterInjection;
259                 }
260                 key = autoIncKey;
261             } else {
262                 // FIXME: Logic to update generator state should go here. Currently it does a scan.
263                 objectStore->resetAutoIncrementKeyCache();
264             }
265         }
266     }
267
268     ASSERT(key && key->isValid());
269
270     RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = objectStore->backingStore()->createInvalidRecordIdentifier();
271     if (putMode == AddOnly && objectStore->backingStore()->keyExistsInObjectStore(objectStore->databaseId(), objectStore->id(), *key, recordIdentifier.get())) {
272         objectStore->resetAutoIncrementKeyCache();
273         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
274         return;
275     }
276
277     Vector<OwnPtr<IndexWriter> > indexWriters;
278     for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
279
280         const RefPtr<IDBIndexBackendImpl>& index = it->second;
281         if (!index->hasValidId())
282             continue; // The index object has been created, but does not exist in the database yet.
283
284         OwnPtr<IndexWriter> indexWriter(adoptPtr(new IndexWriter(index)));
285         String errorMessage;
286         if (!indexWriter->loadIndexKeysForValue(value.get(), key.get(), &errorMessage)) {
287             objectStore->resetAutoIncrementKeyCache();
288             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, errorMessage));
289             return;
290         }
291
292         indexWriters.append(indexWriter.release());
293     }
294
295     // Before this point, don't do any mutation.  After this point, rollback the transaction in case of error.
296
297     if (!objectStore->backingStore()->putObjectStoreRecord(objectStore->databaseId(), objectStore->id(), *key, value->toWireString(), recordIdentifier.get())) {
298         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
299         transaction->abort();
300         return;
301     }
302
303     for (size_t i = 0; i < indexWriters.size(); ++i) {
304         if (!indexWriters[i]->writeIndexKeys(recordIdentifier.get(),
305                                              *objectStore->backingStore(), objectStore->databaseId(),
306                                              objectStore->m_id)) {
307             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
308             transaction->abort();
309             return;
310         }
311     }
312
313     callbacks->onSuccess(key.get());
314 }
315
316 void IDBObjectStoreBackendImpl::deleteFunction(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
317 {
318     IDB_TRACE("IDBObjectStoreBackendImpl::delete");
319
320     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
321
322     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
323     RefPtr<IDBKeyRange> keyRange = prpKeyRange;
324     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
325
326     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::deleteInternal, objectStore, keyRange, callbacks)))
327         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
328 }
329
330 void IDBObjectStoreBackendImpl::deleteInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
331 {
332     IDB_TRACE("IDBObjectStoreBackendImpl::deleteInternal");
333     RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier;
334
335     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), keyRange.get(), IDBCursor::NEXT);
336     if (backingStoreCursor) {
337
338         do {
339             recordIdentifier = backingStoreCursor->objectStoreRecordIdentifier();
340
341             for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
342                 if (!it->second->hasValidId())
343                     continue; // The index object has been created, but does not exist in the database yet.
344
345                 bool success = objectStore->backingStore()->deleteIndexDataForRecord(objectStore->databaseId(), objectStore->id(), it->second->id(), recordIdentifier.get());
346                 ASSERT_UNUSED(success, success);
347             }
348
349             objectStore->backingStore()->deleteObjectStoreRecord(objectStore->databaseId(), objectStore->id(), recordIdentifier.get());
350
351         } while (backingStoreCursor->continueFunction(0));
352
353         backingStoreCursor->close();
354     }
355
356     callbacks->onSuccess(SerializedScriptValue::undefinedValue());
357 }
358
359 void IDBObjectStoreBackendImpl::clear(PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
360 {
361     IDB_TRACE("IDBObjectStoreBackendImpl::clear");
362
363     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
364
365     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
366     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
367
368     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::clearInternal, objectStore, callbacks)))
369         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
370 }
371
372 void IDBObjectStoreBackendImpl::clearInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBCallbacks> callbacks)
373 {
374     objectStore->backingStore()->clearObjectStore(objectStore->databaseId(), objectStore->id());
375     callbacks->onSuccess(SerializedScriptValue::undefinedValue());
376 }
377
378 namespace {
379 class PopulateIndexCallback : public IDBBackingStore::ObjectStoreRecordCallback {
380 public:
381     PopulateIndexCallback(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBIndexBackendImpl> index)
382         : m_backingStore(backingStore)
383         , m_databaseId(databaseId)
384         , m_objectStoreId(objectStoreId)
385         , m_writer(index)
386     {
387     }
388
389     virtual bool callback(const IDBBackingStore::ObjectStoreRecordIdentifier* recordIdentifier, const String& value)
390     {
391         RefPtr<SerializedScriptValue> objectValue = SerializedScriptValue::createFromWire(value);
392         if (!m_writer.loadIndexKeysForValue(objectValue.get()))
393             return false;
394         return m_writer.writeIndexKeys(recordIdentifier, m_backingStore, m_databaseId, m_objectStoreId);
395     }
396
397 private:
398     IDBBackingStore& m_backingStore;
399     int64_t m_databaseId;
400     int64_t m_objectStoreId;
401     IndexWriter m_writer;
402 };
403 }
404
405 bool IDBObjectStoreBackendImpl::populateIndex(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBIndexBackendImpl> index)
406 {
407     PopulateIndexCallback callback(backingStore, databaseId, objectStoreId, index);
408     if (!backingStore.forEachObjectStoreRecord(databaseId, objectStoreId, callback))
409         return false;
410     return true;
411 }
412
413 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::createIndex(const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
414 {
415     ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
416     ASSERT(!m_indexes.contains(name));
417
418     RefPtr<IDBIndexBackendImpl> index = IDBIndexBackendImpl::create(m_database, this, name, keyPath, unique, multiEntry);
419     ASSERT(index->name() == name);
420
421     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
422     RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
423     if (!transaction->scheduleTask(
424               createCallbackTask(&IDBObjectStoreBackendImpl::createIndexInternal,
425                                  objectStore, index, transactionPtr),
426               createCallbackTask(&IDBObjectStoreBackendImpl::removeIndexFromMap,
427                                  objectStore, index))) {
428         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
429         return 0;
430     }
431
432     m_indexes.set(name, index);
433     return index.release();
434 }
435
436 void IDBObjectStoreBackendImpl::createIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
437 {
438     int64_t id;
439     if (!objectStore->backingStore()->createIndex(objectStore->databaseId(), objectStore->id(), index->name(), index->keyPath(), index->unique(), index->multiEntry(), id)) {
440         transaction->abort();
441         return;
442     }
443
444     index->setId(id);
445
446     if (!populateIndex(*objectStore->backingStore(), objectStore->databaseId(), objectStore->m_id, index)) {
447         transaction->abort();
448         return;
449     }
450
451     transaction->didCompleteTaskEvents();
452 }
453
454 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::index(const String& name, ExceptionCode& ec)
455 {
456     RefPtr<IDBIndexBackendInterface> index = m_indexes.get(name);
457     if (!index) {
458         ec = IDBDatabaseException::IDB_NOT_FOUND_ERR;
459         return 0;
460     }
461     return index.release();
462 }
463
464 void IDBObjectStoreBackendImpl::deleteIndex(const String& name, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
465 {
466     ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
467     ASSERT(m_indexes.contains(name));
468
469     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
470     RefPtr<IDBIndexBackendImpl> index = m_indexes.get(name);
471     RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
472     if (!transaction->scheduleTask(
473               createCallbackTask(&IDBObjectStoreBackendImpl::deleteIndexInternal,
474                                  objectStore, index, transactionPtr),
475               createCallbackTask(&IDBObjectStoreBackendImpl::addIndexToMap,
476                                  objectStore, index))) {
477         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
478         return;
479     }
480     m_indexes.remove(name);
481 }
482
483 void IDBObjectStoreBackendImpl::deleteIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
484 {
485     objectStore->backingStore()->deleteIndex(objectStore->databaseId(), objectStore->id(), index->id());
486     transaction->didCompleteTaskEvents();
487 }
488
489 void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
490 {
491     IDB_TRACE("IDBObjectStoreBackendImpl::openCursor");
492     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
493     RefPtr<IDBKeyRange> range = prpRange;
494     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
495     RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
496     if (!transaction->scheduleTask(
497             createCallbackTask(&IDBObjectStoreBackendImpl::openCursorInternal,
498                                objectStore, range, direction, callbacks, transactionPtr))) {
499         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
500     }
501 }
502
503 void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
504 {
505     IDB_TRACE("IDBObjectStoreBackendImpl::openCursorInternal");
506     IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(tmpDirection);
507
508     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), range.get(), direction);
509     if (!backingStoreCursor) {
510         callbacks->onSuccess(SerializedScriptValue::nullValue());
511         return;
512     }
513
514     RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(backingStoreCursor.release(), direction, IDBCursorBackendInterface::ObjectStoreCursor, transaction.get(), objectStore.get());
515     callbacks->onSuccess(cursor.release());
516 }
517
518 void IDBObjectStoreBackendImpl::count(PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
519 {
520     IDB_TRACE("IDBObjectStoreBackendImpl::count");
521     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::countInternal, this, range, callbacks, transaction)))
522         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
523 }
524
525 void IDBObjectStoreBackendImpl::countInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface>)
526 {
527     IDB_TRACE("IDBObjectStoreBackendImpl::countInternal");
528     uint32_t count = 0;
529     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), range.get(), IDBCursor::NEXT);
530     if (!backingStoreCursor) {
531         callbacks->onSuccess(SerializedScriptValue::numberValue(count));
532         return;
533     }
534
535     do {
536         ++count;
537     } while (backingStoreCursor->continueFunction(0));
538
539     backingStoreCursor->close();
540     callbacks->onSuccess(SerializedScriptValue::numberValue(count));
541 }
542
543 void IDBObjectStoreBackendImpl::loadIndexes()
544 {
545     Vector<int64_t> ids;
546     Vector<String> names;
547     Vector<IDBKeyPath> keyPaths;
548     Vector<bool> uniqueFlags;
549     Vector<bool> multiEntryFlags;
550     backingStore()->getIndexes(databaseId(), m_id, ids, names, keyPaths, uniqueFlags, multiEntryFlags);
551
552     ASSERT(names.size() == ids.size());
553     ASSERT(keyPaths.size() == ids.size());
554     ASSERT(uniqueFlags.size() == ids.size());
555     ASSERT(multiEntryFlags.size() == ids.size());
556
557     for (size_t i = 0; i < ids.size(); ++i)
558         m_indexes.set(names[i], IDBIndexBackendImpl::create(m_database, this, ids[i], names[i], keyPaths[i], uniqueFlags[i], multiEntryFlags[i]));
559 }
560
561 void IDBObjectStoreBackendImpl::removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
562 {
563     ASSERT(objectStore->m_indexes.contains(index->name()));
564     objectStore->m_indexes.remove(index->name());
565 }
566
567 void IDBObjectStoreBackendImpl::addIndexToMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
568 {
569     RefPtr<IDBIndexBackendImpl> indexPtr = index;
570     ASSERT(!objectStore->m_indexes.contains(indexPtr->name()));
571     objectStore->m_indexes.set(indexPtr->name(), indexPtr);
572 }
573
574 PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::genAutoIncrementKey()
575 {
576     const int64_t kMaxGeneratorValue = 9007199254740992LL; // Maximum integer storable as ECMAScript number.
577     if (m_autoIncrementNumber > kMaxGeneratorValue)
578         return IDBKey::createInvalid();
579     if (m_autoIncrementNumber > 0)
580         return IDBKey::createNumber(m_autoIncrementNumber++);
581
582     m_autoIncrementNumber = backingStore()->nextAutoIncrementNumber(databaseId(), id());
583     if (m_autoIncrementNumber > kMaxGeneratorValue)
584         return IDBKey::createInvalid();
585     return IDBKey::createNumber(m_autoIncrementNumber++);
586 }
587
588
589 } // namespace WebCore
590
591 #endif