changeset 3080:1a75595d8e44 db-changes

started refactoring of ServerIndex::Store()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 03 Jan 2019 18:21:22 +0100
parents 65e2bfa953ef
children 2e5970ddcfeb
files CMakeLists.txt OrthancServer/IDatabaseWrapper.h OrthancServer/SQLiteDatabaseWrapper.cpp OrthancServer/SQLiteDatabaseWrapper.h OrthancServer/Search/Compatibility/CompatibilityDatabaseWrapper.cpp OrthancServer/Search/Compatibility/CompatibilityDatabaseWrapper.h OrthancServer/Search/Compatibility/ICompatibilityCreateInstance.cpp OrthancServer/Search/Compatibility/ICompatibilityCreateInstance.h OrthancServer/ServerIndex.cpp OrthancServer/ServerIndex.h Plugins/Engine/OrthancPluginDatabase.cpp Plugins/Engine/OrthancPluginDatabase.h UnitTestsSources/ServerIndexTests.cpp
diffstat 13 files changed, 585 insertions(+), 346 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Thu Jan 03 14:03:39 2019 +0100
+++ b/CMakeLists.txt	Thu Jan 03 18:21:22 2019 +0100
@@ -73,6 +73,7 @@
   OrthancServer/SQLiteDatabaseWrapper.cpp
   OrthancServer/Search/Compatibility/CompatibilityDatabaseWrapper.cpp
   OrthancServer/Search/Compatibility/DatabaseLookup.cpp
+  OrthancServer/Search/Compatibility/ICompatibilityCreateInstance.cpp
   OrthancServer/Search/Compatibility/SetOfResources.cpp
   OrthancServer/Search/DatabaseConstraint.cpp
   OrthancServer/Search/DatabaseLookup.cpp
--- a/OrthancServer/IDatabaseWrapper.h	Thu Jan 03 14:03:39 2019 +0100
+++ b/OrthancServer/IDatabaseWrapper.h	Thu Jan 03 18:21:22 2019 +0100
@@ -66,6 +66,17 @@
     };
 
 
+    struct CreateInstanceResult
+    {
+      bool     isNewPatient_;
+      bool     isNewStudy_;
+      bool     isNewSeries_;
+      int64_t  patientId_;
+      int64_t  studyId_;
+      int64_t  seriesId_;
+    };
+
+
     virtual ~IDatabaseWrapper()
     {
     }
@@ -77,16 +88,10 @@
     virtual void AddAttachment(int64_t id,
                                const FileInfo& attachment) = 0;
 
-    virtual void AttachChild(int64_t parent,
-                             int64_t child) = 0;
-
     virtual void ClearChanges() = 0;
 
     virtual void ClearExportedResources() = 0;
 
-    virtual int64_t CreateResource(const std::string& publicId,
-                                   ResourceType type) = 0;
-
     virtual void DeleteAttachment(int64_t id,
                                   FileContentType attachment) = 0;
 
@@ -210,12 +215,28 @@
     virtual void Upgrade(unsigned int targetVersion,
                          IStorageArea& storageArea) = 0;
 
+
+    /**
+     * Primitives introduced in Orthanc 1.5.2
+     **/
+    
     virtual bool IsDiskSizeAbove(uint64_t threshold) = 0;
-
+    
     virtual void ApplyLookupResources(std::list<std::string>& resourcesId,
                                       std::list<std::string>* instancesId, // Can be NULL if not needed
                                       const std::vector<DatabaseConstraint>& lookup,
                                       ResourceType queryLevel,
                                       size_t limit) = 0;
+
+    // Returns "true" iff. the instance already exists *and*
+    // "overwrite" is "false". If "false" is returned, the content of
+    // "result" is undefined, but "instanceId" must be properly set.
+    virtual bool CreateInstance(CreateInstanceResult& result, /* out */
+                                int64_t& instanceId,          /* out */
+                                const std::string& patient,
+                                const std::string& study,
+                                const std::string& series,
+                                const std::string& instance,
+                                bool overwrite) = 0;
   };
 }
--- a/OrthancServer/SQLiteDatabaseWrapper.cpp	Thu Jan 03 14:03:39 2019 +0100
+++ b/OrthancServer/SQLiteDatabaseWrapper.cpp	Thu Jan 03 18:21:22 2019 +0100
@@ -1248,8 +1248,6 @@
     }
 
     {
-      printf("[%s]\n", sql.c_str());
-
       SQLite::Statement statement(db_, sql);
       formatter.Bind(statement);
       statement.Run();
--- a/OrthancServer/SQLiteDatabaseWrapper.h	Thu Jan 03 14:03:39 2019 +0100
+++ b/OrthancServer/SQLiteDatabaseWrapper.h	Thu Jan 03 18:21:22 2019 +0100
@@ -36,6 +36,7 @@
 #include "IDatabaseWrapper.h"
 
 #include "../Core/SQLite/Connection.h"
+#include "Search/Compatibility/ICompatibilityCreateInstance.h"
 
 namespace Orthanc
 {
@@ -49,7 +50,9 @@
    * translates low-level requests into SQL statements. Mutual
    * exclusion MUST be implemented at a higher level.
    **/
-  class SQLiteDatabaseWrapper : public IDatabaseWrapper
+  class SQLiteDatabaseWrapper :
+    public IDatabaseWrapper,
+    public Compatibility::ICompatibilityCreateInstance
   {
   private:
     class Transaction;
@@ -320,5 +323,17 @@
                                       ResourceType queryLevel,
                                       size_t limit)
       ORTHANC_OVERRIDE;
+
+    virtual bool CreateInstance(CreateInstanceResult& result,
+                                int64_t& instanceId,
+                                const std::string& patient,
+                                const std::string& study,
+                                const std::string& series,
+                                const std::string& instance,
+                                bool overwrite)
+    {
+      return ICompatibilityCreateInstance::Apply(
+        result, instanceId, *this, *this, patient, study, series, instance, overwrite);
+    }
   };
 }
--- a/OrthancServer/Search/Compatibility/CompatibilityDatabaseWrapper.cpp	Thu Jan 03 14:03:39 2019 +0100
+++ b/OrthancServer/Search/Compatibility/CompatibilityDatabaseWrapper.cpp	Thu Jan 03 18:21:22 2019 +0100
@@ -40,14 +40,29 @@
 {
   namespace Compatibility
   {
-    void CompatibilityDatabaseWrapper::ApplyLookupResources(std::list<std::string>& resourcesId,
-                                                            std::list<std::string>* instancesId,
-                                                            const std::vector<DatabaseConstraint>& lookup,
-                                                            ResourceType queryLevel,
-                                                            size_t limit)
+    void CompatibilityDatabaseWrapper::ApplyLookupResources(
+      std::list<std::string>& resourcesId,
+      std::list<std::string>* instancesId,
+      const std::vector<DatabaseConstraint>& lookup,
+      ResourceType queryLevel,
+      size_t limit)
     {
       Compatibility::DatabaseLookup compat(*this);
       compat.ApplyLookupResources(resourcesId, instancesId, lookup, queryLevel, limit);
     }
+    
+
+    bool CompatibilityDatabaseWrapper::CreateInstance(
+      IDatabaseWrapper::CreateInstanceResult& result,
+      int64_t& instanceId,
+      const std::string& patient,
+      const std::string& study,
+      const std::string& series,
+      const std::string& instance,
+      bool overwrite)
+    {
+      return ICompatibilityCreateInstance::Apply
+        (result, instanceId, *this, *this, patient, study, series, instance, overwrite);
+    }
   }
 }
