IndexedDB 2.0: Encapsulate cursor iteration parameters for easy future expansion.
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / server / MemoryIDBBackingStore.cpp
index c846357..b8e1a8a 100644 (file)
 
 #if ENABLE(INDEXED_DATABASE)
 
+#include "IDBCursorInfo.h"
+#include "IDBGetAllRecordsData.h"
+#include "IDBGetResult.h"
+#include "IDBIndexInfo.h"
+#include "IDBIterateCursorData.h"
+#include "IDBKeyRangeData.h"
 #include "Logging.h"
+#include "MemoryIndexCursor.h"
 #include "MemoryObjectStore.h"
+#include "MemoryObjectStoreCursor.h"
 
 namespace WebCore {
 namespace IDBServer {
 
+// The IndexedDB spec states the value you can get from the key generator is 2^53
+static uint64_t maxGeneratedKeyValue = 0x20000000000000;
+
 std::unique_ptr<MemoryIDBBackingStore> MemoryIDBBackingStore::create(const IDBDatabaseIdentifier& identifier)
 {
     return std::make_unique<MemoryIDBBackingStore>(identifier);
@@ -48,12 +59,13 @@ MemoryIDBBackingStore::~MemoryIDBBackingStore()
 {
 }
 
-const IDBDatabaseInfo& MemoryIDBBackingStore::getOrEstablishDatabaseInfo()
+IDBError MemoryIDBBackingStore::getOrEstablishDatabaseInfo(IDBDatabaseInfo& info)
 {
     if (!m_databaseInfo)
         m_databaseInfo = std::make_unique<IDBDatabaseInfo>(m_identifier.databaseName(), 0);
 
-    return *m_databaseInfo;
+    info = *m_databaseInfo;
+    return { };
 }
 
 void MemoryIDBBackingStore::setDatabaseInfo(const IDBDatabaseInfo& info)
@@ -69,7 +81,7 @@ IDBError MemoryIDBBackingStore::beginTransaction(const IDBTransactionInfo& info)
     LOG(IndexedDB, "MemoryIDBBackingStore::beginTransaction");
 
     if (m_transactions.contains(info.identifier()))
-        return IDBError(IDBExceptionCode::InvalidStateError, "Backing store asked to create transaction it already has a record of");
+        return { IDBDatabaseException::InvalidStateError, "Backing store asked to create transaction it already has a record of" };
 
     auto transaction = MemoryBackingStoreTransaction::create(*this, info);
 
@@ -84,35 +96,35 @@ IDBError MemoryIDBBackingStore::beginTransaction(const IDBTransactionInfo& info)
         }
     }
 
-    m_transactions.set(info.identifier(), WTF::move(transaction));
+    m_transactions.set(info.identifier(), WTFMove(transaction));
 
-    return IDBError();
+    return { };
 }
 
 IDBError MemoryIDBBackingStore::abortTransaction(const IDBResourceIdentifier& transactionIdentifier)
 {
-    LOG(IndexedDB, "MemoryIDBBackingStore::abortTransaction");
+    LOG(IndexedDB, "MemoryIDBBackingStore::abortTransaction - %s", transactionIdentifier.loggingString().utf8().data());
 
     auto transaction = m_transactions.take(transactionIdentifier);
     if (!transaction)
-        return IDBError(IDBExceptionCode::InvalidStateError, "Backing store asked to abort transaction it didn't have record of");
+        return { IDBDatabaseException::InvalidStateError, "Backing store asked to abort transaction it didn't have record of" };
 
     transaction->abort();
 
-    return IDBError();
+    return { };
 }
 
 IDBError MemoryIDBBackingStore::commitTransaction(const IDBResourceIdentifier& transactionIdentifier)
 {
-    LOG(IndexedDB, "MemoryIDBBackingStore::commitTransaction");
+    LOG(IndexedDB, "MemoryIDBBackingStore::commitTransaction - %s", transactionIdentifier.loggingString().utf8().data());
 
     auto transaction = m_transactions.take(transactionIdentifier);
     if (!transaction)
-        return IDBError(IDBExceptionCode::InvalidStateError, "Backing store asked to commit transaction it didn't have record of");
+        return { IDBDatabaseException::InvalidStateError, "Backing store asked to commit transaction it didn't have record of" };
 
     transaction->commit();
 
-    return IDBError();
+    return { };
 }
 
 IDBError MemoryIDBBackingStore::createObjectStore(const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo& info)
