Upstream version 10.39.225.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/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"
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 blink {
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 }
65
66 void IDBObjectStore::trace(Visitor* visitor)
67 {
68     visitor->trace(m_transaction);
69     visitor->trace(m_indexMap);
70 }
71
72 ScriptValue IDBObjectStore::keyPath(ScriptState* scriptState) const
73 {
74     return idbAnyToScriptValue(scriptState, IDBAny::create(m_metadata.keyPath));
75 }
76
77 PassRefPtrWillBeRawPtr<DOMStringList> IDBObjectStore::indexNames() const
78 {
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);
83     indexNames->sort();
84     return indexNames.release();
85 }
86
87 IDBRequest* IDBObjectStore::get(ScriptState* scriptState, const ScriptValue& key, ExceptionState& exceptionState)
88 {
89     IDB_TRACE("IDBObjectStore::get");
90     if (isDeleted()) {
91         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
92         return 0;
93     }
94     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
95         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
96         return 0;
97     }
98     if (!m_transaction->isActive()) {
99         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
100         return 0;
101     }
102     IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), key, exceptionState);
103     if (exceptionState.hadException())
104         return 0;
105     if (!keyRange) {
106         exceptionState.throwDOMException(DataError, IDBDatabase::noKeyOrKeyRangeErrorMessage);
107         return 0;
108     }
109     if (!backendDB()) {
110         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
111         return 0;
112     }
113
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());
116     return request;
117 }
118
119 static void generateIndexKeysForValue(v8::Isolate* isolate, const IDBIndexMetadata& indexMetadata, const ScriptValue& objectValue, IDBObjectStore::IndexKeys* indexKeys)
120 {
121     ASSERT(indexKeys);
122     IDBKey* indexKey = createIDBKeyFromScriptValueAndKeyPath(isolate, objectValue, indexMetadata.keyPath);
123
124     if (!indexKey)
125         return;
126
127     if (!indexMetadata.multiEntry || indexKey->type() != IDBKey::ArrayType) {
128         if (!indexKey->isValid())
129             return;
130
131         indexKeys->append(indexKey);
132     } else {
133         ASSERT(indexMetadata.multiEntry);
134         ASSERT(indexKey->type() == IDBKey::ArrayType);
135         indexKey = IDBKey::createMultiEntryArray(indexKey->array());
136
137         for (size_t i = 0; i < indexKey->array().size(); ++i)
138             indexKeys->append(indexKey->array()[i]);
139     }
140 }
141
142 IDBRequest* IDBObjectStore::add(ScriptState* scriptState, const ScriptValue& value, const ScriptValue& key, ExceptionState& exceptionState)
143 {
144     IDB_TRACE("IDBObjectStore::add");
145     return put(scriptState, WebIDBPutModeAddOnly, IDBAny::create(this), value, key, exceptionState);
146 }
147
148 IDBRequest* IDBObjectStore::put(ScriptState* scriptState, const ScriptValue& value, const ScriptValue& key, ExceptionState& exceptionState)
149 {
150     IDB_TRACE("IDBObjectStore::put");
151     return put(scriptState, WebIDBPutModeAddOrUpdate, IDBAny::create(this), value, key, exceptionState);
152 }
153
154 IDBRequest* IDBObjectStore::put(ScriptState* scriptState, WebIDBPutMode putMode, IDBAny* source, const ScriptValue& value, const ScriptValue& keyValue, ExceptionState& exceptionState)
155 {
156     IDBKey* key = keyValue.isUndefined() ? nullptr : scriptValueToIDBKey(scriptState->isolate(), keyValue);
157     return put(scriptState, putMode, source, value, key, exceptionState);
158 }
159
160 IDBRequest* IDBObjectStore::put(ScriptState* scriptState, WebIDBPutMode putMode, IDBAny* source, const ScriptValue& value, IDBKey* key, ExceptionState& exceptionState)
161 {
162     if (isDeleted()) {
163         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
164         return 0;
165     }
166     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
167         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
168         return 0;
169     }
170     if (!m_transaction->isActive()) {
171         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
172         return 0;
173     }
174     if (m_transaction->isReadOnly()) {
175         exceptionState.throwDOMException(ReadOnlyError, IDBDatabase::transactionReadOnlyErrorMessage);
176         return 0;
177     }
178
179     Vector<WebBlobInfo> blobInfo;
180     RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(value, &blobInfo, exceptionState, scriptState->isolate());
181     if (exceptionState.hadException())
182         return 0;
183
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.
187     ScriptValue clone;
188
189     const IDBKeyPath& keyPath = m_metadata.keyPath;
190     const bool usesInLineKeys = !keyPath.isNull();
191     const bool hasKeyGenerator = autoIncrement();
192
193     if (putMode != WebIDBPutModeCursorUpdate && usesInLineKeys && key) {
194         exceptionState.throwDOMException(DataError, "The object store uses in-line keys and the key parameter was provided.");
195         return 0;
196     }
197
198     // This test logically belongs in IDBCursor, but must operate on the cloned value.
199     if (putMode == WebIDBPutModeCursorUpdate && usesInLineKeys) {
200         ASSERT(key);
201         if (clone.isEmpty())
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.");
206             return nullptr;
207         }
208     }
209
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.");
212         return 0;
213     }
214     if (usesInLineKeys) {
215         if (clone.isEmpty())
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.");
220             return 0;
221         }
222         if (!hasKeyGenerator && !keyPathKey) {
223             exceptionState.throwDOMException(DataError, "Evaluating the object store's key path did not yield a value.");
224             return 0;
225         }
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.");
229                 return 0;
230             }
231         }
232         if (keyPathKey)
233             key = keyPathKey;
234     }
235     if (key && !key->isValid()) {
236         exceptionState.throwDOMException(DataError, IDBDatabase::notValidKeyErrorMessage);
237         return 0;
238     }
239
240     if (!backendDB()) {
241         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
242         return 0;
243     }
244
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) {
248         if (clone.isEmpty())
249             clone = deserializeScriptValue(scriptState, serializedValue.get(), &blobInfo);
250         IndexKeys keys;
251         generateIndexKeysForValue(scriptState->isolate(), it->value, clone, &keys);
252         indexIds.append(it->key);
253         indexKeys.append(keys);
254     }
255
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);
260
261     backendDB()->put(m_transaction->id(), id(), WebData(valueBuffer), blobInfo, key, static_cast<WebIDBPutMode>(putMode), WebIDBCallbacksImpl::create(request).leakPtr(), indexIds, indexKeys);
262     return request;
263 }
264
265 IDBRequest* IDBObjectStore::deleteFunction(ScriptState* scriptState, const ScriptValue& key, ExceptionState& exceptionState)
266 {
267     IDB_TRACE("IDBObjectStore::delete");
268     if (isDeleted()) {
269         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
270         return 0;
271     }
272     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
273         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
274         return 0;
275     }
276     if (!m_transaction->isActive()) {
277         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
278         return 0;
279     }
280     if (m_transaction->isReadOnly()) {
281         exceptionState.throwDOMException(ReadOnlyError, IDBDatabase::transactionReadOnlyErrorMessage);
282         return 0;
283     }
284
285     IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), key, exceptionState);
286     if (exceptionState.hadException())
287         return 0;
288     if (!keyRange) {
289         exceptionState.throwDOMException(DataError, IDBDatabase::noKeyOrKeyRangeErrorMessage);
290         return 0;
291     }
292     if (!backendDB()) {
293         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
294         return 0;
295     }
296
297     IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get());
298     backendDB()->deleteRange(m_transaction->id(), id(), keyRange, WebIDBCallbacksImpl::create(request).leakPtr());
299     return request;
300 }
301
302 IDBRequest* IDBObjectStore::clear(ScriptState* scriptState, ExceptionState& exceptionState)
303 {
304     IDB_TRACE("IDBObjectStore::clear");
305     if (isDeleted()) {
306         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
307         return 0;
308     }
309     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
310         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
311         return 0;
312     }
313     if (!m_transaction->isActive()) {
314         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
315         return 0;
316     }
317     if (m_transaction->isReadOnly()) {
318         exceptionState.throwDOMException(ReadOnlyError, IDBDatabase::transactionReadOnlyErrorMessage);
319         return 0;
320     }
321     if (!backendDB()) {
322         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
323         return 0;
324     }
325
326     IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get());
327     backendDB()->clear(m_transaction->id(), id(), WebIDBCallbacksImpl::create(request).leakPtr());
328     return request;
329 }
330
331 namespace {
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 {
338 public:
339     static PassRefPtr<IndexPopulator> create(ScriptState* scriptState, IDBDatabase* database, int64_t transactionId, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata)
340     {
341         return adoptRef(new IndexPopulator(scriptState, database, transactionId, objectStoreId, indexMetadata));
342     }
343
344     virtual bool operator==(const EventListener& other) OVERRIDE
345     {
346         return this == &other;
347     }
348
349 private:
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)
357     {
358     }
359
360     virtual void handleEvent(ExecutionContext* executionContext, Event* event) OVERRIDE
361     {
362         ASSERT(m_scriptState->executionContext() == executionContext);
363         ASSERT(event->type() == EventTypeNames::success);
364         EventTarget* target = event->target();
365         IDBRequest* request = static_cast<IDBRequest*>(target);
366
367         if (!m_database->backend()) // If database is stopped?
368             return;
369
370         IDBAny* cursorAny = request->resultAsAny();
371         IDBCursorWithValue* cursor = 0;
372         if (cursorAny->type() == IDBAny::IDBCursorWithValueType)
373             cursor = cursorAny->idbCursorWithValue();
374
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);
379
380             IDBKey* primaryKey = cursor->idbPrimaryKey();
381             ScriptValue value = cursor->value(m_scriptState.get());
382
383             IDBObjectStore::IndexKeys indexKeys;
384             generateIndexKeysForValue(m_scriptState->isolate(), m_indexMetadata, value, &indexKeys);
385
386             HeapVector<IDBObjectStore::IndexKeys> indexKeysList;
387             indexKeysList.append(indexKeys);
388
389             m_database->backend()->setIndexKeys(m_transactionId, m_objectStoreId, primaryKey, indexIds, indexKeysList);
390         } else {
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);
394             m_database.clear();
395         }
396
397     }
398
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;
404 };
405 }
406
407 IDBIndex* IDBObjectStore::createIndex(ScriptState* scriptState, const String& name, const IDBKeyPath& keyPath, const IDBIndexParameters& options, ExceptionState& exceptionState)
408 {
409     IDB_TRACE("IDBObjectStore::createIndex");
410     if (!m_transaction->isVersionChange()) {
411         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::notVersionChangeTransactionErrorMessage);
412         return 0;
413     }
414     if (isDeleted()) {
415         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
416         return 0;
417     }
418     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
419         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
420         return 0;
421     }
422     if (!m_transaction->isActive()) {
423         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
424         return 0;
425     }
426     if (!keyPath.isValid()) {
427         exceptionState.throwDOMException(SyntaxError, "The keyPath argument contains an invalid key path.");
428         return 0;
429     }
430     if (name.isNull()) {
431         exceptionState.throwTypeError("The name provided is null.");
432         return 0;
433     }
434     if (containsIndex(name)) {
435         exceptionState.throwDOMException(ConstraintError, "An index with the specified name already exists.");
436         return 0;
437     }
438
439     if (keyPath.type() == IDBKeyPath::ArrayType && options.multiEntry()) {
440         exceptionState.throwDOMException(InvalidAccessError, "The keyPath argument was an array and the multiEntry option is true.");
441         return 0;
442     }
443     if (!backendDB()) {
444         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
445         return 0;
446     }
447
448     int64_t indexId = m_metadata.maxIndexId + 1;
449     backendDB()->createIndex(m_transaction->id(), id(), indexId, name, keyPath, options.unique(), options.multiEntry());
450
451     ++m_metadata.maxIndexId;
452
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);
458
459     ASSERT(!exceptionState.hadException());
460     if (exceptionState.hadException())
461         return 0;
462
463     IDBRequest* indexRequest = openCursor(scriptState, static_cast<IDBKeyRange*>(0), WebIDBCursorDirectionNext, WebIDBTaskTypePreemptive);
464     indexRequest->preventPropagation();
465
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);
469     return index;
470 }
471
472 IDBIndex* IDBObjectStore::index(const String& name, ExceptionState& exceptionState)
473 {
474     IDB_TRACE("IDBObjectStore::index");
475     if (isDeleted()) {
476         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
477         return 0;
478     }
479     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
480         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::transactionFinishedErrorMessage);
481         return 0;
482     }
483
484     IDBIndexMap::iterator it = m_indexMap.find(name);
485     if (it != m_indexMap.end())
486         return it->value;
487
488     int64_t indexId = findIndexId(name);
489     if (indexId == IDBIndexMetadata::InvalidId) {
490         exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchIndexErrorMessage);
491         return 0;
492     }
493
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;
498             break;
499         }
500     }
501     ASSERT(indexMetadata);
502     ASSERT(indexMetadata->id != IDBIndexMetadata::InvalidId);
503
504     IDBIndex* index = IDBIndex::create(*indexMetadata, this, m_transaction.get());
505     m_indexMap.set(name, index);
506     return index;
507 }
508
509 void IDBObjectStore::deleteIndex(const String& name, ExceptionState& exceptionState)
510 {
511     IDB_TRACE("IDBObjectStore::deleteIndex");
512     if (!m_transaction->isVersionChange()) {
513         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::notVersionChangeTransactionErrorMessage);
514         return;
515     }
516     if (isDeleted()) {
517         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
518         return;
519     }
520     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
521         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
522         return;
523     }
524     if (!m_transaction->isActive()) {
525         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
526         return;
527     }
528     int64_t indexId = findIndexId(name);
529     if (indexId == IDBIndexMetadata::InvalidId) {
530         exceptionState.throwDOMException(NotFoundError, IDBDatabase::noSuchIndexErrorMessage);
531         return;
532     }
533     if (!backendDB()) {
534         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
535         return;
536     }
537
538     backendDB()->deleteIndex(m_transaction->id(), id(), indexId);
539
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);
546     }
547 }
548
549 IDBRequest* IDBObjectStore::openCursor(ScriptState* scriptState, const ScriptValue& range, const String& directionString, ExceptionState& exceptionState)
550 {
551     IDB_TRACE("IDBObjectStore::openCursor");
552     if (isDeleted()) {
553         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
554         return 0;
555     }
556     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
557         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
558         return 0;
559     }
560     if (!m_transaction->isActive()) {
561         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
562         return 0;
563     }
564
565     WebIDBCursorDirection direction = IDBCursor::stringToDirection(directionString, exceptionState);
566     if (exceptionState.hadException())
567         return 0;
568
569     IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), range, exceptionState);
570     if (exceptionState.hadException())
571         return 0;
572
573     if (!backendDB()) {
574         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
575         return 0;
576     }
577
578     return openCursor(scriptState, keyRange, direction, WebIDBTaskTypeNormal);
579 }
580
581 IDBRequest* IDBObjectStore::openCursor(ScriptState* scriptState, IDBKeyRange* range, WebIDBCursorDirection direction, WebIDBTaskType taskType)
582 {
583     IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get());
584     request->setCursorDetails(IndexedDB::CursorKeyAndValue, direction);
585
586     backendDB()->openCursor(m_transaction->id(), id(), IDBIndexMetadata::InvalidId, range, direction, false, taskType, WebIDBCallbacksImpl::create(request).leakPtr());
587     return request;
588 }
589
590 IDBRequest* IDBObjectStore::openKeyCursor(ScriptState* scriptState, const ScriptValue& range, const String& directionString, ExceptionState& exceptionState)
591 {
592     IDB_TRACE("IDBObjectStore::openKeyCursor");
593     if (isDeleted()) {
594         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
595         return 0;
596     }
597     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
598         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
599         return 0;
600     }
601     if (!m_transaction->isActive()) {
602         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
603         return 0;
604     }
605
606     WebIDBCursorDirection direction = IDBCursor::stringToDirection(directionString, exceptionState);
607     if (exceptionState.hadException())
608         return 0;
609
610     IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), range, exceptionState);
611     if (exceptionState.hadException())
612         return 0;
613
614     if (!backendDB()) {
615         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
616         return 0;
617     }
618
619     IDBRequest* request = IDBRequest::create(scriptState, IDBAny::create(this), m_transaction.get());
620     request->setCursorDetails(IndexedDB::CursorKeyOnly, direction);
621
622     backendDB()->openCursor(m_transaction->id(), id(), IDBIndexMetadata::InvalidId, keyRange, direction, true, WebIDBTaskTypeNormal, WebIDBCallbacksImpl::create(request).leakPtr());
623     return request;
624 }
625
626 IDBRequest* IDBObjectStore::count(ScriptState* scriptState, const ScriptValue& range, ExceptionState& exceptionState)
627 {
628     IDB_TRACE("IDBObjectStore::count");
629     if (isDeleted()) {
630         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage);
631         return 0;
632     }
633     if (m_transaction->isFinished() || m_transaction->isFinishing()) {
634         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage);
635         return 0;
636     }
637     if (!m_transaction->isActive()) {
638         exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage);
639         return 0;
640     }
641
642     IDBKeyRange* keyRange = IDBKeyRange::fromScriptValue(scriptState->executionContext(), range, exceptionState);
643     if (exceptionState.hadException())
644         return 0;
645
646     if (!backendDB()) {
647         exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage);
648         return 0;
649     }
650
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());
653     return request;
654 }
655
656 void IDBObjectStore::transactionFinished()
657 {
658     ASSERT(m_transaction->isFinished());
659
660     // Break reference cycles.
661     m_indexMap.clear();
662 }
663
664 int64_t IDBObjectStore::findIndexId(const String& name) const
665 {
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);
669             return it->key;
670         }
671     }
672     return IDBIndexMetadata::InvalidId;
673 }
674
675 WebIDBDatabase* IDBObjectStore::backendDB() const
676 {
677     return m_transaction->backendDB();
678 }
679
680 } // namespace blink