changeset 201:42990b2dd51b

create IDatabaseBackendOutput only if needed
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 18 Mar 2021 16:51:51 +0100
parents 30b210616f4f
children 2def2df94f94
files Framework/Plugins/IndexBackend.cpp Framework/Plugins/IndexBackend.h Framework/Plugins/IndexUnitTests.h Framework/Plugins/OrthancCppDatabasePlugin.h MySQL/Plugins/IndexPlugin.cpp MySQL/Plugins/MySQLIndex.cpp MySQL/Plugins/MySQLIndex.h MySQL/UnitTests/UnitTestsMain.cpp PostgreSQL/Plugins/IndexPlugin.cpp PostgreSQL/Plugins/PostgreSQLIndex.cpp PostgreSQL/Plugins/PostgreSQLIndex.h PostgreSQL/UnitTests/PostgreSQLTests.cpp PostgreSQL/UnitTests/UnitTestsMain.cpp SQLite/Plugins/IndexPlugin.cpp SQLite/Plugins/SQLiteIndex.cpp SQLite/Plugins/SQLiteIndex.h SQLite/UnitTests/UnitTestsMain.cpp
diffstat 17 files changed, 381 insertions(+), 358 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/Plugins/IndexBackend.cpp	Thu Mar 18 15:21:17 2021 +0100
+++ b/Framework/Plugins/IndexBackend.cpp	Thu Mar 18 16:51:51 2021 +0100
@@ -171,7 +171,8 @@
   }
 
 