@@ -121,7 +133,7 @@ IDBError MemoryIDBBackingStore::createObjectStore(const IDBResourceIdentifier& t
 
     ASSERT(m_databaseInfo);
     if (m_databaseInfo->hasObjectStore(info.name()))
-        return IDBError(IDBExceptionCode::ConstraintError);
+        return { IDBDatabaseException::ConstraintError };
 
     ASSERT(!m_objectStoresByIdentifier.contains(info.identifier()));
     auto objectStore = MemoryObjectStore::create(info);
@@ -132,33 +144,59 @@ IDBError MemoryIDBBackingStore::createObjectStore(const IDBResourceIdentifier& t
     ASSERT(rawTransaction);
     ASSERT(rawTransaction->isVersionChange());
 
-    rawTransaction->addNewObjectStore(*objectStore);
-    registerObjectStore(WTF::move(objectStore));
+    rawTransaction->addNewObjectStore(objectStore.get());
+    registerObjectStore(WTFMove(objectStore));
 
-    return IDBError();
+    return { };
 }
 
-IDBError MemoryIDBBackingStore::deleteObjectStore(const IDBResourceIdentifier& transactionIdentifier, const String& objectStoreName)
+IDBError MemoryIDBBackingStore::deleteObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier)
 {
     LOG(IndexedDB, "MemoryIDBBackingStore::deleteObjectStore");
 
     ASSERT(m_databaseInfo);
-    if (!m_databaseInfo->hasObjectStore(objectStoreName))
-        return IDBError(IDBExceptionCode::ConstraintError);
+    if (!m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier))
+        return { IDBDatabaseException::ConstraintError };
+
+    auto transaction = m_transactions.get(transactionIdentifier);
+    ASSERT(transaction);
+    ASSERT(transaction->isVersionChange());
+
+    auto objectStore = takeObjectStoreByIdentifier(objectStoreIdentifier);
+    ASSERT(objectStore);
+    if (!objectStore)
+        return { IDBDatabaseException::ConstraintError };
+
+    m_databaseInfo->deleteObjectStore(objectStore->info().name());
+    transaction->objectStoreDeleted(*objectStore);
+
+    return { };
+}
+
+IDBError MemoryIDBBackingStore::renameObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const String& newName)
+{
+    LOG(IndexedDB, "MemoryIDBBackingStore::renameObjectStore");
+
+    ASSERT(m_databaseInfo);
+    if (!m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier))
+        return { IDBDatabaseException::ConstraintError };
 
     auto transaction = m_transactions.get(transactionIdentifier);
     ASSERT(transaction);
     ASSERT(transaction->isVersionChange());
 
-    auto objectStore = takeObjectStoreByName(objectStoreName);
+    auto objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
     ASSERT(objectStore);
     if (!objectStore)
-        return IDBError(IDBExceptionCode::ConstraintError);
+        return { IDBDatabaseException::ConstraintError };
+
+    String oldName = objectStore->info().name();
+    objectStore->rename(newName);
+    transaction->objectStoreRenamed(*objectStore, oldName);
 
-    m_databaseInfo->deleteObjectStore(objectStoreName);
-    transaction->objectStoreDeleted(WTF::move(objectStore));
+    m_databaseInfo->renameObjectStore(objectStoreIdentifier, newName);
 
-    return IDBError();
+    return { };
 }
 
 IDBError MemoryIDBBackingStore::clearObjectStore(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier)
