blob: e3d3e043d24907ab32408e53854cf756fae302da [file] [log] [blame]
/*
* 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 "IDBMetadata.h"
#include "IDBObjectStoreBackendImpl.h"
#include "IDBTracing.h"
#include "IDBTransactionBackendImpl.h"
namespace WebCore {
IDBIndexBackendImpl::IDBIndexBackendImpl(const IDBDatabaseBackendImpl* database, IDBObjectStoreBackendImpl* objectStoreBackend, int64_t id, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry)
: m_database(database)
, m_objectStoreBackend(objectStoreBackend)
, m_id(id)
, m_name(name)
, m_keyPath(keyPath)
, m_unique(unique)
, m_multiEntry(multiEntry)
{
}
IDBIndexBackendImpl::IDBIndexBackendImpl(const IDBDatabaseBackendImpl* database, IDBObjectStoreBackendImpl* objectStoreBackend, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry)
: m_database(database)
, m_objectStoreBackend(objectStoreBackend)
, m_id(InvalidId)
, m_name(name)
, m_keyPath(keyPath)
, m_unique(unique)
, m_multiEntry(multiEntry)
{
}
IDBIndexBackendImpl::~IDBIndexBackendImpl()
{
}
IDBIndexMetadata IDBIndexBackendImpl::metadata() const
{
return IDBIndexMetadata(m_name, m_keyPath, m_unique, m_multiEntry);
}
void IDBIndexBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> range, unsigned short untypedDirection, IDBCursorBackendInterface::CursorType cursorType, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
{
IDB_TRACE("IDBIndexBackendImpl::openCursorInternal");
IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(untypedDirection);
RefPtr<IDBBackingStore::Cursor> backingStoreCursor;
switch (cursorType) {
case IDBCursorBackendInterface::IndexKeyCursor:
backingStoreCursor = index->backingStore()->openIndexKeyCursor(transaction->backingStoreTransaction(), index->databaseId(), index->m_objectStoreBackend->id(), index->id(), range.get(), direction);
break;
case IDBCursorBackendInterface::IndexCursor:
backingStoreCursor = index->backingStore()->openIndexCursor(transaction->backingStoreTransaction(), index->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;
}
RefPtr<IDBCursorBackendImpl> cursor = IDBCursorBackendImpl::create(backingStoreCursor.get(), cursorType, transaction.get(), index->m_objectStoreBackend);
callbacks->onSuccess(cursor, cursor->key(), cursor->primaryKey(), cursor->value());
}
void IDBIndexBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpKeyRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
{
IDB_TRACE("IDBIndexBackendImpl::openCursor");
RefPtr<IDBIndexBackendImpl> index = this;
RefPtr<IDBKeyRange> keyRange = prpKeyRange;
RefPtr<IDBCallbacks> callbacks = prpCallbacks;
RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
if (!transaction->scheduleTask(
createCallbackTask(&openCursorInternal, index, keyRange, direction, IDBCursorBackendInterface::IndexCursor, callbacks, transaction)))
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
}
void IDBIndexBackendImpl::openKeyCursor(PassRefPtr<IDBKeyRange> prpKeyRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
{
IDB_TRACE("IDBIndexBackendImpl::openKeyCursor");
RefPtr<IDBIndexBackendImpl> index = this;
RefPtr<IDBKeyRange> keyRange = prpKeyRange;
RefPtr<IDBCallbacks> callbacks = prpCallbacks;
RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
if (!transaction->scheduleTask(
createCallbackTask(&openCursorInternal, index, keyRange, direction, IDBCursorBackendInterface::IndexKeyCursor, callbacks, transaction)))
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
}
void IDBIndexBackendImpl::countInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
{
IDB_TRACE("IDBIndexBackendImpl::countInternal");
uint32_t count = 0;
RefPtr<IDBBackingStore::Cursor> backingStoreCursor = index->backingStore()->openIndexKeyCursor(transaction->backingStoreTransaction(), index->databaseId(), index->m_objectStoreBackend->id(), index->id(), range.get(), IDBCursor::NEXT);
if (!backingStoreCursor) {
callbacks->onSuccess(SerializedScriptValue::numberValue(count));
return;
}
do {
++count;
} while (backingStoreCursor->continueFunction(0));
backingStoreCursor->close();
callbacks->onSuccess(SerializedScriptValue::numberValue(count));
}
void IDBIndexBackendImpl::count(PassRefPtr<IDBKeyRange> range, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
{
IDB_TRACE("IDBIndexBackendImpl::count");
RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
if (!transaction->scheduleTask(
createCallbackTask(&countInternal, this, range, callbacks, transaction)))
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
}
void IDBIndexBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
{
IDB_TRACE("IDBIndexBackendImpl::getInternal");
RefPtr<IDBKey> key;
if (keyRange->isOnlyKey())
key = keyRange->lower();
else {
RefPtr<IDBBackingStore::Cursor> backingStoreCursor = index->backingStore()->openIndexCursor(transaction->backingStoreTransaction(), index->databaseId(), index->m_objectStoreBackend->id(), index->id(), keyRange.get(), IDBCursor::NEXT);
if (!backingStoreCursor) {
callbacks->onSuccess(SerializedScriptValue::undefinedValue());
return;
}
key = backingStoreCursor->key();
backingStoreCursor->close();
}
RefPtr<IDBKey> primaryKey = index->backingStore()->getPrimaryKeyViaIndex(transaction->backingStoreTransaction(), index->databaseId(), index->m_objectStoreBackend->id(), index->id(), *key);
String value = index->backingStore()->getObjectStoreRecord(transaction->backingStoreTransaction(), index->databaseId(), index->m_objectStoreBackend->id(), *primaryKey);
if (value.isNull()) {
callbacks->onSuccess(SerializedScriptValue::undefinedValue());
return;
}
if (index->m_objectStoreBackend->autoIncrement() && !index->m_objectStoreBackend->keyPath().isNull()) {
callbacks->onSuccess(SerializedScriptValue::createFromWire(value),
primaryKey, index->m_objectStoreBackend->keyPath());
return;
}
callbacks->onSuccess(SerializedScriptValue::createFromWire(value));
}
void IDBIndexBackendImpl::getKeyInternal(ScriptExecutionContext* context, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendImpl> transaction)
{
IDB_TRACE("IDBIndexBackendImpl::getInternal");
RefPtr<IDBBackingStore::Cursor> backingStoreCursor =
index->backingStore()->openIndexKeyCursor(transaction->backingStoreTransaction(), index->databaseId(), index->m_objectStoreBackend->id(), index->id(), keyRange.get(), IDBCursor::NEXT);
if (!backingStoreCursor) {
callbacks->onSuccess(static_cast<IDBKey*>(0));
return;
}
RefPtr<IDBKey> keyResult = index->backingStore()->getPrimaryKeyViaIndex(transaction->backingStoreTransaction(), index->databaseId(), index->m_objectStoreBackend->id(), index->id(), *backingStoreCursor->key());
if (!keyResult) {
callbacks->onSuccess(static_cast<IDBKey*>(0));
backingStoreCursor->close();
return;
}
callbacks->onSuccess(keyResult.get());
backingStoreCursor->close();
}
void IDBIndexBackendImpl::get(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
{
IDB_TRACE("IDBIndexBackendImpl::get");
RefPtr<IDBIndexBackendImpl> index = this;
RefPtr<IDBKeyRange> keyRange = prpKeyRange;
RefPtr<IDBCallbacks> callbacks = prpCallbacks;
RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
if (!transaction->scheduleTask(createCallbackTask(&getInternal, index, keyRange, callbacks, transaction)))
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
}
void IDBIndexBackendImpl::getKey(PassRefPtr<IDBKeyRange> prpKeyRange, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode&)
{
IDB_TRACE("IDBIndexBackendImpl::getKey");
RefPtr<IDBIndexBackendImpl> index = this;
RefPtr<IDBKeyRange> keyRange = prpKeyRange;
RefPtr<IDBCallbacks> callbacks = prpCallbacks;
RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionPtr);
if (!transaction->scheduleTask(
createCallbackTask(&getKeyInternal, index, keyRange, callbacks, transaction)))
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::IDB_ABORT_ERR));
}
} // namespace WebCore
#endif // ENABLE(INDEXED_DATABASE)