-  void IndexBackend::ReadChangesInternal(bool& done,
+  void IndexBackend::ReadChangesInternal(OrthancPlugins::IDatabaseBackendOutput& output,
+                                         bool& done,
                                          DatabaseManager::CachedStatement& statement,
                                          const Dictionary& args,
                                          uint32_t maxResults)
@@ -183,7 +184,7 @@
     while (count < maxResults &&
            !statement.IsDone())
     {
-      GetOutput().AnswerChange(
+      output.AnswerChange(
         ReadInteger64(statement, 0),
         ReadInteger32(statement, 1),
         static_cast<OrthancPluginResourceType>(ReadInteger32(statement, 3)),
@@ -199,7 +200,8 @@
   }
 
 
-  void IndexBackend::ReadExportedResourcesInternal(bool& done,
+  void IndexBackend::ReadExportedResourcesInternal(OrthancPlugins::IDatabaseBackendOutput& output,
+                                                   bool& done,
                                                    DatabaseManager::CachedStatement& statement,
                                                    const Dictionary& args,
                                                    uint32_t maxResults)
@@ -216,16 +218,16 @@
         static_cast<OrthancPluginResourceType>(ReadInteger32(statement, 1));
       std::string publicId = ReadString(statement, 2);
 
-      GetOutput().AnswerExportedResource(seq, 
-                                         resourceType,
-                                         publicId,
-                                         ReadString(statement, 3),  // modality
-                                         ReadString(statement, 8),  // date
-                                         ReadString(statement, 4),  // patient ID
-                                         ReadString(statement, 5),  // study instance UID
-                                         ReadString(statement, 6),  // series instance UID
-                                         ReadString(statement, 7)); // sop instance UID
-
+      output.AnswerExportedResource(seq, 
+                                    resourceType,
+                                    publicId,
+                                    ReadString(statement, 3),  // modality
+                                    ReadString(statement, 8),  // date
+                                    ReadString(statement, 4),  // patient ID
+                                    ReadString(statement, 5),  // study instance UID
+                                    ReadString(statement, 6),  // series instance UID
+                                    ReadString(statement, 7)); // sop instance UID
+      
       statement.Next();
       count++;
     }
@@ -255,7 +257,7 @@
   }
     
 
-  void IndexBackend::SignalDeletedFiles()
+  void IndexBackend::SignalDeletedFiles(OrthancPlugins::IDatabaseBackendOutput& output)
   {
     DatabaseManager::CachedStatement statement(
       STATEMENT_FROM_HERE, manager_,
@@ -270,20 +272,20 @@
       std::string b = ReadString(statement, 5);
       std::string c = ReadString(statement, 6);
 
-      GetOutput().SignalDeletedAttachment(a.c_str(),
-                                          ReadInteger32(statement, 1),
-                                          ReadInteger64(statement, 3),
-                                          b.c_str(),
-                                          ReadInteger32(statement, 4),
-                                          ReadInteger64(statement, 2),
-                                          c.c_str());
-
+      output.SignalDeletedAttachment(a.c_str(),
+                                     ReadInteger32(statement, 1),
+                                     ReadInteger64(statement, 3),
+                                     b.c_str(),
+                                     ReadInteger32(statement, 4),
+                                     ReadInteger64(statement, 2),
+                                     c.c_str());
+      
       statement.Next();
     }
   }
 
 
-  void IndexBackend::SignalDeletedResources()
+  void IndexBackend::SignalDeletedResources(OrthancPlugins::IDatabaseBackendOutput& output)
   {
     DatabaseManager::CachedStatement statement(
       STATEMENT_FROM_HERE, manager_,
@@ -294,7 +296,7 @@
 
     while (!statement.IsDone())
     {
-      GetOutput().SignalDeletedResource(
+      output.SignalDeletedResource(
         ReadString(statement, 1),
         static_cast<OrthancPluginResourceType>(ReadInteger32(statement, 0)));
 
@@ -303,12 +305,44 @@
   }
 
 
-  IndexBackend::IndexBackend(IDatabaseFactory* factory) :
+  IndexBackend::IndexBackend(OrthancPluginContext* context,
+                             IDatabaseFactory* factory) :
+    context_(context),
     manager_(factory)
   {
   }
 
-    
+
+  void IndexBackend::SetOutputFactory(OrthancPlugins::IDatabaseBackendOutput::IFactory* factory)
+  {
+    if (factory == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+    }
+    else if (outputFactory_.get() != NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    else
+    {
+      outputFactory_.reset(factory);
+    }
+  }
+
+
+  OrthancPlugins::IDatabaseBackendOutput* IndexBackend::CreateOutput()
+  {
+    if (outputFactory_.get() == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    else
+    {
+      return outputFactory_->CreateOutput();
+    }
+  }
+
+  
   void IndexBackend::AddAttachment(int64_t id,
                                    const OrthancPluginAttachment& attachment)
   {
@@ -378,7 +412,8 @@
   }
 
     
-  void IndexBackend::DeleteAttachment(int64_t id,
+  void IndexBackend::DeleteAttachment(OrthancPlugins::IDatabaseBackendOutput& output,
+                                      int64_t id,
                                       int32_t attachment)
   {
     ClearDeletedFiles();
@@ -398,7 +433,7 @@
       statement.Execute(args);
     }
 
-    SignalDeletedFiles();
+    SignalDeletedFiles(output);
   }
 
     
@@ -420,7 +455,8 @@
   }
 
     
-  void IndexBackend::DeleteResource(int64_t id)
+  void IndexBackend::DeleteResource(OrthancPlugins::IDatabaseBackendOutput& output,
+                                    int64_t id)
   {
     assert(manager_.GetDialect() != Dialect_MySQL);
     
@@ -458,7 +494,7 @@
 
       if (!statement.IsDone())
       {
-        GetOutput().SignalRemainingAncestor(
+        output.SignalRemainingAncestor(
           ReadString(statement, 1),
           static_cast<OrthancPluginResourceType>(ReadInteger32(statement, 0)));
           
@@ -467,8 +503,8 @@
       }
     }
     
-    SignalDeletedFiles();
-    SignalDeletedResources();
+    SignalDeletedFiles(output);
+    SignalDeletedResources(output);
   }
 
 
@@ -532,7 +568,8 @@
 
     
   /* Use GetOutput().AnswerChange() */
-  void IndexBackend::GetChanges(bool& done /*out*/,
+  void IndexBackend::GetChanges(OrthancPlugins::IDatabaseBackendOutput& output,
+                                bool& done /*out*/,
                                 int64_t since,
                                 uint32_t maxResults)
   {
@@ -548,7 +585,7 @@
     args.SetIntegerValue("limit", maxResults + 1);
     args.SetIntegerValue("since", since);
 
-    ReadChangesInternal(done, statement, args, maxResults);
+    ReadChangesInternal(output, done, statement, args, maxResults);
   }
 
     
@@ -589,7 +626,8 @@
 
     
   /* Use GetOutput().AnswerExportedResource() */
-  void IndexBackend::GetExportedResources(bool& done /*out*/,
+  void IndexBackend::GetExportedResources(OrthancPlugins::IDatabaseBackendOutput& output,
+                                          bool& done /*out*/,
                                           int64_t since,
                                           uint32_t maxResults)
   {
@@ -605,12 +643,12 @@
     args.SetIntegerValue("limit", maxResults + 1);
     args.SetIntegerValue("since", since);
 
-    ReadExportedResourcesInternal(done, statement, args, maxResults);
+    ReadExportedResourcesInternal(output, done, statement, args, maxResults);
   }
 
     
   /* Use GetOutput().AnswerChange() */
-  void IndexBackend::GetLastChange()
+  void IndexBackend::GetLastChange(OrthancPlugins::IDatabaseBackendOutput& output)
   {
     DatabaseManager::CachedStatement statement(
       STATEMENT_FROM_HERE, manager_,
@@ -621,12 +659,12 @@
     Dictionary args;
 
     bool done;  // Ignored
-    ReadChangesInternal(done, statement, args, 1);
+    ReadChangesInternal(output, done, statement, args, 1);
   }
 
     
   /* Use GetOutput().AnswerExportedResource() */
-  void IndexBackend::GetLastExportedResource()
+  void IndexBackend::GetLastExportedResource(OrthancPlugins::IDatabaseBackendOutput& output)
   {
     DatabaseManager::CachedStatement statement(
       STATEMENT_FROM_HERE, manager_,
@@ -637,12 +675,13 @@
     Dictionary args;
 
     bool done;  // Ignored
-    ReadExportedResourcesInternal(done, statement, args, 1);
+    ReadExportedResourcesInternal(output, done, statement, args, 1);
   }
 
     
   /* Use GetOutput().AnswerDicomTag() */
-  void IndexBackend::GetMainDicomTags(int64_t id)
+  void IndexBackend::GetMainDicomTags(OrthancPlugins::IDatabaseBackendOutput& output,
+                                      int64_t id)
   {
     DatabaseManager::CachedStatement statement(
       STATEMENT_FROM_HERE, manager_,
@@ -658,9 +697,9 @@
 
     while (!statement.IsDone())
     {
-      GetOutput().AnswerDicomTag(static_cast<uint16_t>(ReadInteger64(statement, 1)),
-                                 static_cast<uint16_t>(ReadInteger64(statement, 2)),
-                                 ReadString(statement, 3));
+      output.AnswerDicomTag(static_cast<uint16_t>(ReadInteger64(statement, 1)),
+                            static_cast<uint16_t>(ReadInteger64(statement, 2)),
+                            ReadString(statement, 3));
       statement.Next();
     }
   }
@@ -960,7 +999,8 @@
 
     
   /* Use GetOutput().AnswerAttachment() */
-  bool IndexBackend::LookupAttachment(int64_t id,
+  bool IndexBackend::LookupAttachment(OrthancPlugins::IDatabaseBackendOutput& output,
+                                      int64_t id,
                                       int32_t contentType)
   {
     DatabaseManager::CachedStatement statement(
@@ -984,13 +1024,13 @@
     }
     else
     {
-      GetOutput().AnswerAttachment(ReadString(statement, 0),
-                                   contentType,
-                                   ReadInteger64(statement, 1),
-                                   ReadString(statement, 4),
-                                   ReadInteger32(statement, 2),
-                                   ReadInteger64(statement, 3),
-                                   ReadString(statement, 5));
+      output.AnswerAttachment(ReadString(statement, 0),
+                              contentType,
+                              ReadInteger64(statement, 1),
+                              ReadString(statement, 4),
+                              ReadInteger32(statement, 2),
+                              ReadInteger64(statement, 3),
+                              ReadString(statement, 5));
       return true;
     }
   }
@@ -1653,7 +1693,8 @@
   
 #if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1
   // New primitive since Orthanc 1.5.2
-  void IndexBackend::LookupResources(const std::vector<Orthanc::DatabaseConstraint>& lookup,
+  void IndexBackend::LookupResources(OrthancPlugins::IDatabaseBackendOutput& output,
+                                     const std::vector<Orthanc::DatabaseConstraint>& lookup,
                                      OrthancPluginResourceType queryLevel,
                                      uint32_t limit,
                                      bool requestSomeInstance)
@@ -1708,11 +1749,11 @@
     {
       if (requestSomeInstance)
       {
-        GetOutput().AnswerMatchingResource(ReadString(statement, 0), ReadString(statement, 1));
+        output.AnswerMatchingResource(ReadString(statement, 0), ReadString(statement, 1));
       }
       else
       {
-        GetOutput().AnswerMatchingResource(ReadString(statement, 0));
+        output.AnswerMatchingResource(ReadString(statement, 0));
       }
 
       statement.Next();
--- a/Framework/Plugins/IndexBackend.h	Thu Mar 18 15:21:17 2021 +0100
+++ b/Framework/Plugins/IndexBackend.h	Thu Mar 18 16:51:51 2021 +0100
@@ -31,9 +31,12 @@
   {
   private:
     class LookupFormatter;
+
+    OrthancPluginContext*  context_;
+    DatabaseManager        manager_;
+
+    std::unique_ptr<OrthancPlugins::IDatabaseBackendOutput::IFactory>  outputFactory_;
     
-    DatabaseManager   manager_;
-
   protected:
     DatabaseManager& GetManager()
     {
@@ -62,187 +65,205 @@
 
     void ClearDeletedResources();
 
-    void SignalDeletedFiles();
+    void SignalDeletedFiles(OrthancPlugins::IDatabaseBackendOutput& output);
 
-    void SignalDeletedResources();
+    void SignalDeletedResources(OrthancPlugins::IDatabaseBackendOutput& output);
 
   private:
-    void ReadChangesInternal(bool& done,
+    void ReadChangesInternal(OrthancPlugins::IDatabaseBackendOutput& output,
+                             bool& done,
                              DatabaseManager::CachedStatement& statement,
                              const Dictionary& args,
                              uint32_t maxResults);
 
-    void ReadExportedResourcesInternal(bool& done,
+    void ReadExportedResourcesInternal(OrthancPlugins::IDatabaseBackendOutput& output,
+                                       bool& done,
                                        DatabaseManager::CachedStatement& statement,
                                        const Dictionary& args,
                                        uint32_t maxResults);
 
   public:
-    IndexBackend(IDatabaseFactory* factory);
+    IndexBackend(OrthancPluginContext* context,
+                 IDatabaseFactory* factory);
+
+    virtual OrthancPluginContext* GetContext() ORTHANC_OVERRIDE
+    {
+      return context_;
+    }
+
+    virtual void SetOutputFactory(OrthancPlugins::IDatabaseBackendOutput::IFactory* factory) ORTHANC_OVERRIDE;
     
-    virtual void Open()
+    virtual OrthancPlugins::IDatabaseBackendOutput* CreateOutput() ORTHANC_OVERRIDE;
+    
+    virtual void Open() ORTHANC_OVERRIDE
     {
       manager_.Open();
     }
     
-    virtual void Close()
+    virtual void Close() ORTHANC_OVERRIDE
     {
       manager_.Close();
     }
     
     virtual void AddAttachment(int64_t id,
-                               const OrthancPluginAttachment& attachment);
+                               const OrthancPluginAttachment& attachment) ORTHANC_OVERRIDE;
     
     virtual void AttachChild(int64_t parent,
-                             int64_t child);
+                             int64_t child) ORTHANC_OVERRIDE;
     
-    virtual void ClearChanges();
+    virtual void ClearChanges() ORTHANC_OVERRIDE;
     
-    virtual void ClearExportedResources();
+    virtual void ClearExportedResources() ORTHANC_OVERRIDE;
 
-    virtual void DeleteAttachment(int64_t id,
-                                  int32_t attachment);
+    virtual void DeleteAttachment(OrthancPlugins::IDatabaseBackendOutput& output,
+                                  int64_t id,
+                                  int32_t attachment) ORTHANC_OVERRIDE;
     
     virtual void DeleteMetadata(int64_t id,
-                                int32_t metadataType);
+                                int32_t metadataType) ORTHANC_OVERRIDE;
     
-    virtual void DeleteResource(int64_t id);
+    virtual void DeleteResource(OrthancPlugins::IDatabaseBackendOutput& output,
+                                int64_t id) ORTHANC_OVERRIDE;
 
     virtual void GetAllInternalIds(std::list<int64_t>& target,
-                                   OrthancPluginResourceType resourceType);
+                                   OrthancPluginResourceType resourceType) ORTHANC_OVERRIDE;
     
     virtual void GetAllPublicIds(std::list<std::string>& target,
-                                 OrthancPluginResourceType resourceType);
+                                 OrthancPluginResourceType resourceType) ORTHANC_OVERRIDE;
     
     virtual void GetAllPublicIds(std::list<std::string>& target,
                                  OrthancPluginResourceType resourceType,
                                  uint64_t since,
-                                 uint64_t limit);
+                                 uint64_t limit) ORTHANC_OVERRIDE;
     
-    virtual void GetChanges(bool& done /*out*/,
+    virtual void GetChanges(OrthancPlugins::IDatabaseBackendOutput& output,
+                            bool& done /*out*/,
                             int64_t since,
-                            uint32_t maxResults);
+                            uint32_t maxResults) ORTHANC_OVERRIDE;
     
     virtual void GetChildrenInternalId(std::list<int64_t>& target /*out*/,
-                                       int64_t id);
+                                       int64_t id) ORTHANC_OVERRIDE;
     
     virtual void GetChildrenPublicId(std::list<std::string>& target /*out*/,
-                                     int64_t id);
+                                     int64_t id) ORTHANC_OVERRIDE;
     
-    virtual void GetExportedResources(bool& done /*out*/,
+    virtual void GetExportedResources(OrthancPlugins::IDatabaseBackendOutput& output,
+                                      bool& done /*out*/,
                                       int64_t since,
-                                      uint32_t maxResults);
+                                      uint32_t maxResults) ORTHANC_OVERRIDE;
     
-    virtual void GetLastChange();
+    virtual void GetLastChange(OrthancPlugins::IDatabaseBackendOutput& output) ORTHANC_OVERRIDE;
     
-    virtual void GetLastExportedResource();
+    virtual void GetLastExportedResource(OrthancPlugins::IDatabaseBackendOutput& output) ORTHANC_OVERRIDE;
     
-    virtual void GetMainDicomTags(int64_t id);
+    virtual void GetMainDicomTags(OrthancPlugins::IDatabaseBackendOutput& output,
+                                  int64_t id) ORTHANC_OVERRIDE;
     
-    virtual std::string GetPublicId(int64_t resourceId);
+    virtual std::string GetPublicId(int64_t resourceId) ORTHANC_OVERRIDE;
     
-    virtual uint64_t GetResourceCount(OrthancPluginResourceType resourceType);
+    virtual uint64_t GetResourceCount(OrthancPluginResourceType resourceType) ORTHANC_OVERRIDE;
     
-    virtual OrthancPluginResourceType GetResourceType(int64_t resourceId);
+    virtual OrthancPluginResourceType GetResourceType(int64_t resourceId) ORTHANC_OVERRIDE;
     
-    virtual uint64_t GetTotalCompressedSize();
+    virtual uint64_t GetTotalCompressedSize() ORTHANC_OVERRIDE;
     
-    virtual uint64_t GetTotalUncompressedSize();
+    virtual uint64_t GetTotalUncompressedSize() ORTHANC_OVERRIDE;
     
-    virtual bool IsExistingResource(int64_t internalId);
+    virtual bool IsExistingResource(int64_t internalId) ORTHANC_OVERRIDE;
     
-    virtual bool IsProtectedPatient(int64_t internalId);
+    virtual bool IsProtectedPatient(int64_t internalId) ORTHANC_OVERRIDE;
     
     virtual void ListAvailableMetadata(std::list<int32_t>& target /*out*/,
-                                       int64_t id);
+                                       int64_t id) ORTHANC_OVERRIDE;
     
     virtual void ListAvailableAttachments(std::list<int32_t>& target /*out*/,
-                                          int64_t id);
+                                          int64_t id) ORTHANC_OVERRIDE;
     
-    virtual void LogChange(const OrthancPluginChange& change);
+    virtual void LogChange(const OrthancPluginChange& change) ORTHANC_OVERRIDE;
     
-    virtual void LogExportedResource(const OrthancPluginExportedResource& resource);
+    virtual void LogExportedResource(const OrthancPluginExportedResource& resource) ORTHANC_OVERRIDE;
     
-    virtual bool LookupAttachment(int64_t id,
-                                  int32_t contentType);
+    virtual bool LookupAttachment(OrthancPlugins::IDatabaseBackendOutput& output,
+                                  int64_t id,
+                                  int32_t contentType) ORTHANC_OVERRIDE;
     
     virtual bool LookupGlobalProperty(std::string& target /*out*/,
-                                      int32_t property);
+                                      int32_t property) ORTHANC_OVERRIDE;
     
     virtual void LookupIdentifier(std::list<int64_t>& target /*out*/,
                                   OrthancPluginResourceType resourceType,
                                   uint16_t group,
                                   uint16_t element,
                                   OrthancPluginIdentifierConstraint constraint,
-                                  const char* value);
+                                  const char* value) ORTHANC_OVERRIDE;
     
     virtual void LookupIdentifierRange(std::list<int64_t>& target /*out*/,
                                        OrthancPluginResourceType resourceType,
                                        uint16_t group,
                                        uint16_t element,
                                        const char* start,
-                                       const char* end);
+                                       const char* end) ORTHANC_OVERRIDE;
 
     virtual bool LookupMetadata(std::string& target /*out*/,
                                 int64_t id,
-                                int32_t metadataType);
+                                int32_t metadataType) ORTHANC_OVERRIDE;
 
     virtual bool LookupParent(int64_t& parentId /*out*/,
-                              int64_t resourceId);
+                              int64_t resourceId) ORTHANC_OVERRIDE;
     
     virtual bool LookupResource(int64_t& id /*out*/,
                                 OrthancPluginResourceType& type /*out*/,
-                                const char* publicId);
+                                const char* publicId) ORTHANC_OVERRIDE;
     
-    virtual bool SelectPatientToRecycle(int64_t& internalId /*out*/);
+    virtual bool SelectPatientToRecycle(int64_t& internalId /*out*/) ORTHANC_OVERRIDE;
     
     virtual bool SelectPatientToRecycle(int64_t& internalId /*out*/,
-                                        int64_t patientIdToAvoid);
+                                        int64_t patientIdToAvoid) ORTHANC_OVERRIDE;
     
     virtual void SetGlobalProperty(int32_t property,
-                                   const char* value);
+                                   const char* value) ORTHANC_OVERRIDE;
 
     virtual void SetMainDicomTag(int64_t id,
                                  uint16_t group,
                                  uint16_t element,
-                                 const char* value);
+                                 const char* value) ORTHANC_OVERRIDE;
     
     virtual void SetIdentifierTag(int64_t id,
                                   uint16_t group,
                                   uint16_t element,
-                                  const char* value);
+                                  const char* value) ORTHANC_OVERRIDE;
 
     virtual void SetMetadata(int64_t id,
                              int32_t metadataType,
-                             const char* value);
+                             const char* value) ORTHANC_OVERRIDE;
     
     virtual void SetProtectedPatient(int64_t internalId, 
-                                     bool isProtected);
+                                     bool isProtected) ORTHANC_OVERRIDE;
     