@@ -168,33 +206,101 @@ IDBError MemoryIDBBackingStore::clearObjectStore(const IDBResourceIdentifier& tr
 
     ASSERT_UNUSED(transactionIdentifier, m_transactions.contains(transactionIdentifier));
 
-#ifndef NDEBUG
+#if !LOG_DISABLED
     auto transaction = m_transactions.get(transactionIdentifier);
     ASSERT(transaction->isWriting());
 #endif
 
     auto objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
     if (!objectStore)
-        return IDBError(IDBExceptionCode::ConstraintError);
+        return { IDBDatabaseException::ConstraintError };
 
     objectStore->clear();
 
-    return IDBError();
+    return { };
+}
+
+IDBError MemoryIDBBackingStore::createIndex(const IDBResourceIdentifier& transactionIdentifier, const IDBIndexInfo& info)
+{
+    LOG(IndexedDB, "MemoryIDBBackingStore::createIndex");
+
+    auto rawTransaction = m_transactions.get(transactionIdentifier);
+    ASSERT(rawTransaction);
+    ASSERT(rawTransaction->isVersionChange());
+
+    auto* objectStore = m_objectStoresByIdentifier.get(info.objectStoreIdentifier());
+    if (!objectStore)
+        return { IDBDatabaseException::ConstraintError };
+
+    return objectStore->createIndex(*rawTransaction, info);
+}
+
+IDBError MemoryIDBBackingStore::deleteIndex(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier)
+{
+    LOG(IndexedDB, "MemoryIDBBackingStore::deleteIndex");
+
+    auto rawTransaction = m_transactions.get(transactionIdentifier);
+    ASSERT(rawTransaction);
+    ASSERT(rawTransaction->isVersionChange());
+
+    auto* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
+    if (!objectStore)
+        return { IDBDatabaseException::ConstraintError };
+
+    return objectStore->deleteIndex(*rawTransaction, indexIdentifier);
+}
+
+IDBError MemoryIDBBackingStore::renameIndex(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName)
+{
+    LOG(IndexedDB, "MemoryIDBBackingStore::renameIndex");
+
+    ASSERT(m_databaseInfo);
+    auto* objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
+    if (!objectStoreInfo)
+        return { IDBDatabaseException::ConstraintError };
+
+    auto* indexInfo = objectStoreInfo->infoForExistingIndex(indexIdentifier);
+    if (!indexInfo)
+        return { IDBDatabaseException::ConstraintError };
+
+    auto transaction = m_transactions.get(transactionIdentifier);
+    ASSERT(transaction);
+    ASSERT(transaction->isVersionChange());
+
+    auto objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
+    ASSERT(objectStore);
+    if (!objectStore)
+        return { IDBDatabaseException::ConstraintError };
+
+    auto* index = objectStore->indexForIdentifier(indexIdentifier);
+    ASSERT(index);
+    if (!index)
+        return { IDBDatabaseException::ConstraintError };
+
+    String oldName = index->info().name();
+    objectStore->renameIndex(*index, newName);
+    transaction->indexRenamed(*index, oldName);
+
+    indexInfo->rename(newName);
+
+    return { };
 }
 
 void MemoryIDBBackingStore::removeObjectStoreForVersionChangeAbort(MemoryObjectStore& objectStore)
 {
     LOG(IndexedDB, "MemoryIDBBackingStore::removeObjectStoreForVersionChangeAbort");
 
-    ASSERT(m_objectStoresByIdentifier.contains(objectStore.info().identifier()));
+    if (!m_objectStoresByIdentifier.contains(objectStore.info().identifier()))
+        return;
+
     ASSERT(m_objectStoresByIdentifier.get(objectStore.info().identifier()) == &objectStore);
 
     unregisterObjectStore(objectStore);
 }
 
-void MemoryIDBBackingStore::restoreObjectStoreForVersionChangeAbort(std::unique_ptr<MemoryObjectStore>&& objectStore)
+void MemoryIDBBackingStore::restoreObjectStoreForVersionChangeAbort(Ref<MemoryObjectStore>&& objectStore)
 {
-    registerObjectStore(WTF::move(objectStore));
+    registerObjectStore(WTFMove(objectStore));
 }
 
 IDBError MemoryIDBBackingStore::keyExistsInObjectStore(const IDBResourceIdentifier&, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, bool& keyExists)
@@ -207,56 +313,118 @@ IDBError MemoryIDBBackingStore::keyExistsInObjectStore(const IDBResourceIdentifi
     RELEASE_ASSERT(objectStore);
 
     keyExists = objectStore->containsRecord(keyData);
-    return IDBError();
+    return { };
 }
 
