2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "IDBObjectStoreBackendImpl.h"
29 #if ENABLE(INDEXED_DATABASE)
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"
41 #include "IDBKeyPath.h"
42 #include "IDBKeyPathBackendImpl.h"
43 #include "IDBKeyRange.h"
44 #include "IDBTracing.h"
45 #include "IDBTransactionBackendInterface.h"
46 #include "ScriptExecutionContext.h"
50 IDBObjectStoreBackendImpl::~IDBObjectStoreBackendImpl()
54 IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(const IDBDatabaseBackendImpl* database, int64_t id, const String& name, const IDBKeyPath& keyPath, bool autoIncrement)
55 : m_database(database)
59 , m_autoIncrement(autoIncrement)
60 , m_autoIncrementNumber(-1)
65 IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(const IDBDatabaseBackendImpl* database, const String& name, const IDBKeyPath& keyPath, bool autoIncrement)
66 : m_database(database)
70 , m_autoIncrement(autoIncrement)
71 , m_autoIncrementNumber(-1)
75 IDBObjectStoreMetadata IDBObjectStoreBackendImpl::metadata() const
77 IDBObjectStoreMetadata metadata(m_name, m_keyPath, m_autoIncrement);
78 for (IndexMap::const_iterator it = m_indexes.begin(); it != m_indexes.end(); ++it)
79 metadata.indexes.set(it->first, it->second->metadata());
83 void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
85 IDB_TRACE("IDBObjectStoreBackendImpl::get");
86 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
87 RefPtr<IDBKeyRange> keyRange = prpKeyRange;
88 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
89 if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::getInternal, objectStore, keyRange, callbacks)))
90 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
93 void IDBObjectStoreBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
95 IDB_TRACE("IDBObjectStoreBackendImpl::getByRangeInternal");
97 if (keyRange->isOnlyKey())
98 key = keyRange->lower();
100 RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), keyRange.get(), IDBCursor::NEXT);
101 if (!backingStoreCursor) {
102 callbacks->onSuccess(SerializedScriptValue::undefinedValue());
105 key = backingStoreCursor->key();
106 backingStoreCursor->close();
109 String wireData = objectStore->backingStore()->getObjectStoreRecord(objectStore->databaseId(), objectStore->id(), *key);
110 if (wireData.isNull()) {
111 callbacks->onSuccess(SerializedScriptValue::undefinedValue());
115 callbacks->onSuccess(SerializedScriptValue::createFromWire(wireData));
118 static PassRefPtr<IDBKey> fetchKeyFromKeyPath(SerializedScriptValue* value, const IDBKeyPath& keyPath)
120 IDB_TRACE("IDBObjectStoreBackendImpl::fetchKeyFromKeyPath");
121 ASSERT(!keyPath.isNull());
123 Vector<RefPtr<SerializedScriptValue> > values;
124 values.append(value);
125 Vector<RefPtr<IDBKey> > keys;
126 IDBKeyPathBackendImpl::createIDBKeysFromSerializedValuesAndKeyPath(values, keyPath, keys);
129 ASSERT(keys.size() == 1);
130 return keys[0].release();
133 static PassRefPtr<SerializedScriptValue> injectKeyIntoKeyPath(PassRefPtr<IDBKey> key, PassRefPtr<SerializedScriptValue> value, const IDBKeyPath& keyPath)
135 IDB_TRACE("IDBObjectStoreBackendImpl::injectKeyIntoKeyPath");
136 return IDBKeyPathBackendImpl::injectIDBKeyIntoSerializedValue(key, value, keyPath);
139 void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
141 IDB_TRACE("IDBObjectStoreBackendImpl::put");
143 ASSERT(transactionPtr->mode() != IDBTransaction::READ_ONLY);
145 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
146 RefPtr<SerializedScriptValue> value = prpValue;
147 RefPtr<IDBKey> key = prpKey;
148 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
149 RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
151 if (putMode != CursorUpdate) {
152 const bool autoIncrement = objectStore->autoIncrement();
153 const bool hasKeyPath = !objectStore->m_keyPath.isNull();
155 if (hasKeyPath && key) {
156 ec = IDBDatabaseException::DATA_ERR;
159 if (!hasKeyPath && !autoIncrement && !key) {
160 ec = IDBDatabaseException::DATA_ERR;
164 RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
165 if (keyPathKey && !keyPathKey->isValid()) {
166 ec = IDBDatabaseException::DATA_ERR;
169 if (!autoIncrement && !keyPathKey) {
170 ec = IDBDatabaseException::DATA_ERR;
173 if (autoIncrement && !keyPathKey) {
174 RefPtr<IDBKey> dummyKey = IDBKey::createNumber(-1);
175 RefPtr<SerializedScriptValue> valueAfterInjection = injectKeyIntoKeyPath(dummyKey, value, objectStore->m_keyPath);
176 if (!valueAfterInjection) {
177 ec = IDBDatabaseException::DATA_ERR;
182 if (key && !key->isValid()) {
183 ec = IDBDatabaseException::DATA_ERR;
188 const bool hasKeyPath = !objectStore->m_keyPath.isNull();
190 RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
191 if (!keyPathKey || !keyPathKey->isEqual(key.get())) {
192 ec = IDBDatabaseException::DATA_ERR;
198 if (!transaction->scheduleTask(
199 createCallbackTask(&IDBObjectStoreBackendImpl::putInternal, objectStore, value, key, putMode, callbacks, transaction),
200 // FIXME: One of these per put() is overkill, since it's simply a cache invalidation.
201 createCallbackTask(&IDBObjectStoreBackendImpl::revertAutoIncrementKeyCache, objectStore)))
202 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
205 void IDBObjectStoreBackendImpl::revertAutoIncrementKeyCache(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
207 objectStore->resetAutoIncrementKeyCache();
213 explicit IndexWriter(PassRefPtr<IDBIndexBackendImpl> index)
218 bool loadIndexKeysForValue(SerializedScriptValue* objectValue, const IDBKey* primaryKey = 0, String* errorMessage = 0)
222 RefPtr<IDBKey> indexKey = fetchKeyFromKeyPath(objectValue, m_index->keyPath());
227 if (!m_index->multiEntry() || indexKey->type() != IDBKey::ArrayType) {
228 if (!indexKey->isValid())
231 if (!m_index->addingKeyAllowed(indexKey.get(), primaryKey)) {
233 *errorMessage = String::format("Unable to add key to index '%s': the key does not satisfy its uniqueness requirements.",
234 m_index->name().utf8().data());
237 m_indexKeys.append(indexKey);
239 ASSERT(m_index->multiEntry());
240 ASSERT(indexKey->type() == IDBKey::ArrayType);
241 indexKey = IDBKey::createMultiEntryArray(indexKey->array());
243 for (size_t i = 0; i < indexKey->array().size(); ++i) {
244 if (!m_index->addingKeyAllowed(indexKey->array()[i].get(), primaryKey)) {
246 *errorMessage = String::format("Unable to add key to index '%s': at least one key does not satisfy the uniqueness requirements.",
247 m_index->name().utf8().data());
250 m_indexKeys.append(indexKey->array()[i]);
256 bool writeIndexKeys(const IDBBackingStore::ObjectStoreRecordIdentifier* recordIdentifier, IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, String* errorMessage = 0)
258 for (size_t i = 0; i < m_indexKeys.size(); ++i) {
259 if (!backingStore.deleteIndexDataForRecord(databaseId, objectStoreId, m_index->id(), recordIdentifier))
261 if (!backingStore.putIndexDataForRecord(databaseId, objectStoreId, m_index->id(), *m_indexKeys[i].get(), recordIdentifier))
268 RefPtr<IDBIndexBackendImpl> m_index;
269 Vector<RefPtr<IDBKey> > m_indexKeys;
273 void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
275 IDB_TRACE("IDBObjectStoreBackendImpl::putInternal");
276 ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
277 RefPtr<SerializedScriptValue> value = prpValue;
278 RefPtr<IDBKey> key = prpKey;
280 if (putMode != CursorUpdate) {
281 const bool autoIncrement = objectStore->autoIncrement();
282 const bool hasKeyPath = !objectStore->m_keyPath.isNull();
285 RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
291 RefPtr<IDBKey> autoIncKey = objectStore->genAutoIncrementKey();
292 if (!autoIncKey->isValid()) {
293 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "Maximum key generator value reached."));
297 RefPtr<SerializedScriptValue> valueAfterInjection = injectKeyIntoKeyPath(autoIncKey, value, objectStore->m_keyPath);
298 ASSERT(valueAfterInjection);
299 if (!valueAfterInjection) {
300 objectStore->resetAutoIncrementKeyCache();
301 // Checks in put() ensure this should only happen if I/O error occurs.
302 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error inserting generated key into the object."));
305 value = valueAfterInjection;
309 // FIXME: Logic to update generator state should go here. Currently it does a scan.
310 objectStore->resetAutoIncrementKeyCache();
315 ASSERT(key && key->isValid());
317 RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = objectStore->backingStore()->createInvalidRecordIdentifier();
318 if (putMode == AddOnly && objectStore->backingStore()->keyExistsInObjectStore(objectStore->databaseId(), objectStore->id(), *key, recordIdentifier.get())) {
319 objectStore->resetAutoIncrementKeyCache();
320 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
324 Vector<OwnPtr<IndexWriter> > indexWriters;
325 for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
327 const RefPtr<IDBIndexBackendImpl>& index = it->second;
328 if (!index->hasValidId())
329 continue; // The index object has been created, but does not exist in the database yet.
331 OwnPtr<IndexWriter> indexWriter(adoptPtr(new IndexWriter(index)));
333 if (!indexWriter->loadIndexKeysForValue(value.get(), key.get(), &errorMessage)) {
334 objectStore->resetAutoIncrementKeyCache();
335 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, errorMessage));
339 indexWriters.append(indexWriter.release());
342 // Before this point, don't do any mutation. After this point, rollback the transaction in case of error.
344 if (!objectStore->backingStore()->putObjectStoreRecord(objectStore->databaseId(), objectStore->id(), *key, value->toWireString(), recordIdentifier.get())) {
345 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
346 transaction->abort();
350 for (size_t i = 0; i < indexWriters.size(); ++i) {
351 if (!indexWriters[i]->writeIndexKeys(recordIdentifier.get(),
352 *objectStore->backingStore(), objectStore->databaseId(),
353 objectStore->m_id)) {
354 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
355 transaction->abort();
360 callbacks->onSuccess(key.get());
363 void IDBObjectStoreBackendImpl::deleteFunction(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
365 IDB_TRACE("IDBObjectStoreBackendImpl::delete");
367 ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
369 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
370 RefPtr<IDBKeyRange> keyRange = prpKeyRange;
371 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
373 if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::deleteInternal, objectStore, keyRange, callbacks)))
374 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
377 void IDBObjectStoreBackendImpl::deleteInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
379 IDB_TRACE("IDBObjectStoreBackendImpl::deleteInternal");
380 RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier;
382 RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), keyRange.get(), IDBCursor::NEXT);
383 if (backingStoreCursor) {
386 recordIdentifier = backingStoreCursor->objectStoreRecordIdentifier();
388 for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
389 if (!it->second->hasValidId())
390 continue; // The index object has been created, but does not exist in the database yet.
392 bool success = objectStore->backingStore()->deleteIndexDataForRecord(objectStore->databaseId(), objectStore->id(), it->second->id(), recordIdentifier.get());
393 ASSERT_UNUSED(success, success);
396 objectStore->backingStore()->deleteObjectStoreRecord(objectStore->databaseId(), objectStore->id(), recordIdentifier.get());
398 } while (backingStoreCursor->continueFunction(0));
400 backingStoreCursor->close();
403 callbacks->onSuccess(SerializedScriptValue::undefinedValue());
406 void IDBObjectStoreBackendImpl::clear(PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
408 IDB_TRACE("IDBObjectStoreBackendImpl::clear");
410 ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
412 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
413 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
415 if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::clearInternal, objectStore, callbacks)))
416 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
419 void IDBObjectStoreBackendImpl::clearInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBCallbacks> callbacks)
421 objectStore->backingStore()->clearObjectStore(objectStore->databaseId(), objectStore->id());
422 callbacks->onSuccess(SerializedScriptValue::undefinedValue());
426 class PopulateIndexCallback : public IDBBackingStore::ObjectStoreRecordCallback {
428 PopulateIndexCallback(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBIndexBackendImpl> index)
429 : m_backingStore(backingStore)
430 , m_databaseId(databaseId)
431 , m_objectStoreId(objectStoreId)
436 virtual bool callback(const IDBBackingStore::ObjectStoreRecordIdentifier* recordIdentifier, const String& value)
438 RefPtr<SerializedScriptValue> objectValue = SerializedScriptValue::createFromWire(value);
439 if (!m_writer.loadIndexKeysForValue(objectValue.get()))
441 return m_writer.writeIndexKeys(recordIdentifier, m_backingStore, m_databaseId, m_objectStoreId);
445 IDBBackingStore& m_backingStore;
446 int64_t m_databaseId;
447 int64_t m_objectStoreId;
448 IndexWriter m_writer;
452 bool IDBObjectStoreBackendImpl::populateIndex(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBIndexBackendImpl> index)
454 PopulateIndexCallback callback(backingStore, databaseId, objectStoreId, index);
455 if (!backingStore.forEachObjectStoreRecord(databaseId, objectStoreId, callback))
460 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::createIndex(const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
463 ec = IDBDatabaseException::IDB_TYPE_ERR;
466 if (m_indexes.contains(name)) {
467 ec = IDBDatabaseException::CONSTRAINT_ERR;
470 if (transaction->mode() != IDBTransaction::VERSION_CHANGE) {
471 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
475 RefPtr<IDBIndexBackendImpl> index = IDBIndexBackendImpl::create(m_database, this, name, keyPath, unique, multiEntry);
476 ASSERT(index->name() == name);
478 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
479 RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
480 if (!transaction->scheduleTask(
481 createCallbackTask(&IDBObjectStoreBackendImpl::createIndexInternal,
482 objectStore, index, transactionPtr),
483 createCallbackTask(&IDBObjectStoreBackendImpl::removeIndexFromMap,
484 objectStore, index))) {
485 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
489 m_indexes.set(name, index);
490 return index.release();
493 void IDBObjectStoreBackendImpl::createIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
496 if (!objectStore->backingStore()->createIndex(objectStore->databaseId(), objectStore->id(), index->name(), index->keyPath(), index->unique(), index->multiEntry(), id)) {
497 transaction->abort();
503 if (!populateIndex(*objectStore->backingStore(), objectStore->databaseId(), objectStore->m_id, index)) {
504 transaction->abort();
508 transaction->didCompleteTaskEvents();
511 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::index(const String& name, ExceptionCode& ec)
513 RefPtr<IDBIndexBackendInterface> index = m_indexes.get(name);
515 ec = IDBDatabaseException::IDB_NOT_FOUND_ERR;
518 return index.release();
521 void IDBObjectStoreBackendImpl::deleteIndex(const String& name, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
523 if (transaction->mode() != IDBTransaction::VERSION_CHANGE) {
524 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
528 RefPtr<IDBIndexBackendImpl> index = m_indexes.get(name);
530 ec = IDBDatabaseException::IDB_NOT_FOUND_ERR;
534 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
535 RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
536 if (!transaction->scheduleTask(
537 createCallbackTask(&IDBObjectStoreBackendImpl::deleteIndexInternal,
538 objectStore, index, transactionPtr),
539 createCallbackTask(&IDBObjectStoreBackendImpl::addIndexToMap,
540 objectStore, index))) {
541 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
544 m_indexes.remove(name);
547 void IDBObjectStoreBackendImpl::deleteIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
549 objectStore->backingStore()->deleteIndex(objectStore->databaseId(), objectStore->id(), index->id());
550 transaction->didCompleteTaskEvents();
553 void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
555 IDB_TRACE("IDBObjectStoreBackendImpl::openCursor");
556 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
557 RefPtr<IDBKeyRange> range = prpRange;
558 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
559 RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
560 if (!transaction->scheduleTask(
561 createCallbackTask(&IDBObjectStoreBackendImpl::openCursorInternal,
562 objectStore, range, direction, callbacks, transactionPtr))) {
563 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
567 void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
569 IDB_TRACE("IDBObjectStoreBackendImpl::openCursorInternal");
570 IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(tmpDirection);
572 RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), range.get(), direction);
573 if (!backingStoreCursor) {
574 callbacks->onSuccess(SerializedScriptValue::nullValue());
578 RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(backingStoreCursor.release(), direction, IDBCursorBackendInterface::ObjectStoreCursor, transaction.get(), objectStore.get());
579 callbacks->onSuccess(cursor.release());
582 void IDBObjectStoreBackendImpl::count(PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
584 IDB_TRACE("IDBObjectStoreBackendImpl::count");
585 if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::countInternal, this, range, callbacks, transaction)))
586 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
589 void IDBObjectStoreBackendImpl::countInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface>)
591 IDB_TRACE("IDBObjectStoreBackendImpl::countInternal");
593 RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), range.get(), IDBCursor::NEXT);
594 if (!backingStoreCursor) {
595 callbacks->onSuccess(SerializedScriptValue::numberValue(count));
601 } while (backingStoreCursor->continueFunction(0));
603 backingStoreCursor->close();
604 callbacks->onSuccess(SerializedScriptValue::numberValue(count));
607 void IDBObjectStoreBackendImpl::loadIndexes()
610 Vector<String> names;
611 Vector<IDBKeyPath> keyPaths;
612 Vector<bool> uniqueFlags;
613 Vector<bool> multiEntryFlags;
614 backingStore()->getIndexes(databaseId(), m_id, ids, names, keyPaths, uniqueFlags, multiEntryFlags);
616 ASSERT(names.size() == ids.size());
617 ASSERT(keyPaths.size() == ids.size());
618 ASSERT(uniqueFlags.size() == ids.size());
619 ASSERT(multiEntryFlags.size() == ids.size());
621 for (size_t i = 0; i < ids.size(); ++i)
622 m_indexes.set(names[i], IDBIndexBackendImpl::create(m_database, this, ids[i], names[i], keyPaths[i], uniqueFlags[i], multiEntryFlags[i]));
625 void IDBObjectStoreBackendImpl::removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
627 ASSERT(objectStore->m_indexes.contains(index->name()));
628 objectStore->m_indexes.remove(index->name());
631 void IDBObjectStoreBackendImpl::addIndexToMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
633 RefPtr<IDBIndexBackendImpl> indexPtr = index;
634 ASSERT(!objectStore->m_indexes.contains(indexPtr->name()));
635 objectStore->m_indexes.set(indexPtr->name(), indexPtr);
638 PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::genAutoIncrementKey()
640 const int64_t kMaxGeneratorValue = 9007199254740992LL; // Maximum integer storable as ECMAScript number.
641 if (m_autoIncrementNumber > kMaxGeneratorValue)
642 return IDBKey::createInvalid();
643 if (m_autoIncrementNumber > 0)
644 return IDBKey::createNumber(m_autoIncrementNumber++);
646 m_autoIncrementNumber = backingStore()->nextAutoIncrementNumber(databaseId(), id());
647 if (m_autoIncrementNumber > kMaxGeneratorValue)
648 return IDBKey::createInvalid();
649 return IDBKey::createNumber(m_autoIncrementNumber++);
653 } // namespace WebCore