794d65021b155c630b894bad293f9e49428388c6
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / IDBObjectStoreBackendImpl.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "IDBObjectStoreBackendImpl.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "CrossThreadTask.h"
32 #include "DOMStringList.h"
33 #include "IDBBackingStore.h"
34 #include "IDBBindingUtilities.h"
35 #include "IDBCallbacks.h"
36 #include "IDBCursorBackendImpl.h"
37 #include "IDBDatabaseBackendImpl.h"
38 #include "IDBDatabaseException.h"
39 #include "IDBIndexBackendImpl.h"
40 #include "IDBKey.h"
41 #include "IDBKeyPath.h"
42 #include "IDBKeyPathBackendImpl.h"
43 #include "IDBKeyRange.h"
44 #include "IDBTracing.h"
45 #include "IDBTransactionBackendInterface.h"
46 #include "ScriptExecutionContext.h"
47
48 namespace WebCore {
49
50 IDBObjectStoreBackendImpl::~IDBObjectStoreBackendImpl()
51 {
52 }
53
54 IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBBackingStore* backingStore, int64_t databaseId, int64_t id, const String& name, const String& keyPath, bool autoIncrement)
55     : m_backingStore(backingStore)
56     , m_databaseId(databaseId)
57     , m_id(id)
58     , m_name(name)
59     , m_keyPath(keyPath)
60     , m_autoIncrement(autoIncrement)
61     , m_autoIncrementNumber(-1)
62 {
63     loadIndexes();
64 }
65
66 IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBBackingStore* backingStore, int64_t databaseId, const String& name, const String& keyPath, bool autoIncrement)
67     : m_backingStore(backingStore)
68     , m_databaseId(databaseId)
69     , m_id(InvalidId)
70     , m_name(name)
71     , m_keyPath(keyPath)
72     , m_autoIncrement(autoIncrement)
73     , m_autoIncrementNumber(-1)
74 {
75 }
76
77 PassRefPtr<DOMStringList> IDBObjectStoreBackendImpl::indexNames() const
78 {
79     RefPtr<DOMStringList> indexNames = DOMStringList::create();
80     for (IndexMap::const_iterator it = m_indexes.begin(); it != m_indexes.end(); ++it)
81         indexNames->append(it->first);
82     indexNames->sort();
83     return indexNames.release();
84 }
85
86 // FIXME: This can be removed once all ports have been updated to call
87 // the IDBKeyRange version. https://bugs.webkit.org/show_bug.cgi?id=84285
88 void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
89 {
90     IDB_TRACE("IDBObjectStoreBackendImpl::get");
91     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
92     RefPtr<IDBKey> key = prpKey;
93     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
94     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::getInternal, objectStore, key, callbacks)))
95         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
96 }
97
98 void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
99 {
100     IDB_TRACE("IDBObjectStoreBackendImpl::get");
101     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
102     RefPtr<IDBKeyRange> keyRange = prpKeyRange;
103     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
104     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::getByRangeInternal, objectStore, keyRange, callbacks)))
105         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
106 }
107
108 void IDBObjectStoreBackendImpl::getByRangeInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
109 {
110     IDB_TRACE("IDBObjectStoreBackendImpl::getByRangeInternal");
111     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), keyRange.get(), IDBCursor::NEXT);
112     if (!backingStoreCursor) {
113         callbacks->onSuccess(SerializedScriptValue::undefinedValue());
114         return;
115     }
116
117     String wireData = objectStore->backingStore()->getObjectStoreRecord(objectStore->databaseId(), objectStore->id(), *backingStoreCursor->key());
118     if (wireData.isNull()) {
119         callbacks->onSuccess(SerializedScriptValue::undefinedValue());
120         backingStoreCursor->close();
121         return;
122     }
123
124     callbacks->onSuccess(SerializedScriptValue::createFromWire(wireData));
125     backingStoreCursor->close();
126 }
127
128 void IDBObjectStoreBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
129 {
130     IDB_TRACE("IDBObjectStoreBackendImpl::getInternal");
131     String wireData = objectStore->backingStore()->getObjectStoreRecord(objectStore->databaseId(), objectStore->id(), *key);
132     if (wireData.isNull()) {
133         callbacks->onSuccess(SerializedScriptValue::undefinedValue());
134         return;
135     }
136
137     callbacks->onSuccess(SerializedScriptValue::createFromWire(wireData));
138 }
139
140 static PassRefPtr<IDBKey> fetchKeyFromKeyPath(SerializedScriptValue* value, const String& keyPath)
141 {
142     IDB_TRACE("IDBObjectStoreBackendImpl::fetchKeyFromKeyPath");
143     Vector<RefPtr<SerializedScriptValue> > values;
144     values.append(value);
145     Vector<RefPtr<IDBKey> > keys;
146     IDBKeyPathBackendImpl::createIDBKeysFromSerializedValuesAndKeyPath(values, keyPath, keys);
147     if (keys.isEmpty())
148         return 0;
149     ASSERT(keys.size() == 1);
150     return keys[0].release();
151 }
152
153 static PassRefPtr<SerializedScriptValue> injectKeyIntoKeyPath(PassRefPtr<IDBKey> key, PassRefPtr<SerializedScriptValue> value, const String& keyPath)
154 {
155     IDB_TRACE("IDBObjectStoreBackendImpl::injectKeyIntoKeyPath");
156     return IDBKeyPathBackendImpl::injectIDBKeyIntoSerializedValue(key, value, keyPath);
157 }
158
159 void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
160 {
161     IDB_TRACE("IDBObjectStoreBackendImpl::put");
162     if (transactionPtr->mode() == IDBTransaction::READ_ONLY) {
163         ec = IDBDatabaseException::READ_ONLY_ERR;
164         return;
165     }
166
167     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
168     RefPtr<SerializedScriptValue> value = prpValue;
169     RefPtr<IDBKey> key = prpKey;
170     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
171     RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
172
173     if (putMode != CursorUpdate) {
174         const bool autoIncrement = objectStore->autoIncrement();
175         const bool hasKeyPath = !objectStore->m_keyPath.isNull();
176
177         if (hasKeyPath && key) {
178             ec = IDBDatabaseException::DATA_ERR;
179             return;
180         }
181         if (!hasKeyPath && !autoIncrement && !key) {
182             ec = IDBDatabaseException::DATA_ERR;
183             return;
184         }
185         if (hasKeyPath) {
186             RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
187             if (keyPathKey && !keyPathKey->isValid()) {
188                 ec = IDBDatabaseException::DATA_ERR;
189                 return;
190             }
191             if (!autoIncrement && !keyPathKey) {
192                 ec = IDBDatabaseException::DATA_ERR;
193                 return;
194             }
195             if (autoIncrement && !keyPathKey) {
196                 RefPtr<IDBKey> dummyKey = IDBKey::createNumber(-1);
197                 RefPtr<SerializedScriptValue> valueAfterInjection = injectKeyIntoKeyPath(dummyKey, value, objectStore->m_keyPath);
198                 if (!valueAfterInjection) {
199                     ec = IDBDatabaseException::DATA_ERR;
200                     return;
201                 }
202             }
203         }
204         if (key && !key->isValid()) {
205             ec = IDBDatabaseException::DATA_ERR;
206             return;
207         }
208         for (IndexMap::iterator it = m_indexes.begin(); it != m_indexes.end(); ++it) {
209             const RefPtr<IDBIndexBackendImpl>& index = it->second;
210             RefPtr<IDBKey> indexKey = fetchKeyFromKeyPath(value.get(), index->keyPath());
211             if (indexKey && !indexKey->isValid()) {
212                 ec = IDBDatabaseException::DATA_ERR;
213                 return;
214             }
215         }
216     } else {
217         ASSERT(key);
218         const bool hasKeyPath = !objectStore->m_keyPath.isNull();
219         if (hasKeyPath) {
220             RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
221             if (!keyPathKey || !keyPathKey->isEqual(key.get())) {
222                 ec = IDBDatabaseException::DATA_ERR;
223                 return;
224             }
225         }
226     }
227
228     if (!transaction->scheduleTask(
229             createCallbackTask(&IDBObjectStoreBackendImpl::putInternal, objectStore, value, key, putMode, callbacks, transaction),
230             // FIXME: One of these per put() is overkill, since it's simply a cache invalidation.
231             createCallbackTask(&IDBObjectStoreBackendImpl::revertAutoIncrementKeyCache, objectStore)))
232         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
233 }
234
235 void IDBObjectStoreBackendImpl::revertAutoIncrementKeyCache(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
236 {
237     objectStore->resetAutoIncrementKeyCache();
238 }
239
240 void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
241 {
242     IDB_TRACE("IDBObjectStoreBackendImpl::putInternal");
243     RefPtr<SerializedScriptValue> value = prpValue;
244     RefPtr<IDBKey> key = prpKey;
245
246     if (putMode != CursorUpdate) {
247         const bool autoIncrement = objectStore->autoIncrement();
248         const bool hasKeyPath = !objectStore->m_keyPath.isNull();
249         if (hasKeyPath) {
250             ASSERT(!key);
251             RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
252             if (keyPathKey)
253                 key = keyPathKey;
254         }
255         if (autoIncrement) {
256             if (!key) {
257                 RefPtr<IDBKey> autoIncKey = objectStore->genAutoIncrementKey();
258                 if (!autoIncKey->isValid()) {
259                     callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "Maximum key generator value reached."));
260                     return;
261                 }
262                 if (hasKeyPath) {
263                     RefPtr<SerializedScriptValue> valueAfterInjection = injectKeyIntoKeyPath(autoIncKey, value, objectStore->m_keyPath);
264                     ASSERT(valueAfterInjection);
265                     if (!valueAfterInjection) {
266                         objectStore->resetAutoIncrementKeyCache();
267                         // Checks in put() ensure this should only happen if I/O error occurs.
268                         // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
269                         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error inserting generated key into the object."));
270                         return;
271                     }
272                     value = valueAfterInjection;
273                 }
274                 key = autoIncKey;
275             } else {
276                 // FIXME: Logic to update generator state should go here. Currently it does a scan.
277                 objectStore->resetAutoIncrementKeyCache();
278             }
279         }
280     }
281
282     ASSERT(key && key->isValid());
283
284     RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = objectStore->backingStore()->createInvalidRecordIdentifier();
285     if (putMode == AddOnly && objectStore->backingStore()->keyExistsInObjectStore(objectStore->databaseId(), objectStore->id(), *key, recordIdentifier.get())) {
286         objectStore->resetAutoIncrementKeyCache();
287         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
288         return;
289     }
290
291     Vector<RefPtr<IDBKey> > indexKeys;
292     for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
293         const RefPtr<IDBIndexBackendImpl>& index = it->second;
294
295         RefPtr<IDBKey> indexKey = fetchKeyFromKeyPath(value.get(), index->keyPath());
296         if (!indexKey) {
297             indexKeys.append(indexKey.release());
298             continue;
299         }
300         ASSERT(indexKey->isValid());
301
302         if ((!index->multiEntry() || indexKey->type() != IDBKey::ArrayType) && !index->addingKeyAllowed(indexKey.get(), key.get())) {
303             objectStore->resetAutoIncrementKeyCache();
304             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "One of the derived (from a keyPath) keys for an index does not satisfy its uniqueness requirements."));
305             return;
306         }
307
308         if (index->multiEntry() && indexKey->type() == IDBKey::ArrayType) {
309            for (size_t j = 0; j < indexKey->array().size(); ++j) {
310                 if (!index->addingKeyAllowed(indexKey->array()[j].get(), key.get())) {
311                     objectStore->resetAutoIncrementKeyCache();
312                     callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "One of the derived (from a keyPath) keys for an index does not satisfy its uniqueness requirements."));
313                     return;
314                 }
315             }
316         }
317
318         indexKeys.append(indexKey.release());
319     }
320
321     // Before this point, don't do any mutation.  After this point, rollback the transaction in case of error.
322
323     if (!objectStore->backingStore()->putObjectStoreRecord(objectStore->databaseId(), objectStore->id(), *key, value->toWireString(), recordIdentifier.get())) {
324         // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
325         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
326         transaction->abort();
327         return;
328     }
329
330     int i = 0;
331     for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it, ++i) {
332         RefPtr<IDBIndexBackendImpl>& index = it->second;
333         if (!index->hasValidId())
334             continue; // The index object has been created, but does not exist in the database yet.
335
336         if (!objectStore->backingStore()->deleteIndexDataForRecord(objectStore->databaseId(), objectStore->id(), index->id(), recordIdentifier.get())) {
337             // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
338             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
339             transaction->abort();
340             return;
341         }
342
343         if (!indexKeys[i])
344             continue;
345         RefPtr<IDBKey> indexKey = indexKeys[i];
346
347         if (!index->multiEntry() || indexKey->type() != IDBKey::ArrayType) {
348             if (!objectStore->backingStore()->putIndexDataForRecord(objectStore->databaseId(), objectStore->id(), index->id(), *indexKey, recordIdentifier.get())) {
349                 // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
350                 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
351                 transaction->abort();
352                 return;
353             }
354         } else {
355             ASSERT(index->multiEntry());
356             ASSERT(indexKey->type() == IDBKey::ArrayType);
357             for (size_t j = 0; j < indexKey->array().size(); ++j) {
358                 if (!objectStore->backingStore()->putIndexDataForRecord(objectStore->databaseId(), objectStore->id(), index->id(), *indexKey->array()[j], recordIdentifier.get())) {
359                     // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
360                     callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
361                     transaction->abort();
362                     return;
363                 }
364             }
365         }
366     }
367
368     callbacks->onSuccess(key.get());
369 }
370
371 void IDBObjectStoreBackendImpl::deleteFunction(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
372 {
373     IDB_TRACE("IDBObjectStoreBackendImpl::delete");
374     RefPtr<IDBKey> key = prpKey;
375     if (!key || !key->isValid()) {
376         ec = IDBDatabaseException::DATA_ERR;
377         return;
378     }
379
380     RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(key, ec);
381     if (ec)
382         return;
383
384     deleteFunction(keyRange.release(), prpCallbacks, transaction, ec);
385 }
386
387 void IDBObjectStoreBackendImpl::deleteFunction(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
388 {
389     IDB_TRACE("IDBObjectStoreBackendImpl::delete");
390     if (transaction->mode() == IDBTransaction::READ_ONLY) {
391         ec = IDBDatabaseException::READ_ONLY_ERR;
392         return;
393     }
394
395     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
396     RefPtr<IDBKeyRange> keyRange = prpKeyRange;
397     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
398
399     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::deleteInternal, objectStore, keyRange, callbacks)))
400         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
401 }
402
403 void IDBObjectStoreBackendImpl::deleteInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
404 {
405     IDB_TRACE("IDBObjectStoreBackendImpl::deleteInternal");
406     RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier;
407
408     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), keyRange.get(), IDBCursor::NEXT);
409     if (backingStoreCursor) {
410
411         do {
412             recordIdentifier = backingStoreCursor->objectStoreRecordIdentifier();
413
414             for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
415                 if (!it->second->hasValidId())
416                     continue; // The index object has been created, but does not exist in the database yet.
417
418                 bool success = objectStore->backingStore()->deleteIndexDataForRecord(objectStore->databaseId(), objectStore->id(), it->second->id(), recordIdentifier.get());
419                 ASSERT_UNUSED(success, success);
420             }
421
422             objectStore->backingStore()->deleteObjectStoreRecord(objectStore->databaseId(), objectStore->id(), recordIdentifier.get());
423
424         } while (backingStoreCursor->continueFunction(0));
425
426         backingStoreCursor->close();
427     }
428
429     callbacks->onSuccess(SerializedScriptValue::undefinedValue());
430 }
431
432 void IDBObjectStoreBackendImpl::clear(PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
433 {
434     IDB_TRACE("IDBObjectStoreBackendImpl::clear");
435     if (transaction->mode() == IDBTransaction::READ_ONLY) {
436         ec = IDBDatabaseException::READ_ONLY_ERR;
437         return;
438     }
439
440     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
441     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
442
443     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::clearInternal, objectStore, callbacks)))
444         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
445 }
446
447 void IDBObjectStoreBackendImpl::clearInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBCallbacks> callbacks)
448 {
449     objectStore->backingStore()->clearObjectStore(objectStore->databaseId(), objectStore->id());
450     callbacks->onSuccess(SerializedScriptValue::undefinedValue());
451 }
452
453 namespace {
454 class PopulateIndexCallback : public IDBBackingStore::ObjectStoreRecordCallback {
455 public:
456     PopulateIndexCallback(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBIndexBackendImpl> index)
457         : m_backingStore(backingStore)
458         , m_databaseId(databaseId)
459         , m_objectStoreId(objectStoreId)
460         , m_index(index)
461     {
462     }
463
464     virtual bool callback(const IDBBackingStore::ObjectStoreRecordIdentifier* recordIdentifier, const String& value)
465     {
466         RefPtr<SerializedScriptValue> objectValue = SerializedScriptValue::createFromWire(value);
467         RefPtr<IDBKey> indexKey = fetchKeyFromKeyPath(objectValue.get(), m_index->keyPath());
468
469         if (!indexKey)
470             return true;
471
472         if (!m_index->multiEntry() || indexKey->type() != IDBKey::ArrayType) {
473             if (!m_index->addingKeyAllowed(indexKey.get()))
474                 return false;
475             if (!m_backingStore.putIndexDataForRecord(m_databaseId, m_objectStoreId, m_index->id(), *indexKey, recordIdentifier))
476                 return false;
477         } else {
478             ASSERT(m_index->multiEntry());
479             ASSERT(indexKey->type() == IDBKey::ArrayType);
480             for (size_t i = 0; i < indexKey->array().size(); ++i) {
481                 if (!m_index->addingKeyAllowed(indexKey.get()))
482                     return false;
483                 if (!m_backingStore.putIndexDataForRecord(m_databaseId, m_objectStoreId, m_index->id(), *indexKey->array()[i], recordIdentifier))
484                     return false;
485             }
486         }
487         return true;
488     }
489
490 private:
491     IDBBackingStore& m_backingStore;
492     int64_t m_databaseId;
493     int64_t m_objectStoreId;
494     RefPtr<IDBIndexBackendImpl> m_index;
495 };
496 }
497
498 bool IDBObjectStoreBackendImpl::populateIndex(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBIndexBackendImpl> index)
499 {
500     PopulateIndexCallback callback(backingStore, databaseId, objectStoreId, index);
501     if (!backingStore.forEachObjectStoreRecord(databaseId, objectStoreId, callback))
502         return false;
503     return true;
504 }
505
506 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::createIndex(const String& name, const String& keyPath, bool unique, bool multiEntry, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
507 {
508     if (name.isNull()) {
509         ec = IDBDatabaseException::NON_TRANSIENT_ERR;
510         return 0;
511     }
512     if (m_indexes.contains(name)) {
513         ec = IDBDatabaseException::CONSTRAINT_ERR;
514         return 0;
515     }
516     if (transaction->mode() != IDBTransaction::VERSION_CHANGE) {
517         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
518         return 0;
519     }
520
521     RefPtr<IDBIndexBackendImpl> index = IDBIndexBackendImpl::create(backingStore().get(), databaseId(), this, name, keyPath, unique, multiEntry);
522     ASSERT(index->name() == name);
523
524     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
525     RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
526     if (!transaction->scheduleTask(
527               createCallbackTask(&IDBObjectStoreBackendImpl::createIndexInternal,
528                                  objectStore, index, transactionPtr),
529               createCallbackTask(&IDBObjectStoreBackendImpl::removeIndexFromMap,
530                                  objectStore, index))) {
531         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
532         return 0;
533     }
534
535     m_indexes.set(name, index);
536     return index.release();
537 }
538
539 void IDBObjectStoreBackendImpl::createIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
540 {
541     int64_t id;
542     if (!objectStore->backingStore()->createIndex(objectStore->databaseId(), objectStore->id(), index->name(), index->keyPath(), index->unique(), index->multiEntry(), id)) {
543         transaction->abort();
544         return;
545     }
546
547     index->setId(id);
548
549     if (!populateIndex(*objectStore->backingStore(), objectStore->databaseId(), objectStore->m_id, index)) {
550         transaction->abort();
551         return;
552     }
553
554     transaction->didCompleteTaskEvents();
555 }
556
557 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::index(const String& name, ExceptionCode& ec)
558 {
559     RefPtr<IDBIndexBackendInterface> index = m_indexes.get(name);
560     if (!index) {
561         ec = IDBDatabaseException::NOT_FOUND_ERR;
562         return 0;
563     }
564     return index.release();
565 }
566
567 void IDBObjectStoreBackendImpl::deleteIndex(const String& name, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
568 {
569     if (transaction->mode() != IDBTransaction::VERSION_CHANGE) {
570         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
571         return;
572     }
573
574     RefPtr<IDBIndexBackendImpl> index = m_indexes.get(name);
575     if (!index) {
576         ec = IDBDatabaseException::NOT_FOUND_ERR;
577         return;
578     }
579
580     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
581     RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
582     if (!transaction->scheduleTask(
583               createCallbackTask(&IDBObjectStoreBackendImpl::deleteIndexInternal,
584                                  objectStore, index, transactionPtr),
585               createCallbackTask(&IDBObjectStoreBackendImpl::addIndexToMap,
586                                  objectStore, index))) {
587         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
588         return;
589     }
590     m_indexes.remove(name);
591 }
592
593 void IDBObjectStoreBackendImpl::deleteIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
594 {
595     objectStore->backingStore()->deleteIndex(objectStore->databaseId(), objectStore->id(), index->id());
596     transaction->didCompleteTaskEvents();
597 }
598
599 void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
600 {
601     IDB_TRACE("IDBObjectStoreBackendImpl::openCursor");
602     RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
603     RefPtr<IDBKeyRange> range = prpRange;
604     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
605     RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
606     if (!transaction->scheduleTask(
607             createCallbackTask(&IDBObjectStoreBackendImpl::openCursorInternal,
608                                objectStore, range, direction, callbacks, transactionPtr))) {
609         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
610     }
611 }
612
613 void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
614 {
615     IDB_TRACE("IDBObjectStoreBackendImpl::openCursorInternal");
616     IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(tmpDirection);
617
618     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), range.get(), direction);
619     if (!backingStoreCursor) {
620         callbacks->onSuccess(SerializedScriptValue::nullValue());
621         return;
622     }
623
624     RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(backingStoreCursor.release(), direction, IDBCursorBackendInterface::ObjectStoreCursor, transaction.get(), objectStore.get());
625     callbacks->onSuccess(cursor.release());
626 }
627
628 void IDBObjectStoreBackendImpl::count(PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
629 {
630     IDB_TRACE("IDBObjectStoreBackendImpl::count");
631     if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::countInternal, this, range, callbacks, transaction)))
632         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
633 }
634
635 void IDBObjectStoreBackendImpl::countInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface>)
636 {
637     IDB_TRACE("IDBObjectStoreBackendImpl::countInternal");
638     uint32_t count = 0;
639     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), range.get(), IDBCursor::NEXT);
640     if (!backingStoreCursor) {
641         callbacks->onSuccess(SerializedScriptValue::numberValue(count));
642         return;
643     }
644
645     do {
646         ++count;
647     } while (backingStoreCursor->continueFunction(0));
648
649     backingStoreCursor->close();
650     callbacks->onSuccess(SerializedScriptValue::numberValue(count));
651 }
652
653 void IDBObjectStoreBackendImpl::loadIndexes()
654 {
655     Vector<int64_t> ids;
656     Vector<String> names;
657     Vector<String> keyPaths;
658     Vector<bool> uniqueFlags;
659     Vector<bool> multiEntryFlags;
660     backingStore()->getIndexes(databaseId(), m_id, ids, names, keyPaths, uniqueFlags, multiEntryFlags);
661
662     ASSERT(names.size() == ids.size());
663     ASSERT(keyPaths.size() == ids.size());
664     ASSERT(uniqueFlags.size() == ids.size());
665     ASSERT(multiEntryFlags.size() == ids.size());
666
667     for (size_t i = 0; i < ids.size(); i++)
668         m_indexes.set(names[i], IDBIndexBackendImpl::create(backingStore().get(), databaseId(), this, ids[i], names[i], keyPaths[i], uniqueFlags[i], multiEntryFlags[i]));
669 }
670
671 void IDBObjectStoreBackendImpl::removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
672 {
673     ASSERT(objectStore->m_indexes.contains(index->name()));
674     objectStore->m_indexes.remove(index->name());
675 }
676
677 void IDBObjectStoreBackendImpl::addIndexToMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
678 {
679     RefPtr<IDBIndexBackendImpl> indexPtr = index;
680     ASSERT(!objectStore->m_indexes.contains(indexPtr->name()));
681     objectStore->m_indexes.set(indexPtr->name(), indexPtr);
682 }
683
684 PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::genAutoIncrementKey()
685 {
686     const int64_t kMaxGeneratorValue = 9007199254740992LL; // Maximum integer storable as ECMAScript number.
687     if (m_autoIncrementNumber > kMaxGeneratorValue)
688         return IDBKey::createInvalid();
689     if (m_autoIncrementNumber > 0)
690         return IDBKey::createNumber(m_autoIncrementNumber++);
691
692     m_autoIncrementNumber = backingStore()->nextAutoIncrementNumber(databaseId(), id());
693     if (m_autoIncrementNumber > kMaxGeneratorValue)
694         return IDBKey::createInvalid();
695     return IDBKey::createNumber(m_autoIncrementNumber++);
696 }
697
698
699 } // namespace WebCore
700
701 #endif