# HG changeset patch # User Sebastien Jodogne # Date 1445332970 -7200 # Node ID 9d8bb6bc28902f3f69ecc1aa19c62adec96acec7 # Parent d72cf0c11f422870bc88688f5a9a551fccc0b704# Parent a7c05bbfaf6a991a857e15aad040bf96ade62fe9 integration db-changes->mainline diff -r d72cf0c11f42 -r 9d8bb6bc2890 CMakeLists.txt diff -r d72cf0c11f42 -r 9d8bb6bc2890 Core/DicomFormat/DicomMap.cpp --- a/Core/DicomFormat/DicomMap.cpp Fri Oct 16 17:26:11 2015 +0200 +++ b/Core/DicomFormat/DicomMap.cpp Tue Oct 20 11:22:50 2015 +0200 @@ -57,10 +57,10 @@ { //DicomTag(0x0010, 0x1020), // PatientSize //DicomTag(0x0010, 0x1030) // PatientWeight - DicomTag(0x0008, 0x0020), // StudyDate + DICOM_TAG_STUDY_DATE, DicomTag(0x0008, 0x0030), // StudyTime - DicomTag(0x0008, 0x1030), // StudyDescription DicomTag(0x0020, 0x0010), // StudyID + DICOM_TAG_STUDY_DESCRIPTION, DICOM_TAG_ACCESSION_NUMBER, DICOM_TAG_STUDY_INSTANCE_UID }; @@ -73,7 +73,7 @@ DicomTag(0x0008, 0x0060), // Modality DicomTag(0x0008, 0x0070), // Manufacturer DicomTag(0x0008, 0x1010), // StationName - DicomTag(0x0008, 0x103e), // SeriesDescription + DICOM_TAG_SERIES_DESCRIPTION, DicomTag(0x0018, 0x0015), // BodyPartExamined DicomTag(0x0018, 0x0024), // SequenceName DicomTag(0x0018, 0x1030), // ProtocolName diff -r d72cf0c11f42 -r 9d8bb6bc2890 Core/DicomFormat/DicomTag.cpp --- a/Core/DicomFormat/DicomTag.cpp Fri Oct 16 17:26:11 2015 +0200 +++ b/Core/DicomFormat/DicomTag.cpp Tue Oct 20 11:22:50 2015 +0200 @@ -243,14 +243,4 @@ throw OrthancException(ErrorCode_ParameterOutOfRange); } } - - - bool DicomTag::IsIdentifier() const - { - return (*this == DICOM_TAG_PATIENT_ID || - *this == DICOM_TAG_STUDY_INSTANCE_UID || - *this == DICOM_TAG_ACCESSION_NUMBER || - *this == DICOM_TAG_SERIES_INSTANCE_UID || - *this == DICOM_TAG_SOP_INSTANCE_UID); - } } diff -r d72cf0c11f42 -r 9d8bb6bc2890 Core/DicomFormat/DicomTag.h --- a/Core/DicomFormat/DicomTag.h Fri Oct 16 17:26:11 2015 +0200 +++ b/Core/DicomFormat/DicomTag.h Tue Oct 20 11:22:50 2015 +0200 @@ -86,8 +86,6 @@ static void AddTagsForModule(std::set& target, DicomModule module); - - bool IsIdentifier() const; }; // Aliases for the most useful tags @@ -109,6 +107,9 @@ static const DicomTag DICOM_TAG_PATIENT_NAME(0x0010, 0x0010); static const DicomTag DICOM_TAG_ENCAPSULATED_DOCUMENT(0x0042, 0x0011); + static const DicomTag DICOM_TAG_STUDY_DESCRIPTION(0x0008, 0x1030); + static const DicomTag DICOM_TAG_SERIES_DESCRIPTION(0x0008, 0x103e); + // The following is used for "modify/anonymize" operations static const DicomTag DICOM_TAG_SOP_CLASS_UID(0x0008, 0x0016); static const DicomTag DICOM_TAG_MEDIA_STORAGE_SOP_CLASS_UID(0x0002, 0x0002); diff -r d72cf0c11f42 -r 9d8bb6bc2890 NEWS --- a/NEWS Fri Oct 16 17:26:11 2015 +0200 +++ b/NEWS Tue Oct 20 11:22:50 2015 +0200 @@ -22,6 +22,7 @@ Maintenance ----------- +* C-Move SCP for studies using AccessionNumber tag * Fix issue 4 (C-Store Association not renegotiated on Specific-to-specific transfer syntax change) * "/system" URI gives information about the plugins used for storage area and DB back-end * Plugin callbacks should now return explicit "OrthancPluginErrorCode" instead of integers diff -r d72cf0c11f42 -r 9d8bb6bc2890 OrthancServer/DatabaseWrapper.cpp --- a/OrthancServer/DatabaseWrapper.cpp Fri Oct 16 17:26:11 2015 +0200 +++ b/OrthancServer/DatabaseWrapper.cpp Tue Oct 20 11:22:50 2015 +0200 @@ -268,6 +268,8 @@ void DatabaseWrapper::Open() { + db_.Execute("PRAGMA ENCODING=\"UTF-8\";"); + // Performance tuning of SQLite with PRAGMAs // http://www.sqlite.org/pragma.html db_.Execute("PRAGMA SYNCHRONOUS=NORMAL;"); @@ -462,19 +464,6 @@ } - void DatabaseWrapper::LookupIdentifier(std::list& target, - const DicomTag& tag, - const std::string& value) - { - if (!tag.IsIdentifier()) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - base_.LookupIdentifier(target, tag, value); - } - - void DatabaseWrapper::GetAllMetadata(std::map& target, int64_t id) { diff -r d72cf0c11f42 -r 9d8bb6bc2890 OrthancServer/DatabaseWrapper.h --- a/OrthancServer/DatabaseWrapper.h Fri Oct 16 17:26:11 2015 +0200 +++ b/OrthancServer/DatabaseWrapper.h Tue Oct 20 11:22:50 2015 +0200 @@ -178,6 +178,13 @@ base_.SetMainDicomTag(id, tag, value); } + virtual void SetIdentifierTag(int64_t id, + const DicomTag& tag, + const std::string& value) + { + base_.SetIdentifierTag(id, tag, value); + } + virtual void GetMainDicomTags(DicomMap& map, int64_t id) { @@ -310,12 +317,9 @@ virtual void LookupIdentifier(std::list& target, const DicomTag& tag, - const std::string& value); - - virtual void LookupIdentifier(std::list& target, const std::string& value) { - base_.LookupIdentifier(target, value); + base_.LookupIdentifier(target, tag, value); } virtual void GetAllMetadata(std::map& target, diff -r d72cf0c11f42 -r 9d8bb6bc2890 OrthancServer/DatabaseWrapperBase.cpp --- a/OrthancServer/DatabaseWrapperBase.cpp Fri Oct 16 17:26:11 2015 +0200 +++ b/OrthancServer/DatabaseWrapperBase.cpp Tue Oct 20 11:22:50 2015 +0200 @@ -312,11 +312,11 @@ } - static void SetMainDicomTagsInternal(SQLite::Statement& s, - int64_t id, - const DicomTag& tag, - const std::string& value) + void DatabaseWrapperBase::SetMainDicomTag(int64_t id, + const DicomTag& tag, + const std::string& value) { + SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO MainDicomTags VALUES(?, ?, ?, ?)"); s.BindInt64(0, id); s.BindInt(1, tag.GetGroup()); s.BindInt(2, tag.GetElement()); @@ -325,22 +325,19 @@ } - void DatabaseWrapperBase::SetMainDicomTag(int64_t id, - const DicomTag& tag, - const std::string& value) + void DatabaseWrapperBase::SetIdentifierTag(int64_t id, + const DicomTag& tag, + const std::string& value) { - if (tag.IsIdentifier()) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO DicomIdentifiers VALUES(?, ?, ?, ?)"); - SetMainDicomTagsInternal(s, id, tag, value); - } - else - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO MainDicomTags VALUES(?, ?, ?, ?)"); - SetMainDicomTagsInternal(s, id, tag, value); - } + SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO DicomIdentifiers VALUES(?, ?, ?, ?)"); + s.BindInt64(0, id); + s.BindInt(1, tag.GetGroup()); + s.BindInt(2, tag.GetElement()); + s.BindString(3, value); + s.Run(); } + void DatabaseWrapperBase::GetMainDicomTags(DicomMap& map, int64_t id) { @@ -354,15 +351,6 @@ s.ColumnInt(2), s.ColumnString(3)); } - - SQLite::Statement s2(db_, SQLITE_FROM_HERE, "SELECT * FROM DicomIdentifiers WHERE id=?"); - s2.BindInt64(0, id); - while (s2.Step()) - { - map.SetValue(s2.ColumnInt(1), - s2.ColumnInt(2), - s2.ColumnString(3)); - } } @@ -681,6 +669,12 @@ const DicomTag& tag, const std::string& value) { + assert(tag == DICOM_TAG_PATIENT_ID || + tag == DICOM_TAG_STUDY_INSTANCE_UID || + tag == DICOM_TAG_SERIES_INSTANCE_UID || + tag == DICOM_TAG_SOP_INSTANCE_UID || + tag == DICOM_TAG_ACCESSION_NUMBER); + SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT id FROM DicomIdentifiers WHERE tagGroup=? AND tagElement=? and value=?"); @@ -695,21 +689,4 @@ target.push_back(s.ColumnInt64(0)); } } - - - void DatabaseWrapperBase::LookupIdentifier(std::list& target, - const std::string& value) - { - SQLite::Statement s(db_, SQLITE_FROM_HERE, - "SELECT id FROM DicomIdentifiers WHERE value=?"); - - s.BindString(0, value); - - target.clear(); - - while (s.Step()) - { - target.push_back(s.ColumnInt64(0)); - } - } } diff -r d72cf0c11f42 -r 9d8bb6bc2890 OrthancServer/DatabaseWrapperBase.h --- a/OrthancServer/DatabaseWrapperBase.h Fri Oct 16 17:26:11 2015 +0200 +++ b/OrthancServer/DatabaseWrapperBase.h Tue Oct 20 11:22:50 2015 +0200 @@ -132,6 +132,10 @@ const DicomTag& tag, const std::string& value); + void SetIdentifierTag(int64_t id, + const DicomTag& tag, + const std::string& value); + void GetMainDicomTags(DicomMap& map, int64_t id); @@ -189,9 +193,6 @@ void LookupIdentifier(std::list& target, const DicomTag& tag, const std::string& value); - - void LookupIdentifier(std::list& target, - const std::string& value); }; } diff -r d72cf0c11f42 -r 9d8bb6bc2890 OrthancServer/IDatabaseWrapper.h --- a/OrthancServer/IDatabaseWrapper.h Fri Oct 16 17:26:11 2015 +0200 +++ b/OrthancServer/IDatabaseWrapper.h Tue Oct 20 11:22:50 2015 +0200 @@ -150,9 +150,6 @@ const DicomTag& tag, const std::string& value) = 0; - virtual void LookupIdentifier(std::list& target, - const std::string& value) = 0; - virtual bool LookupMetadata(std::string& target, int64_t id, MetadataType type) = 0; @@ -178,6 +175,10 @@ const DicomTag& tag, const std::string& value) = 0; + virtual void SetIdentifierTag(int64_t id, + const DicomTag& tag, + const std::string& value) = 0; + virtual void SetMetadata(int64_t id, MetadataType type, const std::string& value) = 0; diff -r d72cf0c11f42 -r 9d8bb6bc2890 OrthancServer/OrthancMoveRequestHandler.cpp --- a/OrthancServer/OrthancMoveRequestHandler.cpp Fri Oct 16 17:26:11 2015 +0200 +++ b/OrthancServer/OrthancMoveRequestHandler.cpp Tue Oct 20 11:22:50 2015 +0200 @@ -105,9 +105,34 @@ bool OrthancMoveRequestHandler::LookupIdentifier(std::string& publicId, - DicomTag tag, + ResourceType level, const DicomMap& input) { + DicomTag tag(0, 0); // Dummy initialization + + switch (level) + { + case ResourceType_Patient: + tag = DICOM_TAG_PATIENT_ID; + break; + + case ResourceType_Study: + tag = (input.HasTag(DICOM_TAG_ACCESSION_NUMBER) ? + DICOM_TAG_ACCESSION_NUMBER : DICOM_TAG_STUDY_INSTANCE_UID); + break; + + case ResourceType_Series: + tag = DICOM_TAG_SERIES_INSTANCE_UID; + break; + + case ResourceType_Instance: + tag = DICOM_TAG_SOP_INSTANCE_UID; + break; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + if (!input.HasTag(tag)) { return false; @@ -116,7 +141,7 @@ std::string value = input.GetValue(tag).AsString(); std::list ids; - context_.GetIndex().LookupIdentifier(ids, tag, value); + context_.GetIndex().LookupIdentifier(ids, tag, value, level); if (ids.size() != 1) { @@ -156,14 +181,9 @@ * Retrieve the query level. **/ - ResourceType level; const DicomValue* levelTmp = input.TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL); - if (levelTmp != NULL) - { - level = StringToResourceType(levelTmp->AsString().c_str()); - } - else + if (levelTmp == NULL) { // The query level is not present in the C-Move request, which // does not follow the DICOM standard. This is for instance the @@ -173,10 +193,10 @@ std::string publicId; - if (LookupIdentifier(publicId, DICOM_TAG_SOP_INSTANCE_UID, input) || - LookupIdentifier(publicId, DICOM_TAG_SERIES_INSTANCE_UID, input) || - LookupIdentifier(publicId, DICOM_TAG_STUDY_INSTANCE_UID, input) || - LookupIdentifier(publicId, DICOM_TAG_PATIENT_ID, input)) + if (LookupIdentifier(publicId, ResourceType_Instance, input) || + LookupIdentifier(publicId, ResourceType_Series, input) || + LookupIdentifier(publicId, ResourceType_Study, input) || + LookupIdentifier(publicId, ResourceType_Patient, input)) { return new OrthancMoveRequestIterator(context_, targetAet, publicId); } @@ -187,42 +207,23 @@ } } + assert(levelTmp != NULL); + ResourceType level = StringToResourceType(levelTmp->AsString().c_str()); /** * Lookup for the resource to be sent. **/ - bool ok; std::string publicId; - switch (level) + if (LookupIdentifier(publicId, level, input)) { - case ResourceType_Patient: - ok = LookupIdentifier(publicId, DICOM_TAG_PATIENT_ID, input); - break; - - case ResourceType_Study: - ok = LookupIdentifier(publicId, DICOM_TAG_STUDY_INSTANCE_UID, input); - break; - - case ResourceType_Series: - ok = LookupIdentifier(publicId, DICOM_TAG_SERIES_INSTANCE_UID, input); - break; - - case ResourceType_Instance: - ok = LookupIdentifier(publicId, DICOM_TAG_SOP_INSTANCE_UID, input); - break; - - default: - ok = false; + return new OrthancMoveRequestIterator(context_, targetAet, publicId); } - - if (!ok) + else { throw OrthancException(ErrorCode_BadRequest); } - - return new OrthancMoveRequestIterator(context_, targetAet, publicId); } } diff -r d72cf0c11f42 -r 9d8bb6bc2890 OrthancServer/OrthancMoveRequestHandler.h --- a/OrthancServer/OrthancMoveRequestHandler.h Fri Oct 16 17:26:11 2015 +0200 +++ b/OrthancServer/OrthancMoveRequestHandler.h Tue Oct 20 11:22:50 2015 +0200 @@ -42,7 +42,7 @@ ServerContext& context_; bool LookupIdentifier(std::string& publicId, - DicomTag tag, + ResourceType level, const DicomMap& input); public: diff -r d72cf0c11f42 -r 9d8bb6bc2890 OrthancServer/OrthancRestApi/OrthancRestResources.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Fri Oct 16 17:26:11 2015 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Tue Oct 20 11:22:50 2015 +0200 @@ -879,20 +879,44 @@ } + namespace + { + typedef std::list< std::pair > LookupResults; + } + + + static void AccumulateLookupResults(LookupResults& result, + ServerIndex& index, + const DicomTag& tag, + const std::string& value, + ResourceType level) + { + std::list tmp; + index.LookupIdentifier(tmp, tag, value, level); + + for (std::list::const_iterator + it = tmp.begin(); it != tmp.end(); ++it) + { + result.push_back(std::make_pair(level, *it)); + } + } + + static void Lookup(RestApiPostCall& call) { - typedef std::list< std::pair > Resources; - std::string tag; call.BodyToString(tag); - Resources resources; - - OrthancRestApi::GetIndex(call).LookupIdentifier(resources, tag); - Json::Value result = Json::arrayValue; - - for (Resources::const_iterator it = resources.begin(); - it != resources.end(); ++it) + LookupResults resources; + ServerIndex& index = OrthancRestApi::GetIndex(call); + AccumulateLookupResults(resources, index, DICOM_TAG_PATIENT_ID, tag, ResourceType_Patient); + AccumulateLookupResults(resources, index, DICOM_TAG_STUDY_INSTANCE_UID, tag, ResourceType_Study); + AccumulateLookupResults(resources, index, DICOM_TAG_SERIES_INSTANCE_UID, tag, ResourceType_Series); + AccumulateLookupResults(resources, index, DICOM_TAG_SOP_INSTANCE_UID, tag, ResourceType_Instance); + + Json::Value result = Json::arrayValue; + for (LookupResults::const_iterator + it = resources.begin(); it != resources.end(); ++it) { ResourceType type = it->first; const std::string& id = it->second; diff -r d72cf0c11f42 -r 9d8bb6bc2890 OrthancServer/PrepareDatabase.sql diff -r d72cf0c11f42 -r 9d8bb6bc2890 OrthancServer/ServerEnumerations.cpp --- a/OrthancServer/ServerEnumerations.cpp Fri Oct 16 17:26:11 2015 +0200 +++ b/OrthancServer/ServerEnumerations.cpp Tue Oct 20 11:22:50 2015 +0200 @@ -364,5 +364,4 @@ throw OrthancException(ErrorCode_ParameterOutOfRange); } } - } diff -r d72cf0c11f42 -r 9d8bb6bc2890 OrthancServer/ServerEnumerations.h --- a/OrthancServer/ServerEnumerations.h Fri Oct 16 17:26:11 2015 +0200 +++ b/OrthancServer/ServerEnumerations.h Tue Oct 20 11:22:50 2015 +0200 @@ -35,6 +35,7 @@ #include #include "../Core/Enumerations.h" +#include "../Core/DicomFormat/DicomTag.h" namespace Orthanc { diff -r d72cf0c11f42 -r 9d8bb6bc2890 OrthancServer/ServerIndex.cpp --- a/OrthancServer/ServerIndex.cpp Fri Oct 16 17:26:11 2015 +0200 +++ b/OrthancServer/ServerIndex.cpp Tue Oct 20 11:22:50 2015 +0200 @@ -627,7 +627,7 @@ // Create the instance int64_t instance = CreateResource(hasher.HashInstance(), ResourceType_Instance); - Toolbox::SetMainDicomTags(db_, instance, ResourceType_Instance, dicomSummary, true); + Toolbox::SetMainDicomTags(db_, instance, ResourceType_Instance, dicomSummary); // Detect up to which level the patient/study/series/instance // hierarchy must be created @@ -679,22 +679,21 @@ if (isNewSeries) { series = CreateResource(hasher.HashSeries(), ResourceType_Series); - Toolbox::SetMainDicomTags(db_, series, ResourceType_Series, dicomSummary, true); + Toolbox::SetMainDicomTags(db_, series, ResourceType_Series, dicomSummary); } // Create the study if needed if (isNewStudy) { study = CreateResource(hasher.HashStudy(), ResourceType_Study); - Toolbox::SetMainDicomTags(db_, study, ResourceType_Study, dicomSummary, true); - Toolbox::SetMainDicomTags(db_, study, ResourceType_Patient, dicomSummary, false); // New in version 0.9.5 (db v6) + Toolbox::SetMainDicomTags(db_, study, ResourceType_Study, dicomSummary); } // Create the patient if needed if (isNewPatient) { patient = CreateResource(hasher.HashPatient(), ResourceType_Patient); - Toolbox::SetMainDicomTags(db_, patient, ResourceType_Patient, dicomSummary, true); + Toolbox::SetMainDicomTags(db_, patient, ResourceType_Patient, dicomSummary); } // Create the parent-to-child links @@ -874,29 +873,6 @@ } - static std::string GetPatientIdOfStudy(IDatabaseWrapper& db, - int64_t resourceId) - { - int64_t patient; - if (!db.LookupParent(patient, resourceId)) - { - throw OrthancException(ErrorCode_InternalError); - } - - DicomMap tags; - db.GetMainDicomTags(tags, patient); - - if (tags.HasTag(DICOM_TAG_PATIENT_ID)) - { - return tags.GetValue(DICOM_TAG_PATIENT_ID).AsString(); - } - else - { - return ""; - } - } - - void ServerIndex::MainDicomTagsToJson(Json::Value& target, int64_t resourceId, ResourceType resourceType) @@ -915,8 +891,6 @@ target["PatientMainDicomTags"] = Json::objectValue; FromDcmtkBridge::ToJson(target["PatientMainDicomTags"], t2, true); - - target["PatientMainDicomTags"]["PatientID"] = GetPatientIdOfStudy(db_, resourceId); } else { @@ -1919,6 +1893,12 @@ const std::string& value, ResourceType type) { + assert(tag == DICOM_TAG_PATIENT_ID || + tag == DICOM_TAG_STUDY_INSTANCE_UID || + tag == DICOM_TAG_SERIES_INSTANCE_UID || + tag == DICOM_TAG_SOP_INSTANCE_UID || + tag == DICOM_TAG_ACCESSION_NUMBER); + result.clear(); boost::mutex::scoped_lock lock(mutex_); @@ -1937,44 +1917,6 @@ } - void ServerIndex::LookupIdentifier(std::list& result, - const DicomTag& tag, - const std::string& value) - { - result.clear(); - - boost::mutex::scoped_lock lock(mutex_); - - std::list id; - db_.LookupIdentifier(id, tag, value); - - for (std::list::const_iterator - it = id.begin(); it != id.end(); ++it) - { - result.push_back(db_.GetPublicId(*it)); - } - } - - - void ServerIndex::LookupIdentifier(std::list< std::pair >& result, - const std::string& value) - { - result.clear(); - - boost::mutex::scoped_lock lock(mutex_); - - std::list id; - db_.LookupIdentifier(id, value); - - for (std::list::const_iterator - it = id.begin(); it != id.end(); ++it) - { - result.push_back(std::make_pair(db_.GetResourceType(*it), - db_.GetPublicId(*it))); - } - } - - StoreStatus ServerIndex::AddAttachment(const FileInfo& attachment, const std::string& publicId) { @@ -2137,7 +2079,6 @@ { case ResourceType_Patient: tmp.ExtractPatientInformation(result); - result.SetValue(DICOM_TAG_PATIENT_ID, GetPatientIdOfStudy(db_, id)); return true; case ResourceType_Study: diff -r d72cf0c11f42 -r 9d8bb6bc2890 OrthancServer/ServerIndex.h --- a/OrthancServer/ServerIndex.h Fri Oct 16 17:26:11 2015 +0200 +++ b/OrthancServer/ServerIndex.h Tue Oct 20 11:22:50 2015 +0200 @@ -240,13 +240,6 @@ const std::string& value, ResourceType type); - void LookupIdentifier(std::list& result, - const DicomTag& tag, - const std::string& value); - - void LookupIdentifier(std::list< std::pair >& result, - const std::string& value); - StoreStatus AddAttachment(const FileInfo& attachment, const std::string& publicId); diff -r d72cf0c11f42 -r 9d8bb6bc2890 OrthancServer/ServerToolbox.cpp --- a/OrthancServer/ServerToolbox.cpp Fri Oct 16 17:26:11 2015 +0200 +++ b/OrthancServer/ServerToolbox.cpp Tue Oct 20 11:22:50 2015 +0200 @@ -158,11 +158,63 @@ } + static void SetMainDicomTagsInternal(IDatabaseWrapper& database, + int64_t resource, + const DicomMap& tags) + { + DicomArray flattened(tags); + + for (size_t i = 0; i < flattened.GetSize(); i++) + { + const DicomElement& element = flattened.GetElement(i); + const DicomTag& tag = element.GetTag(); + database.SetMainDicomTag(resource, tag, element.GetValue().AsString()); + } + } + + + static void SetIdentifierTagInternal(IDatabaseWrapper& database, + int64_t resource, + const DicomMap& tags, + const DicomTag& tag) + { + const DicomValue* value = tags.TestAndGetValue(tag); + if (value != NULL && + !value->IsNull()) + { + std::string s = value->AsString(); + + if (tag != DICOM_TAG_PATIENT_ID && + tag != DICOM_TAG_STUDY_INSTANCE_UID && + tag != DICOM_TAG_SERIES_INSTANCE_UID && + tag != DICOM_TAG_SOP_INSTANCE_UID && + tag != DICOM_TAG_ACCESSION_NUMBER) + { + s = NormalizeIdentifierTag(s); + } + + database.SetIdentifierTag(resource, tag, s); + } + } + + + static void AttachPatientInformation(IDatabaseWrapper& database, + int64_t resource, + const DicomMap& dicomSummary) + { + DicomMap tags; + dicomSummary.ExtractPatientInformation(tags); + SetIdentifierTagInternal(database, resource, tags, DICOM_TAG_PATIENT_ID); + SetIdentifierTagInternal(database, resource, tags, DICOM_TAG_PATIENT_NAME); + SetIdentifierTagInternal(database, resource, tags, DICOM_TAG_PATIENT_BIRTH_DATE); + SetMainDicomTagsInternal(database, resource, tags); + } + + void SetMainDicomTags(IDatabaseWrapper& database, int64_t resource, ResourceType level, - const DicomMap& dicomSummary, - bool includeIdentifiers) + const DicomMap& dicomSummary) { // WARNING: The database should be locked with a transaction! @@ -171,36 +223,35 @@ switch (level) { case ResourceType_Patient: - dicomSummary.ExtractPatientInformation(tags); + AttachPatientInformation(database, resource, dicomSummary); break; case ResourceType_Study: + // Duplicate the patient tags at the study level (new in Orthanc 0.9.5 - db v6) + AttachPatientInformation(database, resource, dicomSummary); + dicomSummary.ExtractStudyInformation(tags); + SetIdentifierTagInternal(database, resource, tags, DICOM_TAG_STUDY_INSTANCE_UID); + SetIdentifierTagInternal(database, resource, tags, DICOM_TAG_ACCESSION_NUMBER); + SetIdentifierTagInternal(database, resource, tags, DICOM_TAG_STUDY_DESCRIPTION); + SetIdentifierTagInternal(database, resource, tags, DICOM_TAG_STUDY_DATE); break; case ResourceType_Series: dicomSummary.ExtractSeriesInformation(tags); + SetIdentifierTagInternal(database, resource, tags, DICOM_TAG_SERIES_INSTANCE_UID); break; case ResourceType_Instance: dicomSummary.ExtractInstanceInformation(tags); + SetIdentifierTagInternal(database, resource, tags, DICOM_TAG_SOP_INSTANCE_UID); break; default: throw OrthancException(ErrorCode_InternalError); } - DicomArray flattened(tags); - for (size_t i = 0; i < flattened.GetSize(); i++) - { - const DicomElement& element = flattened.GetElement(i); - - if (includeIdentifiers || - !element.GetTag().IsIdentifier()) - { - database.SetMainDicomTag(resource, element.GetTag(), element.GetValue().AsString()); - } - } + SetMainDicomTagsInternal(database, resource, tags); } @@ -299,32 +350,16 @@ dicom.Convert(dicomSummary); database.ClearMainDicomTags(resource); + Toolbox::SetMainDicomTags(database, resource, level, dicomSummary); + } + } - switch (level) - { - case ResourceType_Patient: - Toolbox::SetMainDicomTags(database, resource, ResourceType_Patient, dicomSummary, true); - break; - - case ResourceType_Study: - Toolbox::SetMainDicomTags(database, resource, ResourceType_Study, dicomSummary, true); - // Duplicate the patient tags at the study level (new in Orthanc 0.9.5 - db v6) - Toolbox::SetMainDicomTags(database, resource, ResourceType_Patient, dicomSummary, false); - break; - - case ResourceType_Series: - Toolbox::SetMainDicomTags(database, resource, ResourceType_Series, dicomSummary, true); - break; - - case ResourceType_Instance: - Toolbox::SetMainDicomTags(database, resource, ResourceType_Instance, dicomSummary, true); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - } + std::string NormalizeIdentifierTag(const std::string& value) + { + std::string s = Toolbox::ConvertToAscii(Toolbox::StripSpaces(value)); + Toolbox::ToUpperCase(s); + return s; } } } diff -r d72cf0c11f42 -r 9d8bb6bc2890 OrthancServer/ServerToolbox.h --- a/OrthancServer/ServerToolbox.h Fri Oct 16 17:26:11 2015 +0200 +++ b/OrthancServer/ServerToolbox.h Tue Oct 20 11:22:50 2015 +0200 @@ -49,8 +49,7 @@ void SetMainDicomTags(IDatabaseWrapper& database, int64_t resource, ResourceType level, - const DicomMap& dicomSummary, - bool includeIdentifiers); + const DicomMap& dicomSummary); bool FindOneChildInstance(int64_t& result, IDatabaseWrapper& database, @@ -60,5 +59,7 @@ void ReconstructMainDicomTags(IDatabaseWrapper& database, IStorageArea& storageArea, ResourceType level); + + std::string NormalizeIdentifierTag(const std::string& value); } } diff -r d72cf0c11f42 -r 9d8bb6bc2890 Plugins/Engine/OrthancPluginDatabase.cpp --- a/Plugins/Engine/OrthancPluginDatabase.cpp Fri Oct 16 17:26:11 2015 +0200 +++ b/Plugins/Engine/OrthancPluginDatabase.cpp Tue Oct 20 11:22:50 2015 +0200 @@ -611,15 +611,6 @@ } - void OrthancPluginDatabase::LookupIdentifier(std::list& target, - const std::string& value) - { - ResetAnswers(); - CheckSuccess(backend_.lookupIdentifier2(GetContext(), payload_, value.c_str())); - ForwardAnswers(target); - } - - bool OrthancPluginDatabase::LookupMetadata(std::string& target, int64_t id, MetadataType type) @@ -711,18 +702,20 @@ tmp.element = tag.GetElement(); tmp.value = value.c_str(); - OrthancPluginErrorCode code; + CheckSuccess(backend_.setMainDicomTag(payload_, id, &tmp)); + } + - if (tag.IsIdentifier()) - { - code = backend_.setIdentifierTag(payload_, id, &tmp); - } - else - { - code = backend_.setMainDicomTag(payload_, id, &tmp); - } + void OrthancPluginDatabase::SetIdentifierTag(int64_t id, + const DicomTag& tag, + const std::string& value) + { + OrthancPluginDicomTag tmp; + tmp.group = tag.GetGroup(); + tmp.element = tag.GetElement(); + tmp.value = value.c_str(); - CheckSuccess(code); + CheckSuccess(backend_.setIdentifierTag(payload_, id, &tmp)); } diff -r d72cf0c11f42 -r 9d8bb6bc2890 Plugins/Engine/OrthancPluginDatabase.h --- a/Plugins/Engine/OrthancPluginDatabase.h Fri Oct 16 17:26:11 2015 +0200 +++ b/Plugins/Engine/OrthancPluginDatabase.h Tue Oct 20 11:22:50 2015 +0200 @@ -207,9 +207,6 @@ const DicomTag& tag, const std::string& value); - virtual void LookupIdentifier(std::list& target, - const std::string& value); - virtual bool LookupMetadata(std::string& target, int64_t id, MetadataType type); @@ -235,6 +232,10 @@ const DicomTag& tag, const std::string& value); + virtual void SetIdentifierTag(int64_t id, + const DicomTag& tag, + const std::string& value); + virtual void SetMetadata(int64_t id, MetadataType type, const std::string& value); diff -r d72cf0c11f42 -r 9d8bb6bc2890 Plugins/Include/orthanc/OrthancCDatabasePlugin.h --- a/Plugins/Include/orthanc/OrthancCDatabasePlugin.h Fri Oct 16 17:26:11 2015 +0200 +++ b/Plugins/Include/orthanc/OrthancCDatabasePlugin.h Tue Oct 20 11:22:50 2015 +0200 @@ -530,7 +530,8 @@ void* payload, const OrthancPluginDicomTag* tag); - /* Output: Use OrthancPluginDatabaseAnswerInt64() */ + /* Unused starting with Orthanc 0.9.5 (db v6), can be set to NULL. + Output: Use OrthancPluginDatabaseAnswerInt64() */ OrthancPluginErrorCode (*lookupIdentifier2) ( /* outputs */ OrthancPluginDatabaseContext* context, diff -r d72cf0c11f42 -r 9d8bb6bc2890 Plugins/Include/orthanc/OrthancCppDatabasePlugin.h --- a/Plugins/Include/orthanc/OrthancCppDatabasePlugin.h Fri Oct 16 17:26:11 2015 +0200 +++ b/Plugins/Include/orthanc/OrthancCppDatabasePlugin.h Tue Oct 20 11:22:50 2015 +0200 @@ -414,9 +414,6 @@ uint16_t element, const char* value) = 0; - virtual void LookupIdentifier(std::list& target /*out*/, - const char* value) = 0; - virtual bool LookupMetadata(std::string& target /*out*/, int64_t id, int32_t metadataType) = 0; @@ -1331,39 +1328,6 @@ } - static OrthancPluginErrorCode LookupIdentifier2(OrthancPluginDatabaseContext* context, - void* payload, - const char* value) - { - IDatabaseBackend* backend = reinterpret_cast(payload); - backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_None); - - try - { - std::list target; - backend->LookupIdentifier(target, value); - - for (std::list::const_iterator - it = target.begin(); it != target.end(); ++it) - { - OrthancPluginDatabaseAnswerInt64(backend->GetOutput().context_, - backend->GetOutput().database_, *it); - } - - return OrthancPluginErrorCode_Success; - } - catch (std::runtime_error& e) - { - LogError(backend, e); - return OrthancPluginErrorCode_DatabasePlugin; - } - catch (DatabaseException& e) - { - return e.GetErrorCode(); - } - } - - static OrthancPluginErrorCode LookupMetadata(OrthancPluginDatabaseContext* context, void* payload, int64_t id, @@ -1861,7 +1825,7 @@ params.lookupAttachment = LookupAttachment; params.lookupGlobalProperty = LookupGlobalProperty; params.lookupIdentifier = LookupIdentifier; - params.lookupIdentifier2 = LookupIdentifier2; + params.lookupIdentifier2 = NULL; // Unused starting with Orthanc 0.9.5 (db v6) params.lookupMetadata = LookupMetadata; params.lookupParent = LookupParent; params.lookupResource = LookupResource; diff -r d72cf0c11f42 -r 9d8bb6bc2890 Plugins/Samples/DatabasePlugin/Database.cpp --- a/Plugins/Samples/DatabasePlugin/Database.cpp Fri Oct 16 17:26:11 2015 +0200 +++ b/Plugins/Samples/DatabasePlugin/Database.cpp Tue Oct 20 11:22:50 2015 +0200 @@ -184,6 +184,8 @@ { db_.Open(path_); + db_.Execute("PRAGMA ENCODING=\"UTF-8\";"); + // http://www.sqlite.org/pragma.html db_.Execute("PRAGMA SYNCHRONOUS=NORMAL;"); db_.Execute("PRAGMA JOURNAL_MODE=WAL;"); diff -r d72cf0c11f42 -r 9d8bb6bc2890 Plugins/Samples/DatabasePlugin/Database.h --- a/Plugins/Samples/DatabasePlugin/Database.h Fri Oct 16 17:26:11 2015 +0200 +++ b/Plugins/Samples/DatabasePlugin/Database.h Tue Oct 20 11:22:50 2015 +0200 @@ -195,12 +195,6 @@ base_.LookupIdentifier(target, Orthanc::DicomTag(group, element), value); } - virtual void LookupIdentifier(std::list& target /*out*/, - const char* value) - { - base_.LookupIdentifier(target, value); - } - virtual bool LookupMetadata(std::string& target /*out*/, int64_t id, int32_t metadataType) @@ -246,7 +240,7 @@ uint16_t element, const char* value) { - base_.SetMainDicomTag(id, Orthanc::DicomTag(group, element), value); + base_.SetIdentifierTag(id, Orthanc::DicomTag(group, element), value); } virtual void SetMetadata(int64_t id, diff -r d72cf0c11f42 -r 9d8bb6bc2890 UnitTestsSources/ServerIndexTests.cpp --- a/UnitTestsSources/ServerIndexTests.cpp Fri Oct 16 17:26:11 2015 +0200 +++ b/UnitTestsSources/ServerIndexTests.cpp Tue Oct 20 11:22:50 2015 +0200 @@ -686,10 +686,10 @@ index_->CreateResource("d", ResourceType_Series) // 3 }; - index_->SetMainDicomTag(a[0], DICOM_TAG_STUDY_INSTANCE_UID, "0"); - index_->SetMainDicomTag(a[1], DICOM_TAG_STUDY_INSTANCE_UID, "1"); - index_->SetMainDicomTag(a[2], DICOM_TAG_STUDY_INSTANCE_UID, "0"); - index_->SetMainDicomTag(a[3], DICOM_TAG_SERIES_INSTANCE_UID, "0"); + index_->SetIdentifierTag(a[0], DICOM_TAG_STUDY_INSTANCE_UID, "0"); + index_->SetIdentifierTag(a[1], DICOM_TAG_STUDY_INSTANCE_UID, "1"); + index_->SetIdentifierTag(a[2], DICOM_TAG_STUDY_INSTANCE_UID, "0"); + index_->SetIdentifierTag(a[3], DICOM_TAG_SERIES_INSTANCE_UID, "0"); std::list s; @@ -698,20 +698,20 @@ ASSERT_TRUE(std::find(s.begin(), s.end(), a[0]) != s.end()); ASSERT_TRUE(std::find(s.begin(), s.end(), a[2]) != s.end()); - index_->LookupIdentifier(s, "0"); - ASSERT_EQ(3u, s.size()); - ASSERT_TRUE(std::find(s.begin(), s.end(), a[0]) != s.end()); - ASSERT_TRUE(std::find(s.begin(), s.end(), a[2]) != s.end()); + index_->LookupIdentifier(s, DICOM_TAG_SERIES_INSTANCE_UID, "0"); + ASSERT_EQ(1u, s.size()); ASSERT_TRUE(std::find(s.begin(), s.end(), a[3]) != s.end()); index_->LookupIdentifier(s, DICOM_TAG_STUDY_INSTANCE_UID, "1"); ASSERT_EQ(1u, s.size()); ASSERT_TRUE(std::find(s.begin(), s.end(), a[1]) != s.end()); - index_->LookupIdentifier(s, "1"); + index_->LookupIdentifier(s, DICOM_TAG_STUDY_INSTANCE_UID, "1"); ASSERT_EQ(1u, s.size()); ASSERT_TRUE(std::find(s.begin(), s.end(), a[1]) != s.end()); + index_->LookupIdentifier(s, DICOM_TAG_SERIES_INSTANCE_UID, "1"); + ASSERT_EQ(0u, s.size()); /*{ std::list s;