changeset 3094:61da3c9b4121 db-changes

cont reorganization
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sat, 05 Jan 2019 17:52:24 +0100
parents 2e1808b6146a
children beeeb6096f27
files CMakeLists.txt OrthancServer/Database/Compatibility/DatabaseLookup.cpp OrthancServer/Database/Compatibility/ISetResourcesContent.h OrthancServer/Database/IDatabaseListener.h OrthancServer/Database/IDatabaseWrapper.h OrthancServer/Database/InstallTrackAttachmentsSize.sql OrthancServer/Database/PrepareDatabase.sql OrthancServer/Database/ResourcesContent.cpp OrthancServer/Database/ResourcesContent.h OrthancServer/Database/SQLiteDatabaseWrapper.h OrthancServer/Database/Upgrade3To4.sql OrthancServer/Database/Upgrade4To5.sql OrthancServer/IDatabaseListener.h OrthancServer/InstallTrackAttachmentsSize.sql OrthancServer/OrthancFindRequestHandler.cpp OrthancServer/OrthancRestApi/OrthancRestResources.cpp OrthancServer/PrepareDatabase.sql OrthancServer/ServerContext.cpp OrthancServer/ServerIndex.cpp OrthancServer/ServerIndex.h OrthancServer/ServerToolbox.cpp OrthancServer/ServerToolbox.h OrthancServer/Upgrade3To4.sql OrthancServer/Upgrade4To5.sql UnitTestsSources/ServerIndexTests.cpp
diffstat 25 files changed, 572 insertions(+), 479 deletions(-) [+]
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"