ca8ad6172de9815b56edd331a9a7356ecf198da6
[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 = objectStore->backingStore()->getRecord(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), *key);
203     if (wireData.isNull()) {
204         callbacks->onSuccess();
205         return;
206     }
207
208     if (objectStore->autoIncrement() && !objectStore->keyPath().isNull()) {
209         callbacks->onSuccess(SerializedScriptValue::createFromWire(wireData),
210                              key, objectStore->keyPath());
211         return;
212     }
213     callbacks->onSuccess(SerializedScriptValue::createFromWire(wireData));
214 }
215
216 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)
217 {
218     IDB_TRACE("IDBObjectStoreBackendImpl::put");
219
220     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
221     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
222     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
223
224     OwnPtr<Vector<int64_t> > newIndexIds = adoptPtr(new Vector<int64_t>(indexIds));
225     OwnPtr<Vector<IndexKeys> > newIndexKeys = adoptPtr(new Vector<IndexKeys>(indexKeys));
226
227     ASSERT(autoIncrement() || key.get());
228
229     if (!transaction->scheduleTask(ObjectStoreStorageOperation::create(this, value, key, putMode, callbacks, transaction, newIndexIds.release(), newIndexKeys.release())))
230         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::AbortError));
231 }
232
233 namespace {
234 class IndexWriter {
235 public:
236     explicit IndexWriter(const IDBIndexMetadata& indexMetadata)
237         : m_indexMetadata(indexMetadata)
238     { }
239
240     IndexWriter(const IDBIndexMetadata& indexMetadata,
241                 const IDBObjectStoreBackendInterface::IndexKeys& indexKeys)
242         : m_indexMetadata(indexMetadata)
243         , m_indexKeys(indexKeys)
244     { }
245
246     bool verifyIndexKeys(IDBBackingStore& backingStore, IDBBackingStore::Transaction* transaction,
247                          int64_t databaseId, int64_t objectStoreId, int64_t indexId,
248                          const IDBKey* primaryKey = 0, String* errorMessage = 0)
249     {
250         for (size_t i = 0; i < m_indexKeys.size(); ++i) {
251             if (!addingKeyAllowed(backingStore, transaction, databaseId, objectStoreId, indexId,
252                                   (m_indexKeys)[i].get(), primaryKey)) {
253                 if (errorMessage)
254                     *errorMessage = String::format("Unable to add key to index '%s': at least one key does not satisfy the uniqueness requirements.",
255                                                    m_indexMetadata.name.utf8().data());
256                 return false;
257             }
258         }
259         return true;
260     }
261
262     void writeIndexKeys(const IDBBackingStore::RecordIdentifier& recordIdentifier, IDBBackingStore& backingStore, IDBBackingStore::Transaction* transaction, int64_t databaseId, int64_t objectStoreId) const
263     {
264         int64_t indexId = m_indexMetadata.id;
265         for (size_t i = 0; i < m_indexKeys.size(); ++i) {
266             backingStore.putIndexDataForRecord(transaction, databaseId, objectStoreId, indexId, *(m_indexKeys)[i].get(), recordIdentifier);
267         }
268     }
269
270 private:
271
272     bool addingKeyAllowed(IDBBackingStore& backingStore, IDBBackingStore::Transaction* transaction,
273                           int64_t databaseId, int64_t objectStoreId, int64_t indexId,
274                           const IDBKey* indexKey, const IDBKey* primaryKey) const
275     {
276         if (!m_indexMetadata.unique)
277             return true;
278
279         RefPtr<IDBKey> foundPrimaryKey;
280         bool found = backingStore.keyExistsInIndex(transaction, databaseId, objectStoreId, indexId, *indexKey, foundPrimaryKey);
281         if (!found)
282             return true;
283         if (primaryKey && foundPrimaryKey->isEqual(primaryKey))
284             return true;
285         return false;
286     }
287
288     const IDBIndexMetadata m_indexMetadata;
289     IDBObjectStoreBackendInterface::IndexKeys m_indexKeys;
290 };
291 }
292
293 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)
294 {
295     ASSERT(indexIds.size() == indexKeys.size());
296
297     HashMap<int64_t, IDBObjectStoreBackendInterface::IndexKeys> indexKeyMap;
298     for (size_t i = 0; i < indexIds.size(); ++i)
299         indexKeyMap.add(indexIds[i], indexKeys[i]);
300
301     for (IDBObjectStoreBackendImpl::IndexMap::iterator it = objectStore->iterIndexesBegin(); it != objectStore->iterIndexesEnd(); ++it) {
302
303         const RefPtr<IDBIndexBackendImpl>& index = it->value;
304
305         IDBObjectStoreBackendInterface::IndexKeys keys = indexKeyMap.get(it->key);
306         // If the objectStore is using autoIncrement, then any indexes with an identical keyPath need to also use the primary (generated) key as a key.
307         if (keyWasGenerated) {
308             const IDBKeyPath& indexKeyPath = index->keyPath();
309             if (indexKeyPath == objectStore->keyPath())
310                 keys.append(primaryKey);
311         }
312
313         OwnPtr<IndexWriter> indexWriter(adoptPtr(new IndexWriter(index->metadata(), keys)));
314         if (!indexWriter->verifyIndexKeys(*objectStore->backingStore(),
315                                           transaction->backingStoreTransaction(),
316                                           objectStore->databaseId(),
317                                           objectStore->id(),
318                                           index->id(), primaryKey.get(), errorMessage)) {
319             return false;
320         }
321
322         indexWriters->append(indexWriter.release());
323     }
324
325     return true;
326 }
327
328 void IDBObjectStoreBackendImpl::setIndexKeys(PassRefPtr<IDBKey> prpPrimaryKey, const Vector<int64_t>& indexIds, const Vector<IndexKeys>& indexKeys, IDBTransactionBackendInterface* transactionPtr)
329 {
330     IDB_TRACE("IDBObjectStoreBackendImpl::setIndexKeys");
331     RefPtr<IDBKey> primaryKey = prpPrimaryKey;
332     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
333     if (transaction->isFinished())
334         return;
335
336     // FIXME: This method could be asynchronous, but we need to evaluate if it's worth the extra complexity.
337     IDBBackingStore::RecordIdentifier recordIdentifier;
338     bool found = false;
339     bool ok = backingStore()->keyExistsInObjectStore(transaction->backingStoreTransaction(), databaseId(), id(), *primaryKey, &recordIdentifier, found);
340     if (!ok) {
341         LOG_ERROR("keyExistsInObjectStore reported an error");
342         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error setting index keys."));
343         return;
344     }
345     if (!found) {
346         transaction->abort();
347         return;
348     }
349
350     Vector<OwnPtr<IndexWriter> > indexWriters;
351     String errorMessage;
352     if (!makeIndexWriters(transaction, this, primaryKey, false, indexIds, indexKeys, &indexWriters, &errorMessage)) {
353         // FIXME: Need to deal with errorMessage here. makeIndexWriters only fails on uniqueness constraint errors.
354         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Duplicate index keys exist in the object store."));
355         return;
356     }
357
358     for (size_t i = 0; i < indexWriters.size(); ++i) {
359         IndexWriter* indexWriter = indexWriters[i].get();
360         indexWriter->writeIndexKeys(recordIdentifier, *backingStore(), transaction->backingStoreTransaction(), databaseId(), m_metadata.id);
361     }
362 }
363
364 void IDBObjectStoreBackendImpl::setIndexesReady(const Vector<int64_t>& indexIds, IDBTransactionBackendInterface* transactionInterface)
365 {
366     IDB_TRACE("IDBObjectStoreBackendImpl::setIndexesReady");
367
368     OwnPtr<Vector<int64_t> > newIndexIds = adoptPtr(new Vector<int64_t>(indexIds));
369     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionInterface);
370     if (transaction->isFinished())
371         return;
372
373     if (!transaction->scheduleTask(IDBTransactionBackendInterface::PreemptiveTask, ObjectStoreIndexesReadyOperation::create(this, newIndexIds.release(), transaction)))
374         ASSERT_NOT_REACHED();
375 }
376
377 void IDBObjectStoreBackendImpl::ObjectStoreIndexesReadyOperation::perform(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassOwnPtr<Vector<int64_t> > popIndexIds, PassRefPtr<IDBTransactionBackendImpl> transaction)
378 {
379     IDB_TRACE("ObjectStoreIndexesReadyOperation");
380     OwnPtr<Vector<int64_t> > indexIds = popIndexIds;
381     for (size_t i = 0; i < indexIds->size(); ++i)
382         transaction->didCompletePreemptiveEvent();
383 }
384
385 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)
386 {
387     IDB_TRACE("ObjectStoreStorageOperation");
388     RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
389     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
390     RefPtr<SerializedScriptValue> value = prpValue;
391     RefPtr<IDBKey> key = prpKey;
392     OwnPtr<Vector<int64_t> > indexIds = popIndexIds;
393     OwnPtr<Vector<IndexKeys> > indexKeys = popIndexKeys;
394     ASSERT(indexIds && indexKeys && indexIds->size() == indexKeys->size());
395     const bool autoIncrement = objectStore->autoIncrement();
396     bool keyWasGenerated = false;
397
398     if (putMode != CursorUpdate && autoIncrement && !key) {
399         RefPtr<IDBKey> autoIncKey = objectStore->generateKey(transaction);
400         keyWasGenerated = true;
401         if (!autoIncKey->isValid()) {
402             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Maximum key generator value reached."));
403             return;
404         }
405         key = autoIncKey;
406     }
407
408     ASSERT(key && key->isValid());
409
410     IDBBackingStore::RecordIdentifier recordIdentifier;
411     if (putMode == AddOnly) {
412         bool found = false;
413         bool ok = objectStore->backingStore()->keyExistsInObjectStore(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), *key, &recordIdentifier, found);
414         if (!ok) {
415             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error checking key existence."));
416             return;
417         }
418         if (found) {
419             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Key already exists in the object store."));
420             return;
421         }
422     }
423
424     Vector<OwnPtr<IndexWriter> > indexWriters;
425     String errorMessage;
426     if (!makeIndexWriters(transaction, objectStore.get(), key, keyWasGenerated, *indexIds, *indexKeys, &indexWriters, &errorMessage)) {
427         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, errorMessage));
428         return;
429     }
430
431     // Before this point, don't do any mutation.  After this point, rollback the transaction in case of error.
432
433     objectStore->backingStore()->putRecord(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), *key, value->toWireString(), &recordIdentifier);
434
435     for (size_t i = 0; i < indexWriters.size(); ++i) {
436         IndexWriter* indexWriter = indexWriters[i].get();
437         indexWriter->writeIndexKeys(recordIdentifier, *objectStore->backingStore(), transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->m_metadata.id);
438     }
439
440     if (autoIncrement && putMode != CursorUpdate && key->type() == IDBKey::NumberType) {
441         bool ok = objectStore->updateKeyGenerator(transaction, key.get(), !keyWasGenerated);
442         if (!ok) {
443             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error updating key generator."));
444             return;
445         }
446     }
447
448     callbacks->onSuccess(key.release());
449 }
450
451 void IDBObjectStoreBackendImpl::deleteFunction(PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
452 {
453     IDB_TRACE("IDBObjectStoreBackendImpl::delete");
454
455     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
456     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
457     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
458
459     if (!transaction->scheduleTask(ObjectStoreDeletionOperation::create(this, keyRange, callbacks, transaction)))
460         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::AbortError));
461 }
462
463 void IDBObjectStoreBackendImpl::ObjectStoreDeletionOperation::perform(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
464 {
465     IDB_TRACE("ObjectStoreDeletionOperation");
466
467     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), keyRange.get(), IDBCursor::NEXT);
468     if (backingStoreCursor) {
469
470         do {
471             objectStore->backingStore()->deleteRecord(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), backingStoreCursor->recordIdentifier());
472
473         } while (backingStoreCursor->continueFunction(0));
474     }
475
476     callbacks->onSuccess();
477 }
478
479 void IDBObjectStoreBackendImpl::clear(PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
480 {
481     IDB_TRACE("IDBObjectStoreBackendImpl::clear");
482
483     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
484     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
485     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
486
487     if (!transaction->scheduleTask(ObjectStoreClearOperation::create(this, callbacks, transaction)))
488         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::AbortError));
489 }
490
491 void IDBObjectStoreBackendImpl::ObjectStoreClearOperation::perform(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
492 {
493     IDB_TRACE("ObjectStoreClearOperation");
494     objectStore->backingStore()->clearObjectStore(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id());
495     callbacks->onSuccess();
496 }
497
498 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::createIndex(int64_t id, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
499 {
500     ASSERT_WITH_MESSAGE(!m_indexes.contains(id), "Indexes already contain %s", name.utf8().data());
501
502     RefPtr<IDBIndexBackendImpl> index = IDBIndexBackendImpl::create(m_database, this, IDBIndexMetadata(name, id, keyPath, unique, multiEntry));
503     ASSERT(index->name() == name);
504
505     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
506     ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
507     ASSERT(id > m_metadata.maxIndexId);
508     m_metadata.maxIndexId = id;
509
510     if (!transaction->scheduleTask(CreateIndexOperation::create(this, index, transaction), CreateIndexAbortOperation::create(this, index))) {
511         ec = IDBDatabaseException::TransactionInactiveError;
512         return 0;
513     }
514
515     m_indexes.set(id, index);
516     return index.release();
517 }
518
519 void IDBObjectStoreBackendImpl::CreateIndexOperation::perform(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendImpl> transaction)
520 {
521     IDB_TRACE("CreateIndexOperation");
522     if (!objectStore->backingStore()->createIndex(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), index->id(), index->name(), index->keyPath(), index->unique(), index->multiEntry())) {
523         transaction->abort();
524         return;
525     }
526 }
527
528 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::index(int64_t indexId)
529 {
530     RefPtr<IDBIndexBackendInterface> index = m_indexes.get(indexId);
531     ASSERT(index);
532     return index.release();
533 }
534
535 void IDBObjectStoreBackendImpl::deleteIndex(int64_t indexId, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
536 {
537     ASSERT(m_indexes.contains(indexId));
538
539     RefPtr<IDBIndexBackendImpl> index = m_indexes.get(indexId);
540     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
541     ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
542
543     if (!transaction->scheduleTask(DeleteIndexOperation::create(this, index, transaction), DeleteIndexAbortOperation::create(this, index))) {
544         ec = IDBDatabaseException::TransactionInactiveError;
545         return;
546     }
547     m_indexes.remove(indexId);
548 }
549
550 void IDBObjectStoreBackendImpl::DeleteIndexOperation::perform(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendImpl> transaction)
551 {
552     IDB_TRACE("DeleteIndexOperation");
553     objectStore->backingStore()->deleteIndex(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), index->id());
554 }
555
556 void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> range, IDBCursor::Direction direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface::TaskType taskType, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
557 {
558     IDB_TRACE("IDBObjectStoreBackendImpl::openCursor");
559     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
560     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
561     if (!transaction->scheduleTask(OpenObjectStoreCursorOperation::create(this, range, direction, callbacks, taskType, transaction))) {
562         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::AbortError));
563     }
564 }
565
566 void IDBObjectStoreBackendImpl::OpenObjectStoreCursorOperation::perform(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, IDBCursor::Direction direction, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface::TaskType taskType, PassRefPtr<IDBTransactionBackendImpl> transaction)
567 {
568     IDB_TRACE("OpenObjectStoreCursor");
569
570     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), range.get(), direction);
571     // The frontend has begun indexing, so this pauses the transaction
572     // until the indexing is complete. This can't happen any earlier
573     // because we don't want to switch to early mode in case multiple
574     // indexes are being created in a row, with put()'s in between.
575     if (taskType == IDBTransactionBackendInterface::PreemptiveTask)
576         transaction->addPreemptiveEvent();
577     if (!backingStoreCursor) {
578         callbacks->onSuccess(static_cast<SerializedScriptValue*>(0));
579         return;
580     }
581
582     RefPtr<IDBCursorBackendImpl> cursor = IDBCursorBackendImpl::create(backingStoreCursor.release(), IDBCursorBackendInterface::ObjectStoreCursor, taskType, transaction.get(), objectStore.get());
583     callbacks->onSuccess(cursor, cursor->key(), cursor->primaryKey(), cursor->value());
584 }
585
586 void IDBObjectStoreBackendImpl::count(PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
587 {
588     IDB_TRACE("IDBObjectStoreBackendImpl::count");
589     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
590     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
591     if (!transaction->scheduleTask(ObjectStoreCountOperation::create(this, range, callbacks, transaction)))
592         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::AbortError));
593 }
594
595 void IDBObjectStoreBackendImpl::ObjectStoreCountOperation::perform(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
596 {
597     IDB_TRACE("ObjectStoreCountOperation");
598     uint32_t count = 0;
599     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreKeyCursor(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), range.get(), IDBCursor::NEXT);
600     if (!backingStoreCursor) {
601         callbacks->onSuccess(count);
602         return;
603     }
604
605     do {
606         ++count;
607     } while (backingStoreCursor->continueFunction(0));
608
609     callbacks->onSuccess(count);
610 }
611
612 void IDBObjectStoreBackendImpl::loadIndexes()
613 {
614     Vector<IDBIndexMetadata> indexes = backingStore()->getIndexes(databaseId(), m_metadata.id);
615
616     for (size_t i = 0; i < indexes.size(); ++i)
617         m_indexes.set(indexes[i].id, IDBIndexBackendImpl::create(m_database, this, indexes[i]));
618 }
619
620 void IDBObjectStoreBackendImpl::CreateIndexAbortOperation::perform(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
621 {
622     ASSERT(objectStore->m_indexes.contains(index->id()));
623     objectStore->m_indexes.remove(index->id());
624 }
625
626 void IDBObjectStoreBackendImpl::DeleteIndexAbortOperation::perform(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> prpIndex)
627 {
628     RefPtr<IDBIndexBackendImpl> index = prpIndex;
629     ASSERT(!objectStore->m_indexes.contains(index->id()));
630     objectStore->m_indexes.set(index->id(), index);
631 }
632
633 PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::generateKey(PassRefPtr<IDBTransactionBackendImpl> transaction)
634 {
635     const int64_t maxGeneratorValue = 9007199254740992LL; // Maximum integer storable as ECMAScript number.
636     int64_t currentNumber;
637     bool ok = backingStore()->getKeyGeneratorCurrentNumber(transaction->backingStoreTransaction(), databaseId(), id(), currentNumber);
638     if (!ok) {
639         LOG_ERROR("Failed to getKeyGeneratorCurrentNumber");
640         return IDBKey::createInvalid();
641     }
642     if (currentNumber < 0 || currentNumber > maxGeneratorValue)
643         return IDBKey::createInvalid();
644
645     return IDBKey::createNumber(currentNumber);
646 }
647
648 bool IDBObjectStoreBackendImpl::updateKeyGenerator(PassRefPtr<IDBTransactionBackendImpl> transaction, const IDBKey* key, bool checkCurrent)
649 {
650     ASSERT(key && key->type() == IDBKey::NumberType);
651     return backingStore()->maybeUpdateKeyGeneratorCurrentNumber(transaction->backingStoreTransaction(), databaseId(), id(), static_cast<int64_t>(floor(key->number())) + 1, checkCurrent);
652 }
653
654 } // namespace WebCore
655
656 #endif