-IDBError MemoryIDBBackingStore::deleteRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData)
+IDBError MemoryIDBBackingStore::deleteRange(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& range)
 {
-    LOG(IndexedDB, "MemoryIDBBackingStore::deleteRecord");
+    LOG(IndexedDB, "MemoryIDBBackingStore::deleteRange");
 
     ASSERT(objectStoreIdentifier);
 
+    if (!m_transactions.contains(transactionIdentifier))
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found to delete from") };
+
     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
-    RELEASE_ASSERT(objectStore);
-    RELEASE_ASSERT(m_transactions.contains(transactionIdentifier));
+    if (!objectStore)
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found") };
 
-    objectStore->deleteRecord(keyData);
-    return IDBError();
+    objectStore->deleteRange(range);
+    return { };
 }
 
-IDBError MemoryIDBBackingStore::putRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const ThreadSafeDataBuffer& value)
+IDBError MemoryIDBBackingStore::addRecord(const IDBResourceIdentifier& transactionIdentifier, const IDBObjectStoreInfo& objectStoreInfo, const IDBKeyData& keyData, const IDBValue& value)
 {
-    LOG(IndexedDB, "MemoryIDBBackingStore::putRecord");
+    LOG(IndexedDB, "MemoryIDBBackingStore::addRecord");
 
-    ASSERT(objectStoreIdentifier);
+    ASSERT(objectStoreInfo.identifier());
 
     auto transaction = m_transactions.get(transactionIdentifier);
     if (!transaction)
-        return IDBError(IDBExceptionCode::Unknown, WTF::ASCIILiteral("No backing store transaction found to put record"));
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found to put record") };
 
-    MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
+    MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreInfo.identifier());
     if (!objectStore)
-        return IDBError(IDBExceptionCode::Unknown, WTF::ASCIILiteral("No backing store object store found to put record"));
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found to put record") };
 
-    objectStore->putRecord(*transaction, keyData, value);
-    return IDBError();
+    return objectStore->addRecord(*transaction, keyData, value);
 }
 
-IDBError MemoryIDBBackingStore::getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, ThreadSafeDataBuffer& outValue)
+IDBError MemoryIDBBackingStore::getRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyRangeData& range, IDBGetResult& outValue)
 {
     LOG(IndexedDB, "MemoryIDBBackingStore::getRecord");
 
     ASSERT(objectStoreIdentifier);
 
     if (!m_transactions.contains(transactionIdentifier))
-        return IDBError(IDBExceptionCode::Unknown, WTF::ASCIILiteral("No backing store transaction found to get record"));
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found to get record") };
 
     MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
     if (!objectStore)
-        return IDBError(IDBExceptionCode::Unknown, WTF::ASCIILiteral("No backing store object store found"));
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found") };
 
-    outValue = objectStore->valueForKey(keyData);
-    return IDBError();
+    outValue = objectStore->valueForKeyRange(range);
+    return { };
+}
+
+IDBError MemoryIDBBackingStore::getAllRecords(const IDBResourceIdentifier& transactionIdentifier, const IDBGetAllRecordsData& getAllRecordsData, IDBGetAllResult& result)
+{
+    LOG(IndexedDB, "MemoryIDBBackingStore::getAllRecords");
+
+    ASSERT(getAllRecordsData.objectStoreIdentifier);
+
+    if (!m_transactions.contains(transactionIdentifier))
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found to get all records") };
+
+    auto* objectStore = m_objectStoresByIdentifier.get(getAllRecordsData.objectStoreIdentifier);
+    if (!objectStore)
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found") };
+
+    if (getAllRecordsData.indexIdentifier) {
+        auto* index = objectStore->indexForIdentifier(getAllRecordsData.indexIdentifier);
+        if (!index)
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store index found") };
+
+        index->getAllRecords(getAllRecordsData.keyRangeData, getAllRecordsData.count, getAllRecordsData.getAllType, result);
+    } else
+        objectStore->getAllRecords(getAllRecordsData.keyRangeData, getAllRecordsData.count, getAllRecordsData.getAllType, result);
+
+    return { };
+}
+
+IDBError MemoryIDBBackingStore::getIndexRecord(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, IndexedDB::IndexRecordType recordType, const IDBKeyRangeData& range, IDBGetResult& outValue)
+{
+    LOG(IndexedDB, "MemoryIDBBackingStore::getIndexRecord");
+
+    ASSERT(objectStoreIdentifier);
+
+    if (!m_transactions.contains(transactionIdentifier))
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found to get record") };
+
+    MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
+    if (!objectStore)
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found") };
+
+    outValue = objectStore->indexValueForKeyRange(indexIdentifier, recordType, range);
+    return { };
+}
+
+IDBError MemoryIDBBackingStore::getCount(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const IDBKeyRangeData& range, uint64_t& outCount)
+{
+    LOG(IndexedDB, "MemoryIDBBackingStore::getCount");
+
+    ASSERT(objectStoreIdentifier);
+
+    if (!m_transactions.contains(transactionIdentifier))
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found to get count") };
+
+    MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
+    if (!objectStore)
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found") };
+
+    outCount = objectStore->countForKeyRange(indexIdentifier, range);
+
+    return { };
 }
 
 IDBError MemoryIDBBackingStore::generateKeyNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t& keyNumber)