--- a/OrthancServer/Search/Compatibility/CompatibilityDatabaseWrapper.h	Thu Jan 03 14:03:39 2019 +0100
+++ b/OrthancServer/Search/Compatibility/CompatibilityDatabaseWrapper.h	Thu Jan 03 18:21:22 2019 +0100
@@ -33,7 +33,7 @@
 
 #pragma once
 
-#include "../../IDatabaseWrapper.h"
+#include "ICompatibilityCreateInstance.h"
 
 namespace Orthanc
 {
@@ -44,7 +44,9 @@
      * that were used in Orthanc <= 1.5.1, and that have been removed
      * during the optimization of the database engine.
      **/
-    class CompatibilityDatabaseWrapper : public IDatabaseWrapper
+    class CompatibilityDatabaseWrapper :
+      public IDatabaseWrapper,
+      public ICompatibilityCreateInstance
     {     
     public:
       virtual void ApplyLookupResources(std::list<std::string>& resourcesId,
@@ -54,9 +56,18 @@
                                         size_t limit)
         ORTHANC_OVERRIDE;
 
+      virtual bool CreateInstance(CreateInstanceResult& result,
+                                  int64_t& instanceId,
+                                  const std::string& patient,
+                                  const std::string& study,
+                                  const std::string& series,
+                                  const std::string& instance,
+                                  bool overwrite)
+        ORTHANC_OVERRIDE;
+
       virtual void GetAllInternalIds(std::list<int64_t>& target,
                                      ResourceType resourceType) = 0;
-
+      
       virtual void LookupIdentifier(std::list<int64_t>& result,
                                     ResourceType level,
                                     const DicomTag& tag,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancServer/Search/Compatibility/ICompatibilityCreateInstance.cpp	Thu Jan 03 18:21:22 2019 +0100
@@ -0,0 +1,167 @@
+/**
+ * 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 "ICompatibilityCreateInstance.h"
+
+#include "../../../Core/OrthancException.h"
+
+namespace Orthanc
+{
+  namespace Compatibility
+  {
+    bool ICompatibilityCreateInstance::Apply(IDatabaseWrapper::CreateInstanceResult& result,
+                                             int64_t& instanceId,
+                                             ICompatibilityCreateInstance& compatibility,
+                                             IDatabaseWrapper& database,
+                                             const std::string& hashPatient,
+                                             const std::string& hashStudy,
+                                             const std::string& hashSeries,
+                                             const std::string& hashInstance,
+                                             bool overwrite)
+    {
+      {
+        ResourceType type;
+        int64_t tmp;
+        
+        if (database.LookupResource(tmp, type, hashInstance))
+        {
+          assert(type == ResourceType_Instance);
+
+          if (overwrite)
+          {
+            // Overwrite the old instance
+            LOG(INFO) << "Overwriting instance: " << hashInstance;
+            database.DeleteResource(tmp);
+          }
+          else
+          {
+            // Do nothing if the instance already exists
+            instanceId = tmp;
+            return false;
+          }
+        }
+      }
+
+      instanceId = compatibility.CreateResource(hashInstance, ResourceType_Instance);
+
+      result.isNewPatient_ = false;
+      result.isNewStudy_ = false;
+      result.isNewSeries_ = false;
+      result.patientId_ = -1;
+      result.studyId_ = -1;
+      result.seriesId_ = -1;
+      
+      // Detect up to which level the patient/study/series/instance
+      // hierarchy must be created
+
+      {
+        ResourceType dummy;
+
+        if (database.LookupResource(result.seriesId_, dummy, hashSeries))
+        {
+          assert(dummy == ResourceType_Series);
+          // The patient, the study and the series already exist
+
+          bool ok = (database.LookupResource(result.patientId_, dummy, hashPatient) &&
+                     database.LookupResource(result.studyId_, dummy, hashStudy));
+          assert(ok);
+        }
+        else if (database.LookupResource(result.studyId_, dummy, hashStudy))
+        {
+          assert(dummy == ResourceType_Study);
+
+          // New series: The patient and the study already exist
+          result.isNewSeries_ = true;
+
+          bool ok = database.LookupResource(result.patientId_, dummy, hashPatient);
+          assert(ok);
+        }
+        else if (database.LookupResource(result.patientId_, dummy, hashPatient))
+        {
+          assert(dummy == ResourceType_Patient);
+
+          // New study and series: The patient already exist
+          result.isNewStudy_ = true;
+          result.isNewSeries_ = true;
+        }
+        else
+        {
+          // New patient, study and series: Nothing exists
+          result.isNewPatient_ = true;
+          result.isNewStudy_ = true;
+          result.isNewSeries_ = true;
+        }
+      }
+
+      // Create the series if needed
+      if (result.isNewSeries_)
+      {
+        result.seriesId_ = compatibility.CreateResource(hashSeries, ResourceType_Series);
+      }
+
+      // Create the study if needed
+      if (result.isNewStudy_)
+      {
+        result.studyId_ = compatibility.CreateResource(hashStudy, ResourceType_Study);
+      }
+
+      // Create the patient if needed
+      if (result.isNewPatient_)
+      {
+        result.patientId_ = compatibility.CreateResource(hashPatient, ResourceType_Patient);
+      }
+
+      // Create the parent-to-child links
+      compatibility.AttachChild(result.seriesId_, instanceId);
+
+      if (result.isNewSeries_)
+      {
+        compatibility.AttachChild(result.studyId_, result.seriesId_);
+      }
+
+      if (result.isNewStudy_)
+      {
+        compatibility.AttachChild(result.patientId_, result.studyId_);
+      }
+
+      // Sanity checks
+      assert(result.patientId_ != -1);
+      assert(result.studyId_ != -1);
+      assert(result.seriesId_ != -1);
+      assert(instanceId != -1);
+
+      return true;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancServer/Search/Compatibility/ICompatibilityCreateInstance.h	Thu Jan 03 18:21:22 2019 +0100
@@ -0,0 +1,62 @@
+/**
+ * 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 "../../IDatabaseWrapper.h"
+
+namespace Orthanc
+{
+  namespace Compatibility
+  {
+    class ICompatibilityCreateInstance : public boost::noncopyable
+    {
+    public:
+      virtual int64_t CreateResource(const std::string& publicId,
+                                     ResourceType type) = 0;
+
+      virtual void AttachChild(int64_t parent,
+                               int64_t child) = 0;
+      
+      static bool Apply(IDatabaseWrapper::CreateInstanceResult& result,
+                        int64_t& instanceId,
+                        ICompatibilityCreateInstance& compatibility,
+                        IDatabaseWrapper& database,
+                        const std::string& patient,
+                        const std::string& study,
+                        const std::string& series,
+                        const std::string& instance,
+                        bool overwrite);
+    };
+  }
+}
--- a/OrthancServer/ServerIndex.cpp	Thu Jan 03 14:03:39 2019 +0100
+++ b/OrthancServer/ServerIndex.cpp	Thu Jan 03 18:21:22 2019 +0100
@@ -612,44 +612,6 @@
 
 
 
-  int64_t ServerIndex::CreateResource(const std::string& publicId,
-                                      ResourceType type)
-  {
-    int64_t id = db_.CreateResource(publicId, type);
-
-    ChangeType changeType;
-    switch (type)
-    {
-    case ResourceType_Patient: 
-      changeType = ChangeType_NewPatient; 
-      break;
-
-    case ResourceType_Study: 
-      changeType = ChangeType_NewStudy; 
-      break;
-
-    case ResourceType_Series: 
-      changeType = ChangeType_NewSeries; 
-      break;
-
-    case ResourceType_Instance: 
-      changeType = ChangeType_NewInstance; 
-      break;
-
-    default:
-      throw OrthancException(ErrorCode_InternalError);
-    }
-
-    ServerIndexChange change(changeType, type, publicId);
-    db_.LogChange(id, change);
-
-    assert(listener_.get() != NULL);
-    listener_->SignalChange(change);
-
-    return id;
-  }
-
-
   ServerIndex::ServerIndex(ServerContext& context,
                            IDatabaseWrapper& db,
                            unsigned int threadSleep) : 
@@ -720,7 +682,19 @@
   }
 
 
-
+  void ServerIndex::SignalNewResource(ChangeType changeType,
+                                      ResourceType level,
+                                      const std::string& publicId,
+                                      int64_t internalId)
+  {
+    ServerIndexChange change(changeType, level, publicId);
+    db_.LogChange(internalId, change);
+    
+    assert(listener_.get() != NULL);
+    listener_->SignalChange(change);
+  }
+
+  
   StoreStatus ServerIndex::Store(std::map<MetadataType, std::string>& instanceMetadata,
                                  DicomInstanceToStore& instanceToStore,
                                  const Attachments& attachments)
@@ -732,33 +706,47 @@
 
     instanceMetadata.clear();
 
+    const std::string hashPatient = instanceToStore.GetHasher().HashPatient();
+    const std::string hashStudy = instanceToStore.GetHasher().HashStudy();
+    const std::string hashSeries = instanceToStore.GetHasher().HashSeries();
+    const std::string hashInstance = instanceToStore.GetHasher().HashInstance();
+
     try
     {
       Transaction t(*this);
 
+      IDatabaseWrapper::CreateInstanceResult status;
+      int64_t instanceId;
+
       // Check whether this instance is already stored
+      if (!db_.CreateInstance(status, instanceId, hashPatient,
+                              hashStudy, hashSeries, hashInstance, overwrite_))
       {
-        ResourceType type;
-        int64_t tmp;
-        if (db_.LookupResource(tmp, type, instanceToStore.GetHasher().HashInstance()))
-        {
-          assert(type == ResourceType_Instance);
-
-          if (overwrite_)
-          {
-            // Overwrite the old instance
-            LOG(INFO) << "Overwriting instance: " << instanceToStore.GetHasher().HashInstance();
-            db_.DeleteResource(tmp);
-          }
-          else
-          {
-            // Do nothing if the instance already exists
-            db_.GetAllMetadata(instanceMetadata, tmp);
-            return StoreStatus_AlreadyStored;
-          }
-        }
+        // Do nothing if the instance already exists and overwriting is disabled
+        db_.GetAllMetadata(instanceMetadata, instanceId);
+        return StoreStatus_AlreadyStored;
+      }
+
+
+      // Warn about the creation of new resources. The order must be from instance to patient.
+      SignalNewResource(ChangeType_NewInstance, ResourceType_Instance, hashInstance, instanceId);
+
+      if (status.isNewSeries_)
+      {
+        SignalNewResource(ChangeType_NewSeries, ResourceType_Series, hashSeries, status.seriesId_);
       }
-
+      
+      if (status.isNewStudy_)
+      {
+        SignalNewResource(ChangeType_NewStudy, ResourceType_Study, hashStudy, status.studyId_);
+      }
+      
+      if (status.isNewPatient_)
+      {
+        SignalNewResource(ChangeType_NewPatient, ResourceType_Patient, hashPatient, status.patientId_);
+      }
+      
+      
       // Ensure there is enough room in the storage for the new instance
       uint64_t instanceSize = 0;
       for (Attachments::const_iterator it = attachments.begin();
@@ -767,125 +755,59 @@
         instanceSize += it->GetCompressedSize();
       }
 
-      Recycle(instanceSize, instanceToStore.GetHasher().HashPatient());
-
-      // Create the instance
-      int64_t instance = CreateResource(instanceToStore.GetHasher().HashInstance(), ResourceType_Instance);
-      ServerToolbox::StoreMainDicomTags(db_, instance, ResourceType_Instance, dicomSummary);
-
-      // Detect up to which level the patient/study/series/instance
-      // hierarchy must be created
-      int64_t patient = -1, study = -1, series = -1;
-      bool isNewPatient = false;
-      bool isNewStudy = false;
-      bool isNewSeries = false;
-
+      Recycle(instanceSize, hashPatient /* don't consider the current patient for recycling */);
+
+      
+      // Populate the newly-created resources
+      // TODO - GROUP THIS
+
+      ServerToolbox::StoreMainDicomTags(db_, instanceId, ResourceType_Instance, dicomSummary);
+
+      if (status.isNewSeries_)
       {
-        ResourceType dummy;
-
-        if (db_.LookupResource(series, dummy, instanceToStore.GetHasher().HashSeries()))
-        {
-          assert(dummy == ResourceType_Series);
-          // The patient, the study and the series already exist
-
-          bool ok = (db_.LookupResource(patient, dummy, instanceToStore.GetHasher().HashPatient()) &&
-                     db_.LookupResource(study, dummy, instanceToStore.GetHasher().HashStudy()));
-          assert(ok);
-        }
-        else if (db_.LookupResource(study, dummy, instanceToStore.GetHasher().HashStudy()))
-        {
-          assert(dummy == ResourceType_Study);
-
-          // New series: The patient and the study already exist
-          isNewSeries = true;
-
-          bool ok = db_.LookupResource(patient, dummy, instanceToStore.GetHasher().HashPatient());
-          assert(ok);
-        }
-        else if (db_.LookupResource(patient, dummy, instanceToStore.GetHasher().HashPatient()))
-        {
-          assert(dummy == ResourceType_Patient);
-
-          // New study and series: The patient already exist
-          isNewStudy = true;
-          isNewSeries = true;
-        }
-        else
-        {
-          // New patient, study and series: Nothing exists
-          isNewPatient = true;
-          isNewStudy = true;
-          isNewSeries = true;
-        }
+        ServerToolbox::StoreMainDicomTags(db_, status.seriesId_, ResourceType_Series, dicomSummary);
+      }
+
+      if (status.isNewStudy_)
+      {
+        ServerToolbox::StoreMainDicomTags(db_, status.studyId_, ResourceType_Study, dicomSummary);
       }
 
-      // Create the series if needed
-      if (isNewSeries)
-      {
-        series = CreateResource(instanceToStore.GetHasher().HashSeries(), ResourceType_Series);
-        ServerToolbox::StoreMainDicomTags(db_, series, ResourceType_Series, dicomSummary);
-      }
-
-      // Create the study if needed
-      if (isNewStudy)
+      if (status.isNewPatient_)
       {
-        study = CreateResource(instanceToStore.GetHasher().HashStudy(), ResourceType_Study);
-        ServerToolbox::StoreMainDicomTags(db_, study, ResourceType_Study, dicomSummary);
-      }
-
-      // Create the patient if needed
-      if (isNewPatient)
-      {
-        patient = CreateResource(instanceToStore.GetHasher().HashPatient(), ResourceType_Patient);
-        ServerToolbox::StoreMainDicomTags(db_, patient, ResourceType_Patient, dicomSummary);
+        ServerToolbox::StoreMainDicomTags(db_, status.patientId_, ResourceType_Patient, dicomSummary);
       }
 
-      // Create the parent-to-child links
-      db_.AttachChild(series, instance);
-
-      if (isNewSeries)
-      {
-        db_.AttachChild(study, series);
-      }
-
-      if (isNewStudy)
-      {
-        db_.AttachChild(patient, study);
-      }
-
-      // Sanity checks
-      assert(patient != -1);
-      assert(study != -1);
-      assert(series != -1);
-      assert(instance != -1);
-
+     
       // Attach the files to the newly created instance
       for (Attachments::const_iterator it = attachments.begin();
            it != attachments.end(); ++it)
       {
-        db_.AddAttachment(instance, *it);
+        db_.AddAttachment(instanceId, *it);
       }
+      
 
       // Attach the user-specified metadata
+      // TODO - GROUP THIS
       for (MetadataMap::const_iterator 
              it = metadata.begin(); it != metadata.end(); ++it)
       {
         switch (it->first.first)
         {
           case ResourceType_Patient:
-            db_.SetMetadata(patient, it->first.second, it->second);
+            db_.SetMetadata(status.patientId_, it->first.second, it->second);
             break;
 
           case ResourceType_Study:
-            db_.SetMetadata(study, it->first.second, it->second);
+            db_.SetMetadata(status.studyId_, it->first.second, it->second);
             break;
 
           case ResourceType_Series:
-            db_.SetMetadata(series, it->first.second, it->second);
+            db_.SetMetadata(status.seriesId_, it->first.second, it->second);
             break;
 
           case ResourceType_Instance:
-            SetInstanceMetadata(instanceMetadata, instance, it->first.second, it->second);
+            SetInstanceMetadata(instanceMetadata, instanceId, it->first.second, it->second);
             break;
 
           default:
@@ -895,16 +817,16 @@
 
       // Attach the auto-computed metadata for the patient/study/series levels
       std::string now = SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */);
-      db_.SetMetadata(series, MetadataType_LastUpdate, now);
-      db_.SetMetadata(study, MetadataType_LastUpdate, now);
-      db_.SetMetadata(patient, MetadataType_LastUpdate, now);
+      db_.SetMetadata(status.seriesId_, MetadataType_LastUpdate, now);
+      db_.SetMetadata(status.studyId_, MetadataType_LastUpdate, now);
+      db_.SetMetadata(status.patientId_, MetadataType_LastUpdate, now);
 
       // Attach the auto-computed metadata for the instance level,
       // reflecting these additions into the input metadata map
-      SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_ReceptionDate, now);
-      SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_RemoteAet,
+      SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_ReceptionDate, now);
+      SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_RemoteAet,
                           instanceToStore.GetOrigin().GetRemoteAetC());
