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