-    virtual void StartTransaction()
+    virtual void StartTransaction() ORTHANC_OVERRIDE
     {
       manager_.StartTransaction();
     }
 
     
-    virtual void RollbackTransaction()
+    virtual void RollbackTransaction() ORTHANC_OVERRIDE
     {
       manager_.RollbackTransaction();
     }
 
     
-    virtual void CommitTransaction()
+    virtual void CommitTransaction() ORTHANC_OVERRIDE
     {
       manager_.CommitTransaction();
     }
 
     
-    virtual uint32_t GetDatabaseVersion();
+    virtual uint32_t GetDatabaseVersion() ORTHANC_OVERRIDE;
     
     virtual void UpgradeDatabase(uint32_t  targetVersion,
-                                 OrthancPluginStorageArea* storageArea);
+                                 OrthancPluginStorageArea* storageArea) ORTHANC_OVERRIDE;
     
-    virtual void ClearMainDicomTags(int64_t internalId);
+    virtual void ClearMainDicomTags(int64_t internalId) ORTHANC_OVERRIDE;
 
     // For unit testing only!
     virtual uint64_t GetResourcesCount();
@@ -260,10 +281,11 @@
 
 #if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1
     // New primitive since Orthanc 1.5.2
-    virtual void LookupResources(const std::vector<Orthanc::DatabaseConstraint>& lookup,
+    virtual void LookupResources(OrthancPlugins::IDatabaseBackendOutput& output,
+                                 const std::vector<Orthanc::DatabaseConstraint>& lookup,
                                  OrthancPluginResourceType queryLevel,
                                  uint32_t limit,
-                                 bool requestSomeInstance);
+                                 bool requestSomeInstance) ORTHANC_OVERRIDE;
 #endif
 
 #if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1