-      SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_Origin, 
+      SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_Origin, 
                           EnumerationToString(instanceToStore.GetOrigin().GetRequestOrigin()));
 
       {
@@ -913,25 +835,25 @@
         if (instanceToStore.LookupTransferSyntax(s))
         {
           // New in Orthanc 1.2.0
-          SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_TransferSyntax, s);
+          SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_TransferSyntax, s);
         }
 
         if (instanceToStore.GetOrigin().LookupRemoteIp(s))
         {
           // New in Orthanc 1.4.0
-          SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_RemoteIp, s);
+          SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_RemoteIp, s);
         }
 
         if (instanceToStore.GetOrigin().LookupCalledAet(s))
         {
           // New in Orthanc 1.4.0
-          SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_CalledAet, s);
+          SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_CalledAet, s);
         }
 
         if (instanceToStore.GetOrigin().LookupHttpUsername(s))
         {
           // New in Orthanc 1.4.0
-          SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_HttpUsername, s);
+          SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_HttpUsername, s);
         }
       }
 
@@ -940,7 +862,7 @@
           !value->IsNull() &&
           !value->IsBinary())
       {
-        SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_SopClassUid, value->GetContent());
+        SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_SopClassUid, value->GetContent());
       }
 
       if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL ||
@@ -949,26 +871,26 @@
         if (!value->IsNull() && 
             !value->IsBinary())
         {
-          SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_IndexInSeries, value->GetContent());
+          SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_IndexInSeries, value->GetContent());
         }
       }
 
       // Check whether the series of this new instance is now completed
