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 "IDBTransactionBackendInterface.h"
45#include "ScriptExecutionContext.h"
46
47namespace WebCore {
48
49IDBObjectStoreBackendImpl::~IDBObjectStoreBackendImpl()
50{
51}
52
53IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBBackingStore* backingStore, int64_t databaseId, int64_t id, const String& name, const String& keyPath, bool autoIncrement)
54    : m_backingStore(backingStore)
55    , m_databaseId(databaseId)
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
65IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBBackingStore* backingStore, int64_t databaseId, const String& name, const String& keyPath, bool autoIncrement)
66    : m_backingStore(backingStore)
67    , m_databaseId(databaseId)
68    , m_id(InvalidId)
69    , m_name(name)
70    , m_keyPath(keyPath)
71    , m_autoIncrement(autoIncrement)
72    , m_autoIncrementNumber(-1)
73{
74}
75
76PassRefPtr<DOMStringList> IDBObjectStoreBackendImpl::indexNames() const
77{
78    RefPtr<DOMStringList> indexNames = DOMStringList::create();
79    for (IndexMap::const_iterator it = m_indexes.begin(); it != m_indexes.end(); ++it)
80        indexNames->append(it->first);
81    return indexNames.release();
82}
83
84void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
85{
86    RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
87    RefPtr<IDBKey> key = prpKey;
88    RefPtr<IDBCallbacks> callbacks = prpCallbacks;
89    if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::getInternal, objectStore, key, callbacks)))
90        ec = IDBDatabaseException::NOT_ALLOWED_ERR;
91}
92
93void IDBObjectStoreBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
94{
95    String wireData = objectStore->m_backingStore->getObjectStoreRecord(objectStore->m_databaseId, objectStore->id(), *key);
96    if (wireData.isNull()) {
97        callbacks->onSuccess(SerializedScriptValue::undefinedValue());
98        return;
99    }
100
101    callbacks->onSuccess(SerializedScriptValue::createFromWire(wireData));
102}
103
104static PassRefPtr<IDBKey> fetchKeyFromKeyPath(SerializedScriptValue* value, const String& keyPath)
105{
106    Vector<RefPtr<SerializedScriptValue> > values;
107    values.append(value);
108    Vector<RefPtr<IDBKey> > keys;
109    IDBKeyPathBackendImpl::createIDBKeysFromSerializedValuesAndKeyPath(values, keyPath, keys);
110    if (keys.isEmpty())
111        return 0;
112    ASSERT(keys.size() == 1);
113    return keys[0].release();
114}
115
116static PassRefPtr<SerializedScriptValue> injectKeyIntoKeyPath(PassRefPtr<IDBKey> key, PassRefPtr<SerializedScriptValue> value, const String& keyPath)
117{
118    return IDBKeyPathBackendImpl::injectIDBKeyIntoSerializedValue(key, value, keyPath);
119}
120
121void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
122{
123    if (transactionPtr->mode() == IDBTransaction::READ_ONLY) {
124        ec = IDBDatabaseException::READ_ONLY_ERR;
125        return;
126    }
127
128    RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
129    RefPtr<SerializedScriptValue> value = prpValue;
130    RefPtr<IDBKey> key = prpKey;
131    RefPtr<IDBCallbacks> callbacks = prpCallbacks;
132    RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
133    // FIXME: This should throw a SERIAL_ERR on structured clone problems.
134    // FIXME: This should throw a DATA_ERR when the wrong key/keyPath data is supplied.
135    if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::putInternal, objectStore, value, key, putMode, callbacks, transaction)))
136        ec = IDBDatabaseException::NOT_ALLOWED_ERR;
137}
138
139PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::selectKeyForPut(IDBObjectStoreBackendImpl* objectStore, IDBKey* key, PutMode putMode, IDBCallbacks* callbacks, RefPtr<SerializedScriptValue>& value)
140{
141    if (putMode == CursorUpdate)
142        ASSERT(key);
143
144    const bool autoIncrement = objectStore->autoIncrement();
145    const bool hasKeyPath = !objectStore->m_keyPath.isNull();
146
147    if (hasKeyPath && key && putMode != CursorUpdate) {
148        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "A key was supplied for an objectStore that has a keyPath."));
149        return 0;
150    }
151
152    if (autoIncrement && key) {
153        objectStore->resetAutoIncrementKeyCache();
154        return key;
155    }
156
157    if (autoIncrement) {
158        ASSERT(!key);
159        if (!hasKeyPath)
160            return objectStore->genAutoIncrementKey();
161
162        RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
163        if (keyPathKey) {
164            objectStore->resetAutoIncrementKeyCache();
165            return keyPathKey;
166        }
167
168        RefPtr<IDBKey> autoIncKey = objectStore->genAutoIncrementKey();
169        RefPtr<SerializedScriptValue> valueAfterInjection = injectKeyIntoKeyPath(autoIncKey, value, objectStore->m_keyPath);
170        if (!valueAfterInjection) {
171            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "The generated key could not be inserted into the object using the keyPath."));
172            return 0;
173        }
174        value = valueAfterInjection;
175        return autoIncKey.release();
176    }
177
178    if (hasKeyPath) {
179        RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
180
181        if (!keyPathKey) {
182            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "The key could not be fetched from the keyPath."));
183            return 0;
184        }
185
186        if (putMode == CursorUpdate && !keyPathKey->isEqual(key)) {
187            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "The key fetched from the keyPath does not match the key of the cursor."));
188            return 0;
189        }
190
191        return keyPathKey.release();
192    }
193
194    if (!key) {
195        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "No key supplied"));
196        return 0;
197    }
198
199    return key;
200}
201
202void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
203{
204    RefPtr<SerializedScriptValue> value = prpValue;
205    RefPtr<IDBKey> key = selectKeyForPut(objectStore.get(), prpKey.get(), putMode, callbacks.get(), value);
206    if (!key)
207        return;
208
209    if (key->type() == IDBKey::NullType) {
210        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "NULL key is not allowed."));
211        return;
212    }
213
214    Vector<RefPtr<IDBKey> > indexKeys;
215    for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
216        RefPtr<IDBKey> key = fetchKeyFromKeyPath(value.get(), it->second->keyPath());
217        if (!key) {
218            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "The key could not be fetched from an index's keyPath."));
219            return;
220        }
221        if (key->type() == IDBKey::NullType) {
222            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "One of the derived (from a keyPath) keys for an index is NULL."));
223            return;
224        }
225        if (!it->second->addingKeyAllowed(key.get())) {
226            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "One of the derived (from a keyPath) keys for an index does not satisfy its uniqueness requirements."));
227            return;
228        }
229        indexKeys.append(key.release());
230    }
231
232    RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = objectStore->m_backingStore->createInvalidRecordIdentifier();
233    bool isExistingValue = objectStore->m_backingStore->keyExistsInObjectStore(objectStore->m_databaseId, objectStore->id(), *key, recordIdentifier.get());
234
235    if (putMode == AddOnly && isExistingValue) {
236        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
237        return;
238    }
239
240    // Before this point, don't do any mutation.  After this point, rollback the transaction in case of error.
241
242    if (!objectStore->m_backingStore->putObjectStoreRecord(objectStore->m_databaseId, objectStore->id(), *key, value->toWireString(), recordIdentifier.get())) {
243        // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
244        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
245        transaction->abort();
246        return;
247    }
248
249    int i = 0;
250    for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it, ++i) {
251        if (!it->second->hasValidId())
252            continue; // The index object has been created, but does not exist in the database yet.
253
254        if (!objectStore->m_backingStore->deleteIndexDataForRecord(objectStore->m_databaseId, objectStore->id(), it->second->id(), recordIdentifier.get())) {
255            // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
256            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
257            transaction->abort();
258            return;
259        }
260
261        if (!objectStore->m_backingStore->putIndexDataForRecord(objectStore->m_databaseId, objectStore->id(), it->second->id(), *indexKeys[i], recordIdentifier.get())) {
262            // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
263            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
264            transaction->abort();
265            return;
266        }
267    }
268
269    callbacks->onSuccess(key.get());
270}
271
272void IDBObjectStoreBackendImpl::deleteFunction(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
273{
274    if (transaction->mode() == IDBTransaction::READ_ONLY) {
275        ec = IDBDatabaseException::READ_ONLY_ERR;
276        return;
277    }
278
279    RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
280    RefPtr<IDBKey> key = prpKey;
281    RefPtr<IDBCallbacks> callbacks = prpCallbacks;
282
283    if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::deleteInternal, objectStore, key, callbacks)))
284        ec = IDBDatabaseException::NOT_ALLOWED_ERR;
285}
286
287void IDBObjectStoreBackendImpl::deleteInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
288{
289    RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = objectStore->m_backingStore->createInvalidRecordIdentifier();
290    if (!objectStore->m_backingStore->keyExistsInObjectStore(objectStore->m_databaseId, objectStore->id(), *key, recordIdentifier.get())) {
291        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the object store."));
292        return;
293    }
294
295    for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
296        if (!it->second->hasValidId())
297            continue; // The index object has been created, but does not exist in the database yet.
298
299        if (!objectStore->m_backingStore->deleteIndexDataForRecord(objectStore->m_databaseId, objectStore->id(), it->second->id(), recordIdentifier.get()))
300            ASSERT_NOT_REACHED();
301    }
302
303    objectStore->m_backingStore->deleteObjectStoreRecord(objectStore->m_databaseId, objectStore->id(), recordIdentifier.get());
304    callbacks->onSuccess(SerializedScriptValue::nullValue());
305}
306
307void IDBObjectStoreBackendImpl::clear(PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
308{
309    if (transaction->mode() == IDBTransaction::READ_ONLY) {
310        ec = IDBDatabaseException::READ_ONLY_ERR;
311        return;
312    }
313
314    RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
315    RefPtr<IDBCallbacks> callbacks = prpCallbacks;
316
317    if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::clearInternal, objectStore, callbacks)))
318        ec = IDBDatabaseException::NOT_ALLOWED_ERR;
319}
320
321void IDBObjectStoreBackendImpl::clearInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBCallbacks> callbacks)
322{
323    objectStore->m_backingStore->clearObjectStore(objectStore->m_databaseId, objectStore->id());
324    callbacks->onSuccess(SerializedScriptValue::undefinedValue());
325}
326
327namespace {
328class PopulateIndexCallback : public IDBBackingStore::ObjectStoreRecordCallback {
329public:
330    PopulateIndexCallback(IDBBackingStore& backingStore, const String& indexKeyPath, int64_t databaseId, int64_t objectStoreId, int64_t indexId)
331        : m_backingStore(backingStore)
332        , m_indexKeyPath(indexKeyPath)
333        , m_databaseId(databaseId)
334        , m_objectStoreId(objectStoreId)
335        , m_indexId(indexId)
336    {
337    }
338
339    virtual bool callback(const IDBBackingStore::ObjectStoreRecordIdentifier* recordIdentifier, const String& value)
340    {
341        RefPtr<SerializedScriptValue> objectValue = SerializedScriptValue::createFromWire(value);
342        RefPtr<IDBKey> indexKey = fetchKeyFromKeyPath(objectValue.get(), m_indexKeyPath);
343
344        if (!indexKey)
345            return true;
346        if (!m_backingStore.putIndexDataForRecord(m_databaseId, m_objectStoreId, m_indexId, *indexKey, recordIdentifier))
347            return false;
348
349        return true;
350    }
351
352private:
353    IDBBackingStore& m_backingStore;
354    const String& m_indexKeyPath;
355    int64_t m_databaseId;
356    int64_t m_objectStoreId;
357    int64_t m_indexId;
358};
359}
360
361static bool populateIndex(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const String& indexKeyPath)
362{
363    PopulateIndexCallback callback(backingStore, indexKeyPath, databaseId, objectStoreId, indexId);
364    if (!backingStore.forEachObjectStoreRecord(databaseId, objectStoreId, callback))
365        return false;
366    return true;
367}
368
369PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::createIndex(const String& name, const String& keyPath, bool unique, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
370{
371    if (m_indexes.contains(name)) {
372        ec = IDBDatabaseException::CONSTRAINT_ERR;
373        return 0;
374    }
375    if (transaction->mode() != IDBTransaction::VERSION_CHANGE) {
376        ec = IDBDatabaseException::NOT_ALLOWED_ERR;
377        return 0;
378    }
379
380    RefPtr<IDBIndexBackendImpl> index = IDBIndexBackendImpl::create(m_backingStore.get(), m_databaseId, this, name, m_name, keyPath, unique);
381    ASSERT(index->name() == name);
382
383    RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
384    RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
385    if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::createIndexInternal, objectStore, index, transaction),
386                                   createCallbackTask(&IDBObjectStoreBackendImpl::removeIndexFromMap, objectStore, index))) {
387        ec = IDBDatabaseException::NOT_ALLOWED_ERR;
388        return 0;
389    }
390
391    m_indexes.set(name, index);
392    return index.release();
393}
394
395void IDBObjectStoreBackendImpl::createIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
396{
397    int64_t id;
398    if (!objectStore->m_backingStore->createIndex(objectStore->m_databaseId, objectStore->id(), index->name(), index->keyPath(), index->unique(), id)) {
399        transaction->abort();
400        return;
401    }
402
403    index->setId(id);
404
405    if (!populateIndex(*objectStore->m_backingStore, objectStore->m_databaseId, objectStore->m_id, id, index->keyPath())) {
406        transaction->abort();
407        return;
408    }
409
410    transaction->didCompleteTaskEvents();
411}
412
413PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::index(const String& name, ExceptionCode& ec)
414{
415    RefPtr<IDBIndexBackendInterface> index = m_indexes.get(name);
416    if (!index) {
417        ec = IDBDatabaseException::NOT_FOUND_ERR;
418        return 0;
419    }
420    return index.release();
421}
422
423void IDBObjectStoreBackendImpl::deleteIndex(const String& name, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
424{
425    if (transaction->mode() != IDBTransaction::VERSION_CHANGE) {
426        ec = IDBDatabaseException::NOT_ALLOWED_ERR;
427        return;
428    }
429
430    RefPtr<IDBIndexBackendImpl> index = m_indexes.get(name);
431    if (!index) {
432        ec = IDBDatabaseException::NOT_FOUND_ERR;
433        return;
434    }
435
436    RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
437    RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
438    if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::deleteIndexInternal, objectStore, index, transactionPtr),
439                                   createCallbackTask(&IDBObjectStoreBackendImpl::addIndexToMap, objectStore, index))) {
440        ec = IDBDatabaseException::NOT_ALLOWED_ERR;
441        return;
442    }
443    m_indexes.remove(name);
444}
445
446void IDBObjectStoreBackendImpl::deleteIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
447{
448    objectStore->m_backingStore->deleteIndex(objectStore->m_databaseId, objectStore->id(), index->id());
449    transaction->didCompleteTaskEvents();
450}
451
452void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
453{
454    RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
455    RefPtr<IDBKeyRange> range = prpRange;
456    RefPtr<IDBCallbacks> callbacks = prpCallbacks;
457    RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
458    if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::openCursorInternal, objectStore, range, direction, callbacks, transaction)))
459        ec = IDBDatabaseException::NOT_ALLOWED_ERR;
460}
461
462void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
463{
464    IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(tmpDirection);
465
466    RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->m_backingStore->openObjectStoreCursor(objectStore->m_databaseId, objectStore->id(), range.get(), direction);
467    if (!backingStoreCursor) {
468        callbacks->onSuccess(SerializedScriptValue::nullValue());
469        return;
470    }
471
472    RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(backingStoreCursor.release(), direction, IDBCursorBackendInterface::ObjectStoreCursor, transaction.get(), objectStore.get());
473    callbacks->onSuccess(cursor.release());
474}
475
476void IDBObjectStoreBackendImpl::loadIndexes()
477{
478    Vector<int64_t> ids;
479    Vector<String> names;
480    Vector<String> keyPaths;
481    Vector<bool> uniqueFlags;
482    m_backingStore->getIndexes(m_databaseId, m_id, ids, names, keyPaths, uniqueFlags);
483
484    ASSERT(names.size() == ids.size());
485    ASSERT(keyPaths.size() == ids.size());
486    ASSERT(uniqueFlags.size() == ids.size());
487
488    for (size_t i = 0; i < ids.size(); i++)
489        m_indexes.set(names[i], IDBIndexBackendImpl::create(m_backingStore.get(), m_databaseId, this, ids[i], names[i], m_name, keyPaths[i], uniqueFlags[i]));
490}
491
492void IDBObjectStoreBackendImpl::removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
493{
494    ASSERT(objectStore->m_indexes.contains(index->name()));
495    objectStore->m_indexes.remove(index->name());
496}
497
498void IDBObjectStoreBackendImpl::addIndexToMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
499{
500    RefPtr<IDBIndexBackendImpl> indexPtr = index;
501    ASSERT(!objectStore->m_indexes.contains(indexPtr->name()));
502    objectStore->m_indexes.set(indexPtr->name(), indexPtr);
503}
504
505PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::genAutoIncrementKey()
506{
507    if (m_autoIncrementNumber > 0)
508        return IDBKey::createNumber(m_autoIncrementNumber++);
509
510    m_autoIncrementNumber = static_cast<int>(m_backingStore->nextAutoIncrementNumber(m_databaseId, id()));
511    return IDBKey::createNumber(m_autoIncrementNumber++);
512}
513
514
515} // namespace WebCore
516
517#endif
518