1327 lines
43 KiB
C++
1327 lines
43 KiB
C++
/**
|
|
* Orthanc - A Lightweight, RESTful DICOM Store
|
|
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
|
|
* Department, University Hospital of Liege, Belgium
|
|
* Copyright (C) 2017-2023 Osimis S.A., Belgium
|
|
* Copyright (C) 2024-2025 Orthanc Team SRL, Belgium
|
|
* Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
|
|
*
|
|
* This program is free software: you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
**/
|
|
|
|
|
|
#include "../../Sources/PrecompiledHeadersServer.h"
|
|
#include "OrthancPluginDatabaseV3.h"
|
|
|
|
#if ORTHANC_ENABLE_PLUGINS != 1
|
|
# error The plugin support is disabled
|
|
#endif
|
|
|
|
#include "../../../OrthancFramework/Sources/Logging.h"
|
|
#include "../../../OrthancFramework/Sources/OrthancException.h"
|
|
#include "../../Sources/Database/ResourcesContent.h"
|
|
#include "../../Sources/Database/VoidDatabaseListener.h"
|
|
#include "PluginsEnumerations.h"
|
|
|
|
#include <cassert>
|
|
|
|
|
|
#define CHECK_FUNCTION_EXISTS(backend, func) \
|
|
if (backend.func == NULL) \
|
|
{ \
|
|
throw OrthancException( \
|
|
ErrorCode_DatabasePlugin, "Missing primitive: " #func "()"); \
|
|
}
|
|
|
|
namespace Orthanc
|
|
{
|
|
class OrthancPluginDatabaseV3::Transaction : public BaseCompatibilityTransaction
|
|
{
|
|
private:
|
|
OrthancPluginDatabaseV3& that_;
|
|
IDatabaseListener& listener_;
|
|
OrthancPluginDatabaseTransaction* transaction_;
|
|
|
|
|
|
void CheckSuccess(OrthancPluginErrorCode code) const
|
|
{
|
|
that_.CheckSuccess(code);
|
|
}
|
|
|
|
|
|
static FileInfo Convert(const OrthancPluginAttachment& attachment)
|
|
{
|
|
return FileInfo(attachment.uuid,
|
|
static_cast<FileContentType>(attachment.contentType),
|
|
attachment.uncompressedSize,
|
|
attachment.uncompressedHash,
|
|
static_cast<CompressionType>(attachment.compressionType),
|
|
attachment.compressedSize,
|
|
attachment.compressedHash);
|
|
}
|
|
|
|
|
|
void ReadStringAnswers(std::list<std::string>& target)
|
|
{
|
|
uint32_t count;
|
|
CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
|
|
|
|
target.clear();
|
|
for (uint32_t i = 0; i < count; i++)
|
|
{
|
|
const char* value = NULL;
|
|
CheckSuccess(that_.backend_.readAnswerString(transaction_, &value, i));
|
|
if (value == NULL)
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
else
|
|
{
|
|
target.push_back(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool ReadSingleStringAnswer(std::string& target)
|
|
{
|
|
uint32_t count;
|
|
CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
|
|
|
|
if (count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
else if (count == 1)
|
|
{
|
|
const char* value = NULL;
|
|
CheckSuccess(that_.backend_.readAnswerString(transaction_, &value, 0));
|
|
if (value == NULL)
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
else
|
|
{
|
|
target.assign(value);
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
}
|
|
|
|
|
|
bool ReadSingleInt64Answer(int64_t& target)
|
|
{
|
|
uint32_t count;
|
|
CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
|
|
|
|
if (count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
else if (count == 1)
|
|
{
|
|
CheckSuccess(that_.backend_.readAnswerInt64(transaction_, &target, 0));
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
}
|
|
|
|
|
|
ExportedResource ReadAnswerExportedResource(uint32_t answerIndex)
|
|
{
|
|
OrthancPluginExportedResource exported;
|
|
CheckSuccess(that_.backend_.readAnswerExportedResource(transaction_, &exported, answerIndex));
|
|
|
|
if (exported.publicId == NULL ||
|
|
exported.modality == NULL ||
|
|
exported.date == NULL ||
|
|
exported.patientId == NULL ||
|
|
exported.studyInstanceUid == NULL ||
|
|
exported.seriesInstanceUid == NULL ||
|
|
exported.sopInstanceUid == NULL)
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
else
|
|
{
|
|
return ExportedResource(exported.seq,
|
|
Plugins::Convert(exported.resourceType),
|
|
exported.publicId,
|
|
exported.modality,
|
|
exported.date,
|
|
exported.patientId,
|
|
exported.studyInstanceUid,
|
|
exported.seriesInstanceUid,
|
|
exported.sopInstanceUid);
|
|
}
|
|
}
|
|
|
|
|
|
ServerIndexChange ReadAnswerChange(uint32_t answerIndex)
|
|
{
|
|
OrthancPluginChange change;
|
|
CheckSuccess(that_.backend_.readAnswerChange(transaction_, &change, answerIndex));
|
|
|
|
if (change.publicId == NULL ||
|
|
change.date == NULL)
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
else
|
|
{
|
|
return ServerIndexChange(change.seq,
|
|
static_cast<ChangeType>(change.changeType),
|
|
Plugins::Convert(change.resourceType),
|
|
change.publicId,
|
|
change.date);
|
|
}
|
|
}
|
|
|
|
|
|
void CheckNoEvent()
|
|
{
|
|
uint32_t count;
|
|
CheckSuccess(that_.backend_.readEventsCount(transaction_, &count));
|
|
if (count != 0)
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
}
|
|
|
|
|
|
void ProcessEvents(bool isDeletingAttachment)
|
|
{
|
|
uint32_t count;
|
|
CheckSuccess(that_.backend_.readEventsCount(transaction_, &count));
|
|
|
|
for (uint32_t i = 0; i < count; i++)
|
|
{
|
|
OrthancPluginDatabaseEvent event;
|
|
CheckSuccess(that_.backend_.readEvent(transaction_, &event, i));
|
|
|
|
switch (event.type)
|
|
{
|
|
case OrthancPluginDatabaseEventType_DeletedAttachment:
|
|
listener_.SignalAttachmentDeleted(Convert(event.content.attachment));
|
|
break;
|
|
|
|
case OrthancPluginDatabaseEventType_DeletedResource:
|
|
if (isDeletingAttachment)
|
|
{
|
|
// This event should only be triggered by "DeleteResource()"
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
else
|
|
{
|
|
listener_.SignalResourceDeleted(Plugins::Convert(event.content.resource.level), event.content.resource.publicId);
|
|
}
|
|
break;
|
|
|
|
case OrthancPluginDatabaseEventType_RemainingAncestor:
|
|
if (isDeletingAttachment)
|
|
{
|
|
// This event should only triggered by "DeleteResource()"
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
else
|
|
{
|
|
listener_.SignalRemainingAncestor(Plugins::Convert(event.content.resource.level), event.content.resource.publicId);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break; // Unhandled event
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public:
|
|
Transaction(OrthancPluginDatabaseV3& that,
|
|
IDatabaseListener& listener,
|
|
OrthancPluginDatabaseTransactionType type) :
|
|
that_(that),
|
|
listener_(listener)
|
|
{
|
|
CheckSuccess(that.backend_.startTransaction(that.database_, &transaction_, type));
|
|
if (transaction_ == NULL)
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
}
|
|
|
|
|
|
virtual ~Transaction()
|
|
{
|
|
OrthancPluginErrorCode code = that_.backend_.destructTransaction(transaction_);
|
|
if (code != OrthancPluginErrorCode_Success)
|
|
{
|
|
// Don't throw exception in destructors
|
|
that_.errorDictionary_.LogError(code, true);
|
|
}
|
|
}
|
|
|
|
virtual void Rollback() ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.rollback(transaction_));
|
|
CheckNoEvent();
|
|
}
|
|
|
|
|
|
virtual void Commit(int64_t fileSizeDelta) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.commit(transaction_, fileSizeDelta));
|
|
CheckNoEvent();
|
|
}
|
|
|
|
|
|
virtual void AddAttachment(int64_t id,
|
|
const FileInfo& attachment,
|
|
int64_t revision) ORTHANC_OVERRIDE
|
|
{
|
|
OrthancPluginAttachment tmp;
|
|
tmp.uuid = attachment.GetUuid().c_str();
|
|
tmp.contentType = static_cast<int32_t>(attachment.GetContentType());
|
|
tmp.uncompressedSize = attachment.GetUncompressedSize();
|
|
tmp.uncompressedHash = attachment.GetUncompressedMD5().c_str();
|
|
tmp.compressionType = static_cast<int32_t>(attachment.GetCompressionType());
|
|
tmp.compressedSize = attachment.GetCompressedSize();
|
|
tmp.compressedHash = attachment.GetCompressedMD5().c_str();
|
|
|
|
CheckSuccess(that_.backend_.addAttachment(transaction_, id, &tmp, revision));
|
|
CheckNoEvent();
|
|
}
|
|
|
|
|
|
virtual void ClearChanges() ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.clearChanges(transaction_));
|
|
CheckNoEvent();
|
|
}
|
|
|
|
|
|
virtual void ClearExportedResources() ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.clearExportedResources(transaction_));
|
|
CheckNoEvent();
|
|
}
|
|
|
|
|
|
virtual void DeleteAttachment(int64_t id,
|
|
FileContentType attachment) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.deleteAttachment(transaction_, id, static_cast<int32_t>(attachment)));
|
|
ProcessEvents(true);
|
|
}
|
|
|
|
|
|
virtual void DeleteMetadata(int64_t id,
|
|
MetadataType type) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.deleteMetadata(transaction_, id, static_cast<int32_t>(type)));
|
|
CheckNoEvent();
|
|
}
|
|
|
|
|
|
virtual void DeleteResource(int64_t id) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.deleteResource(transaction_, id));
|
|
ProcessEvents(false);
|
|
}
|
|
|
|
|
|
virtual void GetAllMetadata(std::map<MetadataType, std::string>& target,
|
|
int64_t id) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.getAllMetadata(transaction_, id));
|
|
CheckNoEvent();
|
|
|
|
uint32_t count;
|
|
CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
|
|
|
|
target.clear();
|
|
for (uint32_t i = 0; i < count; i++)
|
|
{
|
|
int32_t metadata;
|
|
const char* value = NULL;
|
|
CheckSuccess(that_.backend_.readAnswerMetadata(transaction_, &metadata, &value, i));
|
|
|
|
if (value == NULL)
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
else
|
|
{
|
|
target[static_cast<MetadataType>(metadata)] = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
virtual void GetAllPublicIds(std::list<std::string>& target,
|
|
ResourceType resourceType) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.getAllPublicIds(transaction_, Plugins::Convert(resourceType)));
|
|
CheckNoEvent();
|
|
|
|
ReadStringAnswers(target);
|
|
}
|
|
|
|
|
|
virtual void GetAllPublicIdsCompatibility(std::list<std::string>& target,
|
|
ResourceType resourceType,
|
|
int64_t since,
|
|
uint32_t limit) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.getAllPublicIdsWithLimit(
|
|
transaction_, Plugins::Convert(resourceType),
|
|
static_cast<uint64_t>(since), static_cast<uint64_t>(limit)));
|
|
CheckNoEvent();
|
|
|
|
ReadStringAnswers(target);
|
|
}
|
|
|
|
|
|
virtual void GetChanges(std::list<ServerIndexChange>& target /*out*/,
|
|
bool& done /*out*/,
|
|
int64_t since,
|
|
uint32_t limit) ORTHANC_OVERRIDE
|
|
{
|
|
uint8_t tmpDone = true;
|
|
CheckSuccess(that_.backend_.getChanges(transaction_, &tmpDone, since, limit));
|
|
CheckNoEvent();
|
|
|
|
done = (tmpDone != 0);
|
|
|
|
uint32_t count;
|
|
CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
|
|
|
|
target.clear();
|
|
for (uint32_t i = 0; i < count; i++)
|
|
{
|
|
target.push_back(ReadAnswerChange(i));
|
|
}
|
|
}
|
|
|
|
|
|
virtual void GetChildrenInternalId(std::list<int64_t>& target,
|
|
int64_t id) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.getChildrenInternalId(transaction_, id));
|
|
CheckNoEvent();
|
|
|
|
uint32_t count;
|
|
CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
|
|
|
|
target.clear();
|
|
for (uint32_t i = 0; i < count; i++)
|
|
{
|
|
int64_t value;
|
|
CheckSuccess(that_.backend_.readAnswerInt64(transaction_, &value, i));
|
|
target.push_back(value);
|
|
}
|
|
}
|
|
|
|
|
|
virtual void GetChildrenPublicId(std::list<std::string>& target,
|
|
int64_t id) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.getChildrenPublicId(transaction_, id));
|
|
CheckNoEvent();
|
|
|
|
ReadStringAnswers(target);
|
|
}
|
|
|
|
|
|
virtual void GetExportedResources(std::list<ExportedResource>& target /*out*/,
|
|
bool& done /*out*/,
|
|
int64_t since,
|
|
uint32_t limit) ORTHANC_OVERRIDE
|
|
{
|
|
uint8_t tmpDone = true;
|
|
CheckSuccess(that_.backend_.getExportedResources(transaction_, &tmpDone, since, limit));
|
|
CheckNoEvent();
|
|
|
|
done = (tmpDone != 0);
|
|
|
|
uint32_t count;
|
|
CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
|
|
|
|
target.clear();
|
|
for (uint32_t i = 0; i < count; i++)
|
|
{
|
|
target.push_back(ReadAnswerExportedResource(i));
|
|
}
|
|
}
|
|
|
|
|
|
virtual void GetLastChange(std::list<ServerIndexChange>& target /*out*/) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.getLastChange(transaction_));
|
|
CheckNoEvent();
|
|
|
|
uint32_t count;
|
|
CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
|
|
|
|
target.clear();
|
|
if (count == 1)
|
|
{
|
|
target.push_back(ReadAnswerChange(0));
|
|
}
|
|
else if (count > 1)
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
}
|
|
|
|
|
|
virtual void GetLastExportedResource(std::list<ExportedResource>& target /*out*/) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.getLastExportedResource(transaction_));
|
|
CheckNoEvent();
|
|
|
|
uint32_t count;
|
|
CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
|
|
|
|
target.clear();
|
|
if (count == 1)
|
|
{
|
|
target.push_back(ReadAnswerExportedResource(0));
|
|
}
|
|
else if (count > 1)
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
}
|
|
|
|
|
|
virtual void GetMainDicomTags(DicomMap& target,
|
|
int64_t id) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.getMainDicomTags(transaction_, id));
|
|
CheckNoEvent();
|
|
|
|
uint32_t count;
|
|
CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
|
|
|
|
target.Clear();
|
|
for (uint32_t i = 0; i < count; i++)
|
|
{
|
|
uint16_t group, element;
|
|
const char* value = NULL;
|
|
CheckSuccess(that_.backend_.readAnswerDicomTag(transaction_, &group, &element, &value, i));
|
|
|
|
if (value == NULL)
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
else
|
|
{
|
|
target.SetValue(group, element, std::string(value), false);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
virtual std::string GetPublicId(int64_t resourceId) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.getPublicId(transaction_, resourceId));
|
|
CheckNoEvent();
|
|
|
|
std::string s;
|
|
if (ReadSingleStringAnswer(s))
|
|
{
|
|
return s;
|
|
}
|
|
else
|
|
{
|
|
throw OrthancException(ErrorCode_InexistentItem);
|
|
}
|
|
}
|
|
|
|
|
|
virtual uint64_t GetResourcesCount(ResourceType resourceType) ORTHANC_OVERRIDE
|
|
{
|
|
uint64_t value;
|
|
CheckSuccess(that_.backend_.getResourcesCount(transaction_, &value, Plugins::Convert(resourceType)));
|
|
CheckNoEvent();
|
|
return value;
|
|
}
|
|
|
|
|
|
virtual ResourceType GetResourceType(int64_t resourceId) ORTHANC_OVERRIDE
|
|
{
|
|
OrthancPluginResourceType type;
|
|
CheckSuccess(that_.backend_.getResourceType(transaction_, &type, resourceId));
|
|
CheckNoEvent();
|
|
return Plugins::Convert(type);
|
|
}
|
|
|
|
|
|
virtual uint64_t GetTotalCompressedSize() ORTHANC_OVERRIDE
|
|
{
|
|
uint64_t s;
|
|
CheckSuccess(that_.backend_.getTotalCompressedSize(transaction_, &s));
|
|
CheckNoEvent();
|
|
return s;
|
|
}
|
|
|
|
|
|
virtual uint64_t GetTotalUncompressedSize() ORTHANC_OVERRIDE
|
|
{
|
|
uint64_t s;
|
|
CheckSuccess(that_.backend_.getTotalUncompressedSize(transaction_, &s));
|
|
CheckNoEvent();
|
|
return s;
|
|
}
|
|
|
|
|
|
virtual bool IsProtectedPatient(int64_t internalId) ORTHANC_OVERRIDE
|
|
{
|
|
uint8_t b;
|
|
CheckSuccess(that_.backend_.isProtectedPatient(transaction_, &b, internalId));
|
|
CheckNoEvent();
|
|
return (b != 0);
|
|
}
|
|
|
|
|
|
virtual void ListAvailableAttachments(std::set<FileContentType>& target,
|
|
int64_t id) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.listAvailableAttachments(transaction_, id));
|
|
CheckNoEvent();
|
|
|
|
uint32_t count;
|
|
CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
|
|
|
|
target.clear();
|
|
for (uint32_t i = 0; i < count; i++)
|
|
{
|
|
int32_t value;
|
|
CheckSuccess(that_.backend_.readAnswerInt32(transaction_, &value, i));
|
|
target.insert(static_cast<FileContentType>(value));
|
|
}
|
|
}
|
|
|
|
|
|
virtual void LogChange(ChangeType changeType,
|
|
ResourceType resourceType,
|
|
int64_t internalId,
|
|
const std::string& /* publicId - unused */,
|
|
const std::string& date) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.logChange(transaction_, static_cast<int32_t>(changeType),
|
|
internalId, Plugins::Convert(resourceType),
|
|
date.c_str()));
|
|
CheckNoEvent();
|
|
}
|
|
|
|
|
|
virtual void LogExportedResource(const ExportedResource& resource) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.logExportedResource(transaction_, Plugins::Convert(resource.GetResourceType()),
|
|
resource.GetPublicId().c_str(),
|
|
resource.GetModality().c_str(),
|
|
resource.GetDate().c_str(),
|
|
resource.GetPatientId().c_str(),
|
|
resource.GetStudyInstanceUid().c_str(),
|
|
resource.GetSeriesInstanceUid().c_str(),
|
|
resource.GetSopInstanceUid().c_str()));
|
|
CheckNoEvent();
|
|
}
|
|
|
|
|
|
virtual bool LookupAttachment(FileInfo& attachment,
|
|
int64_t& revision,
|
|
int64_t id,
|
|
FileContentType contentType) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.lookupAttachment(transaction_, &revision, id, static_cast<int32_t>(contentType)));
|
|
CheckNoEvent();
|
|
|
|
uint32_t count;
|
|
CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
|
|
|
|
if (count == 0)
|
|
{
|
|
return false;
|
|
}
|
|
else if (count == 1)
|
|
{
|
|
OrthancPluginAttachment tmp;
|
|
CheckSuccess(that_.backend_.readAnswerAttachment(transaction_, &tmp, 0));
|
|
attachment = Convert(tmp);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
}
|
|
|
|
virtual bool LookupGlobalProperty(std::string& target,
|
|
GlobalProperty property,
|
|
bool shared) ORTHANC_OVERRIDE
|
|
{
|
|
const char* id = (shared ? "" : that_.serverIdentifier_.c_str());
|
|
|
|
CheckSuccess(that_.backend_.lookupGlobalProperty(transaction_, id, static_cast<int32_t>(property)));
|
|
CheckNoEvent();
|
|
return ReadSingleStringAnswer(target);
|
|
}
|
|
|
|
|
|
virtual bool LookupMetadata(std::string& target,
|
|
int64_t& revision,
|
|
int64_t id,
|
|
MetadataType type) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.lookupMetadata(transaction_, &revision, id, static_cast<int32_t>(type)));
|
|
CheckNoEvent();
|
|
return ReadSingleStringAnswer(target);
|
|
}
|
|
|
|
|
|
virtual bool LookupParent(int64_t& parentId,
|
|
int64_t resourceId) ORTHANC_OVERRIDE
|
|
{
|
|
uint8_t existing;
|
|
CheckSuccess(that_.backend_.lookupParent(transaction_, &existing, &parentId, resourceId));
|
|
CheckNoEvent();
|
|
return (existing != 0);
|
|
}
|
|
|
|
|
|
virtual bool LookupResource(int64_t& id,
|
|
ResourceType& type,
|
|
const std::string& publicId) ORTHANC_OVERRIDE
|
|
{
|
|
uint8_t existing;
|
|
OrthancPluginResourceType t;
|
|
CheckSuccess(that_.backend_.lookupResource(transaction_, &existing, &id, &t, publicId.c_str()));
|
|
CheckNoEvent();
|
|
|
|
if (existing == 0)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
type = Plugins::Convert(t);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
virtual bool SelectPatientToRecycle(int64_t& internalId) ORTHANC_OVERRIDE
|
|
{
|
|
uint8_t available;
|
|
CheckSuccess(that_.backend_.selectPatientToRecycle(transaction_, &available, &internalId));
|
|
CheckNoEvent();
|
|
return (available != 0);
|
|
}
|
|
|
|
|
|
virtual bool SelectPatientToRecycle(int64_t& internalId,
|
|
int64_t patientIdToAvoid) ORTHANC_OVERRIDE
|
|
{
|
|
uint8_t available;
|
|
CheckSuccess(that_.backend_.selectPatientToRecycle2(transaction_, &available, &internalId, patientIdToAvoid));
|
|
CheckNoEvent();
|
|
return (available != 0);
|
|
}
|
|
|
|
|
|
virtual void SetGlobalProperty(GlobalProperty property,
|
|
bool shared,
|
|
const std::string& value) ORTHANC_OVERRIDE
|
|
{
|
|
const char* id = (shared ? "" : that_.serverIdentifier_.c_str());
|
|
|
|
CheckSuccess(that_.backend_.setGlobalProperty(transaction_, id, static_cast<int32_t>(property), value.c_str()));
|
|
CheckNoEvent();
|
|
}
|
|
|
|
|
|
virtual void ClearMainDicomTags(int64_t id) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.clearMainDicomTags(transaction_, id));
|
|
CheckNoEvent();
|
|
}
|
|
|
|
|
|
virtual void SetMetadata(int64_t id,
|
|
MetadataType type,
|
|
const std::string& value,
|
|
int64_t revision) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.setMetadata(transaction_, id, static_cast<int32_t>(type), value.c_str(), revision));
|
|
CheckNoEvent();
|
|
}
|
|
|
|
|
|
virtual void SetProtectedPatient(int64_t internalId,
|
|
bool isProtected) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.setProtectedPatient(transaction_, internalId, (isProtected ? 1 : 0)));
|
|
CheckNoEvent();
|
|
}
|
|
|
|
|
|
virtual bool IsDiskSizeAbove(uint64_t threshold) ORTHANC_OVERRIDE
|
|
{
|
|
uint8_t tmp;
|
|
CheckSuccess(that_.backend_.isDiskSizeAbove(transaction_, &tmp, threshold));
|
|
CheckNoEvent();
|
|
return (tmp != 0);
|
|
}
|
|
|
|
|
|
virtual void ApplyLookupResources(std::list<std::string>& resourcesId,
|
|
std::list<std::string>* instancesId, // Can be NULL if not needed
|
|
const DatabaseDicomTagConstraints& lookup,
|
|
ResourceType queryLevel,
|
|
const std::set<std::string>& labels,
|
|
LabelsConstraint labelsConstraint,
|
|
uint32_t limit) ORTHANC_OVERRIDE
|
|
{
|
|
if (!labels.empty())
|
|
{
|
|
throw OrthancException(ErrorCode_InternalError); // "HasLabelsSupport()" has returned "false"
|
|
}
|
|
|
|
std::vector<OrthancPluginDatabaseConstraint> constraints;
|
|
std::vector< std::vector<const char*> > constraintsValues;
|
|
|
|
constraints.resize(lookup.GetSize());
|
|
constraintsValues.resize(lookup.GetSize());
|
|
|
|
for (size_t i = 0; i < lookup.GetSize(); i++)
|
|
{
|
|
lookup.GetConstraint(i).EncodeForPlugins(constraints[i], constraintsValues[i]);
|
|
}
|
|
|
|
CheckSuccess(that_.backend_.lookupResources(transaction_, lookup.GetSize(),
|
|
(lookup.IsEmpty() ? NULL : &constraints[0]),
|
|
Plugins::Convert(queryLevel),
|
|
limit, (instancesId == NULL ? 0 : 1)));
|
|
CheckNoEvent();
|
|
|
|
uint32_t count;
|
|
CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
|
|
|
|
resourcesId.clear();
|
|
|
|
if (instancesId != NULL)
|
|
{
|
|
instancesId->clear();
|
|
}
|
|
|
|
for (uint32_t i = 0; i < count; i++)
|
|
{
|
|
OrthancPluginMatchingResource resource;
|
|
CheckSuccess(that_.backend_.readAnswerMatchingResource(transaction_, &resource, i));
|
|
|
|
if (resource.resourceId == NULL)
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
|
|
resourcesId.push_back(resource.resourceId);
|
|
|
|
if (instancesId != NULL)
|
|
{
|
|
if (resource.someInstanceId == NULL)
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
else
|
|
{
|
|
instancesId->push_back(resource.someInstanceId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
virtual bool CreateInstance(CreateInstanceResult& result, /* out */
|
|
int64_t& instanceId, /* out */
|
|
const std::string& patient,
|
|
const std::string& study,
|
|
const std::string& series,
|
|
const std::string& instance) ORTHANC_OVERRIDE
|
|
{
|
|
OrthancPluginCreateInstanceResult output;
|
|
memset(&output, 0, sizeof(output));
|
|
|
|
CheckSuccess(that_.backend_.createInstance(transaction_, &output, patient.c_str(),
|
|
study.c_str(), series.c_str(), instance.c_str()));
|
|
CheckNoEvent();
|
|
|
|
instanceId = output.instanceId;
|
|
|
|
if (output.isNewInstance)
|
|
{
|
|
result.isNewPatient_ = output.isNewPatient;
|
|
result.isNewStudy_ = output.isNewStudy;
|
|
result.isNewSeries_ = output.isNewSeries;
|
|
result.patientId_ = output.patientId;
|
|
result.studyId_ = output.studyId;
|
|
result.seriesId_ = output.seriesId;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
virtual void SetResourcesContent(const ResourcesContent& content) ORTHANC_OVERRIDE
|
|
{
|
|
std::vector<OrthancPluginResourcesContentTags> identifierTags;
|
|
std::vector<OrthancPluginResourcesContentTags> mainDicomTags;
|
|
std::vector<OrthancPluginResourcesContentMetadata> metadata;
|
|
|
|
identifierTags.reserve(content.GetListTags().size());
|
|
mainDicomTags.reserve(content.GetListTags().size());
|
|
metadata.reserve(content.GetListMetadata().size());
|
|
|
|
for (ResourcesContent::ListTags::const_iterator
|
|
it = content.GetListTags().begin(); it != content.GetListTags().end(); ++it)
|
|
{
|
|
OrthancPluginResourcesContentTags tmp;
|
|
tmp.resource = it->GetResourceId();
|
|
tmp.group = it->GetTag().GetGroup();
|
|
tmp.element = it->GetTag().GetElement();
|
|
tmp.value = it->GetValue().c_str();
|
|
|
|
if (it->IsIdentifier())
|
|
{
|
|
identifierTags.push_back(tmp);
|
|
}
|
|
else
|
|
{
|
|
mainDicomTags.push_back(tmp);
|
|
}
|
|
}
|
|
|
|
for (ResourcesContent::ListMetadata::const_iterator
|
|
it = content.GetListMetadata().begin(); it != content.GetListMetadata().end(); ++it)
|
|
{
|
|
OrthancPluginResourcesContentMetadata tmp;
|
|
tmp.resource = it->GetResourceId();
|
|
tmp.metadata = it->GetType();
|
|
tmp.value = it->GetValue().c_str();
|
|
metadata.push_back(tmp);
|
|
}
|
|
|
|
assert(identifierTags.size() + mainDicomTags.size() == content.GetListTags().size() &&
|
|
metadata.size() == content.GetListMetadata().size());
|
|
|
|
CheckSuccess(that_.backend_.setResourcesContent(transaction_,
|
|
identifierTags.size(),
|
|
(identifierTags.empty() ? NULL : &identifierTags[0]),
|
|
mainDicomTags.size(),
|
|
(mainDicomTags.empty() ? NULL : &mainDicomTags[0]),
|
|
metadata.size(),
|
|
(metadata.empty() ? NULL : &metadata[0])));
|
|
CheckNoEvent();
|
|
}
|
|
|
|
|
|
virtual void GetChildrenMetadata(std::list<std::string>& target,
|
|
int64_t resourceId,
|
|
MetadataType metadata) ORTHANC_OVERRIDE
|
|
{
|
|
CheckSuccess(that_.backend_.getChildrenMetadata(transaction_, resourceId, static_cast<int32_t>(metadata)));
|
|
CheckNoEvent();
|
|
ReadStringAnswers(target);
|
|
}
|
|
|
|
|
|
virtual int64_t GetLastChangeIndex() ORTHANC_OVERRIDE
|
|
{
|
|
int64_t tmp;
|
|
CheckSuccess(that_.backend_.getLastChangeIndex(transaction_, &tmp));
|
|
CheckNoEvent();
|
|
return tmp;
|
|
}
|
|
|
|
|
|
virtual bool LookupResourceAndParent(int64_t& id,
|
|
ResourceType& type,
|
|
std::string& parentPublicId,
|
|
const std::string& publicId) ORTHANC_OVERRIDE
|
|
{
|
|
uint8_t isExisting;
|
|
OrthancPluginResourceType tmpType;
|
|
CheckSuccess(that_.backend_.lookupResourceAndParent(transaction_, &isExisting, &id, &tmpType, publicId.c_str()));
|
|
CheckNoEvent();
|
|
|
|
if (isExisting)
|
|
{
|
|
type = Plugins::Convert(tmpType);
|
|
|
|
uint32_t count;
|
|
CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count));
|
|
|
|
if (count > 1)
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
case ResourceType_Patient:
|
|
// A patient has no parent
|
|
if (count == 1)
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
break;
|
|
|
|
case ResourceType_Study:
|
|
case ResourceType_Series:
|
|
case ResourceType_Instance:
|
|
if (count == 0)
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
else
|
|
{
|
|
const char* value = NULL;
|
|
CheckSuccess(that_.backend_.readAnswerString(transaction_, &value, 0));
|
|
if (value == NULL)
|
|
{
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
else
|
|
{
|
|
parentPublicId.assign(value);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
throw OrthancException(ErrorCode_DatabasePlugin);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
virtual void AddLabel(int64_t resource,
|
|
const std::string& label) ORTHANC_OVERRIDE
|
|
{
|
|
throw OrthancException(ErrorCode_InternalError); // Not supported
|
|
}
|
|
|
|
|
|
virtual void RemoveLabel(int64_t resource,
|
|
const std::string& label) ORTHANC_OVERRIDE
|
|
{
|
|
throw OrthancException(ErrorCode_InternalError); // Not supported
|
|
}
|
|
|
|
|
|
virtual void ListLabels(std::set<std::string>& target,
|
|
int64_t resource) ORTHANC_OVERRIDE
|
|
{
|
|
throw OrthancException(ErrorCode_InternalError); // Not supported
|
|
}
|
|
|
|
|
|
virtual void ListAllLabels(std::set<std::string>& target) ORTHANC_OVERRIDE
|
|
{
|
|
throw OrthancException(ErrorCode_InternalError); // Not supported
|
|
}
|
|
|
|
virtual void StoreKeyValue(const std::string& storeId,
|
|
const std::string& key,
|
|
const void* value,
|
|
size_t valueSize) ORTHANC_OVERRIDE
|
|
{
|
|
throw OrthancException(ErrorCode_InternalError); // Not supported
|
|
}
|
|
|
|
virtual void DeleteKeyValue(const std::string& storeId,
|
|
const std::string& key) ORTHANC_OVERRIDE
|
|
{
|
|
throw OrthancException(ErrorCode_InternalError); // Not supported
|
|
}
|
|
|
|
virtual bool GetKeyValue(std::string& value,
|
|
const std::string& storeId,
|
|
const std::string& key) ORTHANC_OVERRIDE
|
|
{
|
|
throw OrthancException(ErrorCode_InternalError); // Not supported
|
|
}
|
|
|
|
virtual void ListKeysValues(std::list<std::string>& keys,
|
|
std::list<std::string>& values,
|
|
const std::string& storeId,
|
|
bool first,
|
|
const std::string& from,
|
|
uint64_t limit) ORTHANC_OVERRIDE
|
|
{
|
|
throw OrthancException(ErrorCode_InternalError); // Not supported
|
|
}
|
|
|
|
virtual void EnqueueValue(const std::string& queueId,
|
|
const void* value,
|
|
size_t valueSize) ORTHANC_OVERRIDE
|
|
{
|
|
throw OrthancException(ErrorCode_InternalError); // Not supported
|
|
}
|
|
|
|
virtual bool DequeueValue(std::string& value,
|
|
const std::string& queueId,
|
|
QueueOrigin origin) ORTHANC_OVERRIDE
|
|
{
|
|
throw OrthancException(ErrorCode_InternalError); // Not supported
|
|
}
|
|
|
|
virtual uint64_t GetQueueSize(const std::string& queueId) ORTHANC_OVERRIDE
|
|
{
|
|
throw OrthancException(ErrorCode_InternalError); // Not supported
|
|
}
|
|
|
|
virtual void GetAttachmentCustomData(std::string& customData,
|
|
const std::string& attachmentUuid) ORTHANC_OVERRIDE
|
|
{
|
|
throw OrthancException(ErrorCode_NotImplemented); // Not supported
|
|
}
|
|
|
|
virtual void SetAttachmentCustomData(const std::string& attachmentUuid,
|
|
const void* customData,
|
|
size_t customDataSize) ORTHANC_OVERRIDE
|
|
{
|
|
throw OrthancException(ErrorCode_NotImplemented); // Not supported
|
|
}
|
|
};
|
|
|
|
|
|
void OrthancPluginDatabaseV3::CheckSuccess(OrthancPluginErrorCode code) const
|
|
{
|
|
if (code != OrthancPluginErrorCode_Success)
|
|
{
|
|
errorDictionary_.LogError(code, true);
|
|
throw OrthancException(static_cast<ErrorCode>(code));
|
|
}
|
|
}
|
|
|
|
|
|
OrthancPluginDatabaseV3::OrthancPluginDatabaseV3(SharedLibrary& library,
|
|
PluginsErrorDictionary& errorDictionary,
|
|
const OrthancPluginDatabaseBackendV3* backend,
|
|
size_t backendSize,
|
|
void* database,
|
|
const std::string& serverIdentifier) :
|
|
library_(library),
|
|
errorDictionary_(errorDictionary),
|
|
database_(database),
|
|
serverIdentifier_(serverIdentifier)
|
|
|
|
{
|
|
CLOG(INFO, PLUGINS) << "Identifier of this Orthanc server for the global properties "
|
|
<< "of the custom database: \"" << serverIdentifier << "\"";
|
|
|
|
if (backendSize >= sizeof(backend_))
|
|
{
|
|
memcpy(&backend_, backend, sizeof(backend_));
|
|
}
|
|
else
|
|
{
|
|
// Not all the primitives are implemented by the plugin
|
|
memset(&backend_, 0, sizeof(backend_));
|
|
memcpy(&backend_, backend, backendSize);
|
|
}
|
|
|
|
// Sanity checks
|
|
CHECK_FUNCTION_EXISTS(backend_, readAnswersCount);
|
|
CHECK_FUNCTION_EXISTS(backend_, readAnswerAttachment);
|
|
CHECK_FUNCTION_EXISTS(backend_, readAnswerChange);
|
|
CHECK_FUNCTION_EXISTS(backend_, readAnswerDicomTag);
|
|
CHECK_FUNCTION_EXISTS(backend_, readAnswerExportedResource);
|
|
CHECK_FUNCTION_EXISTS(backend_, readAnswerInt32);
|
|
CHECK_FUNCTION_EXISTS(backend_, readAnswerInt64);
|
|
CHECK_FUNCTION_EXISTS(backend_, readAnswerMatchingResource);
|
|
CHECK_FUNCTION_EXISTS(backend_, readAnswerMetadata);
|
|
CHECK_FUNCTION_EXISTS(backend_, readAnswerString);
|
|
|
|
CHECK_FUNCTION_EXISTS(backend_, readEventsCount);
|
|
CHECK_FUNCTION_EXISTS(backend_, readEvent);
|
|
|
|
CHECK_FUNCTION_EXISTS(backend_, open);
|
|
CHECK_FUNCTION_EXISTS(backend_, close);
|
|
CHECK_FUNCTION_EXISTS(backend_, destructDatabase);
|
|
CHECK_FUNCTION_EXISTS(backend_, getDatabaseVersion);
|
|
CHECK_FUNCTION_EXISTS(backend_, upgradeDatabase);
|
|
CHECK_FUNCTION_EXISTS(backend_, startTransaction);
|
|
CHECK_FUNCTION_EXISTS(backend_, destructTransaction);
|
|
CHECK_FUNCTION_EXISTS(backend_, hasRevisionsSupport);
|
|
|
|
CHECK_FUNCTION_EXISTS(backend_, rollback);
|
|
CHECK_FUNCTION_EXISTS(backend_, commit);
|
|
|
|
CHECK_FUNCTION_EXISTS(backend_, addAttachment);
|
|
CHECK_FUNCTION_EXISTS(backend_, clearChanges);
|
|
CHECK_FUNCTION_EXISTS(backend_, clearExportedResources);
|
|
CHECK_FUNCTION_EXISTS(backend_, clearMainDicomTags);
|
|
CHECK_FUNCTION_EXISTS(backend_, createInstance);
|
|
CHECK_FUNCTION_EXISTS(backend_, deleteAttachment);
|
|
CHECK_FUNCTION_EXISTS(backend_, deleteMetadata);
|
|
CHECK_FUNCTION_EXISTS(backend_, deleteResource);
|
|
CHECK_FUNCTION_EXISTS(backend_, getAllMetadata);
|
|
CHECK_FUNCTION_EXISTS(backend_, getAllPublicIds);
|
|
CHECK_FUNCTION_EXISTS(backend_, getAllPublicIdsWithLimit);
|
|
CHECK_FUNCTION_EXISTS(backend_, getChanges);
|
|
CHECK_FUNCTION_EXISTS(backend_, getChildrenInternalId);
|
|
CHECK_FUNCTION_EXISTS(backend_, getChildrenMetadata);
|
|
CHECK_FUNCTION_EXISTS(backend_, getChildrenPublicId);
|
|
CHECK_FUNCTION_EXISTS(backend_, getExportedResources);
|
|
CHECK_FUNCTION_EXISTS(backend_, getLastChange);
|
|
CHECK_FUNCTION_EXISTS(backend_, getLastChangeIndex);
|
|
CHECK_FUNCTION_EXISTS(backend_, getLastExportedResource);
|
|
CHECK_FUNCTION_EXISTS(backend_, getMainDicomTags);
|
|
CHECK_FUNCTION_EXISTS(backend_, getPublicId);
|
|
CHECK_FUNCTION_EXISTS(backend_, getResourceType);
|
|
CHECK_FUNCTION_EXISTS(backend_, getResourcesCount);
|
|
CHECK_FUNCTION_EXISTS(backend_, getTotalCompressedSize);
|
|
CHECK_FUNCTION_EXISTS(backend_, getTotalUncompressedSize);
|
|
CHECK_FUNCTION_EXISTS(backend_, isDiskSizeAbove);
|
|
CHECK_FUNCTION_EXISTS(backend_, isExistingResource);
|
|
CHECK_FUNCTION_EXISTS(backend_, isProtectedPatient);
|
|
CHECK_FUNCTION_EXISTS(backend_, listAvailableAttachments);
|
|
CHECK_FUNCTION_EXISTS(backend_, logChange);
|
|
CHECK_FUNCTION_EXISTS(backend_, logExportedResource);
|
|
CHECK_FUNCTION_EXISTS(backend_, lookupAttachment);
|
|
CHECK_FUNCTION_EXISTS(backend_, lookupGlobalProperty);
|
|
CHECK_FUNCTION_EXISTS(backend_, lookupMetadata);
|
|
CHECK_FUNCTION_EXISTS(backend_, lookupParent);
|
|
CHECK_FUNCTION_EXISTS(backend_, lookupResource);
|
|
CHECK_FUNCTION_EXISTS(backend_, lookupResourceAndParent);
|
|
CHECK_FUNCTION_EXISTS(backend_, lookupResources);
|
|
CHECK_FUNCTION_EXISTS(backend_, selectPatientToRecycle);
|
|
CHECK_FUNCTION_EXISTS(backend_, selectPatientToRecycle2);
|
|
CHECK_FUNCTION_EXISTS(backend_, setGlobalProperty);
|
|
CHECK_FUNCTION_EXISTS(backend_, setMetadata);
|
|
CHECK_FUNCTION_EXISTS(backend_, setProtectedPatient);
|
|
CHECK_FUNCTION_EXISTS(backend_, setResourcesContent);
|
|
}
|
|
|
|
|
|
OrthancPluginDatabaseV3::~OrthancPluginDatabaseV3()
|
|
{
|
|
if (database_ != NULL)
|
|
{
|
|
OrthancPluginErrorCode code = backend_.destructDatabase(database_);
|
|
if (code != OrthancPluginErrorCode_Success)
|
|
{
|
|
// Don't throw exception in destructors
|
|
errorDictionary_.LogError(code, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void OrthancPluginDatabaseV3::Open()
|
|
{
|
|
CheckSuccess(backend_.open(database_));
|
|
|
|
// update the db capabilities
|
|
uint8_t hasRevisions;
|
|
CheckSuccess(backend_.hasRevisionsSupport(database_, &hasRevisions));
|
|
dbCapabilities_.SetRevisionsSupport(hasRevisions != 0);
|
|
}
|
|
|
|
|
|
void OrthancPluginDatabaseV3::Close()
|
|
{
|
|
CheckSuccess(backend_.close(database_));
|
|
}
|
|
|
|
|
|
IDatabaseWrapper::ITransaction* OrthancPluginDatabaseV3::StartTransaction(TransactionType type,
|
|
IDatabaseListener& listener)
|
|
{
|
|
switch (type)
|
|
{
|
|
case TransactionType_ReadOnly:
|
|
return new Transaction(*this, listener, OrthancPluginDatabaseTransactionType_ReadOnly);
|
|
|
|
case TransactionType_ReadWrite:
|
|
return new Transaction(*this, listener, OrthancPluginDatabaseTransactionType_ReadWrite);
|
|
|
|
default:
|
|
throw OrthancException(ErrorCode_InternalError);
|
|
}
|
|
}
|
|
|
|
|
|
unsigned int OrthancPluginDatabaseV3::GetDatabaseVersion()
|
|
{
|
|
uint32_t version = 0;
|
|
CheckSuccess(backend_.getDatabaseVersion(database_, &version));
|
|
return version;
|
|
}
|
|
|
|
|
|
void OrthancPluginDatabaseV3::Upgrade(unsigned int targetVersion,
|
|
IPluginStorageArea& storageArea)
|
|
{
|
|
VoidDatabaseListener listener;
|
|
|
|
if (backend_.upgradeDatabase != NULL)
|
|
{
|
|
Transaction transaction(*this, listener, OrthancPluginDatabaseTransactionType_ReadWrite);
|
|
|
|
OrthancPluginErrorCode code = backend_.upgradeDatabase(
|
|
database_, reinterpret_cast<OrthancPluginStorageArea*>(&storageArea),
|
|
static_cast<uint32_t>(targetVersion));
|
|
|
|
if (code == OrthancPluginErrorCode_Success)
|
|
{
|
|
transaction.Commit(0);
|
|
}
|
|
else
|
|
{
|
|
transaction.Rollback();
|
|
errorDictionary_.LogError(code, true);
|
|
throw OrthancException(static_cast<ErrorCode>(code));
|
|
}
|
|
}
|
|
}
|
|
|
|
uint64_t OrthancPluginDatabaseV3::MeasureLatency()
|
|
{
|
|
throw OrthancException(ErrorCode_NotImplemented);
|
|
}
|
|
|
|
}
|