-      if (isNewSeries)
+      if (status.isNewSeries_)
       {
-        ComputeExpectedNumberOfInstances(db_, series, dicomSummary);
+        ComputeExpectedNumberOfInstances(db_, status.seriesId_, dicomSummary);
       }
 
-      SeriesStatus seriesStatus = GetSeriesStatus(series);
+      SeriesStatus seriesStatus = GetSeriesStatus(status.seriesId_);
       if (seriesStatus == SeriesStatus_Complete)
       {
-        LogChange(series, ChangeType_CompletedSeries, ResourceType_Series, instanceToStore.GetHasher().HashSeries());
+        LogChange(status.seriesId_, ChangeType_CompletedSeries, ResourceType_Series, hashSeries);
       }
 
       // Mark the parent resources of this instance as unstable
-      MarkAsUnstable(series, ResourceType_Series, instanceToStore.GetHasher().HashSeries());
-      MarkAsUnstable(study, ResourceType_Study, instanceToStore.GetHasher().HashStudy());
-      MarkAsUnstable(patient, ResourceType_Patient, instanceToStore.GetHasher().HashPatient());
+      MarkAsUnstable(status.seriesId_, ResourceType_Series, hashSeries);
+      MarkAsUnstable(status.studyId_, ResourceType_Study, hashStudy);
+      MarkAsUnstable(status.patientId_, ResourceType_Patient, hashPatient);
 
       t.Commit(instanceSize);
 
--- a/OrthancServer/ServerIndex.h	Thu Jan 03 14:03:39 2019 +0100
+++ b/OrthancServer/ServerIndex.h	Thu Jan 03 18:21:22 2019 +0100
@@ -116,10 +116,12 @@
                    ResourceType resourceType,
                    const std::string& publicId);
 
-    uint64_t IncrementGlobalSequenceInternal(GlobalProperty property);
+    void SignalNewResource(ChangeType changeType,
+                           ResourceType level,
+                           const std::string& publicId,
+                           int64_t internalId);
 
-    int64_t CreateResource(const std::string& publicId,
-                           ResourceType type);
+    uint64_t IncrementGlobalSequenceInternal(GlobalProperty property);
 
     void SetInstanceMetadata(std::map<MetadataType, std::string>& instanceMetadata,
                              int64_t instance,
--- a/Plugins/Engine/OrthancPluginDatabase.cpp	Thu Jan 03 14:03:39 2019 +0100
+++ b/Plugins/Engine/OrthancPluginDatabase.cpp	Thu Jan 03 18:21:22 2019 +0100
@@ -1189,6 +1189,22 @@
   }
 
 