@@ -274,15 +296,15 @@
       uint32_t countMainDicomTags,
       const OrthancPluginResourcesContentTags* mainDicomTags,
       uint32_t countMetadata,
-      const OrthancPluginResourcesContentMetadata* metadata);
+      const OrthancPluginResourcesContentMetadata* metadata) ORTHANC_OVERRIDE;
 #endif
 
     // New primitive since Orthanc 1.5.2
     virtual void GetChildrenMetadata(std::list<std::string>& target,
                                      int64_t resourceId,
-                                     int32_t metadata);
+                                     int32_t metadata) ORTHANC_OVERRIDE;
 
-    virtual void TagMostRecentPatient(int64_t patient);
+    virtual void TagMostRecentPatient(int64_t patient) ORTHANC_OVERRIDE;
 
 #if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)      // Macro introduced in 1.3.1
 #  if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4)
@@ -290,7 +312,7 @@
     virtual bool LookupResourceAndParent(int64_t& id,
                                          OrthancPluginResourceType& type,
                                          std::string& parentPublicId,
-                                         const char* publicId);
+                                         const char* publicId) ORTHANC_OVERRIDE;
 #  endif
 #endif
 
@@ -298,7 +320,7 @@
 #  if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4)
     // New primitive since Orthanc 1.5.4
     virtual void GetAllMetadata(std::map<int32_t, std::string>& result,
-                                int64_t id);
+                                int64_t id) ORTHANC_OVERRIDE;
 #  endif
 #endif
   };
--- a/Framework/Plugins/IndexUnitTests.h	Thu Mar 18 15:21:17 2021 +0100
+++ b/Framework/Plugins/IndexUnitTests.h	Thu Mar 18 16:51:51 2021 +0100
@@ -168,19 +168,21 @@
   ImplicitTransaction::SetErrorOnDoubleExecution(true);
 
 #if ORTHANC_ENABLE_POSTGRESQL == 1
-  PostgreSQLIndex db(globalParameters_);
+  PostgreSQLIndex db(&context, globalParameters_);
   db.SetClearAll(true);
 #elif ORTHANC_ENABLE_MYSQL == 1
-  MySQLIndex db(globalParameters_);
+  MySQLIndex db(&context, globalParameters_);
   db.SetClearAll(true);
 #elif ORTHANC_ENABLE_SQLITE == 1
-  SQLiteIndex db;  // Open in memory
+  SQLiteIndex db(&context);  // Open in memory
 #else
 #  error Unsupported database backend
 #endif
 
-  db.RegisterOutput(&context, new OrthancPlugins::DatabaseBackendOutputV2(&context, NULL));
+  db.SetOutputFactory(new OrthancPlugins::DatabaseBackendOutputV2::Factory(&context, NULL));
   db.Open();
+
+  std::unique_ptr<OrthancPlugins::IDatabaseBackendOutput> output(db.CreateOutput());
   
 
   std::string s;
@@ -329,7 +331,7 @@
   db.AddAttachment(a, a2);
   db.ListAvailableAttachments(fc, a);
   ASSERT_EQ(2u, fc.size());
-  ASSERT_FALSE(db.LookupAttachment(b, Orthanc::FileContentType_Dicom));
+  ASSERT_FALSE(db.LookupAttachment(*output, b, Orthanc::FileContentType_Dicom));
 
   ASSERT_EQ(4284u, db.GetTotalCompressedSize());
   ASSERT_EQ(4284u, db.GetTotalUncompressedSize());
@@ -342,7 +344,7 @@
   expectedAttachment->compressionType = Orthanc::CompressionType_None;
   expectedAttachment->compressedSize = 42;
   expectedAttachment->compressedHash = "md5_1";
-  ASSERT_TRUE(db.LookupAttachment(a, Orthanc::FileContentType_Dicom));
+  ASSERT_TRUE(db.LookupAttachment(*output, a, Orthanc::FileContentType_Dicom));
 
   expectedAttachment.reset(new OrthancPluginAttachment);
   expectedAttachment->uuid = "uuid2";
@@ -352,15 +354,15 @@
   expectedAttachment->compressionType = Orthanc::CompressionType_None;
   expectedAttachment->compressedSize = 4242;
   expectedAttachment->compressedHash = "md5_2";
-  ASSERT_TRUE(db.LookupAttachment(a, Orthanc::FileContentType_DicomAsJson));
+  ASSERT_TRUE(db.LookupAttachment(*output, a, Orthanc::FileContentType_DicomAsJson));
 
   db.ListAvailableAttachments(fc, b);
   ASSERT_EQ(0u, fc.size());
-  db.DeleteAttachment(a, Orthanc::FileContentType_Dicom);
+  db.DeleteAttachment(*output, a, Orthanc::FileContentType_Dicom);
   db.ListAvailableAttachments(fc, a);
   ASSERT_EQ(1u, fc.size());
   ASSERT_EQ(Orthanc::FileContentType_DicomAsJson, fc.front());
-  db.DeleteAttachment(a, Orthanc::FileContentType_DicomAsJson);
+  db.DeleteAttachment(*output, a, Orthanc::FileContentType_DicomAsJson);
   db.ListAvailableAttachments(fc, a);
   ASSERT_EQ(0u, fc.size());
 
@@ -377,7 +379,7 @@
   expectedDicomTags.back().group = 0x0020;
   expectedDicomTags.back().element = 0x000d;
   expectedDicomTags.back().value = "study";
-  db.GetMainDicomTags(a);
+  db.GetMainDicomTags(*output, a);
 
 
   db.LookupIdentifier(ci, OrthancPluginResourceType_Study, 0x0010, 0x0020, 
@@ -406,7 +408,7 @@
   expectedExported->seq = 1;
 
   bool done;
-  db.GetExportedResources(done, 0, 10);
+  db.GetExportedResources(*output, done, 0, 10);
   
 
   db.GetAllPublicIds(pub, OrthancPluginResourceType_Patient); ASSERT_EQ(0u, pub.size());
@@ -423,7 +425,7 @@
     // to implement recursive deletion of resources using pure SQL
     // statements
     db.StartTransaction();    
-    db.DeleteResource(c);
+    db.DeleteResource(*output, c);
     db.CommitTransaction();
   }
   
@@ -431,7 +433,7 @@
   ASSERT_TRUE(db.IsExistingResource(a));
   ASSERT_TRUE(db.IsExistingResource(b));
   ASSERT_EQ(2u, db.GetResourcesCount());
-  db.DeleteResource(a);
+  db.DeleteResource(*output, a);
   ASSERT_EQ(0u, db.GetResourcesCount());
   ASSERT_FALSE(db.IsExistingResource(a));
   ASSERT_FALSE(db.IsExistingResource(b));