@@ -270,19 +438,118 @@ IDBError MemoryIDBBackingStore::generateKeyNumber(const IDBResourceIdentifier& t
     RELEASE_ASSERT(objectStore);
 
     keyNumber = objectStore->currentKeyGeneratorValue();
+    if (keyNumber > maxGeneratedKeyValue)
+        return { IDBDatabaseException::ConstraintError, "Cannot generate new key value over 2^53 for object store operation" };
+
     objectStore->setKeyGeneratorValue(keyNumber + 1);
 
-    return IDBError();
+    return { };
 }
 
-void MemoryIDBBackingStore::registerObjectStore(std::unique_ptr<MemoryObjectStore>&& objectStore)
+IDBError MemoryIDBBackingStore::revertGeneratedKeyNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, uint64_t keyNumber)
+{
+    LOG(IndexedDB, "MemoryIDBBackingStore::revertGeneratedKeyNumber");
+    ASSERT(objectStoreIdentifier);
+    ASSERT_UNUSED(transactionIdentifier, m_transactions.contains(transactionIdentifier));
+    ASSERT_UNUSED(transactionIdentifier, m_transactions.get(transactionIdentifier)->isWriting());
+
+    MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
+    RELEASE_ASSERT(objectStore);
+
+    objectStore->setKeyGeneratorValue(keyNumber);
+
+    return { };
+}
+
+IDBError MemoryIDBBackingStore::maybeUpdateKeyGeneratorNumber(const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, double newKeyNumber)
+{
+    LOG(IndexedDB, "MemoryIDBBackingStore::maybeUpdateKeyGeneratorNumber");
+    ASSERT(objectStoreIdentifier);
+    ASSERT_UNUSED(transactionIdentifier, m_transactions.contains(transactionIdentifier));
+    ASSERT_UNUSED(transactionIdentifier, m_transactions.get(transactionIdentifier)->isWriting());
+
+    MemoryObjectStore* objectStore = m_objectStoresByIdentifier.get(objectStoreIdentifier);
+    RELEASE_ASSERT(objectStore);
+
+    if (newKeyNumber < objectStore->currentKeyGeneratorValue())
+        return { };
+
+    uint64_t newKeyInteger(newKeyNumber);
+    if (newKeyInteger <= uint64_t(newKeyNumber))
+        ++newKeyInteger;
+
+    ASSERT(newKeyInteger > uint64_t(newKeyNumber));
+
+    objectStore->setKeyGeneratorValue(newKeyInteger);
+
+    return { };
+}
+
+IDBError MemoryIDBBackingStore::openCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBCursorInfo& info, IDBGetResult& outData)
+{
+    LOG(IndexedDB, "MemoryIDBBackingStore::openCursor");
+
+    ASSERT(!MemoryCursor::cursorForIdentifier(info.identifier()));
+
+    if (!m_transactions.contains(transactionIdentifier))
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found in which to open a cursor") };
+
+    switch (info.cursorSource()) {
+    case IndexedDB::CursorSource::ObjectStore: {
+        auto* objectStore = m_objectStoresByIdentifier.get(info.sourceIdentifier());
+        if (!objectStore)
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found") };
+
+        MemoryCursor* cursor = objectStore->maybeOpenCursor(info);
+        if (!cursor)
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("Could not create object store cursor in backing store") };
+
+        cursor->currentData(outData);
+        break;
+    }
+    case IndexedDB::CursorSource::Index:
+        auto* objectStore = m_objectStoresByIdentifier.get(info.objectStoreIdentifier());
+        if (!objectStore)
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store object store found") };
+
+        auto* index = objectStore->indexForIdentifier(info.sourceIdentifier());
+        if (!index)
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store index found") };
+
+        MemoryCursor* cursor = index->maybeOpenCursor(info);
+        if (!cursor)
+            return { IDBDatabaseException::UnknownError, ASCIILiteral("Could not create index cursor in backing store") };
+
+        cursor->currentData(outData);
+        break;
+    }
+
+    return { };
+}
+
+IDBError MemoryIDBBackingStore::iterateCursor(const IDBResourceIdentifier& transactionIdentifier, const IDBResourceIdentifier& cursorIdentifier, const IDBIterateCursorData& data, IDBGetResult& outData)
+{
+    LOG(IndexedDB, "MemoryIDBBackingStore::iterateCursor");
+
+    if (!m_transactions.contains(transactionIdentifier))
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store transaction found in which to iterate cursor") };
+
+    auto* cursor = MemoryCursor::cursorForIdentifier(cursorIdentifier);
+    if (!cursor)
+        return { IDBDatabaseException::UnknownError, ASCIILiteral("No backing store cursor found in which to iterate cursor") };
+
+    cursor->iterate(data.keyData, data.count, outData);
+
+    return { };
+}
+
+void MemoryIDBBackingStore::registerObjectStore(Ref<MemoryObjectStore>&& objectStore)
 {
-    ASSERT(objectStore);
     ASSERT(!m_objectStoresByIdentifier.contains(objectStore->info().identifier()));
     ASSERT(!m_objectStoresByName.contains(objectStore->info().name()));
 
-    m_objectStoresByName.set(objectStore->info().name(), objectStore.get());
-    m_objectStoresByIdentifier.set(objectStore->info().identifier(), WTF::move(objectStore));
+    m_objectStoresByName.set(objectStore->info().name(), &objectStore.get());
+    m_objectStoresByIdentifier.set(objectStore->info().identifier(), WTFMove(objectStore));
 }
 
 void MemoryIDBBackingStore::unregisterObjectStore(MemoryObjectStore& objectStore)