+  bool OrthancPluginDatabase::CreateInstance(
+    IDatabaseWrapper::CreateInstanceResult& result,
+    int64_t& instanceId,
+    const std::string& patient,
+    const std::string& study,
+    const std::string& series,
+    const std::string& instance,
+    bool overwrite)
+  {
+    // TODO optimized version
+
+    return CompatibilityDatabaseWrapper::CreateInstance(
+      result, instanceId, patient, study, series, instance, overwrite);
+  }
+
+
   void OrthancPluginDatabase::LookupIdentifier(std::list<int64_t>& result,
                                                ResourceType level,
                                                const DicomTag& tag,
--- a/Plugins/Engine/OrthancPluginDatabase.h	Thu Jan 03 14:03:39 2019 +0100
+++ b/Plugins/Engine/OrthancPluginDatabase.h	Thu Jan 03 18:21:22 2019 +0100
@@ -316,6 +316,15 @@
                                       size_t limit)
       ORTHANC_OVERRIDE;
 
+    virtual bool CreateInstance(CreateInstanceResult& result,
+                                int64_t& instanceId,
+                                const std::string& patient,
+                                const std::string& study,
+                                const std::string& series,
+                                const std::string& instance,
+                                bool overwrite)
+      ORTHANC_OVERRIDE;
+
     // From the "CompatibilityDatabaseWrapper" interface
     virtual void GetAllInternalIds(std::list<int64_t>& target,
                                    ResourceType resourceType) 
--- a/UnitTestsSources/ServerIndexTests.cpp	Thu Jan 03 14:03:39 2019 +0100
+++ b/UnitTestsSources/ServerIndexTests.cpp	Thu Jan 03 18:21:22 2019 +0100
@@ -297,65 +297,65 @@
 TEST_P(DatabaseWrapperTest, Simple)
 {
   int64_t a[] = {
-    index_->CreateResource("a", ResourceType_Patient),   // 0
-    index_->CreateResource("b", ResourceType_Study),     // 1
-    index_->CreateResource("c", ResourceType_Series),    // 2
-    index_->CreateResource("d", ResourceType_Instance),  // 3
-    index_->CreateResource("e", ResourceType_Instance),  // 4
-    index_->CreateResource("f", ResourceType_Instance),  // 5
-    index_->CreateResource("g", ResourceType_Study)      // 6
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("a", ResourceType_Patient),   // 0
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("b", ResourceType_Study),     // 1
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("c", ResourceType_Series),    // 2
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("d", ResourceType_Instance),  // 3
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("e", ResourceType_Instance),  // 4
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("f", ResourceType_Instance),  // 5
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("g", ResourceType_Study)      // 6
   };
 
-  ASSERT_EQ("a", index_->GetPublicId(a[0]));
-  ASSERT_EQ("b", index_->GetPublicId(a[1]));
-  ASSERT_EQ("c", index_->GetPublicId(a[2]));
-  ASSERT_EQ("d", index_->GetPublicId(a[3]));
-  ASSERT_EQ("e", index_->GetPublicId(a[4]));
-  ASSERT_EQ("f", index_->GetPublicId(a[5]));
-  ASSERT_EQ("g", index_->GetPublicId(a[6]));
+  ASSERT_EQ("a", dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetPublicId(a[0]));
+  ASSERT_EQ("b", dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetPublicId(a[1]));
+  ASSERT_EQ("c", dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetPublicId(a[2]));
+  ASSERT_EQ("d", dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetPublicId(a[3]));
+  ASSERT_EQ("e", dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetPublicId(a[4]));
+  ASSERT_EQ("f", dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetPublicId(a[5]));
+  ASSERT_EQ("g", dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetPublicId(a[6]));
 
-  ASSERT_EQ(ResourceType_Patient, index_->GetResourceType(a[0]));
-  ASSERT_EQ(ResourceType_Study, index_->GetResourceType(a[1]));
-  ASSERT_EQ(ResourceType_Series, index_->GetResourceType(a[2]));
-  ASSERT_EQ(ResourceType_Instance, index_->GetResourceType(a[3]));
-  ASSERT_EQ(ResourceType_Instance, index_->GetResourceType(a[4]));
-  ASSERT_EQ(ResourceType_Instance, index_->GetResourceType(a[5]));
-  ASSERT_EQ(ResourceType_Study, index_->GetResourceType(a[6]));
+  ASSERT_EQ(ResourceType_Patient, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetResourceType(a[0]));
+  ASSERT_EQ(ResourceType_Study, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetResourceType(a[1]));
+  ASSERT_EQ(ResourceType_Series, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetResourceType(a[2]));
+  ASSERT_EQ(ResourceType_Instance, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetResourceType(a[3]));
+  ASSERT_EQ(ResourceType_Instance, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetResourceType(a[4]));
+  ASSERT_EQ(ResourceType_Instance, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetResourceType(a[5]));
+  ASSERT_EQ(ResourceType_Study, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetResourceType(a[6]));
 
   {
     std::list<std::string> t;
-    index_->GetAllPublicIds(t, ResourceType_Patient);
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetAllPublicIds(t, ResourceType_Patient);
 
     ASSERT_EQ(1u, t.size());
     ASSERT_EQ("a", t.front());
 
-    index_->GetAllPublicIds(t, ResourceType_Series);
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetAllPublicIds(t, ResourceType_Series);
     ASSERT_EQ(1u, t.size());
     ASSERT_EQ("c", t.front());
 
-    index_->GetAllPublicIds(t, ResourceType_Study);
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetAllPublicIds(t, ResourceType_Study);
     ASSERT_EQ(2u, t.size());
 
-    index_->GetAllPublicIds(t, ResourceType_Instance);
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetAllPublicIds(t, ResourceType_Instance);
     ASSERT_EQ(3u, t.size());
   }
 
-  index_->SetGlobalProperty(GlobalProperty_FlushSleep, "World");
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetGlobalProperty(GlobalProperty_FlushSleep, "World");
 
-  index_->AttachChild(a[0], a[1]);
-  index_->AttachChild(a[1], a[2]);
-  index_->AttachChild(a[2], a[3]);
-  index_->AttachChild(a[2], a[4]);
-  index_->AttachChild(a[6], a[5]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[0], a[1]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[1], a[2]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[2], a[3]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[2], a[4]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[6], a[5]);
 
   int64_t parent;
-  ASSERT_FALSE(index_->LookupParent(parent, a[0]));
-  ASSERT_TRUE(index_->LookupParent(parent, a[1])); ASSERT_EQ(a[0], parent);
-  ASSERT_TRUE(index_->LookupParent(parent, a[2])); ASSERT_EQ(a[1], parent);
-  ASSERT_TRUE(index_->LookupParent(parent, a[3])); ASSERT_EQ(a[2], parent);
-  ASSERT_TRUE(index_->LookupParent(parent, a[4])); ASSERT_EQ(a[2], parent);
-  ASSERT_TRUE(index_->LookupParent(parent, a[5])); ASSERT_EQ(a[6], parent);
-  ASSERT_FALSE(index_->LookupParent(parent, a[6]));
+  ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupParent(parent, a[0]));
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupParent(parent, a[1])); ASSERT_EQ(a[0], parent);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupParent(parent, a[2])); ASSERT_EQ(a[1], parent);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupParent(parent, a[3])); ASSERT_EQ(a[2], parent);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupParent(parent, a[4])); ASSERT_EQ(a[2], parent);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupParent(parent, a[5])); ASSERT_EQ(a[6], parent);
+  ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupParent(parent, a[6]));
 
   std::string s;
 
