# HG changeset patch # User Sebastien Jodogne # Date 1616063170 -3600 # Node ID da2e0a457eae4953977cb4143c98452841e09a10 # Parent cc64385593efc41f68c8d7a385d40e4d13f436a0 OrthancPluginDatabaseV3::Transaction is fully implemented diff -r cc64385593ef -r da2e0a457eae OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp --- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp Tue Mar 16 17:58:16 2021 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp Thu Mar 18 11:26:10 2021 +0100 @@ -40,6 +40,7 @@ #include "../../../OrthancFramework/Sources/Logging.h" #include "../../../OrthancFramework/Sources/OrthancException.h" +#include "../../Sources/Database/ResourcesContent.h" #include "../../Sources/Database/VoidDatabaseListener.h" #include "PluginsEnumerations.h" @@ -82,15 +83,15 @@ } } - - std::string ReadOneStringAnswer() + + bool ReadSingleStringAnswer(std::string& target) { uint32_t count; CheckSuccess(that_.backend_.readAnswersCount(transaction_, &count)); if (count == 0) { - throw OrthancException(ErrorCode_InexistentItem); + return false; } else if (count == 1) { @@ -102,7 +103,8 @@ } else { - return value; + target.assign(value); + return true; } } else @@ -111,6 +113,27 @@ } } + + 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) { @@ -432,7 +455,16 @@ virtual std::string GetPublicId(int64_t resourceId) ORTHANC_OVERRIDE { CheckSuccess(that_.backend_.getPublicId(transaction_, resourceId)); - return ReadOneStringAnswer(); + + std::string s; + if (ReadSingleStringAnswer(s)) + { + return s; + } + else + { + throw OrthancException(ErrorCode_InexistentItem); + } } @@ -507,25 +539,62 @@ { CheckSuccess(that_.backend_.logChange(transaction_, static_cast(change.GetChangeType()), internalId, Plugins::Convert(change.GetResourceType()), - change.GetPublicId().c_str(), change.GetDate().c_str())); + change.GetDate().c_str())); } 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())); + } virtual bool LookupAttachment(FileInfo& attachment, int64_t id, FileContentType contentType) ORTHANC_OVERRIDE { + CheckSuccess(that_.backend_.lookupAttachment(transaction_, id, static_cast(contentType))); + + 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 = FileInfo(tmp.uuid, + static_cast(tmp.contentType), + tmp.uncompressedSize, + tmp.uncompressedHash, + static_cast(tmp.compressionType), + tmp.compressedSize, + tmp.compressedHash); + return true; + } + else + { + throw OrthancException(ErrorCode_DatabasePlugin); + } } virtual bool LookupGlobalProperty(std::string& target, GlobalProperty property) ORTHANC_OVERRIDE { + CheckSuccess(that_.backend_.lookupGlobalProperty(transaction_, static_cast(property))); + return ReadSingleStringAnswer(target); } @@ -533,12 +602,16 @@ int64_t id, MetadataType type) ORTHANC_OVERRIDE { + CheckSuccess(that_.backend_.lookupMetadata(transaction_, id, static_cast(type))); + return ReadSingleStringAnswer(target); } virtual bool LookupParent(int64_t& parentId, int64_t resourceId) ORTHANC_OVERRIDE { + CheckSuccess(that_.backend_.lookupParent(transaction_, resourceId)); + return ReadSingleInt64Answer(parentId); } @@ -546,28 +619,36 @@ ResourceType& type, const std::string& publicId) ORTHANC_OVERRIDE { + CheckSuccess(that_.backend_.lookupResource(transaction_, Plugins::Convert(type), publicId.c_str())); + return ReadSingleInt64Answer(id); } virtual bool SelectPatientToRecycle(int64_t& internalId) ORTHANC_OVERRIDE { + CheckSuccess(that_.backend_.selectPatientToRecycle(transaction_)); + return ReadSingleInt64Answer(internalId); } virtual bool SelectPatientToRecycle(int64_t& internalId, int64_t patientIdToAvoid) ORTHANC_OVERRIDE { + CheckSuccess(that_.backend_.selectPatientToRecycle2(transaction_, patientIdToAvoid)); + return ReadSingleInt64Answer(internalId); } virtual void SetGlobalProperty(GlobalProperty property, const std::string& value) ORTHANC_OVERRIDE { + CheckSuccess(that_.backend_.setGlobalProperty(transaction_, static_cast(property), value.c_str())); } virtual void ClearMainDicomTags(int64_t id) ORTHANC_OVERRIDE { + CheckSuccess(that_.backend_.clearMainDicomTags(transaction_, id)); } @@ -575,17 +656,22 @@ MetadataType type, const std::string& value) ORTHANC_OVERRIDE { + CheckSuccess(that_.backend_.setMetadata(transaction_, id, static_cast(type), value.c_str())); } virtual void SetProtectedPatient(int64_t internalId, bool isProtected) ORTHANC_OVERRIDE { + CheckSuccess(that_.backend_.setProtectedPatient(transaction_, internalId, (isProtected ? 1 : 0))); } virtual bool IsDiskSizeAbove(uint64_t threshold) ORTHANC_OVERRIDE { + uint8_t tmp; + CheckSuccess(that_.backend_.isDiskSizeAbove(transaction_, &tmp, threshold)); + return (tmp != 0); } @@ -595,6 +681,56 @@ ResourceType queryLevel, size_t limit) ORTHANC_OVERRIDE { + std::vector constraints; + std::vector< std::vector > constraintsValues; + + constraints.resize(lookup.size()); + constraintsValues.resize(lookup.size()); + + for (size_t i = 0; i < lookup.size(); i++) + { + lookup[i].EncodeForPlugins(constraints[i], constraintsValues[i]); + } + + CheckSuccess(that_.backend_.lookupResources(transaction_, lookup.size(), + (lookup.empty() ? NULL : &constraints[0]), + Plugins::Convert(queryLevel), + limit, (instancesId == NULL ? 0 : 1))); + + 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); + } + } + } } @@ -605,11 +741,81 @@ 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())); + + 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 identifierTags; + std::vector mainDicomTags; + std::vector 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->resourceId_; + tmp.group = it->tag_.GetGroup(); + tmp.element = it->tag_.GetElement(); + tmp.value = it->value_.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->resourceId_; + tmp.metadata = it->metadata_; + tmp.value = it->value_.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]))); } @@ -617,12 +823,16 @@ int64_t resourceId, MetadataType metadata) ORTHANC_OVERRIDE { + CheckSuccess(that_.backend_.getChildrenMetadata(transaction_, resourceId, static_cast(metadata))); + ReadStringAnswers(target); } virtual int64_t GetLastChangeIndex() ORTHANC_OVERRIDE { - + int64_t tmp; + CheckSuccess(that_.backend_.getLastChangeIndex(transaction_, &tmp)); + return tmp; } @@ -631,6 +841,64 @@ 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())); + + 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; + } } }; diff -r cc64385593ef -r da2e0a457eae OrthancServer/Plugins/Include/orthanc/OrthancCDatabasePlugin.h --- a/OrthancServer/Plugins/Include/orthanc/OrthancCDatabasePlugin.h Tue Mar 16 17:58:16 2021 +0100 +++ b/OrthancServer/Plugins/Include/orthanc/OrthancCDatabasePlugin.h Thu Mar 18 11:26:10 2021 +0100 @@ -994,10 +994,14 @@ **/ OrthancPluginErrorCode (*readAnswersCount) (OrthancPluginDatabaseTransaction* transaction, - uint32_t* target); + uint32_t* target /* out */); + + OrthancPluginErrorCode (*readAnswerAttachment) (OrthancPluginDatabaseTransaction* transaction, + OrthancPluginAttachment* target /* out */, + uint32_t index); OrthancPluginErrorCode (*readAnswerChange) (OrthancPluginDatabaseTransaction* transaction, - OrthancPluginChange* target, + OrthancPluginChange* target /* out */, uint32_t index); OrthancPluginErrorCode (*readAnswerDicomTag) (OrthancPluginDatabaseTransaction* transaction, @@ -1007,23 +1011,28 @@ uint32_t index); OrthancPluginErrorCode (*readAnswerExportedResource) (OrthancPluginDatabaseTransaction* transaction, - OrthancPluginExportedResource* target, + OrthancPluginExportedResource* target /* out */, uint32_t index); OrthancPluginErrorCode (*readAnswerInt32) (OrthancPluginDatabaseTransaction* transaction, - int32_t* target, + int32_t* target /* out */, uint32_t index); OrthancPluginErrorCode (*readAnswerInt64) (OrthancPluginDatabaseTransaction* transaction, - int64_t* target, + int64_t* target /* out */, uint32_t index); + OrthancPluginErrorCode (*readAnswerMatchingResource) (OrthancPluginDatabaseTransaction* transaction, + OrthancPluginMatchingResource* target /* out */, + uint32_t index); + OrthancPluginErrorCode (*readAnswerMetadata) (OrthancPluginDatabaseTransaction* transaction, - int32_t* metadata, - const char** value, + int32_t* metadata /* out */, + const char** value /* out */, uint32_t index); + OrthancPluginErrorCode (*readAnswerString) (OrthancPluginDatabaseTransaction* transaction, - const char** target, + const char** target /* out */, uint32_t index); @@ -1039,14 +1048,14 @@ OrthancPluginErrorCode (*destructDatabase) (OrthancPluginDatabaseContext* database); OrthancPluginErrorCode (*getDatabaseVersion) (OrthancPluginDatabaseContext* database, - uint32_t* target); + uint32_t* target /* out */); OrthancPluginErrorCode (*upgradeDatabase) (OrthancPluginDatabaseContext* database, OrthancPluginStorageArea* storageArea, - uint32_t target); + uint32_t targetVersion); OrthancPluginErrorCode (*startTransaction) (OrthancPluginDatabaseContext* database, - OrthancPluginDatabaseTransaction** target, + OrthancPluginDatabaseTransaction** target /* out */, _OrthancPluginDatabaseTransactionType type); OrthancPluginErrorCode (*destructTransaction) (OrthancPluginDatabaseTransaction* transaction); @@ -1070,6 +1079,16 @@ OrthancPluginErrorCode (*clearExportedResources) (OrthancPluginDatabaseTransaction* transaction); + OrthancPluginErrorCode (*clearMainDicomTags) (OrthancPluginDatabaseTransaction* transaction, + int64_t resourceId); + + OrthancPluginErrorCode (*createInstance) (OrthancPluginDatabaseTransaction* transaction, + OrthancPluginCreateInstanceResult* target /* out */, + const char* hashPatient, + const char* hashStudy, + const char* hashSeries, + const char* hashInstance); + OrthancPluginErrorCode (*deleteAttachment) (OrthancPluginDatabaseTransaction* transaction, int64_t id, int32_t contentType); @@ -1097,7 +1116,7 @@ /* Answers are read using "readAnswerChange()" */ OrthancPluginErrorCode (*getChanges) (OrthancPluginDatabaseTransaction* transaction, - uint8_t* targetDone, + uint8_t* targetDone /* out */, int64_t since, uint32_t maxResults); @@ -1106,18 +1125,26 @@ int64_t id); /* Answers are read using "readAnswerString()" */ + OrthancPluginErrorCode (*getChildrenMetadata) (OrthancPluginDatabaseTransaction* transaction, + int64_t resourceId, + int32_t metadata); + + /* Answers are read using "readAnswerString()" */ OrthancPluginErrorCode (*getChildrenPublicId) (OrthancPluginDatabaseTransaction* transaction, int64_t id); /* Answers are read using "readAnswerExportedResource()" */ OrthancPluginErrorCode (*getExportedResources) (OrthancPluginDatabaseTransaction* transaction, - uint8_t* targetDone, + uint8_t* targetDone /* out */, int64_t since, uint32_t maxResults); /* Answer is read using "readAnswerChange()" */ OrthancPluginErrorCode (*getLastChange) (OrthancPluginDatabaseTransaction* transaction); + OrthancPluginErrorCode (*getLastChangeIndex) (OrthancPluginDatabaseTransaction* transaction, + int64_t* target /* out */); + /* Answer is read using "readAnswerExportedResource()" */ OrthancPluginErrorCode (*getLastExportedResource) (OrthancPluginDatabaseTransaction* transaction); @@ -1130,25 +1157,29 @@ int64_t internalId); OrthancPluginErrorCode (*getResourcesCount) (OrthancPluginDatabaseTransaction* transaction, - uint64_t* target, + uint64_t* target /* out */, OrthancPluginResourceType resourceType); OrthancPluginErrorCode (*getResourceType) (OrthancPluginDatabaseTransaction* transaction, - OrthancPluginResourceType* target, + OrthancPluginResourceType* target /* out */, uint64_t resourceId); OrthancPluginErrorCode (*getTotalCompressedSize) (OrthancPluginDatabaseTransaction* transaction, - uint64_t* target); + uint64_t* target /* out */); OrthancPluginErrorCode (*getTotalUncompressedSize) (OrthancPluginDatabaseTransaction* transaction, - uint64_t* target); + uint64_t* target /* out */); + + OrthancPluginErrorCode (*isDiskSizeAbove) (OrthancPluginDatabaseTransaction* transaction, + uint8_t* target /* out */, + uint64_t threshold); OrthancPluginErrorCode (*isExistingResource) (OrthancPluginDatabaseTransaction* transaction, - uint8_t* target, + uint8_t* target /* out */, int64_t resourceId); OrthancPluginErrorCode (*isProtectedPatient) (OrthancPluginDatabaseTransaction* transaction, - uint8_t* target, + uint8_t* target /* out */, int64_t resourceId); /* Answer is read using "readAnswerInt32()" */ @@ -1157,11 +1188,87 @@ OrthancPluginErrorCode (*logChange) (OrthancPluginDatabaseTransaction* transaction, int32_t changeType, - int64_t internalId, + int64_t resourceId, OrthancPluginResourceType resourceType, - const char* publicId, const char* date); + + OrthancPluginErrorCode (*logExportedResource) (OrthancPluginDatabaseTransaction* transaction, + OrthancPluginResourceType resourceType, + const char* publicId, + const char* modality, + const char* date, + const char* patientId, + const char* studyInstanceUid, + const char* seriesInstanceUid, + const char* sopInstanceUid); + + /* Answer is read using "readAnswerAttachment()" */ + OrthancPluginErrorCode (*lookupAttachment) (OrthancPluginDatabaseTransaction* transaction, + int64_t resourceId, + int32_t contentType); + + /* Answer is read using "readAnswerString()" */ + OrthancPluginErrorCode (*lookupGlobalProperty) (OrthancPluginDatabaseTransaction* transaction, + int32_t property); + /* Answer is read using "readAnswerString()" */ + OrthancPluginErrorCode (*lookupMetadata) (OrthancPluginDatabaseTransaction* transaction, + int64_t id, + int32_t metadata); + + /* Answer is read using "readAnswerInt64()" */ + OrthancPluginErrorCode (*lookupParent) (OrthancPluginDatabaseTransaction* transaction, + int64_t id); + + /* Answer is read using "readAnswerInt64()" */ + OrthancPluginErrorCode (*lookupResource) (OrthancPluginDatabaseTransaction* transaction, + OrthancPluginResourceType level, + const char* publicId); + + /* Answers are read using "readAnswerMatchingResource()" */ + OrthancPluginErrorCode (*lookupResources) (OrthancPluginDatabaseTransaction* transaction, + uint32_t constraintsCount, + const OrthancPluginDatabaseConstraint* constraints, + OrthancPluginResourceType queryLevel, + uint32_t limit, + uint8_t requestSomeInstanceId); + + /* The public ID of the parent resource is read using "readAnswerString()" */ + OrthancPluginErrorCode (*lookupResourceAndParent) (OrthancPluginDatabaseTransaction* transaction, + uint8_t* isExisting /* out */, + int64_t* id /* out */, + OrthancPluginResourceType* type /* out */, + const char* publicId); + + /* Answer is read using "readAnswerInt64()" */ + OrthancPluginErrorCode (*selectPatientToRecycle) (OrthancPluginDatabaseTransaction* transaction); + + /* Answer is read using "readAnswerInt64()" */ + OrthancPluginErrorCode (*selectPatientToRecycle2) (OrthancPluginDatabaseTransaction* transaction, + int64_t patientIdToAvoid); + + OrthancPluginErrorCode (*setGlobalProperty) (OrthancPluginDatabaseTransaction* transaction, + int32_t property, + const char* value); + + OrthancPluginErrorCode (*setMetadata) (OrthancPluginDatabaseTransaction* transaction, + int64_t id, + int32_t metadata, + const char* value); + + OrthancPluginErrorCode (*setProtectedPatient) (OrthancPluginDatabaseTransaction* transaction, + int64_t id, + uint8_t isProtected); + + OrthancPluginErrorCode (*setResourcesContent) (OrthancPluginDatabaseTransaction* transaction, + uint32_t countIdentifierTags, + const OrthancPluginResourcesContentTags* identifierTags, + uint32_t countMainDicomTags, + const OrthancPluginResourcesContentTags* mainDicomTags, + uint32_t countMetadata, + const OrthancPluginResourcesContentMetadata* metadata); + + } OrthancPluginDatabaseBackendV3; /*