@@ -457,7 +459,7 @@
   ASSERT_FALSE(db.IsProtectedPatient(p1));
   ASSERT_TRUE(db.SelectPatientToRecycle(r));
   ASSERT_EQ(p2, r);
-  db.DeleteResource(p2);
+  db.DeleteResource(*output, p2);
   ASSERT_TRUE(db.SelectPatientToRecycle(r, p3));
   ASSERT_EQ(p1, r);
 }
--- a/Framework/Plugins/OrthancCppDatabasePlugin.h	Thu Mar 18 15:21:17 2021 +0100
+++ b/Framework/Plugins/OrthancCppDatabasePlugin.h	Thu Mar 18 16:51:51 2021 +0100
@@ -73,6 +73,16 @@
   class IDatabaseBackendOutput : public boost::noncopyable
   {
   public:
+    class IFactory : public boost::noncopyable
+    {
+    public:
+      virtual ~IFactory()
+      {
+      }
+
+      virtual IDatabaseBackendOutput* CreateOutput() = 0;
+    };
+    
     virtual ~IDatabaseBackendOutput()
     {
     }
@@ -134,41 +144,16 @@
    **/
   class IDatabaseBackend : public boost::noncopyable
   {
-  private:
-    OrthancPluginContext*                    context_;
-    std::unique_ptr<IDatabaseBackendOutput>  output_;
-
   public:
-    // "context" can be NULL iff. running the unit tests
-    IDatabaseBackend() :
-      context_(NULL)
+    virtual ~IDatabaseBackend()
     {
     }
 
-    IDatabaseBackendOutput& GetOutput()
-    {
-      if (output_.get() == NULL)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-      else
-      {
-        return *output_;
-      }
-    }
+    virtual OrthancPluginContext* GetContext() = 0;
 
-    OrthancPluginContext* GetContext() const
-    {
-      return context_;
-    }
-
-    // This takes the ownership of the "output"
-    void RegisterOutput(OrthancPluginContext* context,
-                        IDatabaseBackendOutput* output)
-    {
-      context_ = context;
-      output_.reset(output);
-    }
+    virtual void SetOutputFactory(IDatabaseBackendOutput::IFactory* factory) = 0;
+                        
+    virtual IDatabaseBackendOutput* CreateOutput() = 0;
 
     virtual void Open() = 0;
 
@@ -187,13 +172,15 @@
     virtual int64_t CreateResource(const char* publicId,
                                    OrthancPluginResourceType type) = 0;
 
-    virtual void DeleteAttachment(int64_t id,
+    virtual void DeleteAttachment(OrthancPlugins::IDatabaseBackendOutput& output,
+                                  int64_t id,
                                   int32_t attachment) = 0;
 
     virtual void DeleteMetadata(int64_t id,
                                 int32_t metadataType) = 0;
 
-    virtual void DeleteResource(int64_t id) = 0;
+    virtual void DeleteResource(OrthancPlugins::IDatabaseBackendOutput& output,
+                                int64_t id) = 0;
 
     virtual void GetAllInternalIds(std::list<int64_t>& target,
                                    OrthancPluginResourceType resourceType) = 0;
@@ -207,7 +194,8 @@
                                  uint64_t limit) = 0;
 
     /* Use GetOutput().AnswerChange() */
-    virtual void GetChanges(bool& done /*out*/,
+    virtual void GetChanges(OrthancPlugins::IDatabaseBackendOutput& output,
+                            bool& done /*out*/,
                             int64_t since,
                             uint32_t maxResults) = 0;
 
@@ -218,18 +206,20 @@
                                      int64_t id) = 0;
 
     /* Use GetOutput().AnswerExportedResource() */
-    virtual void GetExportedResources(bool& done /*out*/,
+    virtual void GetExportedResources(OrthancPlugins::IDatabaseBackendOutput& output,
+                                      bool& done /*out*/,
                                       int64_t since,
                                       uint32_t maxResults) = 0;
 
     /* Use GetOutput().AnswerChange() */
-    virtual void GetLastChange() = 0;
+    virtual void GetLastChange(OrthancPlugins::IDatabaseBackendOutput& output) = 0;
 
     /* Use GetOutput().AnswerExportedResource() */
-    virtual void GetLastExportedResource() = 0;
+    virtual void GetLastExportedResource(OrthancPlugins::IDatabaseBackendOutput& output) = 0;
 
     /* Use GetOutput().AnswerDicomTag() */
-    virtual void GetMainDicomTags(int64_t id) = 0;
+    virtual void GetMainDicomTags(OrthancPlugins::IDatabaseBackendOutput& output,
+                                  int64_t id) = 0;
 
     virtual std::string GetPublicId(int64_t resourceId) = 0;
 
@@ -256,7 +246,8 @@
     virtual void LogExportedResource(const OrthancPluginExportedResource& resource) = 0;
     
     /* Use GetOutput().AnswerAttachment() */
-    virtual bool LookupAttachment(int64_t id,
+    virtual bool LookupAttachment(OrthancPlugins::IDatabaseBackendOutput& output,
+                                  int64_t id,
                                   int32_t contentType) = 0;
 
     virtual bool LookupGlobalProperty(std::string& target /*out*/,
@@ -336,7 +327,8 @@
     }
 
 #if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1
-    virtual void LookupResources(const std::vector<Orthanc::DatabaseConstraint>& lookup,
+    virtual void LookupResources(OrthancPlugins::IDatabaseBackendOutput& output,
+                                 const std::vector<Orthanc::DatabaseConstraint>& lookup,
                                  OrthancPluginResourceType queryLevel,
                                  uint32_t limit,
                                  bool requestSomeInstance) = 0;
@@ -415,6 +407,26 @@
     AllowedAnswers                allowedAnswers_;
 
   public:
+    class Factory : public IFactory
+    {
+    private:
+      OrthancPluginContext*         context_;
+      OrthancPluginDatabaseContext* database_;
+
+    public:
+      Factory(OrthancPluginContext*         context,
+              OrthancPluginDatabaseContext* database) :
+        context_(context),
+        database_(database)
+      {
+      }
+
+      virtual IDatabaseBackendOutput* CreateOutput() ORTHANC_OVERRIDE
+      {
+        return new DatabaseBackendOutputV2(context_, database_);
+      }
+    };
+    
     DatabaseBackendOutputV2(OrthancPluginContext*         context,
                             OrthancPluginDatabaseContext* database) :
       context_(context),
@@ -630,8 +642,6 @@
                                                  const OrthancPluginAttachment* attachment)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -647,8 +657,6 @@
                                                int64_t child)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -662,8 +670,6 @@
     static OrthancPluginErrorCode  ClearChanges(void* payload)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -677,8 +683,6 @@
     static OrthancPluginErrorCode  ClearExportedResources(void* payload)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -695,8 +699,6 @@
                                                   OrthancPluginResourceType resourceType)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -712,12 +714,12 @@
                                                     int32_t contentType)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
-        backend->DeleteAttachment(id, contentType);
+        backend->DeleteAttachment(*output, id, contentType);
         return OrthancPluginErrorCode_Success;
       }
       ORTHANC_PLUGINS_DATABASE_CATCH;
@@ -729,8 +731,6 @@
                                                   int32_t metadataType)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -745,12 +745,12 @@
                                                   int64_t id)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
-        backend->DeleteResource(id);
+        backend->DeleteResource(*output, id);
         return OrthancPluginErrorCode_Success;
       }
       ORTHANC_PLUGINS_DATABASE_CATCH;
@@ -762,8 +762,8 @@
                                                      OrthancPluginResourceType resourceType)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -774,7 +774,7 @@
                it = target.begin(); it != target.end(); ++it)
         {
           OrthancPluginDatabaseAnswerInt64(backend->GetContext(),
-                                           output.GetDatabase(), *it);
+                                           output->GetDatabase(), *it);
         }
 
         return OrthancPluginErrorCode_Success;
