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 "IDBKeyRange.h"
43 #include "IDBTracing.h"
44 #include "IDBTransactionBackendImpl.h"
45 #include "ScriptExecutionContext.h"
46 #include <wtf/MathExtras.h>
50 IDBObjectStoreBackendImpl::~IDBObjectStoreBackendImpl()
54 IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(const IDBDatabaseBackendImpl* database, int64_t id, const String& name, const IDBKeyPath& keyPath, bool autoIncrement, int64_t maxIndexId)
55 : m_database(database)
59 , m_autoIncrement(autoIncrement)
60 , m_maxIndexId(maxIndexId)
65 IDBObjectStoreMetadata IDBObjectStoreBackendImpl::metadata() const
67 IDBObjectStoreMetadata metadata(m_name, m_id, m_keyPath, m_autoIncrement, m_maxIndexId);
68 for (IndexMap::const_iterator it = m_indexes.begin(); it != m_indexes.end(); ++it)
69 metadata.indexes.set(it->key, it->value->metadata());
73 void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
75 IDB_TRACE("IDBObjectStoreBackendImpl::get");
76 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
77 RefPtr<IDBKeyRange> keyRange = prpKeyRange;
78 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
79 RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
80 if (!transaction->scheduleTask(
81 createCallbackTask(&IDBObjectStoreBackendImpl::getInternal, objectStore, keyRange, callbacks, transaction)))
82 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
85 void IDBObjectStoreBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
87 IDB_TRACE("IDBObjectStoreBackendImpl::getInternal");
89 if (keyRange->isOnlyKey())
90 key = keyRange->lower();
92 RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), keyRange.get(), IDBCursor::NEXT);
93 if (!backingStoreCursor) {
94 callbacks->onSuccess(SerializedScriptValue::undefinedValue());
97 key = backingStoreCursor->key();
98 backingStoreCursor->close();
101 String wireData = objectStore->backingStore()->getObjectStoreRecord(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), *key);
102 if (wireData.isNull()) {
103 callbacks->onSuccess(SerializedScriptValue::undefinedValue());
107 if (objectStore->autoIncrement() && !objectStore->keyPath().isNull()) {
108 callbacks->onSuccess(SerializedScriptValue::createFromWire(wireData),
109 key, objectStore->keyPath());
112 callbacks->onSuccess(SerializedScriptValue::createFromWire(wireData));
115 void IDBObjectStoreBackendImpl::putWithIndexKeys(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, const Vector<String>& indexNames, const Vector<IndexKeys>& indexKeys, ExceptionCode&)
117 IDB_TRACE("IDBObjectStoreBackendImpl::putWithIndexKeys");
119 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
120 RefPtr<SerializedScriptValue> value = prpValue;
121 RefPtr<IDBKey> key = prpKey;
122 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
123 RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
124 ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
126 OwnPtr<Vector<String> > newIndexNames = adoptPtr(new Vector<String>(indexNames));
127 OwnPtr<Vector<IndexKeys> > newIndexKeys = adoptPtr(new Vector<IndexKeys>(indexKeys));
129 ASSERT(autoIncrement() || key);
131 if (!transaction->scheduleTask(
132 createCallbackTask(&IDBObjectStoreBackendImpl::putInternal, objectStore, value, key, putMode, callbacks, transaction, newIndexNames.release(), newIndexKeys.release())))
133 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
139 explicit IndexWriter(const IDBIndexMetadata& indexMetadata)
140 : m_indexMetadata(indexMetadata)
143 IndexWriter(const IDBIndexMetadata& indexMetadata,
144 const IDBObjectStoreBackendInterface::IndexKeys& indexKeys)
145 : m_indexMetadata(indexMetadata)
146 , m_indexKeys(indexKeys)
149 bool verifyIndexKeys(IDBBackingStore& backingStore, IDBBackingStore::Transaction* transaction,
150 int64_t databaseId, int64_t objectStoreId, int64_t indexId,
151 const IDBKey* primaryKey = 0, String* errorMessage = 0)
153 for (size_t i = 0; i < m_indexKeys.size(); ++i) {
154 if (!addingKeyAllowed(backingStore, transaction, databaseId, objectStoreId, indexId,
155 (m_indexKeys)[i].get(), primaryKey)) {
157 *errorMessage = String::format("Unable to add key to index '%s': at least one key does not satisfy the uniqueness requirements.",
158 m_indexMetadata.name.utf8().data());
165 bool writeIndexKeys(const IDBBackingStore::ObjectStoreRecordIdentifier* recordIdentifier, IDBBackingStore& backingStore, IDBBackingStore::Transaction* transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId) const
167 for (size_t i = 0; i < m_indexKeys.size(); ++i) {
168 if (!backingStore.deleteIndexDataForRecord(transaction, databaseId, objectStoreId, indexId, recordIdentifier))
170 if (!backingStore.putIndexDataForRecord(transaction, databaseId, objectStoreId, indexId, *(m_indexKeys)[i].get(), recordIdentifier))
176 const String& indexName() const { return m_indexMetadata.name; }
180 bool addingKeyAllowed(IDBBackingStore& backingStore, IDBBackingStore::Transaction* transaction,
181 int64_t databaseId, int64_t objectStoreId, int64_t indexId,
182 const IDBKey* indexKey, const IDBKey* primaryKey) const
184 if (!m_indexMetadata.unique)
187 RefPtr<IDBKey> foundPrimaryKey;
188 bool found = backingStore.keyExistsInIndex(transaction, databaseId, objectStoreId, indexId, *indexKey, foundPrimaryKey);
191 if (primaryKey && foundPrimaryKey->isEqual(primaryKey))
196 const IDBIndexMetadata m_indexMetadata;
197 IDBObjectStoreBackendInterface::IndexKeys m_indexKeys;
201 static bool makeIndexWriters(PassRefPtr<IDBTransactionBackendImpl> transaction, IDBObjectStoreBackendImpl* objectStore, PassRefPtr<IDBKey> primaryKey, bool keyWasGenerated, const Vector<String> indexNames, const Vector<IDBObjectStoreBackendInterface::IndexKeys>& indexKeys, Vector<OwnPtr<IndexWriter> >* indexWriters, String* errorMessage)
203 ASSERT(indexNames.size() == indexKeys.size());
205 HashMap<String, IDBObjectStoreBackendInterface::IndexKeys> indexKeyMap;
206 for (size_t i = 0; i < indexNames.size(); i++)
207 indexKeyMap.add(indexNames[i], indexKeys[i]);
209 for (IDBObjectStoreBackendImpl::IndexMap::iterator it = objectStore->iterIndexesBegin(); it != objectStore->iterIndexesEnd(); ++it) {
211 const RefPtr<IDBIndexBackendImpl>& index = it->value;
212 if (!index->hasValidId())
213 continue; // The index object has been created, but does not exist in the database yet.
215 IDBObjectStoreBackendInterface::IndexKeys keys = indexKeyMap.get(it->key);
216 // If the objectStore is using autoIncrement, then any indexes with an identical keyPath need to also use the primary (generated) key as a key.
217 if (keyWasGenerated) {
218 const IDBKeyPath& indexKeyPath = index->keyPath();
219 if (indexKeyPath == objectStore->keyPath())
220 keys.append(primaryKey);
223 OwnPtr<IndexWriter> indexWriter(adoptPtr(new IndexWriter(index->metadata(), keys)));
224 if (!indexWriter->verifyIndexKeys(*objectStore->backingStore(),
225 transaction->backingStoreTransaction(),
226 objectStore->databaseId(),
228 index->id(), primaryKey.get(), errorMessage)) {
232 indexWriters->append(indexWriter.release());
238 void IDBObjectStoreBackendImpl::setIndexKeys(PassRefPtr<IDBKey> prpPrimaryKey, const Vector<String>& indexNames, const Vector<IndexKeys>& indexKeys, IDBTransactionBackendInterface* transactionPtr)
240 IDB_TRACE("IDBObjectStoreBackendImpl::setIndexKeys");
241 RefPtr<IDBKey> primaryKey = prpPrimaryKey;
242 RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
244 // FIXME: This method could be asynchronous, but we need to evaluate if it's worth the extra complexity.
245 RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = backingStore()->createInvalidRecordIdentifier();
246 if (!backingStore()->keyExistsInObjectStore(transaction->backingStoreTransaction(), databaseId(), id(), *primaryKey, recordIdentifier.get())) {
247 transaction->abort();
251 Vector<OwnPtr<IndexWriter> > indexWriters;
253 if (!makeIndexWriters(transaction, this, primaryKey, false, indexNames, indexKeys, &indexWriters, &errorMessage)) {
254 // FIXME: Need to deal with errorMessage here. makeIndexWriters only fails on uniqueness constraint errors.
255 transaction->abort(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Duplicate index keys exist in the object store."));
259 for (size_t i = 0; i < indexWriters.size(); ++i) {
260 IndexWriter* indexWriter = indexWriters[i].get();
261 if (!indexWriter->writeIndexKeys(recordIdentifier.get(),
263 transaction->backingStoreTransaction(),
266 m_indexes.get(indexWriter->indexName())->id())) {
267 transaction->abort();
273 void IDBObjectStoreBackendImpl::setIndexesReady(const Vector<String>& indexNames, IDBTransactionBackendInterface* transactionInterface)
275 IDB_TRACE("IDBObjectStoreBackendImpl::setIndexesReady");
276 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
278 OwnPtr<Vector<String> > names = adoptPtr(new Vector<String>(indexNames));
279 RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionInterface);
281 if (!transaction->scheduleTask(
282 IDBTransactionBackendInterface::PreemptiveTask,
283 createCallbackTask(&IDBObjectStoreBackendImpl::setIndexesReadyInternal, objectStore, names.release(), transaction)))
284 ASSERT_NOT_REACHED();
287 void IDBObjectStoreBackendImpl::setIndexesReadyInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassOwnPtr<Vector<String> > popIndexNames, PassRefPtr<IDBTransactionBackendImpl> transaction)
289 IDB_TRACE("IDBObjectStoreBackendImpl::setIndexesReadyInternal");
290 OwnPtr<Vector<String> > indexNames = popIndexNames;
291 for (size_t i = 0; i < indexNames->size(); ++i)
292 transaction->didCompletePreemptiveEvent();
293 transaction->didCompleteTaskEvents();
296 void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> prpTransaction, PassOwnPtr<Vector<String> > popIndexNames, PassOwnPtr<Vector<IndexKeys> > popIndexKeys)
298 IDB_TRACE("IDBObjectStoreBackendImpl::putInternal");
299 RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
300 ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
301 RefPtr<SerializedScriptValue> value = prpValue;
302 RefPtr<IDBKey> key = prpKey;
303 OwnPtr<Vector<String> > indexNames = popIndexNames;
304 OwnPtr<Vector<IndexKeys> > indexKeys = popIndexKeys;
305 ASSERT(indexNames && indexKeys && indexNames->size() == indexKeys->size());
306 const bool autoIncrement = objectStore->autoIncrement();
307 bool keyWasGenerated = false;
309 if (putMode != CursorUpdate && autoIncrement && !key) {
310 RefPtr<IDBKey> autoIncKey = objectStore->generateKey(transaction);
311 keyWasGenerated = true;
312 if (!autoIncKey->isValid()) {
313 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Maximum key generator value reached."));
319 ASSERT(key && key->isValid());
321 RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = objectStore->backingStore()->createInvalidRecordIdentifier();
322 if (putMode == AddOnly && objectStore->backingStore()->keyExistsInObjectStore(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), *key, recordIdentifier.get())) {
323 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
327 Vector<OwnPtr<IndexWriter> > indexWriters;
329 if (!makeIndexWriters(transaction, objectStore.get(), key, keyWasGenerated, *indexNames, *indexKeys, &indexWriters, &errorMessage)) {
330 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, errorMessage));
334 // Before this point, don't do any mutation. After this point, rollback the transaction in case of error.
336 if (!objectStore->backingStore()->putObjectStoreRecord(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), *key, value->toWireString(), recordIdentifier.get())) {
337 RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage.");
338 callbacks->onError(error);
339 transaction->abort(error);
343 for (size_t i = 0; i < indexWriters.size(); ++i) {
344 IndexWriter* indexWriter = indexWriters[i].get();
345 if (!indexWriter->writeIndexKeys(recordIdentifier.get(),
346 *objectStore->backingStore(),
347 transaction->backingStoreTransaction(),
348 objectStore->databaseId(),
350 objectStore->m_indexes.get(indexWriter->indexName())->id())) {
352 RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage.");
353 callbacks->onError(error);
354 transaction->abort(error);
359 if (autoIncrement && putMode != CursorUpdate && key->type() == IDBKey::NumberType)
360 objectStore->updateKeyGenerator(transaction, key.get(), !keyWasGenerated);
362 callbacks->onSuccess(key.release());
365 void IDBObjectStoreBackendImpl::deleteFunction(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
367 IDB_TRACE("IDBObjectStoreBackendImpl::delete");
369 RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
370 ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
372 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
373 RefPtr<IDBKeyRange> keyRange = prpKeyRange;
374 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
376 if (!transaction->scheduleTask(
377 createCallbackTask(&IDBObjectStoreBackendImpl::deleteInternal, objectStore, keyRange, callbacks, transaction)))
378 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
381 void IDBObjectStoreBackendImpl::deleteInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
383 IDB_TRACE("IDBObjectStoreBackendImpl::deleteInternal");
384 RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier;
386 RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), keyRange.get(), IDBCursor::NEXT);
387 if (backingStoreCursor) {
390 recordIdentifier = backingStoreCursor->objectStoreRecordIdentifier();
392 for (IDBObjectStoreBackendImpl::IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
393 if (!it->value->hasValidId())
394 continue; // The index object has been created, but does not exist in the database yet.
396 bool success = objectStore->backingStore()->deleteIndexDataForRecord(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), it->value->id(), recordIdentifier.get());
397 ASSERT_UNUSED(success, success);
400 objectStore->backingStore()->deleteObjectStoreRecord(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), recordIdentifier.get());
402 } while (backingStoreCursor->continueFunction(0));
404 backingStoreCursor->close();
407 callbacks->onSuccess(SerializedScriptValue::undefinedValue());
410 void IDBObjectStoreBackendImpl::clear(PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
412 IDB_TRACE("IDBObjectStoreBackendImpl::clear");
414 RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
415 ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
417 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
418 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
420 if (!transaction->scheduleTask(
421 createCallbackTask(&IDBObjectStoreBackendImpl::clearInternal, objectStore, callbacks, transaction)))
422 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
425 void IDBObjectStoreBackendImpl::clearInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
427 objectStore->backingStore()->clearObjectStore(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id());
428 callbacks->onSuccess(SerializedScriptValue::undefinedValue());
431 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::createIndex(int64_t id, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
433 ASSERT_WITH_MESSAGE(!m_indexes.contains(name), "Indexes already contain %s", name.utf8().data());
435 RefPtr<IDBIndexBackendImpl> index = IDBIndexBackendImpl::create(m_database, this, id, name, keyPath, unique, multiEntry);
436 ASSERT(index->name() == name);
438 RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
439 ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
440 ASSERT(id > m_maxIndexId);
443 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
444 if (!transaction->scheduleTask(
445 createCallbackTask(&IDBObjectStoreBackendImpl::createIndexInternal, objectStore, index, transaction),
446 createCallbackTask(&IDBObjectStoreBackendImpl::removeIndexFromMap, objectStore, index))) {
447 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
451 m_indexes.set(name, index);
452 return index.release();
455 void IDBObjectStoreBackendImpl::createIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendImpl> transaction)
457 if (!objectStore->backingStore()->createIndex(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), index->id(), index->name(), index->keyPath(), index->unique(), index->multiEntry())) {
458 transaction->abort();
462 transaction->didCompleteTaskEvents();
465 PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::index(const String& name, ExceptionCode& ec)
467 RefPtr<IDBIndexBackendInterface> index = m_indexes.get(name);
469 ec = IDBDatabaseException::IDB_NOT_FOUND_ERR;
472 return index.release();
475 void IDBObjectStoreBackendImpl::deleteIndex(const String& name, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
477 ASSERT(m_indexes.contains(name));
479 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
480 RefPtr<IDBIndexBackendImpl> index = m_indexes.get(name);
481 RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
482 ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
484 if (!transaction->scheduleTask(
485 createCallbackTask(&IDBObjectStoreBackendImpl::deleteIndexInternal, objectStore, index, transaction),
486 createCallbackTask(&IDBObjectStoreBackendImpl::addIndexToMap, objectStore, index))) {
487 ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
490 m_indexes.remove(name);
493 void IDBObjectStoreBackendImpl::deleteIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendImpl> transaction)
495 objectStore->backingStore()->deleteIndex(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), index->id());
496 transaction->didCompleteTaskEvents();
499 void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, IDBCursor::Direction direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface::TaskType taskType, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
501 IDB_TRACE("IDBObjectStoreBackendImpl::openCursor");
502 RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
503 RefPtr<IDBKeyRange> range = prpRange;
504 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
505 RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
506 if (!transaction->scheduleTask(
507 createCallbackTask(&IDBObjectStoreBackendImpl::openCursorInternal, objectStore, range, direction, callbacks, taskType, transaction))) {
508 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
512 void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, IDBCursor::Direction direction, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface::TaskType taskType, PassRefPtr<IDBTransactionBackendImpl> transaction)
514 IDB_TRACE("IDBObjectStoreBackendImpl::openCursorInternal");
516 RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreCursor(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), range.get(), direction);
517 // The frontend has begun indexing, so this pauses the transaction
518 // until the indexing is complete. This can't happen any earlier
519 // because we don't want to switch to early mode in case multiple
520 // indexes are being created in a row, with put()'s in between.
521 if (taskType == IDBTransactionBackendInterface::PreemptiveTask)
522 transaction->addPreemptiveEvent();
523 if (!backingStoreCursor) {
524 callbacks->onSuccess(SerializedScriptValue::nullValue());
528 RefPtr<IDBCursorBackendImpl> cursor = IDBCursorBackendImpl::create(backingStoreCursor.release(), IDBCursorBackendInterface::ObjectStoreCursor, taskType, transaction.get(), objectStore.get());
529 callbacks->onSuccess(cursor, cursor->key(), cursor->primaryKey(), cursor->value());
532 void IDBObjectStoreBackendImpl::count(PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
534 IDB_TRACE("IDBObjectStoreBackendImpl::count");
535 RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
536 if (!transaction->scheduleTask(
537 createCallbackTask(&IDBObjectStoreBackendImpl::countInternal, this, range, callbacks, transaction)))
538 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
541 void IDBObjectStoreBackendImpl::countInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
543 IDB_TRACE("IDBObjectStoreBackendImpl::countInternal");
545 RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->backingStore()->openObjectStoreKeyCursor(transaction->backingStoreTransaction(), objectStore->databaseId(), objectStore->id(), range.get(), IDBCursor::NEXT);
546 if (!backingStoreCursor) {
547 callbacks->onSuccess(SerializedScriptValue::numberValue(count));
553 } while (backingStoreCursor->continueFunction(0));
555 backingStoreCursor->close();
556 callbacks->onSuccess(SerializedScriptValue::numberValue(count));
559 void IDBObjectStoreBackendImpl::loadIndexes()
562 Vector<String> names;
563 Vector<IDBKeyPath> keyPaths;
564 Vector<bool> uniqueFlags;
565 Vector<bool> multiEntryFlags;
566 backingStore()->getIndexes(databaseId(), m_id, ids, names, keyPaths, uniqueFlags, multiEntryFlags);
568 ASSERT(names.size() == ids.size());
569 ASSERT(keyPaths.size() == ids.size());
570 ASSERT(uniqueFlags.size() == ids.size());
571 ASSERT(multiEntryFlags.size() == ids.size());
573 for (size_t i = 0; i < ids.size(); ++i)
574 m_indexes.set(names[i], IDBIndexBackendImpl::create(m_database, this, ids[i], names[i], keyPaths[i], uniqueFlags[i], multiEntryFlags[i]));
577 void IDBObjectStoreBackendImpl::removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
579 ASSERT(objectStore->m_indexes.contains(index->name()));
580 objectStore->m_indexes.remove(index->name());
583 void IDBObjectStoreBackendImpl::addIndexToMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
585 RefPtr<IDBIndexBackendImpl> indexPtr = index;
586 ASSERT(!objectStore->m_indexes.contains(indexPtr->name()));
587 objectStore->m_indexes.set(indexPtr->name(), indexPtr);
590 PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::generateKey(PassRefPtr<IDBTransactionBackendImpl> transaction)
592 const int64_t maxGeneratorValue = 9007199254740992LL; // Maximum integer storable as ECMAScript number.
593 int64_t currentNumber = backingStore()->getKeyGeneratorCurrentNumber(transaction->backingStoreTransaction(), databaseId(), id());
594 if (currentNumber < 0 || currentNumber > maxGeneratorValue)
595 return IDBKey::createInvalid();
597 return IDBKey::createNumber(currentNumber);
600 void IDBObjectStoreBackendImpl::updateKeyGenerator(PassRefPtr<IDBTransactionBackendImpl> transaction, const IDBKey* key, bool checkCurrent)
602 ASSERT(key && key->type() == IDBKey::NumberType);
603 backingStore()->maybeUpdateKeyGeneratorCurrentNumber(transaction->backingStoreTransaction(), databaseId(), id(), static_cast<int64_t>(floor(key->number())) + 1, checkCurrent);
607 } // namespace WebCore