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