@@ -788,8 +788,8 @@
                                                    OrthancPluginResourceType resourceType)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -800,7 +800,7 @@
                it = ids.begin(); it != ids.end(); ++it)
         {
           OrthancPluginDatabaseAnswerString(backend->GetContext(),
-                                            output.GetDatabase(),
+                                            output->GetDatabase(),
                                             it->c_str());
         }
 
@@ -817,8 +817,8 @@
                                                             uint64_t limit)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -829,7 +829,7 @@
                it = ids.begin(); it != ids.end(); ++it)
         {
           OrthancPluginDatabaseAnswerString(backend->GetContext(),
-                                            output.GetDatabase(),
+                                            output->GetDatabase(),
                                             it->c_str());
         }
 
@@ -845,18 +845,18 @@
                                               uint32_t maxResult)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_Change);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_Change);
 
       try
       {
         bool done;
-        backend->GetChanges(done, since, maxResult);
+        backend->GetChanges(*output, done, since, maxResult);
         
         if (done)
         {
           OrthancPluginDatabaseAnswerChangesDone(backend->GetContext(),
-                                                 output.GetDatabase());
+                                                 output->GetDatabase());
         }
 
         return OrthancPluginErrorCode_Success;
@@ -870,8 +870,8 @@
                                                          int64_t id)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -882,7 +882,7 @@
                it = target.begin(); it != target.end(); ++it)
         {
           OrthancPluginDatabaseAnswerInt64(backend->GetContext(),
-                                           output.GetDatabase(), *it);
+                                           output->GetDatabase(), *it);
         }
 
         return OrthancPluginErrorCode_Success;
@@ -896,8 +896,8 @@
                                                        int64_t id)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -908,7 +908,7 @@
                it = ids.begin(); it != ids.end(); ++it)
         {
           OrthancPluginDatabaseAnswerString(backend->GetContext(),
-                                            output.GetDatabase(),
+                                            output->GetDatabase(),
                                             it->c_str());
         }
 
@@ -924,18 +924,18 @@
                                                         uint32_t  maxResult)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_ExportedResource);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_ExportedResource);
 
       try
       {
         bool done;
-        backend->GetExportedResources(done, since, maxResult);
+        backend->GetExportedResources(*output, done, since, maxResult);
 
         if (done)
         {
           OrthancPluginDatabaseAnswerExportedResourcesDone(backend->GetContext(),
-                                                           output.GetDatabase());
+                                                           output->GetDatabase());
         }
         return OrthancPluginErrorCode_Success;
       }
@@ -947,12 +947,12 @@
                                                  void* payload)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_Change);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_Change);
 
       try
       {
-        backend->GetLastChange();
+        backend->GetLastChange(*output);
         return OrthancPluginErrorCode_Success;
       }
       ORTHANC_PLUGINS_DATABASE_CATCH;
@@ -963,12 +963,12 @@
                                                            void* payload)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_ExportedResource);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_ExportedResource);
 
       try
       {
-        backend->GetLastExportedResource();
+        backend->GetLastExportedResource(*output);
         return OrthancPluginErrorCode_Success;
       }
       ORTHANC_PLUGINS_DATABASE_CATCH;
@@ -980,12 +980,12 @@
                                                     int64_t id)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_DicomTag);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_DicomTag);
 
       try
       {
-        backend->GetMainDicomTags(id);
+        backend->GetMainDicomTags(*output, id);
         return OrthancPluginErrorCode_Success;
       }
       ORTHANC_PLUGINS_DATABASE_CATCH;
@@ -997,14 +997,14 @@
                                                int64_t id)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
         std::string s = backend->GetPublicId(id);
         OrthancPluginDatabaseAnswerString(backend->GetContext(),
-                                          output.GetDatabase(),
+                                          output->GetDatabase(),
                                           s.c_str());
 
         return OrthancPluginErrorCode_Success;
@@ -1018,8 +1018,6 @@
                                                     OrthancPluginResourceType  resourceType)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1035,8 +1033,6 @@
                                                    int64_t id)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1051,8 +1047,6 @@
                                                           void* payload)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1067,8 +1061,6 @@
                                                             void* payload)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1084,8 +1076,6 @@
                                                       int64_t id)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1101,8 +1091,6 @@
                                                       int64_t id)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1118,8 +1106,8 @@
                                                          int64_t id)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1130,7 +1118,7 @@
                it = target.begin(); it != target.end(); ++it)
         {
           OrthancPluginDatabaseAnswerInt32(backend->GetContext(),
-                                           output.GetDatabase(),
+                                           output->GetDatabase(),
                                            *it);
         }
 
@@ -1145,8 +1133,8 @@
                                                             int64_t id)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1157,7 +1145,7 @@
                it = target.begin(); it != target.end(); ++it)
         {
           OrthancPluginDatabaseAnswerInt32(backend->GetContext(),
-                                           output.GetDatabase(),
+                                           output->GetDatabase(),
                                            *it);
         }
 
@@ -1171,8 +1159,6 @@
                                              const OrthancPluginChange* change)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1187,8 +1173,6 @@
                                                        const OrthancPluginExportedResource* exported)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1205,12 +1189,12 @@
                                                     int32_t contentType)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_Attachment);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_Attachment);
 
       try
       {
-        backend->LookupAttachment(id, contentType);
+        backend->LookupAttachment(*output, id, contentType);
         return OrthancPluginErrorCode_Success;
       }
       ORTHANC_PLUGINS_DATABASE_CATCH;
@@ -1222,8 +1206,8 @@
                                                         int32_t property)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1231,7 +1215,7 @@
         if (backend->LookupGlobalProperty(s, property))
         {
           OrthancPluginDatabaseAnswerString(backend->GetContext(),
-                                            output.GetDatabase(),
+                                            output->GetDatabase(),
                                             s.c_str());
         }
 
@@ -1248,8 +1232,8 @@
                                                      OrthancPluginIdentifierConstraint constraint)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1260,7 +1244,7 @@
                it = target.begin(); it != target.end(); ++it)
         {
           OrthancPluginDatabaseAnswerInt64(backend->GetContext(),
-                                           output.GetDatabase(), *it);
+                                           output->GetDatabase(), *it);
         }
 
         return OrthancPluginErrorCode_Success;
@@ -1278,8 +1262,8 @@
                                                          const char* end)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1290,7 +1274,7 @@
                it = target.begin(); it != target.end(); ++it)
         {
           OrthancPluginDatabaseAnswerInt64(backend->GetContext(),
-                                           output.GetDatabase(), *it);
+                                           output->GetDatabase(), *it);
         }
 
         return OrthancPluginErrorCode_Success;
@@ -1305,8 +1289,8 @@
                                                   int32_t metadata)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1314,7 +1298,7 @@
         if (backend->LookupMetadata(s, id, metadata))
         {
           OrthancPluginDatabaseAnswerString(backend->GetContext(),
-                                            output.GetDatabase(), s.c_str());
+                                            output->GetDatabase(), s.c_str());
         }
 
         return OrthancPluginErrorCode_Success;
@@ -1328,8 +1312,8 @@
                                                 int64_t id)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1337,7 +1321,7 @@
         if (backend->LookupParent(parent, id))
         {
           OrthancPluginDatabaseAnswerInt64(backend->GetContext(),
-                                           output.GetDatabase(), parent);
+                                           output->GetDatabase(), parent);
         }
 
         return OrthancPluginErrorCode_Success;
@@ -1351,8 +1335,8 @@
                                                   const char* publicId)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1361,7 +1345,7 @@
         if (backend->LookupResource(id, type, publicId))
         {
           OrthancPluginDatabaseAnswerResource(backend->GetContext(),
-                                              output.GetDatabase(), 
+                                              output->GetDatabase(), 
                                               id, type);
         }
 
@@ -1375,8 +1359,8 @@
                                                           void* payload)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1384,7 +1368,7 @@
         if (backend->SelectPatientToRecycle(id))
         {
           OrthancPluginDatabaseAnswerInt64(backend->GetContext(),
-                                           output.GetDatabase(), id);
+                                           output->GetDatabase(), id);
         }
 
         return OrthancPluginErrorCode_Success;
