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