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 "IDBTransactionBackendImpl.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::getInternal");
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 (!transaction->scheduleTask(
152 createCallbackTask(&IDBObjectStoreBackendImpl::putInternal, objectStore, value, key, putMode, callbacks, transaction),
153 // FIXME: One of these per put() is overkill, since it's simply a cache invalidation.
154 createCallbackTask(&IDBObjectStoreBackendImpl::revertAutoIncrementKeyCache, objectStore)))
155 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
158 void IDBObjectStoreBackendImpl::revertAutoIncrementKeyCache(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
160 objectStore->resetAutoIncrementKeyCache();
166 explicit IndexWriter(PassRefPtr<IDBIndexBackendImpl> index)
171 bool loadIndexKeysForValue(SerializedScriptValue* objectValue, const IDBKey* primaryKey = 0, String* errorMessage = 0)
175 RefPtr<IDBKey> indexKey = fetchKeyFromKeyPath(objectValue, m_index->keyPath());
180 if (!m_index->multiEntry() || indexKey->type() != IDBKey::ArrayType) {
181 if (!indexKey->isValid())
184 if (!m_index->addingKeyAllowed(indexKey.get(), primaryKey)) {
186 *errorMessage = String::format("Unable to add key to index '%s': the key does not satisfy its uniqueness requirements.",
187 m_index->name().utf8().data());
190 m_indexKeys.append(indexKey);
192 ASSERT(m_index->multiEntry());
193 ASSERT(indexKey->type() == IDBKey::ArrayType);
194 indexKey = IDBKey::createMultiEntryArray(indexKey->array());
196 for (size_t i = 0; i < indexKey->array().size(); ++i) {
197 if (!m_index->addingKeyAllowed(indexKey->array()[i].get(), primaryKey)) {
199 *errorMessage = String::format("Unable to add key to index '%s': at least one key does not satisfy the uniqueness requirements.",
200 m_index->name().utf8().data());
203 m_indexKeys.append(indexKey->array()[i]);
209 bool writeIndexKeys(const IDBBackingStore::ObjectStoreRecordIdentifier* recordIdentifier, IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, String* errorMessage = 0)
211 for (size_t i = 0; i < m_indexKeys.size(); ++i) {
212 if (!backingStore.deleteIndexDataForRecord(databaseId, objectStoreId, m_index->id(), recordIdentifier))
214 if (!backingStore.putIndexDataForRecord(databaseId, objectStoreId, m_index->id(), *m_indexKeys[i].get(), recordIdentifier))
221 RefPtr<IDBIndexBackendImpl> m_index;
222 Vector<RefPtr<IDBKey> > m_indexKeys;
226 void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
228 IDB_TRACE("IDBObjectStoreBackendImpl::putInternal");
229 ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
230 RefPtr<SerializedScriptValue> value = prpValue;
231 RefPtr<IDBKey> key = prpKey;
233 if (putMode != CursorUpdate) {
234 const bool autoIncrement = objectStore->autoIncrement();
235 const bool hasKeyPath = !objectStore->m_keyPath.isNull();
238 RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
244 RefPtr<IDBKey> autoIncKey = objectStore->genAutoIncrementKey();
245 if (!autoIncKey->isValid()) {
246 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "Maximum key generator value reached."));
250 RefPtr<SerializedScriptValue> valueAfterInjection = injectKeyIntoKeyPath(autoIncKey, value, objectStore->m_keyPath);
251 ASSERT(valueAfterInjection);
252 if (!valueAfterInjection) {
253 objectStore->resetAutoIncrementKeyCache();
254 // Checks in put() ensure this should only happen if I/O error occurs.
255 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error inserting generated key into the object."));
258 value = valueAfterInjection;
262 // FIXME: Logic to update generator state should go here. Currently it does a scan.
263 objectStore->resetAutoIncrementKeyCache();
268 ASSERT(key && key->isValid());
270 RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = objectStore->backingStore()->createInvalidRecordIdentifier();
271 if (putMode == AddOnly && objectStore->backingStore()->keyExistsInObjectStore(objectStore->databaseId(), objectStore->id(), *key, recordIdentifier.get())) {
272 objectStore->resetAutoIncrementKeyCache();
273 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
277 Vector<OwnPtr<IndexWriter> > indexWriters;
278 for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
280 const RefPtr<IDBIndexBackendImpl>& index = it->second;
281 if (!index->hasValidId())
282 continue; // The index object has been created, but does not exist in the database yet.
284 OwnPtr<IndexWriter> indexWriter(adoptPtr(new IndexWriter(index)));
286 if (!indexWriter->loadIndexKeysForValue(value.get(), key.get(), &errorMessage)) {
287 objectStore->resetAutoIncrementKeyCache();
288 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, errorMessage));
292 indexWriters.append(indexWriter.release());
295 // Before this point, don't do any mutation. After this point, rollback the transaction in case of error.
297 if (!objectStore->backingStore()->putObjectStoreRecord(objectStore->databaseId(), objectStore->id(), *key, value->toWireString(), recordIdentifier.get())) {
298 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
299 transaction->abort();
303 for (size_t i = 0; i < indexWriters.size(); ++i) {
304 if (!indexWriters[i]->writeIndexKeys(recordIdentifier.get(),
305 *objectStore->backingStore(), objectStore->databaseId(),
306 objectStore->m_id)) {
307 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
308 transaction->abort();
313 callbacks->onSuccess(key.get());
316 void IDBObjectStoreBackendImpl::deleteFunction(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
318 IDB_TRACE("IDBObjectStoreBackendImpl::delete");
320 ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
322 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
323 RefPtr<IDBKeyRange> keyRange = prpKeyRange;
324 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
326 if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::deleteInternal, objectStore, keyRange, callbacks)))
327 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
330 void IDBObjectStoreBackendImpl::deleteInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
332 IDB_TRACE("IDBObjectStoreBackendImpl::deleteInternal");
333 RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier;
335 RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), keyRange.get(), IDBCursor::NEXT);
336 if (backingStoreCursor) {
339 recordIdentifier = backingStoreCursor->objectStoreRecordIdentifier();
341 for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
342 if (!it->second->hasValidId())
343 continue; // The index object has been created, but does not exist in the database yet.
345 bool success = objectStore->backingStore()->deleteIndexDataForRecord(objectStore->databaseId(), objectStore->id(), it->second->id(), recordIdentifier.get());
346 ASSERT_UNUSED(success, success);
349 objectStore->backingStore()->deleteObjectStoreRecord(objectStore->databaseId(), objectStore->id(), recordIdentifier.get());
351 } while (backingStoreCursor->continueFunction(0));
353 backingStoreCursor->close();
356 callbacks->onSuccess(SerializedScriptValue::undefinedValue());
359 void IDBObjectStoreBackendImpl::clear(PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
361 IDB_TRACE("IDBObjectStoreBackendImpl::clear");
363 ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
365 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
366 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
368 if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::clearInternal, objectStore, callbacks)))
369 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
372 void IDBObjectStoreBackendImpl::clearInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBCallbacks> callbacks)
374 objectStore->backingStore()->clearObjectStore(objectStore->databaseId(), objectStore->id());
375 callbacks->onSuccess(SerializedScriptValue::undefinedValue());
379 class PopulateIndexCallback : public IDBBackingStore::ObjectStoreRecordCallback {
381 PopulateIndexCallback(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBIndexBackendImpl> index)
382 : m_backingStore(backingStore)
383 , m_databaseId(databaseId)
384 , m_objectStoreId(objectStoreId)
389 virtual bool callback(const IDBBackingStore::ObjectStoreRecordIdentifier* recordIdentifier, const String& value)
391 RefPtr<SerializedScriptValue> objectValue = SerializedScriptValue::createFromWire(value);
392 if (!m_writer.loadIndexKeysForValue(objectValue.get()))
394 return m_writer.writeIndexKeys(recordIdentifier, m_backingStore, m_databaseId, m_objectStoreId);
398 IDBBackingStore& m_backingStore;
399 int64_t m_databaseId;
400 int64_t m_objectStoreId;
401 IndexWriter m_writer;
405 bool IDBObjectStoreBackendImpl::populateIndex(IDBBackingStore& backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBIndexBackendImpl> index)
407 PopulateIndexCallback callback(backingStore, databaseId, objectStoreId, index);
408 if (!backingStore.forEachObjectStoreRecord(databaseId, objectStoreId, callback))
413 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::createIndex(const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
415 ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
416 ASSERT(!m_indexes.contains(name));
418 RefPtr<IDBIndexBackendImpl> index = IDBIndexBackendImpl::create(m_database, this, name, keyPath, unique, multiEntry);
419 ASSERT(index->name() == name);
421 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
422 RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
423 if (!transaction->scheduleTask(
424 createCallbackTask(&IDBObjectStoreBackendImpl::createIndexInternal,
425 objectStore, index, transactionPtr),
426 createCallbackTask(&IDBObjectStoreBackendImpl::removeIndexFromMap,
427 objectStore, index))) {
428 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
432 m_indexes.set(name, index);
433 return index.release();
436 void IDBObjectStoreBackendImpl::createIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
439 if (!objectStore->backingStore()->createIndex(objectStore->databaseId(), objectStore->id(), index->name(), index->keyPath(), index->unique(), index->multiEntry(), id)) {
440 transaction->abort();
446 if (!populateIndex(*objectStore->backingStore(), objectStore->databaseId(), objectStore->m_id, index)) {
447 transaction->abort();
451 transaction->didCompleteTaskEvents();
454 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::index(const String& name, ExceptionCode& ec)
456 RefPtr<IDBIndexBackendInterface> index = m_indexes.get(name);
458 ec = IDBDatabaseException::IDB_NOT_FOUND_ERR;
461 return index.release();
464 void IDBObjectStoreBackendImpl::deleteIndex(const String& name, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
466 ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
467 ASSERT(m_indexes.contains(name));
469 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
470 RefPtr<IDBIndexBackendImpl> index = m_indexes.get(name);
471 RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
472 if (!transaction->scheduleTask(
473 createCallbackTask(&IDBObjectStoreBackendImpl::deleteIndexInternal,
474 objectStore, index, transactionPtr),
475 createCallbackTask(&IDBObjectStoreBackendImpl::addIndexToMap,
476 objectStore, index))) {
477 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
480 m_indexes.remove(name);
483 void IDBObjectStoreBackendImpl::deleteIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
485 objectStore->backingStore()->deleteIndex(objectStore->databaseId(), objectStore->id(), index->id());
486 transaction->didCompleteTaskEvents();
489 void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
491 IDB_TRACE("IDBObjectStoreBackendImpl::openCursor");
492 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
493 RefPtr<IDBKeyRange> range = prpRange;
494 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
495 RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
496 if (!transaction->scheduleTask(
497 createCallbackTask(&IDBObjectStoreBackendImpl::openCursorInternal,
498 objectStore, range, direction, callbacks, transactionPtr))) {
499 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
503 void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
505 IDB_TRACE("IDBObjectStoreBackendImpl::openCursorInternal");
506 IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(tmpDirection);
508 RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), range.get(), direction);
509 if (!backingStoreCursor) {
510 callbacks->onSuccess(SerializedScriptValue::nullValue());
514 RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(backingStoreCursor.release(), direction, IDBCursorBackendInterface::ObjectStoreCursor, transaction.get(), objectStore.get());
515 callbacks->onSuccess(cursor.release());
518 void IDBObjectStoreBackendImpl::count(PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
520 IDB_TRACE("IDBObjectStoreBackendImpl::count");
521 if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::countInternal, this, range, callbacks, transaction)))
522 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
525 void IDBObjectStoreBackendImpl::countInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface>)
527 IDB_TRACE("IDBObjectStoreBackendImpl::countInternal");
529 RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(objectStore->databaseId(), objectStore->id(), range.get(), IDBCursor::NEXT);
530 if (!backingStoreCursor) {
531 callbacks->onSuccess(SerializedScriptValue::numberValue(count));
537 } while (backingStoreCursor->continueFunction(0));
539 backingStoreCursor->close();
540 callbacks->onSuccess(SerializedScriptValue::numberValue(count));
543 void IDBObjectStoreBackendImpl::loadIndexes()
546 Vector<String> names;
547 Vector<IDBKeyPath> keyPaths;
548 Vector<bool> uniqueFlags;
549 Vector<bool> multiEntryFlags;
550 backingStore()->getIndexes(databaseId(), m_id, ids, names, keyPaths, uniqueFlags, multiEntryFlags);
552 ASSERT(names.size() == ids.size());
553 ASSERT(keyPaths.size() == ids.size());
554 ASSERT(uniqueFlags.size() == ids.size());
555 ASSERT(multiEntryFlags.size() == ids.size());
557 for (size_t i = 0; i < ids.size(); ++i)
558 m_indexes.set(names[i], IDBIndexBackendImpl::create(m_database, this, ids[i], names[i], keyPaths[i], uniqueFlags[i], multiEntryFlags[i]));
561 void IDBObjectStoreBackendImpl::removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
563 ASSERT(objectStore->m_indexes.contains(index->name()));
564 objectStore->m_indexes.remove(index->name());
567 void IDBObjectStoreBackendImpl::addIndexToMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
569 RefPtr<IDBIndexBackendImpl> indexPtr = index;
570 ASSERT(!objectStore->m_indexes.contains(indexPtr->name()));
571 objectStore->m_indexes.set(indexPtr->name(), indexPtr);
574 PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::genAutoIncrementKey()
576 const int64_t kMaxGeneratorValue = 9007199254740992LL; // Maximum integer storable as ECMAScript number.
577 if (m_autoIncrementNumber > kMaxGeneratorValue)
578 return IDBKey::createInvalid();
579 if (m_autoIncrementNumber > 0)
580 return IDBKey::createNumber(m_autoIncrementNumber++);
582 m_autoIncrementNumber = backingStore()->nextAutoIncrementNumber(databaseId(), id());
583 if (m_autoIncrementNumber > kMaxGeneratorValue)
584 return IDBKey::createInvalid();
585 return IDBKey::createNumber(m_autoIncrementNumber++);
589 } // namespace WebCore