2 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "modules/indexeddb/IDBObjectStore.h"
29 #include "bindings/core/v8/ExceptionState.h"
30 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
31 #include "bindings/core/v8/ScriptState.h"
32 #include "bindings/modules/v8/IDBBindingUtilities.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"
50 using blink::WebBlobInfo;
51 using blink::WebIDBCallbacks;
52 using blink::WebIDBCursor;
53 using blink::WebIDBDatabase;
54 using blink::WebVector;
58 IDBObjectStore::IDBObjectStore(const IDBObjectStoreMetadata& metadata, IDBTransaction* transaction)
59 : m_metadata(metadata)
60 , m_transaction(transaction)
63 ASSERT(m_transaction);
66 void IDBObjectStore::trace(Visitor* visitor)
68 visitor->trace(m_transaction);
69 visitor->trace(m_indexMap);
72 ScriptValue IDBObjectStore::keyPath(ScriptState* scriptState) const
74 return idbAnyToScriptValue(scriptState, IDBAny::create(m_metadata.keyPath));
77 PassRefPtrWillBeRawPtr<DOMStringList> IDBObjectStore::indexNames() const
79 IDB_TRACE("IDBObjectStore::indexNames");
80 RefPtrWillBeRawPtr<DOMStringList> indexNames = DOMStringList::create();
81 for (IDBObjectStoreMetadata::IndexMap::const_iterator it = m_metadata.indexes.begin(); it != m_metadata.indexes.end(); ++it)
82 indexNames->append(it->value.name);
84 return indexNames.release();
87 IDBRequest* IDBObjectStore::get(ScriptState* scriptState, const ScriptValue& key, ExceptionState& exceptionState)
89 IDB_TRACE("IDBObjectStore::get");
91 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
94 if (m_transaction->isFinished() || m_transaction->isFinishing()) {
95 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
98 if (!m_transaction->isActive()) {
99 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
102 IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), key, exceptionState);
103 if (exceptionState.hadException())
106 exceptionState.throwDOMException(DataError, IDBDatabase::noKeyOrKeyRangeErrorMessage);
110 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
114 IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get());
115 backendDB()->get(m_transaction->id(), id(), IDBIndexMetadata::InvalidId, keyRange, false, WebIDBCallbacksImpl::create(request).leakPtr());
119 static void generateIndexKeysForValue(v8::Isolate* isolate, const IDBIndexMetadata& indexMetadata, const ScriptValue& objectValue, IDBObjectStore::IndexKeys* indexKeys)
122 IDBKey* indexKey = createIDBKeyFromScriptValueAndKeyPath(isolate, objectValue, indexMetadata.keyPath);
127 if (!indexMetadata.multiEntry || indexKey->type() != IDBKey::ArrayType) {
128 if (!indexKey->isValid())
131 indexKeys->append(indexKey);
133 ASSERT(indexMetadata.multiEntry);
134 ASSERT(indexKey->type() == IDBKey::ArrayType);
135 indexKey = IDBKey::createMultiEntryArray(indexKey->array());
137 for (size_t i = 0; i < indexKey->array().size(); ++i)
138 indexKeys->append(indexKey->array()[i]);
142 IDBRequest* IDBObjectStore::add(ScriptState* scriptState, const ScriptValue& value, const ScriptValue& key, ExceptionState& exceptionState)
144 IDB_TRACE("IDBObjectStore::add");
145 return put(scriptState, WebIDBPutModeAddOnly, IDBAny::create(this), value, key, exceptionState);
148 IDBRequest* IDBObjectStore::put(ScriptState* scriptState, const ScriptValue& value, const ScriptValue& key, ExceptionState& exceptionState)
150 IDB_TRACE("IDBObjectStore::put");
151 return put(scriptState, WebIDBPutModeAddOrUpdate, IDBAny::create(this), value, key, exceptionState);
154 IDBRequest* IDBObjectStore::put(ScriptState* scriptState, WebIDBPutMode putMode, IDBAny* source, const ScriptValue& value, const ScriptValue& keyValue, ExceptionState& exceptionState)
156 IDBKey* key = keyValue.isUndefined() ? nullptr : scriptValueToIDBKey(scriptState->isolate(), keyValue);
157 return put(scriptState, putMode, source, value, key, exceptionState);
160 IDBRequest* IDBObjectStore::put(ScriptState* scriptState, WebIDBPutMode putMode, IDBAny* source, const ScriptValue& value, IDBKey* key, ExceptionState& exceptionState)
163 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
166 if (m_transaction->isFinished() || m_transaction->isFinishing()) {
167 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
170 if (!m_transaction->isActive()) {
171 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
174 if (m_transaction->isReadOnly()) {
175 exceptionState.throwDOMException(ReadOnlyError, IDBDatabase::transactionReadOnlyErrorMessage);
179 Vector<WebBlobInfo> blobInfo;
180 RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(value, &blobInfo, exceptionState, scriptState->isolate());
181 if (exceptionState.hadException())
184 // Keys that need to be extracted must be taken from a clone so that
185 // side effects (i.e. getters) are not triggered. Construct the
186 // clone lazily since the operation may be expensive.
189 const IDBKeyPath& keyPath = m_metadata.keyPath;
190 const bool usesInLineKeys = !keyPath.isNull();
191 const bool hasKeyGenerator = autoIncrement();
193 if (putMode != WebIDBPutModeCursorUpdate && usesInLineKeys && key) {
194 exceptionState.throwDOMException(DataError, "The object store uses in-line keys and the key parameter was provided.");
198 // This test logically belongs in IDBCursor, but must operate on the cloned value.
199 if (putMode == WebIDBPutModeCursorUpdate && usesInLineKeys) {
202 clone = deserializeScriptValue(scriptState, serializedValue.get(), &blobInfo);
203 IDBKey* keyPathKey = createIDBKeyFromScriptValueAndKeyPath(scriptState->isolate(), clone, keyPath);
204 if (!keyPathKey || !keyPathKey->isEqual(key)) {
205 exceptionState.throwDOMException(DataError, "The effective object store of this cursor uses in-line keys and evaluating the key path of the value parameter results in a different value than the cursor's effective key.");
210 if (!usesInLineKeys && !hasKeyGenerator && !key) {
211 exceptionState.throwDOMException(DataError, "The object store uses out-of-line keys and has no key generator and the key parameter was not provided.");
214 if (usesInLineKeys) {
216 clone = deserializeScriptValue(scriptState, serializedValue.get(), &blobInfo);
217 IDBKey* keyPathKey = createIDBKeyFromScriptValueAndKeyPath(scriptState->isolate(), clone, keyPath);
218 if (keyPathKey && !keyPathKey->isValid()) {
219 exceptionState.throwDOMException(DataError, "Evaluating the object store's key path yielded a value that is not a valid key.");
222 if (!hasKeyGenerator && !keyPathKey) {
223 exceptionState.throwDOMException(DataError, "Evaluating the object store's key path did not yield a value.");
226 if (hasKeyGenerator && !keyPathKey) {
227 if (!canInjectIDBKeyIntoScriptValue(scriptState->isolate(), clone, keyPath)) {
228 exceptionState.throwDOMException(DataError, "A generated key could not be inserted into the value.");
235 if (key && !key->isValid()) {
236 exceptionState.throwDOMException(DataError, IDBDatabase::notValidKeyErrorMessage);
241 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
245 Vector<int64_t> indexIds;
246 HeapVector<IndexKeys> indexKeys;
247 for (IDBObjectStoreMetadata::IndexMap::const_iterator it = m_metadata.indexes.begin(); it != m_metadata.indexes.end(); ++it) {
249 clone = deserializeScriptValue(scriptState, serializedValue.get(), &blobInfo);
251 generateIndexKeysForValue(scriptState->isolate(), it->value, clone, &keys);
252 indexIds.append(it->key);
253 indexKeys.append(keys);
256 IDBRequest* request = IDBRequest::create(scriptState, source, m_transaction.get());
257 Vector<char> wireBytes;
258 serializedValue->toWireBytes(wireBytes);
259 RefPtr<SharedBuffer> valueBuffer = SharedBuffer::adoptVector(wireBytes);
261 backendDB()->put(m_transaction->id(), id(), WebData(valueBuffer), blobInfo, key, static_cast<WebIDBPutMode>(putMode), WebIDBCallbacksImpl::create(request).leakPtr(), indexIds, indexKeys);
265 IDBRequest* IDBObjectStore::deleteFunction(ScriptState* scriptState, const ScriptValue& key, ExceptionState& exceptionState)
267 IDB_TRACE("IDBObjectStore::delete");
269 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
272 if (m_transaction->isFinished() || m_transaction->isFinishing()) {
273 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
276 if (!m_transaction->isActive()) {
277 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
280 if (m_transaction->isReadOnly()) {
281 exceptionState.throwDOMException(ReadOnlyError, IDBDatabase::transactionReadOnlyErrorMessage);
285 IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), key, exceptionState);
286 if (exceptionState.hadException())
289 exceptionState.throwDOMException(DataError, IDBDatabase::noKeyOrKeyRangeErrorMessage);
293 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
297 IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get());
298 backendDB()->deleteRange(m_transaction->id(), id(), keyRange, WebIDBCallbacksImpl::create(request).leakPtr());
302 IDBRequest* IDBObjectStore::clear(ScriptState* scriptState, ExceptionState& exceptionState)
304 IDB_TRACE("IDBObjectStore::clear");
306 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
309 if (m_transaction->isFinished() || m_transaction->isFinishing()) {
310 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
313 if (!m_transaction->isActive()) {
314 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
317 if (m_transaction->isReadOnly()) {
318 exceptionState.throwDOMException(ReadOnlyError, IDBDatabase::transactionReadOnlyErrorMessage);
322 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
326 IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get());
327 backendDB()->clear(m_transaction->id(), id(), WebIDBCallbacksImpl::create(request).leakPtr());
332 // This class creates the index keys for a given index by extracting
333 // them from the SerializedScriptValue, for all the existing values in
334 // the objectStore. It only needs to be kept alive by virtue of being
335 // a listener on an IDBRequest object, in the same way that JavaScript
336 // cursor success handlers are kept alive.
337 class IndexPopulator FINAL : public EventListener {
339 static PassRefPtr<IndexPopulator> create(ScriptState* scriptState, IDBDatabase* database, int64_t transactionId, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata)
341 return adoptRef(new IndexPopulator(scriptState, database, transactionId, objectStoreId, indexMetadata));
344 virtual bool operator==(const EventListener& other) OVERRIDE
346 return this == &other;
350 IndexPopulator(ScriptState* scriptState, IDBDatabase* database, int64_t transactionId, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata)
351 : EventListener(CPPEventListenerType)
352 , m_scriptState(scriptState)
353 , m_database(database)
354 , m_transactionId(transactionId)
355 , m_objectStoreId(objectStoreId)
356 , m_indexMetadata(indexMetadata)
360 virtual void handleEvent(ExecutionContext* executionContext, Event* event) OVERRIDE
362 ASSERT(m_scriptState->executionContext() == executionContext);
363 ASSERT(event->type() == EventTypeNames::success);
364 EventTarget* target = event->target();
365 IDBRequest* request = static_cast<IDBRequest*>(target);
367 if (!m_database->backend()) // If database is stopped?
370 IDBAny* cursorAny = request->resultAsAny();
371 IDBCursorWithValue* cursor = 0;
372 if (cursorAny->type() == IDBAny::IDBCursorWithValueType)
373 cursor = cursorAny->idbCursorWithValue();
375 Vector<int64_t> indexIds;
376 indexIds.append(m_indexMetadata.id);
377 if (cursor && !cursor->isDeleted()) {
378 cursor->continueFunction(static_cast<IDBKey*>(0), static_cast<IDBKey*>(0), ASSERT_NO_EXCEPTION);
380 IDBKey* primaryKey = cursor->idbPrimaryKey();
381 ScriptValue value = cursor->value(m_scriptState.get());
383 IDBObjectStore::IndexKeys indexKeys;
384 generateIndexKeysForValue(m_scriptState->isolate(), m_indexMetadata, value, &indexKeys);
386 HeapVector<IDBObjectStore::IndexKeys> indexKeysList;
387 indexKeysList.append(indexKeys);
389 m_database->backend()->setIndexKeys(m_transactionId, m_objectStoreId, primaryKey, indexIds, indexKeysList);
391 // Now that we are done indexing, tell the backend to go
392 // back to processing tasks of type NormalTask.
393 m_database->backend()->setIndexesReady(m_transactionId, m_objectStoreId, indexIds);
399 RefPtr<ScriptState> m_scriptState;
400 Persistent<IDBDatabase> m_database;
401 const int64_t m_transactionId;
402 const int64_t m_objectStoreId;
403 const IDBIndexMetadata m_indexMetadata;
407 IDBIndex* IDBObjectStore::createIndex(ScriptState* scriptState, const String& name, const IDBKeyPath& keyPath, const IDBIndexParameters& options, ExceptionState& exceptionState)
409 IDB_TRACE("IDBObjectStore::createIndex");
410 if (!m_transaction->isVersionChange()) {
411 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::notVersionChangeTransactionErrorMessage);
415 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
418 if (m_transaction->isFinished() || m_transaction->isFinishing()) {
419 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
422 if (!m_transaction->isActive()) {
423 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
426 if (!keyPath.isValid()) {
427 exceptionState.throwDOMException(SyntaxError, "The keyPath argument contains an invalid key path.");
431 exceptionState.throwTypeError("The name provided is null.");
434 if (containsIndex(name)) {
435 exceptionState.throwDOMException(ConstraintError, "An index with the specified name already exists.");
439 if (keyPath.type() == IDBKeyPath::ArrayType && options.multiEntry()) {
440 exceptionState.throwDOMException(InvalidAccessError, "The keyPath argument was an array and the multiEntry option is true.");
444 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
448 int64_t indexId = m_metadata.maxIndexId + 1;
449 backendDB()->createIndex(m_transaction->id(), id(), indexId, name, keyPath, options.unique(), options.multiEntry());
451 ++m_metadata.maxIndexId;
453 IDBIndexMetadata metadata(name, indexId, keyPath, options.unique(), options.multiEntry());
454 IDBIndex* index = IDBIndex::create(metadata, this, m_transaction.get());
455 m_indexMap.set(name, index);
456 m_metadata.indexes.set(indexId, metadata);
457 m_transaction->db()->indexCreated(id(), metadata);
459 ASSERT(!exceptionState.hadException());
460 if (exceptionState.hadException())
463 IDBRequest* indexRequest = openCursor(scriptState, static_cast<IDBKeyRange*>(0), WebIDBCursorDirectionNext, WebIDBTaskTypePreemptive);
464 indexRequest->preventPropagation();
466 // This is kept alive by being the success handler of the request, which is in turn kept alive by the owning transaction.
467 RefPtr<IndexPopulator> indexPopulator = IndexPopulator::create(scriptState, transaction()->db(), m_transaction->id(), id(), metadata);
468 indexRequest->setOnsuccess(indexPopulator);
472 IDBIndex* IDBObjectStore::index(const String& name, ExceptionState& exceptionState)
474 IDB_TRACE("IDBObjectStore::index");
476 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
479 if (m_transaction->isFinished() || m_transaction->isFinishing()) {
480 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::transactionFinishedErrorMessage);
484 IDBIndexMap::iterator it = m_indexMap.find(name);
485 if (it != m_indexMap.end())
488 int64_t indexId = findIndexId(name);
489 if (indexId == IDBIndexMetadata::InvalidId) {
490 exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchIndexErrorMessage);
494 const IDBIndexMetadata* indexMetadata(0);
495 for (IDBObjectStoreMetadata::IndexMap::const_iterator it = m_metadata.indexes.begin(); it != m_metadata.indexes.end(); ++it) {
496 if (it->value.name == name) {
497 indexMetadata = &it->value;
501 ASSERT(indexMetadata);
502 ASSERT(indexMetadata->id != IDBIndexMetadata::InvalidId);
504 IDBIndex* index = IDBIndex::create(*indexMetadata, this, m_transaction.get());
505 m_indexMap.set(name, index);
509 void IDBObjectStore::deleteIndex(const String& name, ExceptionState& exceptionState)
511 IDB_TRACE("IDBObjectStore::deleteIndex");
512 if (!m_transaction->isVersionChange()) {
513 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::notVersionChangeTransactionErrorMessage);
517 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
520 if (m_transaction->isFinished() || m_transaction->isFinishing()) {
521 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
524 if (!m_transaction->isActive()) {
525 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
528 int64_t indexId = findIndexId(name);
529 if (indexId == IDBIndexMetadata::InvalidId) {
530 exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchIndexErrorMessage);
534 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
538 backendDB()->deleteIndex(m_transaction->id(), id(), indexId);
540 m_metadata.indexes.remove(indexId);
541 m_transaction->db()->indexDeleted(id(), indexId);
542 IDBIndexMap::iterator it = m_indexMap.find(name);
543 if (it != m_indexMap.end()) {
544 it->value->markDeleted();
545 m_indexMap.remove(name);
549 IDBRequest* IDBObjectStore::openCursor(ScriptState* scriptState, const ScriptValue& range, const String& directionString, ExceptionState& exceptionState)
551 IDB_TRACE("IDBObjectStore::openCursor");
553 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
556 if (m_transaction->isFinished() || m_transaction->isFinishing()) {
557 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
560 if (!m_transaction->isActive()) {
561 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
565 WebIDBCursorDirection direction = IDBCursor::stringToDirection(directionString, exceptionState);
566 if (exceptionState.hadException())
569 IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), range, exceptionState);
570 if (exceptionState.hadException())
574 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
578 return openCursor(scriptState, keyRange, direction, WebIDBTaskTypeNormal);
581 IDBRequest* IDBObjectStore::openCursor(ScriptState* scriptState, IDBKeyRange* range, WebIDBCursorDirection direction, WebIDBTaskType taskType)
583 IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get());
584 request->setCursorDetails(IndexedDB::CursorKeyAndValue, direction);
586 backendDB()->openCursor(m_transaction->id(), id(), IDBIndexMetadata::InvalidId, range, direction, false, taskType, WebIDBCallbacksImpl::create(request).leakPtr());
590 IDBRequest* IDBObjectStore::openKeyCursor(ScriptState* scriptState, const ScriptValue& range, const String& directionString, ExceptionState& exceptionState)
592 IDB_TRACE("IDBObjectStore::openKeyCursor");
594 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
597 if (m_transaction->isFinished() || m_transaction->isFinishing()) {
598 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
601 if (!m_transaction->isActive()) {
602 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
606 WebIDBCursorDirection direction = IDBCursor::stringToDirection(directionString, exceptionState);
607 if (exceptionState.hadException())
610 IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), range, exceptionState);
611 if (exceptionState.hadException())
615 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
619 IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get());
620 request->setCursorDetails(IndexedDB::CursorKeyOnly, direction);
622 backendDB()->openCursor(m_transaction->id(), id(), IDBIndexMetadata::InvalidId, keyRange, direction, true, WebIDBTaskTypeNormal, WebIDBCallbacksImpl::create(request).leakPtr());
626 IDBRequest* IDBObjectStore::count(ScriptState* scriptState, const ScriptValue& range, ExceptionState& exceptionState)
628 IDB_TRACE("IDBObjectStore::count");
630 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
633 if (m_transaction->isFinished() || m_transaction->isFinishing()) {
634 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
637 if (!m_transaction->isActive()) {
638 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
642 IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), range, exceptionState);
643 if (exceptionState.hadException())
647 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
651 IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get());
652 backendDB()->count(m_transaction->id(), id(), IDBIndexMetadata::InvalidId, keyRange, WebIDBCallbacksImpl::create(request).leakPtr());
656 void IDBObjectStore::transactionFinished()
658 ASSERT(m_transaction->isFinished());
660 // Break reference cycles.
664 int64_t IDBObjectStore::findIndexId(const String& name) const
666 for (IDBObjectStoreMetadata::IndexMap::const_iterator it = m_metadata.indexes.begin(); it != m_metadata.indexes.end(); ++it) {
667 if (it->value.name == name) {
668 ASSERT(it->key != IDBIndexMetadata::InvalidId);
672 return IDBIndexMetadata::InvalidId;
675 WebIDBDatabase* IDBObjectStore::backendDB() const
677 return m_transaction->backendDB();