Home | History | Annotate | Download | only in indexeddb
      1 /*
      2  * Copyright (C) 2010 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 "modules/indexeddb/IDBObjectStore.h"
     28 
     29 #include "bindings/v8/ExceptionState.h"
     30 #include "bindings/v8/ExceptionStatePlaceholder.h"
     31 #include "bindings/v8/IDBBindingUtilities.h"
     32 #include "bindings/v8/ScriptState.h"
     33 #include "core/dom/DOMStringList.h"
     34 #include "core/dom/ExceptionCode.h"
     35 #include "core/dom/ExecutionContext.h"
     36 #include "modules/indexeddb/IDBAny.h"
     37 #include "modules/indexeddb/IDBCursorWithValue.h"
     38 #include "modules/indexeddb/IDBDatabase.h"
     39 #include "modules/indexeddb/IDBKeyPath.h"
     40 #include "modules/indexeddb/IDBTracing.h"
     41 #include "modules/indexeddb/WebIDBCallbacksImpl.h"
     42 #include "platform/SharedBuffer.h"
     43 #include "public/platform/WebBlobInfo.h"
     44 #include "public/platform/WebData.h"
     45 #include "public/platform/WebIDBKey.h"
     46 #include "public/platform/WebIDBKeyRange.h"
     47 #include "public/platform/WebVector.h"
     48 #include <v8.h>
     49 
     50 using blink::WebBlobInfo;
     51 using blink::WebIDBCallbacks;
     52 using blink::WebIDBCursor;
     53 using blink::WebIDBDatabase;
     54 using blink::WebVector;
     55 
     56 namespace WebCore {
     57 
     58 IDBObjectStore::IDBObjectStore(const IDBObjectStoreMetadata& metadata, IDBTransaction* transaction)
     59     : m_metadata(metadata)
     60     , m_transaction(transaction)
     61     , m_deleted(false)
     62 {
     63     ASSERT(m_transaction);
     64     ScriptWrappable::init(this);
     65 }
     66 
     67 void IDBObjectStore::trace(Visitor* visitor)
     68 {
     69     visitor->trace(m_transaction);
     70     visitor->trace(m_indexMap);
     71 }
     72 
     73 ScriptValue IDBObjectStore::keyPath(ScriptState* scriptState) const
     74 {
     75     return idbAnyToScriptValue(scriptState, IDBAny::create(m_metadata.keyPath));
     76 }
     77 
     78 PassRefPtrWillBeRawPtr<DOMStringList> IDBObjectStore::indexNames() const
     79 {
     80     IDB_TRACE("IDBObjectStore::indexNames");
     81     RefPtrWillBeRawPtr<DOMStringList> indexNames = DOMStringList::create();
     82     for (IDBObjectStoreMetadata::IndexMap::const_iterator it = m_metadata.indexes.begin(); it != m_metadata.indexes.end(); ++it)
     83         indexNames->append(it->value.name);
     84     indexNames->sort();
     85     return indexNames.release();
     86 }
     87 
     88 IDBRequest* IDBObjectStore::get(ScriptState* scriptState, const ScriptValue& key, ExceptionState& exceptionState)
     89 {
     90     IDB_TRACE("IDBObjectStore::get");
     91     if (isDeleted()) {
     92         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
     93         return 0;
     94     }
     95     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
     96         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
     97         return 0;
     98     }
     99     if (!m_transaction->isActive()) {
    100         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
    101         return 0;
    102     }
    103     IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), key, exceptionState);
    104     if (exceptionState.hadException())
    105         return 0;
    106     if (!keyRange) {
    107         exceptionState.throwDOMException(DataError, IDBDatabase::noKeyOrKeyRangeErrorMessage);
    108         return 0;
    109     }
    110     if (!backendDB()) {
    111         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
    112         return 0;
    113     }
    114 
    115     IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get());
    116     backendDB()->get(m_transaction->id(), id(), IDBIndexMetadata::InvalidId, keyRange, false, WebIDBCallbacksImpl::create(request).leakPtr());
    117     return request;
    118 }
    119 
    120 static void generateIndexKeysForValue(v8::Isolate* isolate, const IDBIndexMetadata& indexMetadata, const ScriptValue& objectValue, IDBObjectStore::IndexKeys* indexKeys)
    121 {
    122     ASSERT(indexKeys);
    123     IDBKey* indexKey = createIDBKeyFromScriptValueAndKeyPath(isolate, objectValue, indexMetadata.keyPath);
    124 
    125     if (!indexKey)
    126         return;
    127 
    128     if (!indexMetadata.multiEntry || indexKey->type() != IDBKey::ArrayType) {
    129         if (!indexKey->isValid())
    130             return;
    131 
    132         indexKeys->append(indexKey);
    133     } else {
    134         ASSERT(indexMetadata.multiEntry);
    135         ASSERT(indexKey->type() == IDBKey::ArrayType);
    136         indexKey = IDBKey::createMultiEntryArray(indexKey->array());
    137 
    138         for (size_t i = 0; i < indexKey->array().size(); ++i)
    139             indexKeys->append(indexKey->array()[i]);
    140     }
    141 }
    142 
    143 IDBRequest* IDBObjectStore::add(ScriptState* scriptState, ScriptValue& value, const ScriptValue& key, ExceptionState& exceptionState)
    144 {
    145     IDB_TRACE("IDBObjectStore::add");
    146     return put(scriptState, blink::WebIDBPutModeAddOnly, IDBAny::create(this), value, key, exceptionState);
    147 }
    148 
    149 IDBRequest* IDBObjectStore::put(ScriptState* scriptState, ScriptValue& value, const ScriptValue& key, ExceptionState& exceptionState)
    150 {
    151     IDB_TRACE("IDBObjectStore::put");
    152     return put(scriptState, blink::WebIDBPutModeAddOrUpdate, IDBAny::create(this), value, key, exceptionState);
    153 }
    154 
    155 IDBRequest* IDBObjectStore::put(ScriptState* scriptState, blink::WebIDBPutMode putMode, IDBAny* source, ScriptValue& value, const ScriptValue& keyValue, ExceptionState& exceptionState)
    156 {
    157     IDBKey* key = keyValue.isUndefined() ? nullptr : scriptValueToIDBKey(scriptState->isolate(), keyValue);
    158     return put(scriptState, putMode, source, value, key, exceptionState);
    159 }
    160 
    161 IDBRequest* IDBObjectStore::put(ScriptState* scriptState, blink::WebIDBPutMode putMode, IDBAny* source, ScriptValue& value, IDBKey* key, ExceptionState& exceptionState)
    162 {
    163     if (isDeleted()) {
    164         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
    165         return 0;
    166     }
    167     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
    168         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
    169         return 0;
    170     }
    171     if (!m_transaction->isActive()) {
    172         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
    173         return 0;
    174     }
    175     if (m_transaction->isReadOnly()) {
    176         exceptionState.throwDOMException(ReadOnlyError, IDBDatabase::transactionReadOnlyErrorMessage);
    177         return 0;
    178     }
    179 
    180     Vector<WebBlobInfo> blobInfo;
    181     RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(value, &blobInfo, exceptionState, scriptState->isolate());
    182     if (exceptionState.hadException())
    183         return 0;
    184 
    185     const IDBKeyPath& keyPath = m_metadata.keyPath;
    186     const bool usesInLineKeys = !keyPath.isNull();
    187     const bool hasKeyGenerator = autoIncrement();
    188 
    189     if (putMode != blink::WebIDBPutModeCursorUpdate && usesInLineKeys && key) {
    190         exceptionState.throwDOMException(DataError, "The object store uses in-line keys and the key parameter was provided.");
    191         return 0;
    192     }
    193     if (!usesInLineKeys && !hasKeyGenerator && !key) {
    194         exceptionState.throwDOMException(DataError, "The object store uses out-of-line keys and has no key generator and the key parameter was not provided.");
    195         return 0;
    196     }
    197     if (usesInLineKeys) {
    198         IDBKey* keyPathKey = createIDBKeyFromScriptValueAndKeyPath(scriptState->isolate(), value, keyPath);
    199         if (keyPathKey && !keyPathKey->isValid()) {
    200             exceptionState.throwDOMException(DataError, "Evaluating the object store's key path yielded a value that is not a valid key.");
    201             return 0;
    202         }
    203         if (!hasKeyGenerator && !keyPathKey) {
    204             exceptionState.throwDOMException(DataError, "Evaluating the object store's key path did not yield a value.");
    205             return 0;
    206         }
    207         if (hasKeyGenerator && !keyPathKey) {
    208             if (!canInjectIDBKeyIntoScriptValue(scriptState->isolate(), value, keyPath)) {
    209                 exceptionState.throwDOMException(DataError, "A generated key could not be inserted into the value.");
    210                 return 0;
    211             }
    212         }
    213         if (keyPathKey)
    214             key = keyPathKey;
    215     }
    216     if (key && !key->isValid()) {
    217         exceptionState.throwDOMException(DataError, IDBDatabase::notValidKeyErrorMessage);
    218         return 0;
    219     }
    220 
    221     if (!backendDB()) {
    222         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
    223         return 0;
    224     }
    225 
    226     Vector<int64_t> indexIds;
    227     HeapVector<IndexKeys> indexKeys;
    228     for (IDBObjectStoreMetadata::IndexMap::const_iterator it = m_metadata.indexes.begin(); it != m_metadata.indexes.end(); ++it) {
    229         IndexKeys keys;
    230         generateIndexKeysForValue(scriptState->isolate(), it->value, value, &keys);
    231         indexIds.append(it->key);
    232         indexKeys.append(keys);
    233     }
    234 
    235     IDBRequest* request = IDBRequest::create(scriptState, source, m_transaction.get());
    236     Vector<char> wireBytes;
    237     serializedValue->toWireBytes(wireBytes);
    238     RefPtr<SharedBuffer> valueBuffer = SharedBuffer::adoptVector(wireBytes);
    239 
    240     backendDB()->put(m_transaction->id(), id(), blink::WebData(valueBuffer), blobInfo, key, static_cast<blink::WebIDBPutMode>(putMode), WebIDBCallbacksImpl::create(request).leakPtr(), indexIds, indexKeys);
    241     return request;
    242 }
    243 
    244 IDBRequest* IDBObjectStore::deleteFunction(ScriptState* scriptState, const ScriptValue& key, ExceptionState& exceptionState)
    245 {
    246     IDB_TRACE("IDBObjectStore::delete");
    247     if (isDeleted()) {
    248         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
    249         return 0;
    250     }
    251     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
    252         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
    253         return 0;
    254     }
    255     if (!m_transaction->isActive()) {
    256         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
    257         return 0;
    258     }
    259     if (m_transaction->isReadOnly()) {
    260         exceptionState.throwDOMException(ReadOnlyError, IDBDatabase::transactionReadOnlyErrorMessage);
    261         return 0;
    262     }
    263 
    264     IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), key, exceptionState);
    265     if (exceptionState.hadException())
    266         return 0;
    267     if (!keyRange) {
    268         exceptionState.throwDOMException(DataError, IDBDatabase::noKeyOrKeyRangeErrorMessage);
    269         return 0;
    270     }
    271     if (!backendDB()) {
    272         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
    273         return 0;
    274     }
    275 
    276     IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get());
    277     backendDB()->deleteRange(m_transaction->id(), id(), keyRange, WebIDBCallbacksImpl::create(request).leakPtr());
    278     return request;
    279 }
    280 
    281 IDBRequest* IDBObjectStore::clear(ScriptState* scriptState, ExceptionState& exceptionState)
    282 {
    283     IDB_TRACE("IDBObjectStore::clear");
    284     if (isDeleted()) {
    285         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
    286         return 0;
    287     }
    288     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
    289         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
    290         return 0;
    291     }
    292     if (!m_transaction->isActive()) {
    293         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
    294         return 0;
    295     }
    296     if (m_transaction->isReadOnly()) {
    297         exceptionState.throwDOMException(ReadOnlyError, IDBDatabase::transactionReadOnlyErrorMessage);
    298         return 0;
    299     }
    300     if (!backendDB()) {
    301         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
    302         return 0;
    303     }
    304 
    305     IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get());
    306     backendDB()->clear(m_transaction->id(), id(), WebIDBCallbacksImpl::create(request).leakPtr());
    307     return request;
    308 }
    309 
    310 namespace {
    311 // This class creates the index keys for a given index by extracting
    312 // them from the SerializedScriptValue, for all the existing values in
    313 // the objectStore. It only needs to be kept alive by virtue of being
    314 // a listener on an IDBRequest object, in the same way that JavaScript
    315 // cursor success handlers are kept alive.
    316 class IndexPopulator FINAL : public EventListener {
    317 public:
    318     static PassRefPtr<IndexPopulator> create(ScriptState* scriptState, IDBDatabase* database, int64_t transactionId, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata)
    319     {
    320         return adoptRef(new IndexPopulator(scriptState, database, transactionId, objectStoreId, indexMetadata));
    321     }
    322 
    323     virtual bool operator==(const EventListener& other) OVERRIDE
    324     {
    325         return this == &other;
    326     }
    327 
    328 private:
    329     IndexPopulator(ScriptState* scriptState, IDBDatabase* database, int64_t transactionId, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata)
    330         : EventListener(CPPEventListenerType)
    331         , m_scriptState(scriptState)
    332         , m_database(database)
    333         , m_transactionId(transactionId)
    334         , m_objectStoreId(objectStoreId)
    335         , m_indexMetadata(indexMetadata)
    336     {
    337     }
    338 
    339     virtual void handleEvent(ExecutionContext* executionContext, Event* event) OVERRIDE
    340     {
    341         ASSERT(m_scriptState->executionContext() == executionContext);
    342         ASSERT(event->type() == EventTypeNames::success);
    343         EventTarget* target = event->target();
    344         IDBRequest* request = static_cast<IDBRequest*>(target);
    345 
    346         if (!m_database->backend()) // If database is stopped?
    347             return;
    348 
    349         IDBAny* cursorAny = request->resultAsAny();
    350         IDBCursorWithValue* cursor = 0;
    351         if (cursorAny->type() == IDBAny::IDBCursorWithValueType)
    352             cursor = cursorAny->idbCursorWithValue();
    353 
    354         Vector<int64_t> indexIds;
    355         indexIds.append(m_indexMetadata.id);
    356         if (cursor && !cursor->isDeleted()) {
    357             cursor->continueFunction(static_cast<IDBKey*>(0), static_cast<IDBKey*>(0), ASSERT_NO_EXCEPTION);
    358 
    359             IDBKey* primaryKey = cursor->idbPrimaryKey();
    360             ScriptValue value = cursor->value(m_scriptState.get());
    361 
    362             IDBObjectStore::IndexKeys indexKeys;
    363             generateIndexKeysForValue(m_scriptState->isolate(), m_indexMetadata, value, &indexKeys);
    364 
    365             HeapVector<IDBObjectStore::IndexKeys> indexKeysList;
    366             indexKeysList.append(indexKeys);
    367 
    368             m_database->backend()->setIndexKeys(m_transactionId, m_objectStoreId, primaryKey, indexIds, indexKeysList);
    369         } else {
    370             // Now that we are done indexing, tell the backend to go
    371             // back to processing tasks of type NormalTask.
    372             m_database->backend()->setIndexesReady(m_transactionId, m_objectStoreId, indexIds);
    373             m_database.clear();
    374         }
    375 
    376     }
    377 
    378     RefPtr<ScriptState> m_scriptState;
    379     Persistent<IDBDatabase> m_database;
    380     const int64_t m_transactionId;
    381     const int64_t m_objectStoreId;
    382     const IDBIndexMetadata m_indexMetadata;
    383 };
    384 }
    385 
    386 IDBIndex* IDBObjectStore::createIndex(ScriptState* scriptState, const String& name, const IDBKeyPath& keyPath, const Dictionary& options, ExceptionState& exceptionState)
    387 {
    388     bool unique = false;
    389     options.get("unique", unique);
    390 
    391     bool multiEntry = false;
    392     options.get("multiEntry", multiEntry);
    393 
    394     return createIndex(scriptState, name, keyPath, unique, multiEntry, exceptionState);
    395 }
    396 
    397 IDBIndex* IDBObjectStore::createIndex(ScriptState* scriptState, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, ExceptionState& exceptionState)
    398 {
    399     IDB_TRACE("IDBObjectStore::createIndex");
    400     if (!m_transaction->isVersionChange()) {
    401         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::notVersionChangeTransactionErrorMessage);
    402         return 0;
    403     }
    404     if (isDeleted()) {
    405         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
    406         return 0;
    407     }
    408     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
    409         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
    410         return 0;
    411     }
    412     if (!m_transaction->isActive()) {
    413         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
    414         return 0;
    415     }
    416     if (!keyPath.isValid()) {
    417         exceptionState.throwDOMException(SyntaxError, "The keyPath argument contains an invalid key path.");
    418         return 0;
    419     }
    420     if (name.isNull()) {
    421         exceptionState.throwTypeError("The name provided is null.");
    422         return 0;
    423     }
    424     if (containsIndex(name)) {
    425         exceptionState.throwDOMException(ConstraintError, "An index with the specified name already exists.");
    426         return 0;
    427     }
    428 
    429     if (keyPath.type() == IDBKeyPath::ArrayType && multiEntry) {
    430         exceptionState.throwDOMException(InvalidAccessError, "The keyPath argument was an array and the multiEntry option is true.");
    431         return 0;
    432     }
    433     if (!backendDB()) {
    434         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
    435         return 0;
    436     }
    437 
    438     int64_t indexId = m_metadata.maxIndexId + 1;
    439     backendDB()->createIndex(m_transaction->id(), id(), indexId, name, keyPath, unique, multiEntry);
    440 
    441     ++m_metadata.maxIndexId;
    442 
    443     IDBIndexMetadata metadata(name, indexId, keyPath, unique, multiEntry);
    444     IDBIndex* index = IDBIndex::create(metadata, this, m_transaction.get());
    445     m_indexMap.set(name, index);
    446     m_metadata.indexes.set(indexId, metadata);
    447     m_transaction->db()->indexCreated(id(), metadata);
    448 
    449     ASSERT(!exceptionState.hadException());
    450     if (exceptionState.hadException())
    451         return 0;
    452 
    453     IDBRequest* indexRequest = openCursor(scriptState, static_cast<IDBKeyRange*>(0), blink::WebIDBCursorDirectionNext, blink::WebIDBTaskTypePreemptive);
    454     indexRequest->preventPropagation();
    455 
    456     // This is kept alive by being the success handler of the request, which is in turn kept alive by the owning transaction.
    457     RefPtr<IndexPopulator> indexPopulator = IndexPopulator::create(scriptState, transaction()->db(), m_transaction->id(), id(), metadata);
    458     indexRequest->setOnsuccess(indexPopulator);
    459     return index;
    460 }
    461 
    462 IDBIndex* IDBObjectStore::index(const String& name, ExceptionState& exceptionState)
    463 {
    464     IDB_TRACE("IDBObjectStore::index");
    465     if (isDeleted()) {
    466         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
    467         return 0;
    468     }
    469     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
    470         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::transactionFinishedErrorMessage);
    471         return 0;
    472     }
    473 
    474     IDBIndexMap::iterator it = m_indexMap.find(name);
    475     if (it != m_indexMap.end())
    476         return it->value;
    477 
    478     int64_t indexId = findIndexId(name);
    479     if (indexId == IDBIndexMetadata::InvalidId) {
    480         exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchIndexErrorMessage);
    481         return 0;
    482     }
    483 
    484     const IDBIndexMetadata* indexMetadata(0);
    485     for (IDBObjectStoreMetadata::IndexMap::const_iterator it = m_metadata.indexes.begin(); it != m_metadata.indexes.end(); ++it) {
    486         if (it->value.name == name) {
    487             indexMetadata = &it->value;
    488             break;
    489         }
    490     }
    491     ASSERT(indexMetadata);
    492     ASSERT(indexMetadata->id != IDBIndexMetadata::InvalidId);
    493 
    494     IDBIndex* index = IDBIndex::create(*indexMetadata, this, m_transaction.get());
    495     m_indexMap.set(name, index);
    496     return index;
    497 }
    498 
    499 void IDBObjectStore::deleteIndex(const String& name, ExceptionState& exceptionState)
    500 {
    501     IDB_TRACE("IDBObjectStore::deleteIndex");
    502     if (!m_transaction->isVersionChange()) {
    503         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::notVersionChangeTransactionErrorMessage);
    504         return;
    505     }
    506     if (isDeleted()) {
    507         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
    508         return;
    509     }
    510     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
    511         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
    512         return;
    513     }
    514     if (!m_transaction->isActive()) {
    515         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
    516         return;
    517     }
    518     int64_t indexId = findIndexId(name);
    519     if (indexId == IDBIndexMetadata::InvalidId) {
    520         exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchIndexErrorMessage);
    521         return;
    522     }
    523     if (!backendDB()) {
    524         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
    525         return;
    526     }
    527 
    528     backendDB()->deleteIndex(m_transaction->id(), id(), indexId);
    529 
    530     m_metadata.indexes.remove(indexId);
    531     m_transaction->db()->indexDeleted(id(), indexId);
    532     IDBIndexMap::iterator it = m_indexMap.find(name);
    533     if (it != m_indexMap.end()) {
    534         it->value->markDeleted();
    535         m_indexMap.remove(name);
    536     }
    537 }
    538 
    539 IDBRequest* IDBObjectStore::openCursor(ScriptState* scriptState, const ScriptValue& range, const String& directionString, ExceptionState& exceptionState)
    540 {
    541     IDB_TRACE("IDBObjectStore::openCursor");
    542     if (isDeleted()) {
    543         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
    544         return 0;
    545     }
    546     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
    547         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
    548         return 0;
    549     }
    550     if (!m_transaction->isActive()) {
    551         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
    552         return 0;
    553     }
    554 
    555     blink::WebIDBCursorDirection direction = IDBCursor::stringToDirection(directionString, exceptionState);
    556     if (exceptionState.hadException())
    557         return 0;
    558 
    559     IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), range, exceptionState);
    560     if (exceptionState.hadException())
    561         return 0;
    562 
    563     if (!backendDB()) {
    564         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
    565         return 0;
    566     }
    567 
    568     return openCursor(scriptState, keyRange, direction, blink::WebIDBTaskTypeNormal);
    569 }
    570 
    571 IDBRequest* IDBObjectStore::openCursor(ScriptState* scriptState, IDBKeyRange* range, blink::WebIDBCursorDirection direction, blink::WebIDBTaskType taskType)
    572 {
    573     IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get());
    574     request->setCursorDetails(IndexedDB::CursorKeyAndValue, direction);
    575 
    576     backendDB()->openCursor(m_transaction->id(), id(), IDBIndexMetadata::InvalidId, range, direction, false, taskType, WebIDBCallbacksImpl::create(request).leakPtr());
    577     return request;
    578 }
    579 
    580 IDBRequest* IDBObjectStore::openKeyCursor(ScriptState* scriptState, const ScriptValue& range, const String& directionString, ExceptionState& exceptionState)
    581 {
    582     IDB_TRACE("IDBObjectStore::openKeyCursor");
    583     if (isDeleted()) {
    584         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
    585         return 0;
    586     }
    587     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
    588         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
    589         return 0;
    590     }
    591     if (!m_transaction->isActive()) {
    592         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
    593         return 0;
    594     }
    595 
    596     blink::WebIDBCursorDirection direction = IDBCursor::stringToDirection(directionString, exceptionState);
    597     if (exceptionState.hadException())
    598         return 0;
    599 
    600     IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), range, exceptionState);
    601     if (exceptionState.hadException())
    602         return 0;
    603 
    604     if (!backendDB()) {
    605         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
    606         return 0;
    607     }
    608 
    609     IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get());
    610     request->setCursorDetails(IndexedDB::CursorKeyOnly, direction);
    611 
    612     backendDB()->openCursor(m_transaction->id(), id(), IDBIndexMetadata::InvalidId, keyRange, direction, true, blink::WebIDBTaskTypeNormal, WebIDBCallbacksImpl::create(request).leakPtr());
    613     return request;
    614 }
    615 
    616 IDBRequest* IDBObjectStore::count(ScriptState* scriptState, const ScriptValue& range, ExceptionState& exceptionState)
    617 {
    618     IDB_TRACE("IDBObjectStore::count");
    619     if (isDeleted()) {
    620         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
    621         return 0;
    622     }
    623     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
    624         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
    625         return 0;
    626     }
    627     if (!m_transaction->isActive()) {
    628         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
    629         return 0;
    630     }
    631 
    632     IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), range, exceptionState);
    633     if (exceptionState.hadException())
    634         return 0;
    635 
    636     if (!backendDB()) {
    637         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
    638         return 0;
    639     }
    640 
    641     IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get());
    642     backendDB()->count(m_transaction->id(), id(), IDBIndexMetadata::InvalidId, keyRange, WebIDBCallbacksImpl::create(request).leakPtr());
    643     return request;
    644 }
    645 
    646 void IDBObjectStore::transactionFinished()
    647 {
    648     ASSERT(m_transaction->isFinished());
    649 
    650     // Break reference cycles.
    651     m_indexMap.clear();
    652 }
    653 
    654 int64_t IDBObjectStore::findIndexId(const String& name) const
    655 {
    656     for (IDBObjectStoreMetadata::IndexMap::const_iterator it = m_metadata.indexes.begin(); it != m_metadata.indexes.end(); ++it) {
    657         if (it->value.name == name) {
    658             ASSERT(it->key != IDBIndexMetadata::InvalidId);
    659             return it->key;
    660         }
    661     }
    662     return IDBIndexMetadata::InvalidId;
    663 }
    664 
    665 WebIDBDatabase* IDBObjectStore::backendDB() const
    666 {
    667     return m_transaction->backendDB();
    668 }
    669 
    670 } // namespace WebCore
    671