Mercurial > hg > orthanc
changeset 3094:61da3c9b4121 db-changes
cont reorganization
line wrap: on
line diff
--- a/CMakeLists.txt Sat Jan 05 16:09:21 2019 +0100 +++ b/CMakeLists.txt Sat Jan 05 17:52:24 2019 +0100 @@ -58,6 +58,7 @@ OrthancServer/Database/Compatibility/IGetChildrenMetadata.cpp OrthancServer/Database/Compatibility/ILookupResources.cpp OrthancServer/Database/Compatibility/SetOfResources.cpp + OrthancServer/Database/ResourcesContent.cpp OrthancServer/Database/SQLiteDatabaseWrapper.cpp OrthancServer/DicomInstanceOrigin.cpp OrthancServer/DicomInstanceToStore.cpp @@ -169,14 +170,16 @@ ##################################################################### set(ORTHANC_EMBEDDED_FILES - PREPARE_DATABASE ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/PrepareDatabase.sql - UPGRADE_DATABASE_3_TO_4 ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/Upgrade3To4.sql - UPGRADE_DATABASE_4_TO_5 ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/Upgrade4To5.sql - CONFIGURATION_SAMPLE ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Configuration.json - DICOM_CONFORMANCE_STATEMENT ${CMAKE_CURRENT_SOURCE_DIR}/Resources/DicomConformanceStatement.txt - LUA_TOOLBOX ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Toolbox.lua - FONT_UBUNTU_MONO_BOLD_16 ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Fonts/UbuntuMonoBold-16.json - INSTALL_TRACK_ATTACHMENTS_SIZE ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/InstallTrackAttachmentsSize.sql + CONFIGURATION_SAMPLE ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Configuration.json + DICOM_CONFORMANCE_STATEMENT ${CMAKE_CURRENT_SOURCE_DIR}/Resources/DicomConformanceStatement.txt + FONT_UBUNTU_MONO_BOLD_16 ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Fonts/UbuntuMonoBold-16.json + LUA_TOOLBOX ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Toolbox.lua + PREPARE_DATABASE ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/Database/PrepareDatabase.sql + UPGRADE_DATABASE_3_TO_4 ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/Database/Upgrade3To4.sql + UPGRADE_DATABASE_4_TO_5 ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/Database/Upgrade4To5.sql + + INSTALL_TRACK_ATTACHMENTS_SIZE + ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/Database/InstallTrackAttachmentsSize.sql ) if (STANDALONE_BUILD)
--- a/OrthancServer/Database/Compatibility/DatabaseLookup.cpp Sat Jan 05 16:09:21 2019 +0100 +++ b/OrthancServer/Database/Compatibility/DatabaseLookup.cpp Sat Jan 05 17:52:24 2019 +0100 @@ -35,6 +35,7 @@ #include "DatabaseLookup.h" #include "../../../Core/OrthancException.h" +#include "../../Search/DicomTagConstraint.h" #include "../../ServerToolbox.h" #include "SetOfResources.h"
--- a/OrthancServer/Database/Compatibility/ISetResourcesContent.h Sat Jan 05 16:09:21 2019 +0100 +++ b/OrthancServer/Database/Compatibility/ISetResourcesContent.h Sat Jan 05 17:52:24 2019 +0100 @@ -33,7 +33,7 @@ #pragma once -#include "../../ServerToolbox.h" +#include "../ResourcesContent.h" namespace Orthanc {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Database/IDatabaseListener.h Sat Jan 05 17:52:24 2019 +0100 @@ -0,0 +1,57 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * 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/>. + **/ + + +#pragma once + +#include "../ServerEnumerations.h" +#include "../ServerIndexChange.h" + +#include <string> + +namespace Orthanc +{ + class IDatabaseListener : public boost::noncopyable + { + public: + virtual ~IDatabaseListener() + { + } + + virtual void SignalRemainingAncestor(ResourceType parentType, + const std::string& publicId) = 0; + + virtual void SignalFileDeleted(const FileInfo& info) = 0; + + virtual void SignalChange(const ServerIndexChange& change) = 0; + }; +}
--- a/OrthancServer/Database/IDatabaseWrapper.h Sat Jan 05 16:09:21 2019 +0100 +++ b/OrthancServer/Database/IDatabaseWrapper.h Sat Jan 05 17:52:24 2019 +0100 @@ -39,9 +39,8 @@ #include "../../Core/SQLite/ITransaction.h" #include "../ExportedResource.h" -#include "../IDatabaseListener.h" #include "../Search/DatabaseConstraint.h" -#include "../Search/DatabaseLookup.h" +#include "IDatabaseListener.h" #include <list> #include <boost/noncopyable.hpp>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Database/InstallTrackAttachmentsSize.sql Sat Jan 05 17:52:24 2019 +0100 @@ -0,0 +1,22 @@ +CREATE TABLE GlobalIntegers( + key INTEGER PRIMARY KEY, + value INTEGER); + +INSERT INTO GlobalProperties VALUES (6, 1); -- GlobalProperty_GetTotalSizeIsFast + +INSERT INTO GlobalIntegers SELECT 0, IFNULL(SUM(compressedSize), 0) FROM AttachedFiles; +INSERT INTO GlobalIntegers SELECT 1, IFNULL(SUM(uncompressedSize), 0) FROM AttachedFiles; + +CREATE TRIGGER AttachedFileIncrementSize +AFTER INSERT ON AttachedFiles +BEGIN + UPDATE GlobalIntegers SET value = value + new.compressedSize WHERE key = 0; + UPDATE GlobalIntegers SET value = value + new.uncompressedSize WHERE key = 1; +END; + +CREATE TRIGGER AttachedFileDecrementSize +AFTER DELETE ON AttachedFiles +BEGIN + UPDATE GlobalIntegers SET value = value - old.compressedSize WHERE key = 0; + UPDATE GlobalIntegers SET value = value - old.uncompressedSize WHERE key = 1; +END;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Database/PrepareDatabase.sql Sat Jan 05 17:52:24 2019 +0100 @@ -0,0 +1,126 @@ +CREATE TABLE GlobalProperties( + property INTEGER PRIMARY KEY, + value TEXT + ); + +CREATE TABLE Resources( + internalId INTEGER PRIMARY KEY AUTOINCREMENT, + resourceType INTEGER, + publicId TEXT, + parentId INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE + ); + +CREATE TABLE MainDicomTags( + id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, + tagGroup INTEGER, + tagElement INTEGER, + value TEXT, + PRIMARY KEY(id, tagGroup, tagElement) + ); + +-- The following table was added in Orthanc 0.8.5 (database v5) +CREATE TABLE DicomIdentifiers( + id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, + tagGroup INTEGER, + tagElement INTEGER, + value TEXT, + PRIMARY KEY(id, tagGroup, tagElement) + ); + +CREATE TABLE Metadata( + id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, + type INTEGER, + value TEXT, + PRIMARY KEY(id, type) + ); + +CREATE TABLE AttachedFiles( + id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, + fileType INTEGER, + uuid TEXT, + compressedSize INTEGER, + uncompressedSize INTEGER, + compressionType INTEGER, + uncompressedMD5 TEXT, -- New in Orthanc 0.7.3 (database v4) + compressedMD5 TEXT, -- New in Orthanc 0.7.3 (database v4) + PRIMARY KEY(id, fileType) + ); + +CREATE TABLE Changes( + seq INTEGER PRIMARY KEY AUTOINCREMENT, + changeType INTEGER, + internalId INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, + resourceType INTEGER, + date TEXT + ); + +CREATE TABLE ExportedResources( + seq INTEGER PRIMARY KEY AUTOINCREMENT, + resourceType INTEGER, + publicId TEXT, + remoteModality TEXT, + patientId TEXT, + studyInstanceUid TEXT, + seriesInstanceUid TEXT, + sopInstanceUid TEXT, + date TEXT + ); + +CREATE TABLE PatientRecyclingOrder( + seq INTEGER PRIMARY KEY AUTOINCREMENT, + patientId INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE + ); + +CREATE INDEX ChildrenIndex ON Resources(parentId); +CREATE INDEX PublicIndex ON Resources(publicId); +CREATE INDEX ResourceTypeIndex ON Resources(resourceType); +CREATE INDEX PatientRecyclingIndex ON PatientRecyclingOrder(patientId); + +CREATE INDEX MainDicomTagsIndex1 ON MainDicomTags(id); +-- The 2 following indexes were removed in Orthanc 0.8.5 (database v5), to speed up +-- CREATE INDEX MainDicomTagsIndex2 ON MainDicomTags(tagGroup, tagElement); +-- CREATE INDEX MainDicomTagsIndexValues ON MainDicomTags(value COLLATE BINARY); + +-- The 3 following indexes were added in Orthanc 0.8.5 (database v5) +CREATE INDEX DicomIdentifiersIndex1 ON DicomIdentifiers(id); +CREATE INDEX DicomIdentifiersIndex2 ON DicomIdentifiers(tagGroup, tagElement); +CREATE INDEX DicomIdentifiersIndexValues ON DicomIdentifiers(value COLLATE BINARY); + +CREATE INDEX ChangesIndex ON Changes(internalId); + +CREATE TRIGGER AttachedFileDeleted +AFTER DELETE ON AttachedFiles +BEGIN + SELECT SignalFileDeleted(old.uuid, old.fileType, old.uncompressedSize, + old.compressionType, old.compressedSize, + -- These 2 arguments are new in Orthanc 0.7.3 (database v4) + old.uncompressedMD5, old.compressedMD5); +END; + +CREATE TRIGGER ResourceDeleted +AFTER DELETE ON Resources +BEGIN + SELECT SignalResourceDeleted(old.publicId, old.resourceType); -- New in Orthanc 0.8.5 (db v5) + SELECT SignalRemainingAncestor(parent.publicId, parent.resourceType) + FROM Resources AS parent WHERE internalId = old.parentId; +END; + +-- Delete a parent resource when its unique child is deleted +CREATE TRIGGER ResourceDeletedParentCleaning +AFTER DELETE ON Resources +FOR EACH ROW WHEN (SELECT COUNT(*) FROM Resources WHERE parentId = old.parentId) = 0 +BEGIN + DELETE FROM Resources WHERE internalId = old.parentId; +END; + +CREATE TRIGGER PatientAdded +AFTER INSERT ON Resources +FOR EACH ROW WHEN new.resourceType = 1 -- "1" corresponds to "ResourceType_Patient" in C++ +BEGIN + INSERT INTO PatientRecyclingOrder VALUES (NULL, new.internalId); +END; + + +-- Set the version of the database schema +-- The "1" corresponds to the "GlobalProperty_DatabaseSchemaVersion" enumeration +INSERT INTO GlobalProperties VALUES (1, "6");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Database/ResourcesContent.cpp Sat Jan 05 17:52:24 2019 +0100 @@ -0,0 +1,108 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * 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 "../PrecompiledHeadersServer.h" +#include "ResourcesContent.h" + +#include "Compatibility/ISetResourcesContent.h" + +#include <cassert> + + +namespace Orthanc +{ + void ResourcesContent::Store(Compatibility::ISetResourcesContent& compatibility) const + { + for (std::list<TagValue>::const_iterator + it = tags_.begin(); it != tags_.end(); ++it) + { + if (it->isIdentifier_) + { + compatibility.SetIdentifierTag(it->resourceId_, it->tag_, it->value_); + } + else + { + compatibility.SetMainDicomTag(it->resourceId_, it->tag_, it->value_); + } + } + + for (std::list<Metadata>::const_iterator + it = metadata_.begin(); it != metadata_.end(); ++it) + { + compatibility.SetMetadata(it->resourceId_, it->metadata_, it->value_); + } + } + + + void ResourcesContent::EncodeForPlugins( + std::vector<OrthancPluginResourcesContentTags>& identifierTags, + std::vector<OrthancPluginResourcesContentTags>& mainDicomTags, + std::vector<OrthancPluginResourcesContentMetadata>& metadata) const + { + identifierTags.reserve(tags_.size()); + mainDicomTags.reserve(tags_.size()); + metadata.reserve(metadata_.size()); + + for (std::list<TagValue>::const_iterator + it = tags_.begin(); it != tags_.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 (std::list<Metadata>::const_iterator + it = metadata_.begin(); it != metadata_.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() == tags_.size() && + metadata.size() == metadata_.size()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Database/ResourcesContent.h Sat Jan 05 17:52:24 2019 +0100 @@ -0,0 +1,128 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * 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/>. + **/ + + +#pragma once + +#include "../../Core/DicomFormat/DicomMap.h" +#include "../ServerEnumerations.h" + +#include <orthanc/OrthancCDatabasePlugin.h> + +#include <boost/noncopyable.hpp> +#include <list> + +namespace Orthanc +{ + namespace Compatibility + { + class ISetResourcesContent; + } + + class ResourcesContent : public boost::noncopyable + { + private: + struct TagValue + { + int64_t resourceId_; + bool isIdentifier_; + DicomTag tag_; + std::string value_; + + TagValue(int64_t resourceId, + bool isIdentifier, + const DicomTag& tag, + const std::string& value) : + resourceId_(resourceId), + isIdentifier_(isIdentifier), + tag_(tag), + value_(value) + { + } + }; + + struct Metadata + { + int64_t resourceId_; + MetadataType metadata_; + std::string value_; + + Metadata(int64_t resourceId, + MetadataType metadata, + const std::string& value) : + resourceId_(resourceId), + metadata_(metadata), + value_(value) + { + } + }; + + std::list<TagValue> tags_; + std::list<Metadata> metadata_; + + public: + void AddMainDicomTag(int64_t resourceId, + const DicomTag& tag, + const std::string& value) + { + tags_.push_back(TagValue(resourceId, false, tag, value)); + } + + void AddIdentifierTag(int64_t resourceId, + const DicomTag& tag, + const std::string& value) + { + tags_.push_back(TagValue(resourceId, true, tag, value)); + } + + void AddMetadata(int64_t resourceId, + MetadataType metadata, + const std::string& value) + { + metadata_.push_back(Metadata(resourceId, metadata, value)); + } + + void AddResource(int64_t resource, + ResourceType level, + const DicomMap& dicomSummary); + + // WARNING: The database should be locked with a transaction! + void Store(Compatibility::ISetResourcesContent& target) const; + + // WARNING: The resulting C structure will contain pointers to the + // current object. Don't delete or modify it! + void EncodeForPlugins( + std::vector<OrthancPluginResourcesContentTags>& identifierTags, + std::vector<OrthancPluginResourcesContentTags>& mainDicomTags, + std::vector<OrthancPluginResourcesContentMetadata>& metadata) const; + }; +}
--- a/OrthancServer/Database/SQLiteDatabaseWrapper.h Sat Jan 05 16:09:21 2019 +0100 +++ b/OrthancServer/Database/SQLiteDatabaseWrapper.h Sat Jan 05 17:52:24 2019 +0100 @@ -36,7 +36,6 @@ #include "IDatabaseWrapper.h" #include "../../Core/SQLite/Connection.h" -#include "../ServerToolbox.h" #include "Compatibility/ICreateInstance.h" #include "Compatibility/IGetChildrenMetadata.h" #include "Compatibility/ISetResourcesContent.h"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Database/Upgrade3To4.sql Sat Jan 05 17:52:24 2019 +0100 @@ -0,0 +1,24 @@ +-- This SQLite script updates the version of the Orthanc database from 3 to 4. + +-- Add 2 new columns at "AttachedFiles" + +ALTER TABLE AttachedFiles ADD COLUMN uncompressedMD5 TEXT; +ALTER TABLE AttachedFiles ADD COLUMN compressedMD5 TEXT; + +-- Update the "AttachedFileDeleted" trigger + +DROP TRIGGER AttachedFileDeleted; + +CREATE TRIGGER AttachedFileDeleted +AFTER DELETE ON AttachedFiles +BEGIN + SELECT SignalFileDeleted(old.uuid, old.fileType, old.uncompressedSize, + old.compressionType, old.compressedSize, + -- These 2 arguments are new in Orthanc 0.7.3 (database v4) + old.uncompressedMD5, old.compressedMD5); +END; + +-- Change the database version +-- The "1" corresponds to the "GlobalProperty_DatabaseSchemaVersion" enumeration + +UPDATE GlobalProperties SET value="4" WHERE property=1;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Database/Upgrade4To5.sql Sat Jan 05 17:52:24 2019 +0100 @@ -0,0 +1,66 @@ +-- This SQLite script updates the version of the Orthanc database from 4 to 5. + + +-- Remove 2 indexes to speed up + +DROP INDEX MainDicomTagsIndex2; +DROP INDEX MainDicomTagsIndexValues; + + +-- Add a new table to index the DICOM identifiers + +CREATE TABLE DicomIdentifiers( + id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, + tagGroup INTEGER, + tagElement INTEGER, + value TEXT, + PRIMARY KEY(id, tagGroup, tagElement) + ); + +CREATE INDEX DicomIdentifiersIndex1 ON DicomIdentifiers(id); +CREATE INDEX DicomIdentifiersIndex2 ON DicomIdentifiers(tagGroup, tagElement); +CREATE INDEX DicomIdentifiersIndexValues ON DicomIdentifiers(value COLLATE BINARY); + + +-- Migrate data from MainDicomTags to MainResourcesTags and MainInstancesTags + +INSERT INTO DicomIdentifiers SELECT * FROM MainDicomTags + WHERE ((tagGroup = 16 AND tagElement = 32) OR -- PatientID (0x0010, 0x0020) + (tagGroup = 32 AND tagElement = 13) OR -- StudyInstanceUID (0x0020, 0x000d) + (tagGroup = 8 AND tagElement = 80) OR -- AccessionNumber (0x0008, 0x0050) + (tagGroup = 32 AND tagElement = 14) OR -- SeriesInstanceUID (0x0020, 0x000e) + (tagGroup = 8 AND tagElement = 24)); -- SOPInstanceUID (0x0008, 0x0018) + +DELETE FROM MainDicomTags + WHERE ((tagGroup = 16 AND tagElement = 32) OR -- PatientID (0x0010, 0x0020) + (tagGroup = 32 AND tagElement = 13) OR -- StudyInstanceUID (0x0020, 0x000d) + (tagGroup = 8 AND tagElement = 80) OR -- AccessionNumber (0x0008, 0x0050) + (tagGroup = 32 AND tagElement = 14) OR -- SeriesInstanceUID (0x0020, 0x000e) + (tagGroup = 8 AND tagElement = 24)); -- SOPInstanceUID (0x0008, 0x0018) + + +-- Upgrade the "ResourceDeleted" trigger + +DROP TRIGGER ResourceDeleted; +DROP TRIGGER ResourceDeletedParentCleaning; + +CREATE TRIGGER ResourceDeleted +AFTER DELETE ON Resources +BEGIN + SELECT SignalResourceDeleted(old.publicId, old.resourceType); + SELECT SignalRemainingAncestor(parent.publicId, parent.resourceType) + FROM Resources AS parent WHERE internalId = old.parentId; +END; + +CREATE TRIGGER ResourceDeletedParentCleaning +AFTER DELETE ON Resources +FOR EACH ROW WHEN (SELECT COUNT(*) FROM Resources WHERE parentId = old.parentId) = 0 +BEGIN + DELETE FROM Resources WHERE internalId = old.parentId; +END; + + +-- Change the database version +-- The "1" corresponds to the "GlobalProperty_DatabaseSchemaVersion" enumeration + +UPDATE GlobalProperties SET value="5" WHERE property=1;
--- a/OrthancServer/IDatabaseListener.h Sat Jan 05 16:09:21 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * 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/>. - **/ - - -#pragma once - -#include <string> -#include "ServerEnumerations.h" -#include "ServerIndexChange.h" - -namespace Orthanc -{ - class IDatabaseListener - { - public: - virtual ~IDatabaseListener() - { - } - - virtual void SignalRemainingAncestor(ResourceType parentType, - const std::string& publicId) = 0; - - virtual void SignalFileDeleted(const FileInfo& info) = 0; - - virtual void SignalChange(const ServerIndexChange& change) = 0; - }; -}
--- a/OrthancServer/InstallTrackAttachmentsSize.sql Sat Jan 05 16:09:21 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -CREATE TABLE GlobalIntegers( - key INTEGER PRIMARY KEY, - value INTEGER); - -INSERT INTO GlobalProperties VALUES (6, 1); -- GlobalProperty_GetTotalSizeIsFast - -INSERT INTO GlobalIntegers SELECT 0, IFNULL(SUM(compressedSize), 0) FROM AttachedFiles; -INSERT INTO GlobalIntegers SELECT 1, IFNULL(SUM(uncompressedSize), 0) FROM AttachedFiles; - -CREATE TRIGGER AttachedFileIncrementSize -AFTER INSERT ON AttachedFiles -BEGIN - UPDATE GlobalIntegers SET value = value + new.compressedSize WHERE key = 0; - UPDATE GlobalIntegers SET value = value + new.uncompressedSize WHERE key = 1; -END; - -CREATE TRIGGER AttachedFileDecrementSize -AFTER DELETE ON AttachedFiles -BEGIN - UPDATE GlobalIntegers SET value = value - old.compressedSize WHERE key = 0; - UPDATE GlobalIntegers SET value = value - old.uncompressedSize WHERE key = 1; -END;
--- a/OrthancServer/OrthancFindRequestHandler.cpp Sat Jan 05 16:09:21 2019 +0100 +++ b/OrthancServer/OrthancFindRequestHandler.cpp Sat Jan 05 17:52:24 2019 +0100 @@ -35,10 +35,11 @@ #include "OrthancFindRequestHandler.h" #include "../Core/DicomFormat/DicomArray.h" -#include "../Core/Lua/LuaFunctionCall.h" +#include "../Core/DicomParsing/FromDcmtkBridge.h" #include "../Core/Logging.h" -#include "../Core/DicomParsing/FromDcmtkBridge.h" +#include "../Core/Lua/LuaFunctionCall.h" #include "OrthancConfiguration.h" +#include "Search/DatabaseLookup.h" #include "ServerToolbox.h" #include <boost/regex.hpp>
--- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Sat Jan 05 16:09:21 2019 +0100 +++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Sat Jan 05 17:52:24 2019 +0100 @@ -41,6 +41,7 @@ #include "../../Core/Logging.h" #include "../DefaultDicomImageDecoder.h" #include "../OrthancConfiguration.h" +#include "../Search/DatabaseLookup.h" #include "../ServerContext.h" #include "../ServerToolbox.h" #include "../SliceOrdering.h"
--- a/OrthancServer/PrepareDatabase.sql Sat Jan 05 16:09:21 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -CREATE TABLE GlobalProperties( - property INTEGER PRIMARY KEY, - value TEXT - ); - -CREATE TABLE Resources( - internalId INTEGER PRIMARY KEY AUTOINCREMENT, - resourceType INTEGER, - publicId TEXT, - parentId INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE - ); - -CREATE TABLE MainDicomTags( - id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, - tagGroup INTEGER, - tagElement INTEGER, - value TEXT, - PRIMARY KEY(id, tagGroup, tagElement) - ); - --- The following table was added in Orthanc 0.8.5 (database v5) -CREATE TABLE DicomIdentifiers( - id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, - tagGroup INTEGER, - tagElement INTEGER, - value TEXT, - PRIMARY KEY(id, tagGroup, tagElement) - ); - -CREATE TABLE Metadata( - id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, - type INTEGER, - value TEXT, - PRIMARY KEY(id, type) - ); - -CREATE TABLE AttachedFiles( - id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, - fileType INTEGER, - uuid TEXT, - compressedSize INTEGER, - uncompressedSize INTEGER, - compressionType INTEGER, - uncompressedMD5 TEXT, -- New in Orthanc 0.7.3 (database v4) - compressedMD5 TEXT, -- New in Orthanc 0.7.3 (database v4) - PRIMARY KEY(id, fileType) - ); - -CREATE TABLE Changes( - seq INTEGER PRIMARY KEY AUTOINCREMENT, - changeType INTEGER, - internalId INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, - resourceType INTEGER, - date TEXT - ); - -CREATE TABLE ExportedResources( - seq INTEGER PRIMARY KEY AUTOINCREMENT, - resourceType INTEGER, - publicId TEXT, - remoteModality TEXT, - patientId TEXT, - studyInstanceUid TEXT, - seriesInstanceUid TEXT, - sopInstanceUid TEXT, - date TEXT - ); - -CREATE TABLE PatientRecyclingOrder( - seq INTEGER PRIMARY KEY AUTOINCREMENT, - patientId INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE - ); - -CREATE INDEX ChildrenIndex ON Resources(parentId); -CREATE INDEX PublicIndex ON Resources(publicId); -CREATE INDEX ResourceTypeIndex ON Resources(resourceType); -CREATE INDEX PatientRecyclingIndex ON PatientRecyclingOrder(patientId); - -CREATE INDEX MainDicomTagsIndex1 ON MainDicomTags(id); --- The 2 following indexes were removed in Orthanc 0.8.5 (database v5), to speed up --- CREATE INDEX MainDicomTagsIndex2 ON MainDicomTags(tagGroup, tagElement); --- CREATE INDEX MainDicomTagsIndexValues ON MainDicomTags(value COLLATE BINARY); - --- The 3 following indexes were added in Orthanc 0.8.5 (database v5) -CREATE INDEX DicomIdentifiersIndex1 ON DicomIdentifiers(id); -CREATE INDEX DicomIdentifiersIndex2 ON DicomIdentifiers(tagGroup, tagElement); -CREATE INDEX DicomIdentifiersIndexValues ON DicomIdentifiers(value COLLATE BINARY); - -CREATE INDEX ChangesIndex ON Changes(internalId); - -CREATE TRIGGER AttachedFileDeleted -AFTER DELETE ON AttachedFiles -BEGIN - SELECT SignalFileDeleted(old.uuid, old.fileType, old.uncompressedSize, - old.compressionType, old.compressedSize, - -- These 2 arguments are new in Orthanc 0.7.3 (database v4) - old.uncompressedMD5, old.compressedMD5); -END; - -CREATE TRIGGER ResourceDeleted -AFTER DELETE ON Resources -BEGIN - SELECT SignalResourceDeleted(old.publicId, old.resourceType); -- New in Orthanc 0.8.5 (db v5) - SELECT SignalRemainingAncestor(parent.publicId, parent.resourceType) - FROM Resources AS parent WHERE internalId = old.parentId; -END; - --- Delete a parent resource when its unique child is deleted -CREATE TRIGGER ResourceDeletedParentCleaning -AFTER DELETE ON Resources -FOR EACH ROW WHEN (SELECT COUNT(*) FROM Resources WHERE parentId = old.parentId) = 0 -BEGIN - DELETE FROM Resources WHERE internalId = old.parentId; -END; - -CREATE TRIGGER PatientAdded -AFTER INSERT ON Resources -FOR EACH ROW WHEN new.resourceType = 1 -- "1" corresponds to "ResourceType_Patient" in C++ -BEGIN - INSERT INTO PatientRecyclingOrder VALUES (NULL, new.internalId); -END; - - --- Set the version of the database schema --- The "1" corresponds to the "GlobalProperty_DatabaseSchemaVersion" enumeration -INSERT INTO GlobalProperties VALUES (1, "6");
--- a/OrthancServer/ServerContext.cpp Sat Jan 05 16:09:21 2019 +0100 +++ b/OrthancServer/ServerContext.cpp Sat Jan 05 17:52:24 2019 +0100 @@ -42,6 +42,7 @@ #include "../Plugins/Engine/OrthancPlugins.h" #include "OrthancConfiguration.h" #include "OrthancRestApi/OrthancRestApi.h" +#include "Search/DatabaseLookup.h" #include "ServerJobs/OrthancJobUnserializer.h" #include "ServerToolbox.h"
--- a/OrthancServer/ServerIndex.cpp Sat Jan 05 16:09:21 2019 +0100 +++ b/OrthancServer/ServerIndex.cpp Sat Jan 05 17:52:24 2019 +0100 @@ -38,18 +38,21 @@ #define NOMINMAX #endif -#include "ServerIndexChange.h" +#include "../Core/DicomFormat/DicomArray.h" +#include "../Core/DicomParsing/FromDcmtkBridge.h" +#include "../Core/DicomParsing/ParsedDicomFile.h" +#include "../Core/Logging.h" +#include "../Core/Toolbox.h" + +#include "Database/ResourcesContent.h" +#include "DicomInstanceToStore.h" #include "EmbeddedResources.h" #include "OrthancConfiguration.h" -#include "../Core/DicomParsing/ParsedDicomFile.h" +#include "Search/DatabaseLookup.h" +#include "Search/DicomTagConstraint.h" +#include "ServerContext.h" +#include "ServerIndexChange.h" #include "ServerToolbox.h" -#include "../Core/Toolbox.h" -#include "../Core/Logging.h" -#include "../Core/DicomFormat/DicomArray.h" - -#include "../Core/DicomParsing/FromDcmtkBridge.h" -#include "ServerContext.h" -#include "DicomInstanceToStore.h" #include <boost/lexical_cast.hpp> #include <stdio.h>
--- a/OrthancServer/ServerIndex.h Sat Jan 05 16:09:21 2019 +0100 +++ b/OrthancServer/ServerIndex.h Sat Jan 05 17:52:24 2019 +0100 @@ -33,20 +33,22 @@ #pragma once +#include "../Core/Cache/LeastRecentlyUsedIndex.h" +#include "../Core/DicomFormat/DicomMap.h" +#include "../Core/SQLite/Connection.h" + +#include "Database/IDatabaseWrapper.h" +#include "ServerEnumerations.h" + #include <boost/thread.hpp> #include <boost/noncopyable.hpp> -#include "../Core/Cache/LeastRecentlyUsedIndex.h" -#include "../Core/SQLite/Connection.h" -#include "../Core/DicomFormat/DicomMap.h" -#include "ServerEnumerations.h" - -#include "Database/IDatabaseWrapper.h" namespace Orthanc { - class ServerContext; + class DatabaseLookup; class DicomInstanceToStore; class ParsedDicomFile; + class ServerContext; class ServerIndex : public boost::noncopyable {
--- a/OrthancServer/ServerToolbox.cpp Sat Jan 05 16:09:21 2019 +0100 +++ b/OrthancServer/ServerToolbox.cpp Sat Jan 05 17:52:24 2019 +0100 @@ -76,72 +76,6 @@ }; - void ResourcesContent::Store(Compatibility::ISetResourcesContent& compatibility) const - { - for (std::list<TagValue>::const_iterator - it = tags_.begin(); it != tags_.end(); ++it) - { - if (it->isIdentifier_) - { - compatibility.SetIdentifierTag(it->resourceId_, it->tag_, it->value_); - } - else - { - compatibility.SetMainDicomTag(it->resourceId_, it->tag_, it->value_); - } - } - - for (std::list<Metadata>::const_iterator - it = metadata_.begin(); it != metadata_.end(); ++it) - { - compatibility.SetMetadata(it->resourceId_, it->metadata_, it->value_); - } - } - - - void ResourcesContent::EncodeForPlugins( - std::vector<OrthancPluginResourcesContentTags>& identifierTags, - std::vector<OrthancPluginResourcesContentTags>& mainDicomTags, - std::vector<OrthancPluginResourcesContentMetadata>& metadata) const - { - identifierTags.reserve(tags_.size()); - mainDicomTags.reserve(tags_.size()); - metadata.reserve(metadata_.size()); - - for (std::list<TagValue>::const_iterator - it = tags_.begin(); it != tags_.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 (std::list<Metadata>::const_iterator - it = metadata_.begin(); it != metadata_.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() == tags_.size() && - metadata.size() == metadata_.size()); - } - - static void StoreMainDicomTagsInternal(ResourcesContent& target, int64_t resource, const DicomMap& tags)
--- a/OrthancServer/ServerToolbox.h Sat Jan 05 16:09:21 2019 +0100 +++ b/OrthancServer/ServerToolbox.h Sat Jan 05 17:52:24 2019 +0100 @@ -39,101 +39,12 @@ #include <boost/noncopyable.hpp> #include <list> -#include <orthanc/OrthancCDatabasePlugin.h> - namespace Orthanc { class ServerContext; class IDatabaseWrapper; - class DicomMap; class IStorageArea; - namespace Compatibility - { - class ISetResourcesContent; - } - - - // TODO - Move this to a separate file - class ResourcesContent : public boost::noncopyable - { - private: - struct TagValue - { - int64_t resourceId_; - bool isIdentifier_; - DicomTag tag_; - std::string value_; - - TagValue(int64_t resourceId, - bool isIdentifier, - const DicomTag& tag, - const std::string& value) : - resourceId_(resourceId), - isIdentifier_(isIdentifier), - tag_(tag), - value_(value) - { - } - }; - - struct Metadata - { - int64_t resourceId_; - MetadataType metadata_; - std::string value_; - - Metadata(int64_t resourceId, - MetadataType metadata, - const std::string& value) : - resourceId_(resourceId), - metadata_(metadata), - value_(value) - { - } - }; - - std::list<TagValue> tags_; - std::list<Metadata> metadata_; - - public: - void AddMainDicomTag(int64_t resourceId, - const DicomTag& tag, - const std::string& value) - { - tags_.push_back(TagValue(resourceId, false, tag, value)); - } - - void AddIdentifierTag(int64_t resourceId, - const DicomTag& tag, - const std::string& value) - { - tags_.push_back(TagValue(resourceId, true, tag, value)); - } - - void AddMetadata(int64_t resourceId, - MetadataType metadata, - const std::string& value) - { - metadata_.push_back(Metadata(resourceId, metadata, value)); - } - - void AddResource(int64_t resource, - ResourceType level, - const DicomMap& dicomSummary); - - // WARNING: The database should be locked with a transaction! - void Store(Compatibility::ISetResourcesContent& target) const; - - // WARNING: The resulting C structure will contain pointers to the - // current object. Don't delete or modify it! - void EncodeForPlugins( - std::vector<OrthancPluginResourcesContentTags>& identifierTags, - std::vector<OrthancPluginResourcesContentTags>& mainDicomTags, - std::vector<OrthancPluginResourcesContentMetadata>& metadata) const; - }; - - namespace ServerToolbox { void SimplifyTags(Json::Value& target,
--- a/OrthancServer/Upgrade3To4.sql Sat Jan 05 16:09:21 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ --- This SQLite script updates the version of the Orthanc database from 3 to 4. - --- Add 2 new columns at "AttachedFiles" - -ALTER TABLE AttachedFiles ADD COLUMN uncompressedMD5 TEXT; -ALTER TABLE AttachedFiles ADD COLUMN compressedMD5 TEXT; - --- Update the "AttachedFileDeleted" trigger - -DROP TRIGGER AttachedFileDeleted; - -CREATE TRIGGER AttachedFileDeleted -AFTER DELETE ON AttachedFiles -BEGIN - SELECT SignalFileDeleted(old.uuid, old.fileType, old.uncompressedSize, - old.compressionType, old.compressedSize, - -- These 2 arguments are new in Orthanc 0.7.3 (database v4) - old.uncompressedMD5, old.compressedMD5); -END; - --- Change the database version --- The "1" corresponds to the "GlobalProperty_DatabaseSchemaVersion" enumeration - -UPDATE GlobalProperties SET value="4" WHERE property=1;
--- a/OrthancServer/Upgrade4To5.sql Sat Jan 05 16:09:21 2019 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ --- This SQLite script updates the version of the Orthanc database from 4 to 5. - - --- Remove 2 indexes to speed up - -DROP INDEX MainDicomTagsIndex2; -DROP INDEX MainDicomTagsIndexValues; - - --- Add a new table to index the DICOM identifiers - -CREATE TABLE DicomIdentifiers( - id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE, - tagGroup INTEGER, - tagElement INTEGER, - value TEXT, - PRIMARY KEY(id, tagGroup, tagElement) - ); - -CREATE INDEX DicomIdentifiersIndex1 ON DicomIdentifiers(id); -CREATE INDEX DicomIdentifiersIndex2 ON DicomIdentifiers(tagGroup, tagElement); -CREATE INDEX DicomIdentifiersIndexValues ON DicomIdentifiers(value COLLATE BINARY); - - --- Migrate data from MainDicomTags to MainResourcesTags and MainInstancesTags - -INSERT INTO DicomIdentifiers SELECT * FROM MainDicomTags - WHERE ((tagGroup = 16 AND tagElement = 32) OR -- PatientID (0x0010, 0x0020) - (tagGroup = 32 AND tagElement = 13) OR -- StudyInstanceUID (0x0020, 0x000d) - (tagGroup = 8 AND tagElement = 80) OR -- AccessionNumber (0x0008, 0x0050) - (tagGroup = 32 AND tagElement = 14) OR -- SeriesInstanceUID (0x0020, 0x000e) - (tagGroup = 8 AND tagElement = 24)); -- SOPInstanceUID (0x0008, 0x0018) - -DELETE FROM MainDicomTags - WHERE ((tagGroup = 16 AND tagElement = 32) OR -- PatientID (0x0010, 0x0020) - (tagGroup = 32 AND tagElement = 13) OR -- StudyInstanceUID (0x0020, 0x000d) - (tagGroup = 8 AND tagElement = 80) OR -- AccessionNumber (0x0008, 0x0050) - (tagGroup = 32 AND tagElement = 14) OR -- SeriesInstanceUID (0x0020, 0x000e) - (tagGroup = 8 AND tagElement = 24)); -- SOPInstanceUID (0x0008, 0x0018) - - --- Upgrade the "ResourceDeleted" trigger - -DROP TRIGGER ResourceDeleted; -DROP TRIGGER ResourceDeletedParentCleaning; - -CREATE TRIGGER ResourceDeleted -AFTER DELETE ON Resources -BEGIN - SELECT SignalResourceDeleted(old.publicId, old.resourceType); - SELECT SignalRemainingAncestor(parent.publicId, parent.resourceType) - FROM Resources AS parent WHERE internalId = old.parentId; -END; - -CREATE TRIGGER ResourceDeletedParentCleaning -AFTER DELETE ON Resources -FOR EACH ROW WHEN (SELECT COUNT(*) FROM Resources WHERE parentId = old.parentId) = 0 -BEGIN - DELETE FROM Resources WHERE internalId = old.parentId; -END; - - --- Change the database version --- The "1" corresponds to the "GlobalProperty_DatabaseSchemaVersion" enumeration - -UPDATE GlobalProperties SET value="5" WHERE property=1;
--- a/UnitTestsSources/ServerIndexTests.cpp Sat Jan 05 16:09:21 2019 +0100 +++ b/UnitTestsSources/ServerIndexTests.cpp Sat Jan 05 17:52:24 2019 +0100 @@ -38,6 +38,7 @@ #include "../Core/FileStorage/MemoryStorageArea.h" #include "../Core/Logging.h" #include "../OrthancServer/Database/SQLiteDatabaseWrapper.h" +#include "../OrthancServer/Search/DatabaseLookup.h" #include "../OrthancServer/ServerContext.h" #include "../OrthancServer/ServerToolbox.h"