/* * Copyright (C) 2011 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "IDBIndexBackendImpl.h" #if ENABLE(INDEXED_DATABASE) #include "CrossThreadTask.h" #include "IDBBackingStore.h" #include "IDBCallbacks.h" #include "IDBCursorBackendImpl.h" #include "IDBDatabaseBackendImpl.h" #include "IDBDatabaseException.h" #include "IDBKey.h" #include "IDBKeyRange.h" #include "IDBObjectStoreBackendImpl.h" namespace WebCore { IDBIndexBackendImpl::IDBIndexBackendImpl(IDBBackingStore* backingStore, int64_t databaseId, const IDBObjectStoreBackendImpl* objectStoreBackend, int64_t id, const String& name, const String& storeName, const String& keyPath, bool unique) : m_backingStore(backingStore) , m_databaseId(databaseId) , m_objectStoreBackend(objectStoreBackend) , m_id(id) , m_name(name) , m_storeName(storeName) , m_keyPath(keyPath) , m_unique(unique) { } IDBIndexBackendImpl::IDBIndexBackendImpl(IDBBackingStore* backingStore, int64_t databaseId, const IDBObjectStoreBackendImpl* objectStoreBackend, const String& name, const String& storeName, const String& keyPath, bool unique) : m_backingStore(backingStore) , m_databaseId(databaseId) , m_objectStoreBackend(objectStoreBackend) , m_id(InvalidId) , m_name(name) , m_storeName(storeName) , m_keyPath(keyPath) , m_unique(unique) { } IDBIndexBackendImpl::~IDBIndexBackendImpl() { } void IDBIndexBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> range, unsigned short untypedDirection, IDBCursorBackendInterface::CursorType cursorType, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction) { IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(untypedDirection); RefPtr<IDBBackingStore::Cursor> backingStoreCursor; switch (cursorType) { case IDBCursorBackendInterface::IndexKeyCursor: backingStoreCursor = index->m_backingStore->openIndexKeyCursor(index->m_databaseId, index->m_objectStoreBackend->id(), index->id(), range.get(), direction); break; case IDBCursorBackendInterface::IndexCursor: backingStoreCursor = index->m_backingStore->openIndexCursor(index->m_databaseId, index->m_objectStoreBackend->id(), index->id(), range.get(), direction); break; case IDBCursorBackendInterface::ObjectStoreCursor: case IDBCursorBackendInterface::InvalidCursorType: ASSERT_NOT_REACHED(); break; } if (!backingStoreCursor) { callbacks->onSuccess(SerializedScriptValue::nullValue()); return; } ExceptionCode ec = 0; RefPtr<IDBObjectStoreBackendInterface> objectStore = transaction->objectStore(index->m_storeName, ec); ASSERT(objectStore && !ec); RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(backingStoreCursor.get(), direction, cursorType, transaction.get(), objectStore.get()); callbacks->onSuccess(cursor.release()); } void IDBIndexBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpKeyRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec) { RefPtr<IDBIndexBackendImpl> index = this; RefPtr<IDBKeyRange> keyRange = prpKeyRange; RefPtr<IDBCallbacks> callbacks = prpCallbacks; RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr; if (!transaction->scheduleTask(createCallbackTask(&openCursorInternal, index, keyRange, direction, IDBCursorBackendInterface::IndexCursor, callbacks, transaction))) ec = IDBDatabaseException::NOT_ALLOWED_ERR; } void IDBIndexBackendImpl::openKeyCursor(PassRefPtr<IDBKeyRange> prpKeyRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec) { RefPtr<IDBIndexBackendImpl> index = this; RefPtr<IDBKeyRange> keyRange = prpKeyRange; RefPtr<IDBCallbacks> callbacks = prpCallbacks; RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr; if (!transaction->scheduleTask(createCallbackTask(&openCursorInternal, index, keyRange, direction, IDBCursorBackendInterface::IndexKeyCursor, callbacks, transaction))) ec = IDBDatabaseException::NOT_ALLOWED_ERR; } void IDBIndexBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKey> key, bool getObject, PassRefPtr<IDBCallbacks> callbacks) { // FIXME: Split getInternal into two functions, getting rid off |getObject|. if (getObject) { String value = index->m_backingStore->getObjectViaIndex(index->m_databaseId, index->m_objectStoreBackend->id(), index->id(), *key); if (value.isNull()) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the index.")); return; } callbacks->onSuccess(SerializedScriptValue::createFromWire(value)); } else { RefPtr<IDBKey> keyResult = index->m_backingStore->getPrimaryKeyViaIndex(index->m_databaseId, index->m_objectStoreBackend->id(), index->id(), *key); if (!keyResult) { callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the index.")); return; } callbacks->onSuccess(keyResult.get()); } } void IDBIndexBackendImpl::get(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec) { RefPtr<IDBIndexBackendImpl> index = this; RefPtr<IDBKey> key = prpKey; RefPtr<IDBCallbacks> callbacks = prpCallbacks; if (!transaction->scheduleTask(createCallbackTask(&getInternal, index, key, true, callbacks))) ec = IDBDatabaseException::NOT_ALLOWED_ERR; } void IDBIndexBackendImpl::getKey(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec) { RefPtr<IDBIndexBackendImpl> index = this; RefPtr<IDBKey> key = prpKey; RefPtr<IDBCallbacks> callbacks = prpCallbacks; if (!transaction->scheduleTask(createCallbackTask(&getInternal, index, key, false, callbacks))) ec = IDBDatabaseException::NOT_ALLOWED_ERR; } bool IDBIndexBackendImpl::addingKeyAllowed(IDBKey* key) { if (!m_unique) return true; return !m_backingStore->keyExistsInIndex(m_databaseId, m_objectStoreBackend->id(), m_id, *key); } } // namespace WebCore #endif // ENABLE(INDEXED_DATABASE)