@@ -1398,8 +1382,8 @@
                                                            int64_t patientIdToAvoid)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1407,7 +1391,7 @@
         if (backend->SelectPatientToRecycle(id, patientIdToAvoid))
         {
           OrthancPluginDatabaseAnswerInt64(backend->GetContext(),
-                                           output.GetDatabase(), id);
+                                           output->GetDatabase(), id);
         }
 
         return OrthancPluginErrorCode_Success;
@@ -1421,8 +1405,6 @@
                                                      const char* value)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1438,8 +1420,6 @@
                                                    const OrthancPluginDicomTag* tag)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1455,8 +1435,6 @@
                                                     const OrthancPluginDicomTag* tag)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1473,8 +1451,6 @@
                                                const char* value)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1490,8 +1466,6 @@
                                                        int32_t isProtected)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1505,8 +1479,6 @@
     static OrthancPluginErrorCode StartTransaction(void* payload)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1520,8 +1492,6 @@
     static OrthancPluginErrorCode RollbackTransaction(void* payload)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1535,8 +1505,6 @@
     static OrthancPluginErrorCode CommitTransaction(void* payload)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1550,8 +1518,6 @@
     static OrthancPluginErrorCode Open(void* payload)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1565,8 +1531,6 @@
     static OrthancPluginErrorCode Close(void* payload)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1581,8 +1545,6 @@
                                                      void* payload)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
       
       try
       {
@@ -1598,8 +1560,6 @@
                                                   OrthancPluginStorageArea* storageArea)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
       
       try
       {
@@ -1614,8 +1574,6 @@
                                                      int64_t internalId)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
       
       try
       {
@@ -1638,8 +1596,8 @@
       uint8_t requestSomeInstance)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_MatchingResource);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_MatchingResource);
 
       try
       {
@@ -1651,7 +1609,7 @@
           lookup.push_back(Orthanc::DatabaseConstraint(constraints[i]));
         }
         
-        backend->LookupResources(lookup, queryLevel, limit, (requestSomeInstance != 0));
+        backend->LookupResources(*output, lookup, queryLevel, limit, (requestSomeInstance != 0));
         return OrthancPluginErrorCode_Success;
       }
       ORTHANC_PLUGINS_DATABASE_CATCH;
@@ -1668,8 +1626,6 @@
                                                  const char* hashInstance)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1692,8 +1648,6 @@
       const OrthancPluginResourcesContentMetadata* metadata)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1714,8 +1668,8 @@
                                                       int32_t metadata)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1726,7 +1680,7 @@
                it = values.begin(); it != values.end(); ++it)
         {
           OrthancPluginDatabaseAnswerString(backend->GetContext(),
-                                            output.GetDatabase(),
+                                            output->GetDatabase(),
                                             it->c_str());
         }
 
@@ -1741,8 +1695,6 @@
                                                      void* payload)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1758,8 +1710,6 @@
                                                        int64_t patientId)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_None);
 
       try
       {
@@ -1778,8 +1728,8 @@
                                                  int64_t resourceId)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_Metadata);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_Metadata);
 
       try
       {
@@ -1790,7 +1740,7 @@
                it = result.begin(); it != result.end(); ++it)
         {
           OrthancPluginDatabaseAnswerMetadata(backend->GetContext(),
-                                              output.GetDatabase(),
+                                              output->GetDatabase(),
                                               resourceId, it->first, it->second.c_str());
         }
         
@@ -1813,8 +1763,8 @@
                                                           const char* publicId)
     {
       IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
-      DatabaseBackendOutputV2& output = dynamic_cast<DatabaseBackendOutputV2&>(backend->GetOutput());
-      output.SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_String);
+      std::unique_ptr<DatabaseBackendOutputV2> output(dynamic_cast<DatabaseBackendOutputV2*>(backend->CreateOutput()));
+      output->SetAllowedAnswers(DatabaseBackendOutputV2::AllowedAnswers_String);
 
       try
       {
@@ -1826,7 +1776,7 @@
           if (!parent.empty())
           {
             OrthancPluginDatabaseAnswerString(backend->GetContext(),
-                                              output.GetDatabase(),
+                                              output->GetDatabase(),
                                               parent.c_str());
           }
         }
@@ -1969,7 +1919,7 @@
         throw std::runtime_error("Unable to register the database backend");
       }
 
-      backend.RegisterOutput(context, new DatabaseBackendOutputV2(context, database));
+      backend.SetOutputFactory(new DatabaseBackendOutputV2::Factory(context, database));
     }
   };
 }
--- a/MySQL/Plugins/IndexPlugin.cpp	Thu Mar 18 15:21:17 2021 +0100
+++ b/MySQL/Plugins/IndexPlugin.cpp	Thu Mar 18 16:51:51 2021 +0100
@@ -68,7 +68,7 @@
       OrthancDatabases::MySQLParameters parameters(mysql, configuration);
 
       /* Create the database back-end */
-      backend_.reset(new OrthancDatabases::MySQLIndex(parameters));
+      backend_.reset(new OrthancDatabases::MySQLIndex(context, parameters));
 
       /* Register the MySQL index into Orthanc */
       OrthancPlugins::DatabaseBackendAdapterV2::Register(context, *backend_);
--- a/MySQL/Plugins/MySQLIndex.cpp	Thu Mar 18 15:21:17 2021 +0100
+++ b/MySQL/Plugins/MySQLIndex.cpp	Thu Mar 18 16:51:51 2021 +0100
@@ -267,8 +267,9 @@
   }
 
 
-  MySQLIndex::MySQLIndex(const MySQLParameters& parameters) :
-    IndexBackend(new Factory(*this)),
+  MySQLIndex::MySQLIndex(OrthancPluginContext* context,
+                         const MySQLParameters& parameters) :
+    IndexBackend(context, new Factory(*this)),
     parameters_(parameters),
     clearAll_(false)
   {
@@ -305,7 +306,8 @@
   }
 
 
-  void MySQLIndex::DeleteResource(int64_t id)
+  void MySQLIndex::DeleteResource(OrthancPlugins::IDatabaseBackendOutput& output,
+                                  int64_t id)
   {
     ClearDeletedFiles();
 
@@ -363,7 +365,7 @@
     
             parent.Execute(args);
 
-            GetOutput().SignalRemainingAncestor(
+            output.SignalRemainingAncestor(
               ReadString(parent, 0),
               static_cast<OrthancPluginResourceType>(ReadInteger32(parent, 1)));
           }
@@ -384,7 +386,7 @@
       deleteHierarchy.Execute(args);
     }
 
-    SignalDeletedFiles();
+    SignalDeletedFiles(output);
   }
 
   
--- a/MySQL/Plugins/MySQLIndex.h	Thu Mar 18 15:21:17 2021 +0100
+++ b/MySQL/Plugins/MySQLIndex.h	Thu Mar 18 16:51:51 2021 +0100
@@ -63,7 +63,8 @@
     IDatabase* OpenInternal();
 
   public:
-    MySQLIndex(const MySQLParameters& parameters);
+    MySQLIndex(OrthancPluginContext* context,
+               const MySQLParameters& parameters);
 
     void SetClearAll(bool clear)
     {
@@ -74,7 +75,8 @@
                                    OrthancPluginResourceType type)
       ORTHANC_OVERRIDE;
 
-    virtual void DeleteResource(int64_t id) ORTHANC_OVERRIDE;
+    virtual void DeleteResource(OrthancPlugins::IDatabaseBackendOutput& output,
+                                int64_t id) ORTHANC_OVERRIDE;
 
     virtual int64_t GetLastChangeIndex() ORTHANC_OVERRIDE;
 
--- a/MySQL/UnitTests/UnitTestsMain.cpp	Thu Mar 18 15:21:17 2021 +0100
+++ b/MySQL/UnitTests/UnitTestsMain.cpp	Thu Mar 18 16:51:51 2021 +0100
@@ -47,19 +47,19 @@
   OrthancDatabases::MySQLParameters lock = globalParameters_;
   lock.SetLock(true);
 
