a468654e07b8162f1a57bd5054e0359c8e2c7e4d
[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 "IDBTransactionBackendInterface.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::getByRangeInternal");
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 (putMode != CursorUpdate) {
152         const bool autoIncrement = objectStore->autoIncrement();
153         const bool hasKeyPath = !objectStore->m_keyPath.isNull();
154
155         if (hasKeyPath && key) {
156             ec = IDBDatabaseException::DATA_ERR;
157             return;
158         }
159         if (!hasKeyPath && !autoIncrement && !key) {
160             ec = IDBDatabaseException::DATA_ERR;
161             return;
162         }
163         if (hasKeyPath) {
164             RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
165             if (keyPathKey && !keyPathKey->isValid()) {
166                 ec = IDBDatabaseException::DATA_ERR;
167                 return;
168             }
169             if (!autoIncrement && !keyPathKey) {
170                 ec = IDBDatabaseException::DATA_ERR;
171                 return;
172             }
173             if (autoIncrement && !keyPathKey) {
174                 RefPtr<IDBKey> dummyKey = IDBKey::createNumber(-1);
175                 RefPtr<SerializedScriptValue> valueAfterInjection = injectKeyIntoKeyPath(dummyKey, value, objectStore->m_keyPath);
176                 if (!valueAfterInjection) {
177                     ec = IDBDatabaseException::DATA_ERR;
178                     return;
179                 }
180             }
181         }
182         if (key && !key->isValid()) {
183             ec = IDBDatabaseException::DATA_ERR;
184             return;
185         }
186     } else {
187         ASSERT(key);
188         const bool hasKeyPath = !objectStore->m_keyPath.isNull();
189         if (hasKeyPath) {
190             RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
191             if (!keyPathKey || !keyPathKey->isEqual(key.get())) {
192                 ec = IDBDatabaseException::DATA_ERR;
193                 return;
194             }
195         }
196     }
197
198     if (!transaction->scheduleTask(
199             createCallbackTask(&IDBObjectStoreBackendImpl::putInternal, objectStore, value, key, putMode, callbacks, transaction),
200             // FIXME: One of these per put() is overkill, since it's simply a cache invalidation.
201             createCallbackTask(&IDBObjectStoreBackendImpl::revertAutoIncrementKeyCache, objectStore)))
202         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
203 }
204
205 void IDBObjectStoreBackendImpl::revertAutoIncrementKeyCache(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
206 {
207     objectStore->resetAutoIncrementKeyCache();
208 }
209
210 namespace {
211 class IndexWriter {
212 public:
213     explicit IndexWriter(PassRefPtr<IDBIndexBackendImpl> index)
214         : m_index(index)
215     {
216     }
217
218     bool loadIndexKeysForValue(SerializedScriptValue* objectValue, const IDBKey* primaryKey = 0, String* errorMessage = 0)
219     {
220         m_indexKeys.clear();
221
222         RefPtr<IDBKey> indexKey = fetchKeyFromKeyPath(objectValue, m_index->keyPath());
223
224         if (!indexKey)
225             return true;
226
227         if (!m_index->multiEntry() || indexKey->type() != IDBKey::ArrayType) {
228             if (!indexKey->isValid())
229                 return true;
230
231             if (!m_index->addingKeyAllowed(indexKey.get(), primaryKey)) {
232                 if (errorMessage)
233                     *errorMessage = String::format("Unable to add key to index '%s': the key does not satisfy its uniqueness requirements.",
234                                                    m_index->name().utf8().data());
235                 return false;
236             }
237             m_indexKeys.append(indexKey);
238         } else {
239             ASSERT(m_index->multiEntry());
240             ASSERT(indexKey->type() == IDBKey::ArrayType);
241             indexKey = IDBKey::createMultiEntryArray(indexKey->array());
242
243             for (size_t i = 0; i < indexKey->array().size(); ++i) {
244                 if (!m_index->addingKeyAllowed(indexKey->array()[i].get(), primaryKey)) {
245                     if (errorMessage)
246                         *errorMessage = String::format("Unable to add key to index '%s': at least one key does not satisfy the uniqueness requirements.",
247                                                        m_index->name().utf8().data());
248                     return false;
249                 }
250                 m_indexKeys.append(indexKey->array()[i]);
251             }
252         }
253         return true;
254     }
255
256     bool writeIndexKeys(const IDBBackingStore::ObjectStoreRecordIdentifier* recordIdentifier, IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, String* errorMessage = 0)
257     {
258         for (size_t i = 0; i < m_indexKeys.size(); ++i) {
259             if (!backingStore.deleteIndexDataForRecord(databaseId, objectStoreId, m_index->id(), recordIdentifier))
260                 return false;
261             if (!backingStore.putIndexDataForRecord(databaseId, objectStoreId, m_index->id(), *m_indexKeys[i].get(), recordIdentifier))
262                 return false;
263         }
264         return true;
265     }
266
267 private:
268     RefPtr<IDBIndexBackendImpl> m_index;
269     Vector<RefPtr<IDBKey> > m_indexKeys;
270 };
271 }
272
273 void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
274 {
275     IDB_TRACE("IDBObjectStoreBackendImpl::putInternal");
276     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
277     RefPtr<SerializedScriptValue> value = prpValue;
278     RefPtr<IDBKey> key = prpKey;
279
280     if (putMode != CursorUpdate) {
281         const bool autoIncrement = objectStore->autoIncrement();
282         const bool hasKeyPath = !objectStore->m_keyPath.isNull();
283         if (hasKeyPath) {
284             ASSERT(!key);
285             RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
286             if (keyPathKey)
287                 key = keyPathKey;
288         }
289         if (autoIncrement) {
290             if (!key) {
291                 RefPtr<IDBKey> autoIncKey = objectStore->genAutoIncrementKey();
292                 if (!autoIncKey->isValid()) {
293                     callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "Maximum key generator value reached."));
294                     return;
295                 }
296                 if (hasKeyPath) {
297                     RefPtr<SerializedScriptValue> valueAfterInjection = injectKeyIntoKeyPath(autoIncKey, value, objectStore->m_keyPath);
298                     ASSERT(valueAfterInjection);
299                     if (!valueAfterInjection) {
300                         objectStore->resetAutoIncrementKeyCache();
301                         // Checks in put() ensure this should only happen if I/O error occurs.
302                         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error inserting generated key into the object."));
303                         return;
304                     }
305                     value = valueAfterInjection;
306                 }
307                 key = autoIncKey;
308             } else {
309                 // FIXME: Logic to update generator state should go here. Currently it does a scan.
310                 objectStore->resetAutoIncrementKeyCache();
311             }
312         }
313     }
314
315     ASSERT(key && key->isValid());
316
317     RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = objectStore->backingStore()->createInvalidRecordIdentifier();
318     if (putMode == AddOnly && objectStore->backingStore()->keyExistsInObjectStore(objectStore->databaseId(), objectStore->id(), *key, recordIdentifier.get())) {
319         objectStore->resetAutoIncrementKeyCache();
320         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
321         return;
322     }
323
324     Vector<OwnPtr<IndexWriter> > indexWriters;
325     for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
326
327         const RefPtr<IDBIndexBackendImpl>& index = it->second;
328         if (!index->hasValidId())
329             continue; // The index object has been created, but does not exist in the database yet.
330
331         OwnPtr<IndexWriter> indexWriter(adoptPtr(new IndexWriter(index)));
332         String errorMessage;
333         if (!indexWriter->loadIndexKeysForValue(value.get(), key.get(), &errorMessage)) {
334             objectStore->resetAutoIncrementKeyCache();
335             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, errorMessage));
336             return;
337         }
338
339         indexWriters.append(indexWriter.release());
340     }
341
342     // Before this point, don't do any mutation.  After this point, rollback the transaction in case of error.
343
344     if (!objectStore->backingStore()->putObjectStoreRecord(objectStore->databaseId(), objectStore->id(), *key, value->toWireString(), recordIdentifier.get())) {
345         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
346         transaction->abort();
347         return;
348     }
349
350     for (size_t i = 0; i < indexWriters.size(); ++i) {
351         if (!indexWriters[i]->writeIndexKeys(recordIdentifier.get(),
352                                              *objectStore->backingStore(), objectStore->databaseId(),
353                                              objectStore->m_id)) {
354             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
355             transaction->abort();
356             return;
357         }
358     }
359
360     callbacks->onSuccess(key.get());
361 }
362
363 void IDBObjectStoreBackendImpl::deleteFunction(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
364 {
365     IDB_TRACE("IDBObjectStoreBackendImpl::delete");
366
367     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
368
369     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
370     RefPtr<IDBKeyRange> keyRange = prpKeyRange;
371     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
372
373     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::deleteInternal, objectStore, keyRange, callbacks)))
374         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
375 }
376
377 void IDBObjectStoreBackendImpl::deleteInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
378 {
379     IDB_TRACE("IDBObjectStoreBackendImpl::deleteInternal");
380     RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier;
381
382     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), keyRange.get(), IDBCursor::NEXT);
383     if (backingStoreCursor) {
384
385         do {
386             recordIdentifier = backingStoreCursor->objectStoreRecordIdentifier();
387
388             for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
389                 if (!it->second->hasValidId())
390                     continue; // The index object has been created, but does not exist in the database yet.
391
392                 bool success = objectStore->backingStore()->deleteIndexDataForRecord(objectStore->databaseId(), objectStore->id(), it->second->id(), recordIdentifier.get());
393                 ASSERT_UNUSED(success, success);
394             }
395
396             objectStore->backingStore()->deleteObjectStoreRecord(objectStore->databaseId(), objectStore->id(), recordIdentifier.get());
397
398         } while (backingStoreCursor->continueFunction(0));
399
400         backingStoreCursor->close();
401     }
402
403     callbacks->onSuccess(SerializedScriptValue::undefinedValue());
404 }
405
406 void IDBObjectStoreBackendImpl::clear(PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
407 {
408     IDB_TRACE("IDBObjectStoreBackendImpl::clear");
409
410     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
411
412     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
413     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
414
415     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::clearInternal, objectStore, callbacks)))
416         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
417 }
418
419 void IDBObjectStoreBackendImpl::clearInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBCallbacks> callbacks)
420 {
421     objectStore->backingStore()->clearObjectStore(objectStore->databaseId(), objectStore->id());
422     callbacks->onSuccess(SerializedScriptValue::undefinedValue());
423 }
424
425 namespace {
426 class PopulateIndexCallback : public IDBBackingStore::ObjectStoreRecordCallback {
427 public:
428     PopulateIndexCallback(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBIndexBackendImpl> index)
429         : m_backingStore(backingStore)
430         , m_databaseId(databaseId)
431         , m_objectStoreId(objectStoreId)
432         , m_writer(index)
433     {
434     }
435
436     virtual bool callback(const IDBBackingStore::ObjectStoreRecordIdentifier* recordIdentifier, const String& value)
437     {
438         RefPtr<SerializedScriptValue> objectValue = SerializedScriptValue::createFromWire(value);
439         if (!m_writer.loadIndexKeysForValue(objectValue.get()))
440             return false;
441         return m_writer.writeIndexKeys(recordIdentifier, m_backingStore, m_databaseId, m_objectStoreId);
442     }
443
444 private:
445     IDBBackingStore& m_backingStore;
446     int64_t m_databaseId;
447     int64_t m_objectStoreId;
448     IndexWriter m_writer;
449 };
450 }
451
452 bool IDBObjectStoreBackendImpl::populateIndex(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBIndexBackendImpl> index)
453 {
454     PopulateIndexCallback callback(backingStore, databaseId, objectStoreId, index);
455     if (!backingStore.forEachObjectStoreRecord(databaseId, objectStoreId, callback))
456         return false;
457     return true;
458 }
459
460 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::createIndex(const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
461 {
462     if (name.isNull()) {
463         ec = IDBDatabaseException::IDB_TYPE_ERR;
464         return 0;
465     }
466     if (m_indexes.contains(name)) {
467         ec = IDBDatabaseException::CONSTRAINT_ERR;
468         return 0;
469     }
470     if (transaction->mode() != IDBTransaction::VERSION_CHANGE) {
471         ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
472         return 0;
473     }
474
475     RefPtr<IDBIndexBackendImpl> index = IDBIndexBackendImpl::create(m_database, this, name, keyPath, unique, multiEntry);
476     ASSERT(index->name() == name);
477
478     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
479     RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
480     if (!transaction->scheduleTask(
481               createCallbackTask(&IDBObjectStoreBackendImpl::createIndexInternal,
482                                  objectStore, index, transactionPtr),
483               createCallbackTask(&IDBObjectStoreBackendImpl::removeIndexFromMap,
484                                  objectStore, index))) {
485         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
486         return 0;
487     }
488
489     m_indexes.set(name, index);
490     return index.release();
491 }
492
493 void IDBObjectStoreBackendImpl::createIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
494 {
495     int64_t id;
496     if (!objectStore->backingStore()->createIndex(objectStore->databaseId(), objectStore->id(), index->name(), index->keyPath(), index->unique(), index->multiEntry(), id)) {
497         transaction->abort();
498         return;
499     }
500
501     index->setId(id);
502
503     if (!populateIndex(*objectStore->backingStore(), objectStore->databaseId(), objectStore->m_id, index)) {
504         transaction->abort();
505         return;
506     }
507
508     transaction->didCompleteTaskEvents();
509 }
510
511 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::index(const String& name, ExceptionCode& ec)
512 {
513     RefPtr<IDBIndexBackendInterface> index = m_indexes.get(name);
514     if (!index) {
515         ec = IDBDatabaseException::IDB_NOT_FOUND_ERR;
516         return 0;
517     }
518     return index.release();
519 }
520
521 void IDBObjectStoreBackendImpl::deleteIndex(const String& name, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
522 {
523     if (transaction->mode() != IDBTransaction::VERSION_CHANGE) {
524         ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
525         return;
526     }
527
528     RefPtr<IDBIndexBackendImpl> index = m_indexes.get(name);
529     if (!index) {
530         ec = IDBDatabaseException::IDB_NOT_FOUND_ERR;
531         return;
532     }
533
534     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
535     RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
536     if (!transaction->scheduleTask(
537               createCallbackTask(&IDBObjectStoreBackendImpl::deleteIndexInternal,
538                                  objectStore, index, transactionPtr),
539               createCallbackTask(&IDBObjectStoreBackendImpl::addIndexToMap,
540                                  objectStore, index))) {
541         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
542         return;
543     }
544     m_indexes.remove(name);
545 }
546
547 void IDBObjectStoreBackendImpl::deleteIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
548 {
549     objectStore->backingStore()->deleteIndex(objectStore->databaseId(), objectStore->id(), index->id());
550     transaction->didCompleteTaskEvents();
551 }
552
553 void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
554 {
555     IDB_TRACE("IDBObjectStoreBackendImpl::openCursor");
556     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
557     RefPtr<IDBKeyRange> range = prpRange;
558     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
559     RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
560     if (!transaction->scheduleTask(
561             createCallbackTask(&IDBObjectStoreBackendImpl::openCursorInternal,
562                                objectStore, range, direction, callbacks, transactionPtr))) {
563         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
564     }
565 }
566
567 void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
568 {
569     IDB_TRACE("IDBObjectStoreBackendImpl::openCursorInternal");
570     IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(tmpDirection);
571
572     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), range.get(), direction);
573     if (!backingStoreCursor) {
574         callbacks->onSuccess(SerializedScriptValue::nullValue());
575         return;
576     }
577
578     RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(backingStoreCursor.release(), direction, IDBCursorBackendInterface::ObjectStoreCursor, transaction.get(), objectStore.get());
579     callbacks->onSuccess(cursor.release());
580 }
581
582 void IDBObjectStoreBackendImpl::count(PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
583 {
584     IDB_TRACE("IDBObjectStoreBackendImpl::count");
585     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::countInternal, this, range, callbacks, transaction)))
586         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
587 }
588
589 void IDBObjectStoreBackendImpl::countInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface>)
590 {
591     IDB_TRACE("IDBObjectStoreBackendImpl::countInternal");
592     uint32_t count = 0;
593     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), range.get(), IDBCursor::NEXT);
594     if (!backingStoreCursor) {
595         callbacks->onSuccess(SerializedScriptValue::numberValue(count));
596         return;
597     }
598
599     do {
600         ++count;
601     } while (backingStoreCursor->continueFunction(0));
602
603     backingStoreCursor->close();
604     callbacks->onSuccess(SerializedScriptValue::numberValue(count));
605 }
606
607 void IDBObjectStoreBackendImpl::loadIndexes()
608 {
609     Vector<int64_t> ids;
610     Vector<String> names;
611     Vector<IDBKeyPath> keyPaths;
612     Vector<bool> uniqueFlags;
613     Vector<bool> multiEntryFlags;
614     backingStore()->getIndexes(databaseId(), m_id, ids, names, keyPaths, uniqueFlags, multiEntryFlags);
615
616     ASSERT(names.size() == ids.size());
617     ASSERT(keyPaths.size() == ids.size());
618     ASSERT(uniqueFlags.size() == ids.size());
619     ASSERT(multiEntryFlags.size() == ids.size());
620
621     for (size_t i = 0; i < ids.size(); ++i)
622         m_indexes.set(names[i], IDBIndexBackendImpl::create(m_database, this, ids[i], names[i], keyPaths[i], uniqueFlags[i], multiEntryFlags[i]));
623 }
624
625 void IDBObjectStoreBackendImpl::removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
626 {
627     ASSERT(objectStore->m_indexes.contains(index->name()));
628     objectStore->m_indexes.remove(index->name());
629 }
630
631 void IDBObjectStoreBackendImpl::addIndexToMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
632 {
633     RefPtr<IDBIndexBackendImpl> indexPtr = index;
634     ASSERT(!objectStore->m_indexes.contains(indexPtr->name()));
635     objectStore->m_indexes.set(indexPtr->name(), indexPtr);
636 }
637
638 PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::genAutoIncrementKey()
639 {
640     const int64_t kMaxGeneratorValue = 9007199254740992LL; // Maximum integer storable as ECMAScript number.
641     if (m_autoIncrementNumber > kMaxGeneratorValue)
642         return IDBKey::createInvalid();
643     if (m_autoIncrementNumber > 0)
644         return IDBKey::createNumber(m_autoIncrementNumber++);
645
646     m_autoIncrementNumber = backingStore()->nextAutoIncrementNumber(databaseId(), id());
647     if (m_autoIncrementNumber > kMaxGeneratorValue)
648         return IDBKey::createInvalid();
649     return IDBKey::createNumber(m_autoIncrementNumber++);
650 }
651
652
653 } // namespace WebCore
654
655 #endif