IndexedDB: Remove redundant IDBObjectStore.delete() overloads
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / IDBObjectStoreBackendImpl.cpp
1 /*
2  * Copyright (C) 2011 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 "IDBObjectStoreBackendImpl.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "CrossThreadTask.h"
32 #include "DOMStringList.h"
33 #include "IDBBackingStore.h"
34 #include "IDBBindingUtilities.h"
35 #include "IDBCallbacks.h"
36 #include "IDBCursorBackendImpl.h"
37 #include "IDBDatabaseBackendImpl.h"
38 #include "IDBDatabaseException.h"
39 #include "IDBIndexBackendImpl.h"
40 #include "IDBKey.h"
41 #include "IDBKeyPath.h"
42 #include "IDBKeyPathBackendImpl.h"
43 #include "IDBKeyRange.h"
44 #include "IDBTracing.h"
45 #include "IDBTransactionBackendInterface.h"
46 #include "ScriptExecutionContext.h"
47
48 namespace WebCore {
49
50 IDBObjectStoreBackendImpl::~IDBObjectStoreBackendImpl()
51 {
52 }
53
54 IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(const IDBDatabaseBackendImpl* database, int64_t id, const String& name, const IDBKeyPath& keyPath, bool autoIncrement)
55     : m_database(database)
56     , m_id(id)
57     , m_name(name)
58     , m_keyPath(keyPath)
59     , m_autoIncrement(autoIncrement)
60     , m_autoIncrementNumber(-1)
61 {
62     loadIndexes();
63 }
64
65 IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(const IDBDatabaseBackendImpl* database, const String& name, const IDBKeyPath& keyPath, bool autoIncrement)
66     : m_database(database)
67     , m_id(InvalidId)
68     , m_name(name)
69     , m_keyPath(keyPath)
70     , m_autoIncrement(autoIncrement)
71     , m_autoIncrementNumber(-1)
72 {
73 }
74
75 PassRefPtr<DOMStringList> IDBObjectStoreBackendImpl::indexNames() const
76 {
77     RefPtr<DOMStringList> indexNames = DOMStringList::create();
78     for (IndexMap::const_iterator it = m_indexes.begin(); it != m_indexes.end(); ++it)
79         indexNames->append(it->first);
80     indexNames->sort();
81     return indexNames.release();
82 }
83
84 void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
85 {
86     IDB_TRACE("IDBObjectStoreBackendImpl::get");
87     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
88     RefPtr<IDBKeyRange> keyRange = prpKeyRange;
89     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
90     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::getInternal, objectStore, keyRange, callbacks)))
91         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
92 }
93
94 void IDBObjectStoreBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
95 {
96     IDB_TRACE("IDBObjectStoreBackendImpl::getByRangeInternal");
97     RefPtr<IDBKey> key;
98     if (keyRange->isOnlyKey())
99         key = keyRange->lower();
100     else {
101         RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), keyRange.get(), IDBCursor::NEXT);
102         if (!backingStoreCursor) {
103             callbacks->onSuccess(SerializedScriptValue::undefinedValue());
104             return;
105         }
106         key = backingStoreCursor->key();
107         backingStoreCursor->close();
108     }
109
110     String wireData = objectStore->backingStore()->getObjectStoreRecord(objectStore->databaseId(), objectStore->id(), *key);
111     if (wireData.isNull()) {
112         callbacks->onSuccess(SerializedScriptValue::undefinedValue());
113         return;
114     }
115
116     callbacks->onSuccess(SerializedScriptValue::createFromWire(wireData));
117 }
118
119 static PassRefPtr<IDBKey> fetchKeyFromKeyPath(SerializedScriptValue* value, const IDBKeyPath& keyPath)
120 {
121     IDB_TRACE("IDBObjectStoreBackendImpl::fetchKeyFromKeyPath");
122     ASSERT(!keyPath.isNull());
123
124     Vector<RefPtr<SerializedScriptValue> > values;
125     values.append(value);
126     Vector<RefPtr<IDBKey> > keys;
127     IDBKeyPathBackendImpl::createIDBKeysFromSerializedValuesAndKeyPath(values, keyPath, keys);
128     if (keys.isEmpty())
129         return 0;
130     ASSERT(keys.size() == 1);
131     return keys[0].release();
132 }
133
134 static PassRefPtr<SerializedScriptValue> injectKeyIntoKeyPath(PassRefPtr<IDBKey> key, PassRefPtr<SerializedScriptValue> value, const IDBKeyPath& keyPath)
135 {
136     IDB_TRACE("IDBObjectStoreBackendImpl::injectKeyIntoKeyPath");
137     return IDBKeyPathBackendImpl::injectIDBKeyIntoSerializedValue(key, value, keyPath);
138 }
139
140 void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
141 {
142     IDB_TRACE("IDBObjectStoreBackendImpl::put");
143
144     ASSERT(transactionPtr->mode() != IDBTransaction::READ_ONLY);
145
146     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
147     RefPtr<SerializedScriptValue> value = prpValue;
148     RefPtr<IDBKey> key = prpKey;
149     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
150     RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
151
152     if (putMode != CursorUpdate) {
153         const bool autoIncrement = objectStore->autoIncrement();
154         const bool hasKeyPath = !objectStore->m_keyPath.isNull();
155
156         if (hasKeyPath && key) {
157             ec = IDBDatabaseException::DATA_ERR;
158             return;
159         }
160         if (!hasKeyPath && !autoIncrement && !key) {
161             ec = IDBDatabaseException::DATA_ERR;
162             return;
163         }
164         if (hasKeyPath) {
165             RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
166             if (keyPathKey && !keyPathKey->isValid()) {
167                 ec = IDBDatabaseException::DATA_ERR;
168                 return;
169             }
170             if (!autoIncrement && !keyPathKey) {
171                 ec = IDBDatabaseException::DATA_ERR;
172                 return;
173             }
174             if (autoIncrement && !keyPathKey) {
175                 RefPtr<IDBKey> dummyKey = IDBKey::createNumber(-1);
176                 RefPtr<SerializedScriptValue> valueAfterInjection = injectKeyIntoKeyPath(dummyKey, value, objectStore->m_keyPath);
177                 if (!valueAfterInjection) {
178                     ec = IDBDatabaseException::DATA_ERR;
179                     return;
180                 }
181             }
182         }
183         if (key && !key->isValid()) {
184             ec = IDBDatabaseException::DATA_ERR;
185             return;
186         }
187     } else {
188         ASSERT(key);
189         const bool hasKeyPath = !objectStore->m_keyPath.isNull();
190         if (hasKeyPath) {
191             RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
192             if (!keyPathKey || !keyPathKey->isEqual(key.get())) {
193                 ec = IDBDatabaseException::DATA_ERR;
194                 return;
195             }
196         }
197     }
198
199     if (!transaction->scheduleTask(
200             createCallbackTask(&IDBObjectStoreBackendImpl::putInternal, objectStore, value, key, putMode, callbacks, transaction),
201             // FIXME: One of these per put() is overkill, since it's simply a cache invalidation.
202             createCallbackTask(&IDBObjectStoreBackendImpl::revertAutoIncrementKeyCache, objectStore)))
203         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
204 }
205
206 void IDBObjectStoreBackendImpl::revertAutoIncrementKeyCache(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
207 {
208     objectStore->resetAutoIncrementKeyCache();
209 }
210
211 void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
212 {
213     IDB_TRACE("IDBObjectStoreBackendImpl::putInternal");
214     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
215     RefPtr<SerializedScriptValue> value = prpValue;
216     RefPtr<IDBKey> key = prpKey;
217
218     if (putMode != CursorUpdate) {
219         const bool autoIncrement = objectStore->autoIncrement();
220         const bool hasKeyPath = !objectStore->m_keyPath.isNull();
221         if (hasKeyPath) {
222             ASSERT(!key);
223             RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
224             if (keyPathKey)
225                 key = keyPathKey;
226         }
227         if (autoIncrement) {
228             if (!key) {
229                 RefPtr<IDBKey> autoIncKey = objectStore->genAutoIncrementKey();
230                 if (!autoIncKey->isValid()) {
231                     callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "Maximum key generator value reached."));
232                     return;
233                 }
234                 if (hasKeyPath) {
235                     RefPtr<SerializedScriptValue> valueAfterInjection = injectKeyIntoKeyPath(autoIncKey, value, objectStore->m_keyPath);
236                     ASSERT(valueAfterInjection);
237                     if (!valueAfterInjection) {
238                         objectStore->resetAutoIncrementKeyCache();
239                         // Checks in put() ensure this should only happen if I/O error occurs.
240                         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error inserting generated key into the object."));
241                         return;
242                     }
243                     value = valueAfterInjection;
244                 }
245                 key = autoIncKey;
246             } else {
247                 // FIXME: Logic to update generator state should go here. Currently it does a scan.
248                 objectStore->resetAutoIncrementKeyCache();
249             }
250         }
251     }
252
253     ASSERT(key && key->isValid());
254
255     RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = objectStore->backingStore()->createInvalidRecordIdentifier();
256     if (putMode == AddOnly && objectStore->backingStore()->keyExistsInObjectStore(objectStore->databaseId(), objectStore->id(), *key, recordIdentifier.get())) {
257         objectStore->resetAutoIncrementKeyCache();
258         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
259         return;
260     }
261
262     Vector<RefPtr<IDBKey> > indexKeys;
263     for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
264         const RefPtr<IDBIndexBackendImpl>& index = it->second;
265
266         RefPtr<IDBKey> indexKey = fetchKeyFromKeyPath(value.get(), index->keyPath());
267         if (!indexKey || !indexKey->isValid()) {
268             // Null/invalid keys not added to index; null entry keeps iterator/vector indexes consistent.
269             indexKey.clear();
270             indexKeys.append(indexKey);
271             continue;
272         }
273         ASSERT(indexKey->isValid());
274
275         if ((!index->multiEntry() || indexKey->type() != IDBKey::ArrayType) && !index->addingKeyAllowed(indexKey.get(), key.get())) {
276             objectStore->resetAutoIncrementKeyCache();
277             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "One of the derived (from a keyPath) keys for an index does not satisfy its uniqueness requirements."));
278             return;
279         }
280
281         if (index->multiEntry() && indexKey->type() == IDBKey::ArrayType) {
282            for (size_t j = 0; j < indexKey->array().size(); ++j) {
283                 if (!index->addingKeyAllowed(indexKey->array()[j].get(), key.get())) {
284                     objectStore->resetAutoIncrementKeyCache();
285                     callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "One of the derived (from a keyPath) keys for an index does not satisfy its uniqueness requirements."));
286                     return;
287                 }
288             }
289         }
290
291         indexKeys.append(indexKey.release());
292     }
293
294     // Before this point, don't do any mutation.  After this point, rollback the transaction in case of error.
295
296     if (!objectStore->backingStore()->putObjectStoreRecord(objectStore->databaseId(), objectStore->id(), *key, value->toWireString(), recordIdentifier.get())) {
297         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
298         transaction->abort();
299         return;
300     }
301
302     int i = 0;
303     for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it, ++i) {
304         RefPtr<IDBIndexBackendImpl>& index = it->second;
305         if (!index->hasValidId())
306             continue; // The index object has been created, but does not exist in the database yet.
307
308         if (!objectStore->backingStore()->deleteIndexDataForRecord(objectStore->databaseId(), objectStore->id(), index->id(), recordIdentifier.get())) {
309             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
310             transaction->abort();
311             return;
312         }
313
314         if (!indexKeys[i])
315             continue;
316         RefPtr<IDBKey> indexKey = indexKeys[i];
317
318         if (!index->multiEntry() || indexKey->type() != IDBKey::ArrayType) {
319             if (!objectStore->backingStore()->putIndexDataForRecord(objectStore->databaseId(), objectStore->id(), index->id(), *indexKey, recordIdentifier.get())) {
320                 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
321                 transaction->abort();
322                 return;
323             }
324         } else {
325             ASSERT(index->multiEntry());
326             ASSERT(indexKey->type() == IDBKey::ArrayType);
327             for (size_t j = 0; j < indexKey->array().size(); ++j) {
328                 if (!objectStore->backingStore()->putIndexDataForRecord(objectStore->databaseId(), objectStore->id(), index->id(), *indexKey->array()[j], recordIdentifier.get())) {
329                     callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
330                     transaction->abort();
331                     return;
332                 }
333             }
334         }
335     }
336
337     callbacks->onSuccess(key.get());
338 }
339
340 void IDBObjectStoreBackendImpl::deleteFunction(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
341 {
342     IDB_TRACE("IDBObjectStoreBackendImpl::delete");
343
344     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
345
346     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
347     RefPtr<IDBKeyRange> keyRange = prpKeyRange;
348     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
349
350     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::deleteInternal, objectStore, keyRange, callbacks)))
351         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
352 }
353
354 void IDBObjectStoreBackendImpl::deleteInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
355 {
356     IDB_TRACE("IDBObjectStoreBackendImpl::deleteInternal");
357     RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier;
358
359     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), keyRange.get(), IDBCursor::NEXT);
360     if (backingStoreCursor) {
361
362         do {
363             recordIdentifier = backingStoreCursor->objectStoreRecordIdentifier();
364
365             for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
366                 if (!it->second->hasValidId())
367                     continue; // The index object has been created, but does not exist in the database yet.
368
369                 bool success = objectStore->backingStore()->deleteIndexDataForRecord(objectStore->databaseId(), objectStore->id(), it->second->id(), recordIdentifier.get());
370                 ASSERT_UNUSED(success, success);
371             }
372
373             objectStore->backingStore()->deleteObjectStoreRecord(objectStore->databaseId(), objectStore->id(), recordIdentifier.get());
374
375         } while (backingStoreCursor->continueFunction(0));
376
377         backingStoreCursor->close();
378     }
379
380     callbacks->onSuccess(SerializedScriptValue::undefinedValue());
381 }
382
383 void IDBObjectStoreBackendImpl::clear(PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
384 {
385     IDB_TRACE("IDBObjectStoreBackendImpl::clear");
386
387     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
388
389     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
390     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
391
392     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::clearInternal, objectStore, callbacks)))
393         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
394 }
395
396 void IDBObjectStoreBackendImpl::clearInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBCallbacks> callbacks)
397 {
398     objectStore->backingStore()->clearObjectStore(objectStore->databaseId(), objectStore->id());
399     callbacks->onSuccess(SerializedScriptValue::undefinedValue());
400 }
401
402 namespace {
403 class PopulateIndexCallback : public IDBBackingStore::ObjectStoreRecordCallback {
404 public:
405     PopulateIndexCallback(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBIndexBackendImpl> index)
406         : m_backingStore(backingStore)
407         , m_databaseId(databaseId)
408         , m_objectStoreId(objectStoreId)
409         , m_index(index)
410     {
411     }
412
413     virtual bool callback(const IDBBackingStore::ObjectStoreRecordIdentifier* recordIdentifier, const String& value)
414     {
415         RefPtr<SerializedScriptValue> objectValue = SerializedScriptValue::createFromWire(value);
416         RefPtr<IDBKey> indexKey = fetchKeyFromKeyPath(objectValue.get(), m_index->keyPath());
417
418         if (!indexKey)
419             return true;
420
421         if (!m_index->multiEntry() || indexKey->type() != IDBKey::ArrayType) {
422             if (!m_index->addingKeyAllowed(indexKey.get()))
423                 return false;
424             if (!m_backingStore.putIndexDataForRecord(m_databaseId, m_objectStoreId, m_index->id(), *indexKey, recordIdentifier))
425                 return false;
426         } else {
427             ASSERT(m_index->multiEntry());
428             ASSERT(indexKey->type() == IDBKey::ArrayType);
429             for (size_t i = 0; i < indexKey->array().size(); ++i) {
430                 if (!m_index->addingKeyAllowed(indexKey.get()))
431                     return false;
432                 if (!m_backingStore.putIndexDataForRecord(m_databaseId, m_objectStoreId, m_index->id(), *indexKey->array()[i], recordIdentifier))
433                     return false;
434             }
435         }
436         return true;
437     }
438
439 private:
440     IDBBackingStore& m_backingStore;
441     int64_t m_databaseId;
442     int64_t m_objectStoreId;
443     RefPtr<IDBIndexBackendImpl> m_index;
444 };
445 }
446
447 bool IDBObjectStoreBackendImpl::populateIndex(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBIndexBackendImpl> index)
448 {
449     PopulateIndexCallback callback(backingStore, databaseId, objectStoreId, index);
450     if (!backingStore.forEachObjectStoreRecord(databaseId, objectStoreId, callback))
451         return false;
452     return true;
453 }
454
455 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::createIndex(const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
456 {
457     if (name.isNull()) {
458         ec = IDBDatabaseException::IDB_TYPE_ERR;
459         return 0;
460     }
461     if (m_indexes.contains(name)) {
462         ec = IDBDatabaseException::CONSTRAINT_ERR;
463         return 0;
464     }
465     if (transaction->mode() != IDBTransaction::VERSION_CHANGE) {
466         ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
467         return 0;
468     }
469
470     RefPtr<IDBIndexBackendImpl> index = IDBIndexBackendImpl::create(m_database, this, name, keyPath, unique, multiEntry);
471     ASSERT(index->name() == name);
472
473     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
474     RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
475     if (!transaction->scheduleTask(
476               createCallbackTask(&IDBObjectStoreBackendImpl::createIndexInternal,
477                                  objectStore, index, transactionPtr),
478               createCallbackTask(&IDBObjectStoreBackendImpl::removeIndexFromMap,
479                                  objectStore, index))) {
480         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
481         return 0;
482     }
483
484     m_indexes.set(name, index);
485     return index.release();
486 }
487
488 void IDBObjectStoreBackendImpl::createIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
489 {
490     int64_t id;
491     if (!objectStore->backingStore()->createIndex(objectStore->databaseId(), objectStore->id(), index->name(), index->keyPath(), index->unique(), index->multiEntry(), id)) {
492         transaction->abort();
493         return;
494     }
495
496     index->setId(id);
497
498     if (!populateIndex(*objectStore->backingStore(), objectStore->databaseId(), objectStore->m_id, index)) {
499         transaction->abort();
500         return;
501     }
502
503     transaction->didCompleteTaskEvents();
504 }
505
506 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::index(const String& name, ExceptionCode& ec)
507 {
508     RefPtr<IDBIndexBackendInterface> index = m_indexes.get(name);
509     if (!index) {
510         ec = IDBDatabaseException::IDB_NOT_FOUND_ERR;
511         return 0;
512     }
513     return index.release();
514 }
515
516 void IDBObjectStoreBackendImpl::deleteIndex(const String& name, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
517 {
518     if (transaction->mode() != IDBTransaction::VERSION_CHANGE) {
519         ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
520         return;
521     }
522
523     RefPtr<IDBIndexBackendImpl> index = m_indexes.get(name);
524     if (!index) {
525         ec = IDBDatabaseException::IDB_NOT_FOUND_ERR;
526         return;
527     }
528
529     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
530     RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
531     if (!transaction->scheduleTask(
532               createCallbackTask(&IDBObjectStoreBackendImpl::deleteIndexInternal,
533                                  objectStore, index, transactionPtr),
534               createCallbackTask(&IDBObjectStoreBackendImpl::addIndexToMap,
535                                  objectStore, index))) {
536         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
537         return;
538     }
539     m_indexes.remove(name);
540 }
541
542 void IDBObjectStoreBackendImpl::deleteIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
543 {
544     objectStore->backingStore()->deleteIndex(objectStore->databaseId(), objectStore->id(), index->id());
545     transaction->didCompleteTaskEvents();
546 }
547
548 void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
549 {
550     IDB_TRACE("IDBObjectStoreBackendImpl::openCursor");
551     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
552     RefPtr<IDBKeyRange> range = prpRange;
553     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
554     RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
555     if (!transaction->scheduleTask(
556             createCallbackTask(&IDBObjectStoreBackendImpl::openCursorInternal,
557                                objectStore, range, direction, callbacks, transactionPtr))) {
558         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
559     }
560 }
561
562 void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
563 {
564     IDB_TRACE("IDBObjectStoreBackendImpl::openCursorInternal");
565     IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(tmpDirection);
566
567     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), range.get(), direction);
568     if (!backingStoreCursor) {
569         callbacks->onSuccess(SerializedScriptValue::nullValue());
570         return;
571     }
572
573     RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(backingStoreCursor.release(), direction, IDBCursorBackendInterface::ObjectStoreCursor, transaction.get(), objectStore.get());
574     callbacks->onSuccess(cursor.release());
575 }
576
577 void IDBObjectStoreBackendImpl::count(PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
578 {
579     IDB_TRACE("IDBObjectStoreBackendImpl::count");
580     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::countInternal, this, range, callbacks, transaction)))
581         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
582 }
583
584 void IDBObjectStoreBackendImpl::countInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface>)
585 {
586     IDB_TRACE("IDBObjectStoreBackendImpl::countInternal");
587     uint32_t count = 0;
588     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), range.get(), IDBCursor::NEXT);
589     if (!backingStoreCursor) {
590         callbacks->onSuccess(SerializedScriptValue::numberValue(count));
591         return;
592     }
593
594     do {
595         ++count;
596     } while (backingStoreCursor->continueFunction(0));
597
598     backingStoreCursor->close();
599     callbacks->onSuccess(SerializedScriptValue::numberValue(count));
600 }
601
602 void IDBObjectStoreBackendImpl::loadIndexes()
603 {
604     Vector<int64_t> ids;
605     Vector<String> names;
606     Vector<IDBKeyPath> keyPaths;
607     Vector<bool> uniqueFlags;
608     Vector<bool> multiEntryFlags;
609     backingStore()->getIndexes(databaseId(), m_id, ids, names, keyPaths, uniqueFlags, multiEntryFlags);
610
611     ASSERT(names.size() == ids.size());
612     ASSERT(keyPaths.size() == ids.size());
613     ASSERT(uniqueFlags.size() == ids.size());
614     ASSERT(multiEntryFlags.size() == ids.size());
615
616     for (size_t i = 0; i < ids.size(); i++)
617         m_indexes.set(names[i], IDBIndexBackendImpl::create(m_database, this, ids[i], names[i], keyPaths[i], uniqueFlags[i], multiEntryFlags[i]));
618 }
619
620 void IDBObjectStoreBackendImpl::removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
621 {
622     ASSERT(objectStore->m_indexes.contains(index->name()));
623     objectStore->m_indexes.remove(index->name());
624 }
625
626 void IDBObjectStoreBackendImpl::addIndexToMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
627 {
628     RefPtr<IDBIndexBackendImpl> indexPtr = index;
629     ASSERT(!objectStore->m_indexes.contains(indexPtr->name()));
630     objectStore->m_indexes.set(indexPtr->name(), indexPtr);
631 }
632
633 PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::genAutoIncrementKey()
634 {
635     const int64_t kMaxGeneratorValue = 9007199254740992LL; // Maximum integer storable as ECMAScript number.
636     if (m_autoIncrementNumber > kMaxGeneratorValue)
637         return IDBKey::createInvalid();
638     if (m_autoIncrementNumber > 0)
639         return IDBKey::createNumber(m_autoIncrementNumber++);
640
641     m_autoIncrementNumber = backingStore()->nextAutoIncrementNumber(databaseId(), id());
642     if (m_autoIncrementNumber > kMaxGeneratorValue)
643         return IDBKey::createInvalid();
644     return IDBKey::createNumber(m_autoIncrementNumber++);
645 }
646
647
648 } // namespace WebCore
649
650 #endif