@@ -294,16 +561,27 @@ void MemoryIDBBackingStore::unregisterObjectStore(MemoryObjectStore& objectStore
     m_objectStoresByIdentifier.remove(objectStore.info().identifier());
 }
 
-std::unique_ptr<MemoryObjectStore> MemoryIDBBackingStore::takeObjectStoreByName(const String& name)
+RefPtr<MemoryObjectStore> MemoryIDBBackingStore::takeObjectStoreByIdentifier(uint64_t identifier)
 {
-    auto rawObjectStore = m_objectStoresByName.take(name);
-    if (!rawObjectStore)
+    auto objectStoreByIdentifier = m_objectStoresByIdentifier.take(identifier);
+    if (!objectStoreByIdentifier)
         return nullptr;
 
-    auto objectStore = m_objectStoresByIdentifier.take(rawObjectStore->info().identifier());
-    ASSERT(objectStore);
+    auto objectStore = m_objectStoresByName.take(objectStoreByIdentifier->info().name());
+    ASSERT_UNUSED(objectStore, objectStore);
 
-    return objectStore;
+    return objectStoreByIdentifier;
+}
+
+IDBObjectStoreInfo* MemoryIDBBackingStore::infoForObjectStore(uint64_t objectStoreIdentifier)
+{
+    ASSERT(m_databaseInfo);
+    return m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
+}
+
+void MemoryIDBBackingStore::deleteBackingStore()
+{
+    // The in-memory IDB backing store doesn't need to do any cleanup when it is deleted.
 }
 
 } // namespace IDBServer