@@ -368,14 +368,14 @@
   CheckParentPublicId("g", a[5]);
 
   std::list<std::string> l;
-  index_->GetChildrenPublicId(l, a[0]); ASSERT_EQ(1u, l.size()); ASSERT_EQ("b", l.front());
-  index_->GetChildrenPublicId(l, a[1]); ASSERT_EQ(1u, l.size()); ASSERT_EQ("c", l.front());
-  index_->GetChildrenPublicId(l, a[3]); ASSERT_EQ(0u, l.size()); 
-  index_->GetChildrenPublicId(l, a[4]); ASSERT_EQ(0u, l.size()); 
-  index_->GetChildrenPublicId(l, a[5]); ASSERT_EQ(0u, l.size()); 
-  index_->GetChildrenPublicId(l, a[6]); ASSERT_EQ(1u, l.size()); ASSERT_EQ("f", l.front());
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetChildrenPublicId(l, a[0]); ASSERT_EQ(1u, l.size()); ASSERT_EQ("b", l.front());
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetChildrenPublicId(l, a[1]); ASSERT_EQ(1u, l.size()); ASSERT_EQ("c", l.front());
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetChildrenPublicId(l, a[3]); ASSERT_EQ(0u, l.size()); 
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetChildrenPublicId(l, a[4]); ASSERT_EQ(0u, l.size()); 
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetChildrenPublicId(l, a[5]); ASSERT_EQ(0u, l.size()); 
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetChildrenPublicId(l, a[6]); ASSERT_EQ(1u, l.size()); ASSERT_EQ("f", l.front());
 
-  index_->GetChildrenPublicId(l, a[2]); ASSERT_EQ(2u, l.size()); 
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetChildrenPublicId(l, a[2]); ASSERT_EQ(2u, l.size()); 
   if (l.front() == "d")
   {
     ASSERT_EQ("e", l.back());
@@ -387,64 +387,64 @@
   }
 
   std::list<MetadataType> md;
-  index_->ListAvailableMetadata(md, a[4]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).ListAvailableMetadata(md, a[4]);
   ASSERT_EQ(0u, md.size());
 
-  index_->AddAttachment(a[4], FileInfo("my json file", FileContentType_DicomAsJson, 42, "md5", 
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AddAttachment(a[4], FileInfo("my json file", FileContentType_DicomAsJson, 42, "md5", 
                                        CompressionType_ZlibWithSize, 21, "compressedMD5"));
-  index_->AddAttachment(a[4], FileInfo("my dicom file", FileContentType_Dicom, 42, "md5"));
-  index_->AddAttachment(a[6], FileInfo("world", FileContentType_Dicom, 44, "md5"));
-  index_->SetMetadata(a[4], MetadataType_Instance_RemoteAet, "PINNACLE");
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AddAttachment(a[4], FileInfo("my dicom file", FileContentType_Dicom, 42, "md5"));
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AddAttachment(a[6], FileInfo("world", FileContentType_Dicom, 44, "md5"));
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetMetadata(a[4], MetadataType_Instance_RemoteAet, "PINNACLE");
   
-  index_->ListAvailableMetadata(md, a[4]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).ListAvailableMetadata(md, a[4]);
   ASSERT_EQ(1u, md.size());
   ASSERT_EQ(MetadataType_Instance_RemoteAet, md.front());
-  index_->SetMetadata(a[4], MetadataType_ModifiedFrom, "TUTU");
-  index_->ListAvailableMetadata(md, a[4]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetMetadata(a[4], MetadataType_ModifiedFrom, "TUTU");
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).ListAvailableMetadata(md, a[4]);
   ASSERT_EQ(2u, md.size());
 
   std::map<MetadataType, std::string> md2;
-  index_->GetAllMetadata(md2, a[4]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetAllMetadata(md2, a[4]);
   ASSERT_EQ(2u, md2.size());
   ASSERT_EQ("TUTU", md2[MetadataType_ModifiedFrom]);
   ASSERT_EQ("PINNACLE", md2[MetadataType_Instance_RemoteAet]);
 
-  index_->DeleteMetadata(a[4], MetadataType_ModifiedFrom);
-  index_->ListAvailableMetadata(md, a[4]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteMetadata(a[4], MetadataType_ModifiedFrom);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).ListAvailableMetadata(md, a[4]);
   ASSERT_EQ(1u, md.size());
   ASSERT_EQ(MetadataType_Instance_RemoteAet, md.front());
 
-  index_->GetAllMetadata(md2, a[4]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetAllMetadata(md2, a[4]);
   ASSERT_EQ(1u, md2.size());
   ASSERT_EQ("PINNACLE", md2[MetadataType_Instance_RemoteAet]);
 
 
-  ASSERT_EQ(21u + 42u + 44u, index_->GetTotalCompressedSize());
-  ASSERT_EQ(42u + 42u + 44u, index_->GetTotalUncompressedSize());
+  ASSERT_EQ(21u + 42u + 44u, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetTotalCompressedSize());
+  ASSERT_EQ(42u + 42u + 44u, dynamic_cast<SQLiteDatabaseWrapper&>(*index_).GetTotalUncompressedSize());
 
-  index_->SetMainDicomTag(a[3], DicomTag(0x0010, 0x0010), "PatientName");
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetMainDicomTag(a[3], DicomTag(0x0010, 0x0010), "PatientName");
 
   int64_t b;
   ResourceType t;
-  ASSERT_TRUE(index_->LookupResource(b, t, "g"));
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupResource(b, t, "g"));
   ASSERT_EQ(7, b);
   ASSERT_EQ(ResourceType_Study, t);
 
-  ASSERT_TRUE(index_->LookupMetadata(s, a[4], MetadataType_Instance_RemoteAet));
-  ASSERT_FALSE(index_->LookupMetadata(s, a[4], MetadataType_Instance_IndexInSeries));
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupMetadata(s, a[4], MetadataType_Instance_RemoteAet));
+  ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupMetadata(s, a[4], MetadataType_Instance_IndexInSeries));
   ASSERT_EQ("PINNACLE", s);
 
   std::string u;
-  ASSERT_TRUE(index_->LookupMetadata(u, a[4], MetadataType_Instance_RemoteAet));
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupMetadata(u, a[4], MetadataType_Instance_RemoteAet));
   ASSERT_EQ("PINNACLE", u);
-  ASSERT_FALSE(index_->LookupMetadata(u, a[4], MetadataType_Instance_IndexInSeries));
+  ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupMetadata(u, a[4], MetadataType_Instance_IndexInSeries));
 
-  ASSERT_TRUE(index_->LookupGlobalProperty(s, GlobalProperty_FlushSleep));
-  ASSERT_FALSE(index_->LookupGlobalProperty(s, static_cast<GlobalProperty>(42)));
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupGlobalProperty(s, GlobalProperty_FlushSleep));
+  ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupGlobalProperty(s, static_cast<GlobalProperty>(42)));
   ASSERT_EQ("World", s);
 
   FileInfo att;