-  OrthancDatabases::MySQLIndex db1(noLock);
+  OrthancDatabases::MySQLIndex db1(NULL, noLock);
   db1.SetClearAll(true);
   db1.Open();
 
   {
-    OrthancDatabases::MySQLIndex db2(lock);
+    OrthancDatabases::MySQLIndex db2(NULL, lock);
     db2.Open();
 
-    OrthancDatabases::MySQLIndex db3(lock);
+    OrthancDatabases::MySQLIndex db3(NULL, lock);
     ASSERT_THROW(db3.Open(), Orthanc::OrthancException);
   }
 
-  OrthancDatabases::MySQLIndex db4(lock);
+  OrthancDatabases::MySQLIndex db4(NULL, lock);
   db4.Open();
 }
 
--- a/PostgreSQL/Plugins/IndexPlugin.cpp	Thu Mar 18 15:21:17 2021 +0100
+++ b/PostgreSQL/Plugins/IndexPlugin.cpp	Thu Mar 18 16:51:51 2021 +0100
@@ -62,7 +62,7 @@
       OrthancDatabases::PostgreSQLParameters parameters(postgresql);
 
       /* Create the database back-end */
-      backend_.reset(new OrthancDatabases::PostgreSQLIndex(parameters));
+      backend_.reset(new OrthancDatabases::PostgreSQLIndex(context, parameters));
 
       /* Register the PostgreSQL index into Orthanc */
       OrthancPlugins::DatabaseBackendAdapterV2::Register(context, *backend_);
--- a/PostgreSQL/Plugins/PostgreSQLIndex.cpp	Thu Mar 18 15:21:17 2021 +0100
+++ b/PostgreSQL/Plugins/PostgreSQLIndex.cpp	Thu Mar 18 16:51:51 2021 +0100
@@ -257,8 +257,9 @@
   }
 
 
-  PostgreSQLIndex::PostgreSQLIndex(const PostgreSQLParameters& parameters) :
-    IndexBackend(new Factory(*this)),
+  PostgreSQLIndex::PostgreSQLIndex(OrthancPluginContext* context,
+                                   const PostgreSQLParameters& parameters) :
+    IndexBackend(context, new Factory(*this)),
     parameters_(parameters),
     clearAll_(false)
   {
--- a/PostgreSQL/Plugins/PostgreSQLIndex.h	Thu Mar 18 15:21:17 2021 +0100
+++ b/PostgreSQL/Plugins/PostgreSQLIndex.h	Thu Mar 18 16:51:51 2021 +0100
@@ -63,7 +63,8 @@
     IDatabase* OpenInternal();
 
   public:
-    PostgreSQLIndex(const PostgreSQLParameters& parameters);
+    PostgreSQLIndex(OrthancPluginContext* context,
+                    const PostgreSQLParameters& parameters);
 
     void SetClearAll(bool clear)
     {
--- a/PostgreSQL/UnitTests/PostgreSQLTests.cpp	Thu Mar 18 15:21:17 2021 +0100
+++ b/PostgreSQL/UnitTests/PostgreSQLTests.cpp	Thu Mar 18 16:51:51 2021 +0100
@@ -446,7 +446,7 @@
 #if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1
 TEST(PostgreSQLIndex, CreateInstance)
 {
-  OrthancDatabases::PostgreSQLIndex db(globalParameters_);
+  OrthancDatabases::PostgreSQLIndex db(NULL, globalParameters_);
   db.SetClearAll(true);
   db.Open();
 
--- a/PostgreSQL/UnitTests/UnitTestsMain.cpp	Thu Mar 18 15:21:17 2021 +0100
+++ b/PostgreSQL/UnitTests/UnitTestsMain.cpp	Thu Mar 18 16:51:51 2021 +0100
@@ -89,19 +89,19 @@
   OrthancDatabases::PostgreSQLParameters lock = globalParameters_;
   lock.SetLock(true);
 
-  OrthancDatabases::PostgreSQLIndex db1(noLock);
+  OrthancDatabases::PostgreSQLIndex db1(NULL, noLock);
   db1.SetClearAll(true);
   db1.Open();
 
   {
-    OrthancDatabases::PostgreSQLIndex db2(lock);
+    OrthancDatabases::PostgreSQLIndex db2(NULL, lock);
     db2.Open();
 
-    OrthancDatabases::PostgreSQLIndex db3(lock);
+    OrthancDatabases::PostgreSQLIndex db3(NULL, lock);
     ASSERT_THROW(db3.Open(), Orthanc::OrthancException);
   }
 
-  OrthancDatabases::PostgreSQLIndex db4(lock);
+  OrthancDatabases::PostgreSQLIndex db4(NULL, lock);
   db4.Open();
 }
 
--- a/SQLite/Plugins/IndexPlugin.cpp	Thu Mar 18 15:21:17 2021 +0100
+++ b/SQLite/Plugins/IndexPlugin.cpp	Thu Mar 18 16:51:51 2021 +0100
@@ -62,7 +62,7 @@
     try
     {
       /* Create the database back-end */
-      backend_.reset(new OrthancDatabases::SQLiteIndex("index.db"));  // TODO parameter
+      backend_.reset(new OrthancDatabases::SQLiteIndex(context, "index.db"));  // TODO parameter
 
       /* Register the SQLite index into Orthanc */
       OrthancPlugins::DatabaseBackendAdapterV2::Register(context, *backend_);
--- a/SQLite/Plugins/SQLiteIndex.cpp	Thu Mar 18 15:21:17 2021 +0100
+++ b/SQLite/Plugins/SQLiteIndex.cpp	Thu Mar 18 16:51:51 2021 +0100
@@ -132,8 +132,9 @@
   }
 
 
-  SQLiteIndex::SQLiteIndex(const std::string& path) :
-    IndexBackend(new Factory(*this)),
+  SQLiteIndex::SQLiteIndex(OrthancPluginContext* context,
+                           const std::string& path) :
+    IndexBackend(context, new Factory(*this)),
     path_(path),
     fast_(true)
   {
@@ -144,8 +145,8 @@
   }
 
 
-  SQLiteIndex::SQLiteIndex() :
-    IndexBackend(new Factory(*this)),
+  SQLiteIndex::SQLiteIndex(OrthancPluginContext* context) :
+    IndexBackend(context, new Factory(*this)),
     fast_(true)
   {
   }
--- a/SQLite/Plugins/SQLiteIndex.h	Thu Mar 18 15:21:17 2021 +0100
+++ b/SQLite/Plugins/SQLiteIndex.h	Thu Mar 18 16:51:51 2021 +0100
@@ -64,9 +64,10 @@
     IDatabase* OpenInternal();
 
   public:
-    SQLiteIndex();  // Opens in memory
+    SQLiteIndex(OrthancPluginContext* context);  // Opens in memory
 
-    SQLiteIndex(const std::string& path);
+    SQLiteIndex(OrthancPluginContext* context,
+                const std::string& path);
 
     void SetFast(bool fast)
     {
--- a/SQLite/UnitTests/UnitTestsMain.cpp	Thu Mar 18 15:21:17 2021 +0100
+++ b/SQLite/UnitTests/UnitTestsMain.cpp	Thu Mar 18 16:51:51 2021 +0100
@@ -36,8 +36,8 @@
 {
   {
     // No locking if using memory backend
-    OrthancDatabases::SQLiteIndex db1;
-    OrthancDatabases::SQLiteIndex db2;
+    OrthancDatabases::SQLiteIndex db1(NULL);
+    OrthancDatabases::SQLiteIndex db2(NULL);
 
     db1.Open();
     db2.Open();
@@ -46,15 +46,15 @@
   Orthanc::SystemToolbox::RemoveFile("index.db");
 
   {
-    OrthancDatabases::SQLiteIndex db1("index.db");
-    OrthancDatabases::SQLiteIndex db2("index.db");
+    OrthancDatabases::SQLiteIndex db1(NULL, "index.db");
+    OrthancDatabases::SQLiteIndex db2(NULL, "index.db");
 
     db1.Open();
     ASSERT_THROW(db2.Open(), Orthanc::OrthancException);
   }
 
   {
-    OrthancDatabases::SQLiteIndex db3("index.db");
+    OrthancDatabases::SQLiteIndex db3(NULL, "index.db");
     db3.Open();
   }
 }