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