-  ASSERT_TRUE(index_->LookupAttachment(att, a[4], FileContentType_DicomAsJson));
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupAttachment(att, a[4], FileContentType_DicomAsJson));
   ASSERT_EQ("my json file", att.GetUuid());
   ASSERT_EQ(21u, att.GetCompressedSize());
   ASSERT_EQ("md5", att.GetUncompressedMD5());
@@ -452,7 +452,7 @@
   ASSERT_EQ(42u, att.GetUncompressedSize());
   ASSERT_EQ(CompressionType_ZlibWithSize, att.GetCompressionType());
 
-  ASSERT_TRUE(index_->LookupAttachment(att, a[6], FileContentType_Dicom));
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupAttachment(att, a[6], FileContentType_Dicom));
   ASSERT_EQ("world", att.GetUuid());
   ASSERT_EQ(44u, att.GetCompressedSize());
   ASSERT_EQ("md5", att.GetUncompressedMD5());
@@ -468,7 +468,7 @@
   CheckTableRecordCount(1, "Metadata");
   CheckTableRecordCount(1, "MainDicomTags");
 
-  index_->DeleteResource(a[0]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(a[0]);
   ASSERT_EQ(5u, listener_->deletedResources_.size());
   ASSERT_EQ(2u, listener_->deletedFiles_.size());
   ASSERT_FALSE(std::find(listener_->deletedFiles_.begin(), 
@@ -483,7 +483,7 @@
   CheckTableRecordCount(1, "AttachedFiles");
   CheckTableRecordCount(0, "MainDicomTags");
 
-  index_->DeleteResource(a[5]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(a[5]);
   ASSERT_EQ(7u, listener_->deletedResources_.size());
 
   CheckTableRecordCount(0, "Resources");
@@ -491,11 +491,11 @@
   CheckTableRecordCount(3, "GlobalProperties");
 
   std::string tmp;
-  ASSERT_TRUE(index_->LookupGlobalProperty(tmp, GlobalProperty_DatabaseSchemaVersion));
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupGlobalProperty(tmp, GlobalProperty_DatabaseSchemaVersion));
   ASSERT_EQ("6", tmp);
-  ASSERT_TRUE(index_->LookupGlobalProperty(tmp, GlobalProperty_FlushSleep));
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupGlobalProperty(tmp, GlobalProperty_FlushSleep));
   ASSERT_EQ("World", tmp);
-  ASSERT_TRUE(index_->LookupGlobalProperty(tmp, GlobalProperty_GetTotalSizeIsFast));
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).LookupGlobalProperty(tmp, GlobalProperty_GetTotalSizeIsFast));
   ASSERT_EQ("1", tmp);
 
   ASSERT_EQ(3u, listener_->deletedFiles_.size());
@@ -510,23 +510,23 @@
 TEST_P(DatabaseWrapperTest, Upward)
 {
   int64_t a[] = {
-    index_->CreateResource("a", ResourceType_Patient),   // 0
-    index_->CreateResource("b", ResourceType_Study),     // 1
-    index_->CreateResource("c", ResourceType_Series),    // 2
-    index_->CreateResource("d", ResourceType_Instance),  // 3
-    index_->CreateResource("e", ResourceType_Instance),  // 4
-    index_->CreateResource("f", ResourceType_Study),     // 5
-    index_->CreateResource("g", ResourceType_Series),    // 6
-    index_->CreateResource("h", ResourceType_Series)     // 7
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("a", ResourceType_Patient),   // 0
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("b", ResourceType_Study),     // 1
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("c", ResourceType_Series),    // 2
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("d", ResourceType_Instance),  // 3
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("e", ResourceType_Instance),  // 4
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("f", ResourceType_Study),     // 5
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("g", ResourceType_Series),    // 6
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("h", ResourceType_Series)     // 7
   };
 
-  index_->AttachChild(a[0], a[1]);
-  index_->AttachChild(a[1], a[2]);
-  index_->AttachChild(a[2], a[3]);
-  index_->AttachChild(a[2], a[4]);
-  index_->AttachChild(a[1], a[6]);
-  index_->AttachChild(a[0], a[5]);
-  index_->AttachChild(a[5], a[7]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[0], a[1]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[1], a[2]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[2], a[3]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[2], a[4]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[1], a[6]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[0], a[5]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AttachChild(a[5], a[7]);
 
   CheckTwoChildren("b", "f", a[0]);
   CheckTwoChildren("c", "g", a[1]);
@@ -538,22 +538,22 @@
   CheckNoChild(a[7]);
 
   listener_->Reset();
-  index_->DeleteResource(a[3]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(a[3]);
   ASSERT_EQ("c", listener_->ancestorId_);
   ASSERT_EQ(ResourceType_Series, listener_->ancestorType_);
 
   listener_->Reset();
-  index_->DeleteResource(a[4]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(a[4]);
   ASSERT_EQ("b", listener_->ancestorId_);
   ASSERT_EQ(ResourceType_Study, listener_->ancestorType_);
 
   listener_->Reset();
-  index_->DeleteResource(a[7]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(a[7]);
   ASSERT_EQ("a", listener_->ancestorId_);
   ASSERT_EQ(ResourceType_Patient, listener_->ancestorType_);
 
   listener_->Reset();
-  index_->DeleteResource(a[6]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(a[6]);
   ASSERT_EQ("", listener_->ancestorId_);  // No more ancestor
 }
 
@@ -564,10 +564,10 @@
   for (int i = 0; i < 10; i++)
   {
     std::string p = "Patient " + boost::lexical_cast<std::string>(i);
-    patients.push_back(index_->CreateResource(p, ResourceType_Patient));
-    index_->AddAttachment(patients[i], FileInfo(p, FileContentType_Dicom, i + 10, 
+    patients.push_back(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource(p, ResourceType_Patient));
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AddAttachment(patients[i], FileInfo(p, FileContentType_Dicom, i + 10, 
                                                 "md5-" + boost::lexical_cast<std::string>(i)));
-    ASSERT_FALSE(index_->IsProtectedPatient(patients[i]));
+    ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[i]));
   }
 
   CheckTableRecordCount(10u, "Resources");
@@ -576,8 +576,8 @@
   listener_->Reset();
   ASSERT_EQ(0u, listener_->deletedResources_.size());
 
-  index_->DeleteResource(patients[5]);
-  index_->DeleteResource(patients[0]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(patients[5]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(patients[0]);
   ASSERT_EQ(2u, listener_->deletedResources_.size());
 
   CheckTableRecordCount(8u, "Resources");
@@ -588,28 +588,28 @@
   ASSERT_EQ("Patient 0", listener_->deletedFiles_[1]);
 
   int64_t p;
-  ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[1]);
-  index_->DeleteResource(p);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[1]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p);
   ASSERT_EQ(3u, listener_->deletedResources_.size());
-  ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[2]);
-  index_->DeleteResource(p);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[2]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p);
   ASSERT_EQ(4u, listener_->deletedResources_.size());
-  ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[3]);
-  index_->DeleteResource(p);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[3]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p);
   ASSERT_EQ(5u, listener_->deletedResources_.size());
-  ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[4]);
-  index_->DeleteResource(p);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[4]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p);
   ASSERT_EQ(6u, listener_->deletedResources_.size());
