blob: d98e14fe6a8a2cb9f054e96033de5e68e949a0c6 [file] [log] [blame]
/*
* Copyright (C) 2015 Apple 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 INC. 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 INC. 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 "UniqueIDBDatabaseTransaction.h"
#include "IDBIterateCursorData.h"
#include "IDBResultData.h"
#include "Logging.h"
#include "UniqueIDBDatabase.h"
#include "UniqueIDBDatabaseConnection.h"
#include "UniqueIDBDatabaseManager.h"
namespace WebCore {
namespace IDBServer {
Ref<UniqueIDBDatabaseTransaction> UniqueIDBDatabaseTransaction::create(UniqueIDBDatabaseConnection& connection, const IDBTransactionInfo& info)
{
return adoptRef(*new UniqueIDBDatabaseTransaction(connection, info));
}
UniqueIDBDatabaseTransaction::UniqueIDBDatabaseTransaction(UniqueIDBDatabaseConnection& connection, const IDBTransactionInfo& info)
: m_databaseConnection(connection)
, m_transactionInfo(info)
{
ASSERT(database());
if (m_transactionInfo.mode() == IDBTransactionMode::Versionchange)
m_originalDatabaseInfo = makeUnique<IDBDatabaseInfo>(database()->info());
if (!m_databaseConnection)
return;
if (auto* manager = m_databaseConnection->manager())
manager->registerTransaction(*this);
}
UniqueIDBDatabaseTransaction::~UniqueIDBDatabaseTransaction()
{
if (!m_databaseConnection)
return;
if (auto* manager = m_databaseConnection->manager())
manager->unregisterTransaction(*this);
}
UniqueIDBDatabaseConnection* UniqueIDBDatabaseTransaction::databaseConnection() const
{
return m_databaseConnection.get();
}
IDBDatabaseInfo* UniqueIDBDatabaseTransaction::originalDatabaseInfo() const
{
ASSERT(m_transactionInfo.mode() == IDBTransactionMode::Versionchange);
return m_originalDatabaseInfo.get();
}
void UniqueIDBDatabaseTransaction::abort()
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::abort");
auto* database = this->database();
if (!database)
return;
database->abortTransaction(*this, [this, weakThis = WeakPtr { *this }](auto& error) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::abort (callback)");
if (weakThis && m_databaseConnection)
m_databaseConnection->didAbortTransaction(*this, error);
});
}
void UniqueIDBDatabaseTransaction::abortWithoutCallback()
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::abortWithoutCallback");
if (m_databaseConnection)
m_databaseConnection->abortTransactionWithoutCallback(*this);
}
UniqueIDBDatabase* UniqueIDBDatabaseTransaction::database() const
{
return m_databaseConnection ? m_databaseConnection->database() : nullptr;
}
bool UniqueIDBDatabaseTransaction::isVersionChange() const
{
return m_transactionInfo.mode() == IDBTransactionMode::Versionchange;
}
bool UniqueIDBDatabaseTransaction::isReadOnly() const
{
return m_transactionInfo.mode() == IDBTransactionMode::Readonly;
}
void UniqueIDBDatabaseTransaction::commit(uint64_t pendingRequestCount)
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::commit");
auto* database = this->database();
if (!database)
return;
std::optional<IDBError> errorInPendingRequests;
while (pendingRequestCount--) {
auto error = m_requestResults.takeLast();
if (!error.isNull()) {
errorInPendingRequests = error;
break;
}
}
if (errorInPendingRequests) {
database->abortTransaction(*this, [this, weakThis = WeakPtr { *this }, &errorInPendingRequests](auto&) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::commit with error (callback)");
if (weakThis && m_databaseConnection)
m_databaseConnection->didCommitTransaction(*this, *errorInPendingRequests);
});
return;
}
database->commitTransaction(*this, [this, weakThis = WeakPtr { *this }](auto& error) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::commit (callback)");
if (weakThis && m_databaseConnection)
m_databaseConnection->didCommitTransaction(*this, error);
});
}
void UniqueIDBDatabaseTransaction::createObjectStore(const IDBRequestData& requestData, const IDBObjectStoreInfo& info)
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::createObjectStore");
ASSERT(isVersionChange());
ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
auto* database = this->database();
if (!database)
return;
database->createObjectStore(*this, info, [this, weakThis = WeakPtr { *this }, requestData](auto& error) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::createObjectStore (callback)");
if (!weakThis || !m_databaseConnection)
return;
m_requestResults.append(error);
if (error.isNull())
m_databaseConnection->didCreateObjectStore(IDBResultData::createObjectStoreSuccess(requestData.requestIdentifier()));
else
m_databaseConnection->didCreateObjectStore(IDBResultData::error(requestData.requestIdentifier(), error));
});
}
void UniqueIDBDatabaseTransaction::deleteObjectStore(const IDBRequestData& requestData, const String& objectStoreName)
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::deleteObjectStore");
ASSERT(isVersionChange());
ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
auto* database = this->database();
if (!database)
return;
database->deleteObjectStore(*this, objectStoreName, [this, weakThis = WeakPtr { *this }, requestData](const IDBError& error) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::deleteObjectStore (callback)");
if (!weakThis || !m_databaseConnection)
return;
m_requestResults.append(error);
if (error.isNull())
m_databaseConnection->didDeleteObjectStore(IDBResultData::deleteObjectStoreSuccess(requestData.requestIdentifier()));
else
m_databaseConnection->didDeleteObjectStore(IDBResultData::error(requestData.requestIdentifier(), error));
});
}
void UniqueIDBDatabaseTransaction::renameObjectStore(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, const String& newName)
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::renameObjectStore");
ASSERT(isVersionChange());
ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
auto* database = this->database();
if (!database)
return;
database->renameObjectStore(*this, objectStoreIdentifier, newName, [this, weakThis = WeakPtr { *this }, requestData](auto& error) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::renameObjectStore (callback)");
if (!weakThis || !m_databaseConnection)
return;
m_requestResults.append(error);
if (error.isNull())
m_databaseConnection->didRenameObjectStore(IDBResultData::renameObjectStoreSuccess(requestData.requestIdentifier()));
else
m_databaseConnection->didRenameObjectStore(IDBResultData::error(requestData.requestIdentifier(), error));
});
}
void UniqueIDBDatabaseTransaction::clearObjectStore(const IDBRequestData& requestData, uint64_t objectStoreIdentifier)
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::clearObjectStore");
ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
auto* database = this->database();
if (!database)
return;
database->clearObjectStore(*this, objectStoreIdentifier, [this, weakThis = WeakPtr { *this }, requestData](auto& error) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::clearObjectStore (callback)");
if (!weakThis || !m_databaseConnection)
return;
m_requestResults.append(error);
if (error.isNull())
m_databaseConnection->didClearObjectStore(IDBResultData::clearObjectStoreSuccess(requestData.requestIdentifier()));
else
m_databaseConnection->didClearObjectStore(IDBResultData::error(requestData.requestIdentifier(), error));
});
}
void UniqueIDBDatabaseTransaction::createIndex(const IDBRequestData& requestData, const IDBIndexInfo& info)
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::createIndex");
ASSERT(isVersionChange());
ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
auto* database = this->database();
if (!database)
return;
database->createIndex(*this, info, [this, weakThis = WeakPtr { *this }, requestData](auto& error) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::createIndex (callback)");
if (!weakThis || !m_databaseConnection)
return;
m_requestResults.append(error);
if (error.isNull())
m_databaseConnection->didCreateIndex(IDBResultData::createIndexSuccess(requestData.requestIdentifier()));
else
m_databaseConnection->didCreateIndex(IDBResultData::error(requestData.requestIdentifier(), error));
});
}
void UniqueIDBDatabaseTransaction::deleteIndex(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, const String& indexName)
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::deleteIndex");
ASSERT(isVersionChange());
ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
auto* database = this->database();
if (!database)
return;
database->deleteIndex(*this, objectStoreIdentifier, indexName, [this, weakThis = WeakPtr { *this }, requestData](auto& error) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::createIndex (callback)");
if (!weakThis || !m_databaseConnection)
return;
m_requestResults.append(error);
if (error.isNull())
m_databaseConnection->didDeleteIndex(IDBResultData::deleteIndexSuccess(requestData.requestIdentifier()));
else
m_databaseConnection->didDeleteIndex(IDBResultData::error(requestData.requestIdentifier(), error));
});
}
void UniqueIDBDatabaseTransaction::renameIndex(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName)
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::renameIndex");
ASSERT(isVersionChange());
ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
auto* database = this->database();
if (!database)
return;
database->renameIndex(*this, objectStoreIdentifier, indexIdentifier, newName, [this, weakThis = WeakPtr { *this }, requestData](auto& error) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::renameIndex (callback)");
if (!weakThis || !m_databaseConnection)
return;
m_requestResults.append(error);
if (error.isNull())
m_databaseConnection->didRenameIndex(IDBResultData::renameIndexSuccess(requestData.requestIdentifier()));
else
m_databaseConnection->didRenameIndex(IDBResultData::error(requestData.requestIdentifier(), error));
});
}
void UniqueIDBDatabaseTransaction::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& keyData, const IDBValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::putOrAdd");
ASSERT(!isReadOnly());
ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
auto* database = this->database();
if (!database)
return;
database->putOrAdd(requestData, keyData, value, overwriteMode, [this, weakThis = WeakPtr { *this }, requestData](auto& error, const IDBKeyData& key) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::putOrAdd (callback)");
if (!weakThis || !m_databaseConnection)
return;
m_requestResults.append(error);
if (error.isNull())
m_databaseConnection->connectionToClient().didPutOrAdd(IDBResultData::putOrAddSuccess(requestData.requestIdentifier(), key));
else
m_databaseConnection->connectionToClient().didPutOrAdd(IDBResultData::error(requestData.requestIdentifier(), error));
});
}
void UniqueIDBDatabaseTransaction::getRecord(const IDBRequestData& requestData, const IDBGetRecordData& getRecordData)
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getRecord");
ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
auto* database = this->database();
if (!database)
return;
database->getRecord(requestData, getRecordData, [this, weakThis = WeakPtr { *this }, requestData](auto& error, const IDBGetResult& result) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getRecord (callback)");
if (!weakThis || !m_databaseConnection)
return;
m_requestResults.append(error);
if (error.isNull())
m_databaseConnection->connectionToClient().didGetRecord(IDBResultData::getRecordSuccess(requestData.requestIdentifier(), result));
else
m_databaseConnection->connectionToClient().didGetRecord(IDBResultData::error(requestData.requestIdentifier(), error));
});
}
void UniqueIDBDatabaseTransaction::getAllRecords(const IDBRequestData& requestData, const IDBGetAllRecordsData& getAllRecordsData)
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getAllRecords");
ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
auto* database = this->database();
if (!database)
return;
database->getAllRecords(requestData, getAllRecordsData, [this, weakThis = WeakPtr { *this }, requestData](auto& error, const IDBGetAllResult& result) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getAllRecords (callback)");
if (!weakThis || !m_databaseConnection)
return;
m_requestResults.append(error);
if (error.isNull())
m_databaseConnection->connectionToClient().didGetAllRecords(IDBResultData::getAllRecordsSuccess(requestData.requestIdentifier(), result));
else
m_databaseConnection->connectionToClient().didGetAllRecords(IDBResultData::error(requestData.requestIdentifier(), error));
});
}
void UniqueIDBDatabaseTransaction::getCount(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData)
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getCount");
ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
auto* database = this->database();
if (!database)
return;
database->getCount(requestData, keyRangeData, [this, weakThis = WeakPtr { *this }, requestData](auto& error, uint64_t count) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getCount (callback)");
if (!weakThis || !m_databaseConnection)
return;
m_requestResults.append(error);
if (error.isNull())
m_databaseConnection->connectionToClient().didGetCount(IDBResultData::getCountSuccess(requestData.requestIdentifier(), count));
else
m_databaseConnection->connectionToClient().didGetCount(IDBResultData::error(requestData.requestIdentifier(), error));
});
}
void UniqueIDBDatabaseTransaction::deleteRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData)
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::deleteRecord");
ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
auto* database = this->database();
if (!database)
return;
database->deleteRecord(requestData, keyRangeData, [this, weakThis = WeakPtr { *this }, requestData](auto& error) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::deleteRecord (callback)");
if (!weakThis || !m_databaseConnection)
return;
m_requestResults.append(error);
if (error.isNull())
m_databaseConnection->connectionToClient().didDeleteRecord(IDBResultData::deleteRecordSuccess(requestData.requestIdentifier()));
else
m_databaseConnection->connectionToClient().didDeleteRecord(IDBResultData::error(requestData.requestIdentifier(), error));
});
}
void UniqueIDBDatabaseTransaction::openCursor(const IDBRequestData& requestData, const IDBCursorInfo& info)
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::openCursor");
ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
auto* database = this->database();
if (!database)
return;
database->openCursor(requestData, info, [this, weakThis = WeakPtr { *this }, requestData](auto& error, const IDBGetResult& result) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::openCursor (callback)");
if (!weakThis || !m_databaseConnection)
return;
m_requestResults.append(error);
if (error.isNull())
m_databaseConnection->connectionToClient().didOpenCursor(IDBResultData::openCursorSuccess(requestData.requestIdentifier(), result));
else
m_databaseConnection->connectionToClient().didOpenCursor(IDBResultData::error(requestData.requestIdentifier(), error));
});
}
void UniqueIDBDatabaseTransaction::iterateCursor(const IDBRequestData& requestData, const IDBIterateCursorData& data)
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::iterateCursor");
ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
auto* database = this->database();
if (!database)
return;
database->iterateCursor(requestData, data, [this, weakThis = WeakPtr { *this }, requestData, option = data.option](auto& error, const IDBGetResult& result) {
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::iterateCursor (callback)");
if (option == IndexedDB::CursorIterateOption::DoNotReply)
return;
if (!weakThis || !m_databaseConnection)
return;
m_requestResults.append(error);
if (error.isNull())
m_databaseConnection->connectionToClient().didIterateCursor(IDBResultData::iterateCursorSuccess(requestData.requestIdentifier(), result));
else
m_databaseConnection->connectionToClient().didIterateCursor(IDBResultData::error(requestData.requestIdentifier(), error));
});
}
const Vector<uint64_t>& UniqueIDBDatabaseTransaction::objectStoreIdentifiers()
{
if (!m_objectStoreIdentifiers.isEmpty())
return m_objectStoreIdentifiers;
auto* database = this->database();
if (!database)
return m_objectStoreIdentifiers;
auto& info = database->info();
for (const auto& objectStoreName : info.objectStoreNames()) {
auto objectStoreInfo = info.infoForExistingObjectStore(objectStoreName);
ASSERT(objectStoreInfo);
if (!objectStoreInfo)
continue;
if (m_transactionInfo.objectStores().contains(objectStoreName))
m_objectStoreIdentifiers.append(objectStoreInfo->identifier());
}
return m_objectStoreIdentifiers;
}
void UniqueIDBDatabaseTransaction::didActivateInBackingStore(const IDBError& error)
{
LOG(IndexedDB, "UniqueIDBDatabaseTransaction::didActivateInBackingStore");
if (m_databaseConnection)
m_databaseConnection->connectionToClient().didStartTransaction(m_transactionInfo.identifier(), error);
}
} // namespace IDBServer
} // namespace WebCore