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