-  ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[6]);
-  index_->DeleteResource(p);
-  index_->DeleteResource(patients[8]);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[6]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(patients[8]);
   ASSERT_EQ(8u, listener_->deletedResources_.size());
-  ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[7]);
-  index_->DeleteResource(p);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[7]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p);
   ASSERT_EQ(9u, listener_->deletedResources_.size());
-  ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[9]);
-  index_->DeleteResource(p);
-  ASSERT_FALSE(index_->SelectPatientToRecycle(p));
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[9]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p);
+  ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p));
   ASSERT_EQ(10u, listener_->deletedResources_.size());
 
   ASSERT_EQ(10u, listener_->deletedFiles_.size());
@@ -625,39 +625,39 @@
   for (int i = 0; i < 5; i++)
   {
     std::string p = "Patient " + boost::lexical_cast<std::string>(i);
-    patients.push_back(index_->CreateResource(p, ResourceType_Patient));
-    index_->AddAttachment(patients[i], FileInfo(p, FileContentType_Dicom, i + 10,
+    patients.push_back(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource(p, ResourceType_Patient));
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).AddAttachment(patients[i], FileInfo(p, FileContentType_Dicom, i + 10,
                                                 "md5-" + boost::lexical_cast<std::string>(i)));
-    ASSERT_FALSE(index_->IsProtectedPatient(patients[i]));
+    ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[i]));
   }
 
   CheckTableRecordCount(5, "Resources");
   CheckTableRecordCount(5, "PatientRecyclingOrder");
 
-  ASSERT_FALSE(index_->IsProtectedPatient(patients[2]));
-  index_->SetProtectedPatient(patients[2], true);
-  ASSERT_TRUE(index_->IsProtectedPatient(patients[2]));
+  ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[2]));
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetProtectedPatient(patients[2], true);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[2]));
   CheckTableRecordCount(5, "Resources");
   CheckTableRecordCount(4, "PatientRecyclingOrder");
 
-  index_->SetProtectedPatient(patients[2], true);
-  ASSERT_TRUE(index_->IsProtectedPatient(patients[2]));
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetProtectedPatient(patients[2], true);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[2]));
   CheckTableRecordCount(4, "PatientRecyclingOrder");
-  index_->SetProtectedPatient(patients[2], false);
-  ASSERT_FALSE(index_->IsProtectedPatient(patients[2]));
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetProtectedPatient(patients[2], false);
+  ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[2]));
   CheckTableRecordCount(5, "PatientRecyclingOrder");
-  index_->SetProtectedPatient(patients[2], false);
-  ASSERT_FALSE(index_->IsProtectedPatient(patients[2]));
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetProtectedPatient(patients[2], false);
+  ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[2]));
   CheckTableRecordCount(5, "PatientRecyclingOrder");
   CheckTableRecordCount(5, "Resources");
-  index_->SetProtectedPatient(patients[2], true);
-  ASSERT_TRUE(index_->IsProtectedPatient(patients[2]));
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetProtectedPatient(patients[2], true);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[2]));
   CheckTableRecordCount(4, "PatientRecyclingOrder");
-  index_->SetProtectedPatient(patients[2], false);
-  ASSERT_FALSE(index_->IsProtectedPatient(patients[2]));
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetProtectedPatient(patients[2], false);
+  ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[2]));
   CheckTableRecordCount(5, "PatientRecyclingOrder");
-  index_->SetProtectedPatient(patients[3], true);
-  ASSERT_TRUE(index_->IsProtectedPatient(patients[3]));
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetProtectedPatient(patients[3], true);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).IsProtectedPatient(patients[3]));
   CheckTableRecordCount(4, "PatientRecyclingOrder");
 
   CheckTableRecordCount(5, "Resources");
@@ -666,33 +666,33 @@
   // Unprotecting a patient puts it at the last position in the recycling queue
   int64_t p;
   ASSERT_EQ(0u, listener_->deletedResources_.size());
-  ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[0]);
-  index_->DeleteResource(p);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[0]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p);
   ASSERT_EQ(1u, listener_->deletedResources_.size());
-  ASSERT_TRUE(index_->SelectPatientToRecycle(p, patients[1])); ASSERT_EQ(p, patients[4]);
-  ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[1]);
-  index_->DeleteResource(p);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p, patients[1])); ASSERT_EQ(p, patients[4]);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[1]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p);
   ASSERT_EQ(2u, listener_->deletedResources_.size());
-  ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[4]);
-  index_->DeleteResource(p);
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[4]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p);
   ASSERT_EQ(3u, listener_->deletedResources_.size());
-  ASSERT_FALSE(index_->SelectPatientToRecycle(p, patients[2]));
-  ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[2]);
-  index_->DeleteResource(p);
+  ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p, patients[2]));
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[2]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p);
   ASSERT_EQ(4u, listener_->deletedResources_.size());
   // "patients[3]" is still protected
-  ASSERT_FALSE(index_->SelectPatientToRecycle(p));
+  ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p));
 
   ASSERT_EQ(4u, listener_->deletedFiles_.size());
   CheckTableRecordCount(1, "Resources");
   CheckTableRecordCount(0, "PatientRecyclingOrder");
 
-  index_->SetProtectedPatient(patients[3], false);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetProtectedPatient(patients[3], false);
   CheckTableRecordCount(1, "PatientRecyclingOrder");
-  ASSERT_FALSE(index_->SelectPatientToRecycle(p, patients[3]));
-  ASSERT_TRUE(index_->SelectPatientToRecycle(p, patients[2]));
-  ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[3]);
-  index_->DeleteResource(p);
+  ASSERT_FALSE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p, patients[3]));
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p, patients[2]));
+  ASSERT_TRUE(dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[3]);
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).DeleteResource(p);
   ASSERT_EQ(5u, listener_->deletedResources_.size());
 
   ASSERT_EQ(5u, listener_->deletedFiles_.size());
@@ -729,16 +729,16 @@
 TEST_P(DatabaseWrapperTest, LookupIdentifier)
 {
   int64_t a[] = {
-    index_->CreateResource("a", ResourceType_Study),   // 0
-    index_->CreateResource("b", ResourceType_Study),   // 1
-    index_->CreateResource("c", ResourceType_Study),   // 2
-    index_->CreateResource("d", ResourceType_Series)   // 3
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("a", ResourceType_Study),   // 0
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("b", ResourceType_Study),   // 1
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("c", ResourceType_Study),   // 2
+    dynamic_cast<SQLiteDatabaseWrapper&>(*index_).CreateResource("d", ResourceType_Series)   // 3
   };
 
-  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");
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetIdentifierTag(a[0], DICOM_TAG_STUDY_INSTANCE_UID, "0");
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetIdentifierTag(a[1], DICOM_TAG_STUDY_INSTANCE_UID, "1");
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetIdentifierTag(a[2], DICOM_TAG_STUDY_INSTANCE_UID, "0");
+  dynamic_cast<SQLiteDatabaseWrapper&>(*index_).SetIdentifierTag(a[3], DICOM_TAG_SERIES_INSTANCE_UID, "0");
 
   std::list<std::string> s;