[med-svn] [Git][med-team/orthanc-postgresql][upstream] New upstream version 3.1

Sebastien Jodogne gitlab at salsa.debian.org
Sat Feb 9 11:03:18 GMT 2019


Sebastien Jodogne pushed to branch upstream at Debian Med / orthanc-postgresql


Commits:
ed942e11 by jodogne-guest at 2019-02-09T10:27:31Z
New upstream version 3.1
- - - - -


23 changed files:

- .hg_archival.txt
- Framework/Common/DatabaseManager.cpp
- Framework/Plugins/IndexBackend.cpp
- Framework/Plugins/IndexBackend.h
- Framework/Plugins/OrthancCppDatabasePlugin.h
- Framework/Plugins/PluginInitialization.cpp
- Framework/PostgreSQL/PostgreSQLDatabase.cpp
- + Framework/PostgreSQL/PostgreSQLIncludes.h
- Framework/PostgreSQL/PostgreSQLLargeObject.cpp
- Framework/PostgreSQL/PostgreSQLResult.cpp
- Framework/PostgreSQL/PostgreSQLStatement.cpp
- Framework/PostgreSQL/PostgreSQLTransaction.cpp
- PostgreSQL/CMakeLists.txt
- PostgreSQL/NEWS
- PostgreSQL/Plugins/CreateInstance.sql
- Resources/CMake/DatabasesPluginConfiguration.cmake
- Resources/CMake/DatabasesPluginParameters.cmake
- − Resources/CMake/FindPostgreSQL.cmake
- Resources/CMake/PostgreSQLConfiguration.cmake
- Resources/Orthanc/DownloadOrthancFramework.cmake
- + Resources/Orthanc/Sdk-1.5.4/orthanc/OrthancCDatabasePlugin.h
- + Resources/Orthanc/Sdk-1.5.4/orthanc/OrthancCPlugin.h
- Resources/SyncOrthancFolder.py


Changes:

=====================================
.hg_archival.txt
=====================================
@@ -1,6 +1,6 @@
 repo: 7cea966b682978aa285eb9b3a7a9cff81df464b3
-node: deab01d8e1c85149e9059194bec266abd038c152
-branch: OrthancPostgreSQL-3.0
+node: 3424a54ca2ee52448369fd249af954d225164e62
+branch: OrthancPostgreSQL-3.1
 latesttag: null
-latesttagdistance: 90
-changessincelatesttag: 100
+latesttagdistance: 112
+changessincelatesttag: 124


=====================================
Framework/Common/DatabaseManager.cpp
=====================================
@@ -21,6 +21,8 @@
 
 #include "DatabaseManager.h"
 
+#include <Plugins/Samples/Common/OrthancPluginCppWrapper.h>
+
 #include <Core/Logging.h>
 #include <Core/OrthancException.h>
 
@@ -510,6 +512,18 @@ namespace OrthancDatabases
       }
         
       assert(statement_ != NULL);
+
+      /*
+        TODO - Sample code to monitor the execution time of each
+        cached statement, and publish it as an Orthanc metrics
+
+        #if HAS_ORTHANC_PLUGIN_METRICS == 1
+        std::string name = (std::string(location_.GetFile()) + "_" +
+        boost::lexical_cast<std::string>(location_.GetLine()));
+        OrthancPlugins::MetricsTimer timer(name.c_str());
+        #endif
+      */
+
       SetResult(GetTransaction().Execute(*statement_, parameters));
     }
     catch (Orthanc::OrthancException& e)


=====================================
Framework/Plugins/IndexBackend.cpp
=====================================
@@ -1739,9 +1739,9 @@ namespace OrthancDatabases
       args.SetUtf8Value(name, tags[i].value);
       
       std::string insert = ("(" + boost::lexical_cast<std::string>(tags[i].resource) + ", " +
-                           boost::lexical_cast<std::string>(tags[i].group) + ", " +
-                           boost::lexical_cast<std::string>(tags[i].element) + ", " +
-                           "${" + name + "})");
+                            boost::lexical_cast<std::string>(tags[i].group) + ", " +
+                            boost::lexical_cast<std::string>(tags[i].element) + ", " +
+                            "${" + name + "})");
 
       if (sql.empty())
       {
@@ -1787,7 +1787,7 @@ namespace OrthancDatabases
       
       std::string insert = ("(" + boost::lexical_cast<std::string>(metadata[i].resource) + ", " +
                             boost::lexical_cast<std::string>(metadata[i].metadata) + ", " +
-                           "${" + name + "})");
+                            "${" + name + "})");
 
       std::string remove = ("(id=" + boost::lexical_cast<std::string>(metadata[i].resource) +
                             " AND type=" + boost::lexical_cast<std::string>(metadata[i].metadata)
@@ -1951,4 +1951,108 @@ namespace OrthancDatabases
       statement.Execute(args);
     }
   }
+
+
+#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)      // Macro introduced in 1.3.1
+#  if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4)
+  // New primitive since Orthanc 1.5.4
+  bool IndexBackend::LookupResourceAndParent(int64_t& id,
+                                             OrthancPluginResourceType& type,
+                                             std::string& parentPublicId,
+                                             const char* publicId)
+  {
+    DatabaseManager::CachedStatement statement(
+      STATEMENT_FROM_HERE, manager_,
+      "SELECT resource.internalId, resource.resourceType, parent.publicId "
+      "FROM Resources AS resource LEFT JOIN Resources parent ON parent.internalId=resource.parentId "
+      "WHERE resource.publicId=${id}");
+
+    statement.SetParameterType("id", ValueType_Utf8String);
+        
+    Dictionary args;
+    args.SetUtf8Value("id", publicId);
+
+    statement.Execute(args);
+
+    if (statement.IsDone())
+    {
+      return false;
+    }
+    else
+    {
+      if (statement.GetResultFieldsCount() != 3)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }
+
+      statement.SetResultFieldType(0, ValueType_Integer64);
+      statement.SetResultFieldType(1, ValueType_Integer64);      
+      statement.SetResultFieldType(2, ValueType_Utf8String);
+
+      id = ReadInteger64(statement, 0);
+      type = static_cast<OrthancPluginResourceType>(ReadInteger32(statement, 1));
+
+      const IValue& value = statement.GetResultField(2);
+      
+      switch (value.GetType())
+      {
+        case ValueType_Null:
+          parentPublicId.clear();
+          break;
+
+        case ValueType_Utf8String:
+          parentPublicId = dynamic_cast<const Utf8StringValue&>(value).GetContent();
+          break;
+
+        default:
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }
+      
+      assert((statement.Next(), statement.IsDone()));
+      return true;
+    }
+  }
+#  endif
+#endif
+  
+
+#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)      // Macro introduced in 1.3.1
+#  if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4)
+  // New primitive since Orthanc 1.5.4
+  void IndexBackend::GetAllMetadata(std::map<int32_t, std::string>& result,
+                                    int64_t id)
+  {
+    DatabaseManager::CachedStatement statement(
+      STATEMENT_FROM_HERE, manager_,
+      "SELECT type, value FROM Metadata WHERE id=${id}");
+      
+    statement.SetReadOnly(true);
+    statement.SetParameterType("id", ValueType_Integer64);
+
+    Dictionary args;
+    args.SetIntegerValue("id", id);
+
+    statement.Execute(args);
+      
+    result.clear();
+
+    if (!statement.IsDone())
+    {
+      if (statement.GetResultFieldsCount() != 2)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
+      }
+      
+      statement.SetResultFieldType(0, ValueType_Integer64);
+      statement.SetResultFieldType(1, ValueType_Utf8String);
+
+      while (!statement.IsDone())
+      {
+        result[ReadInteger32(statement, 0)] = ReadString(statement, 1);
+        statement.Next();
+      }
+    }
+  }
+#  endif
+#endif
 }


=====================================
Framework/Plugins/IndexBackend.h
=====================================
@@ -283,5 +283,23 @@ namespace OrthancDatabases
                                      int32_t metadata);
 
     virtual void TagMostRecentPatient(int64_t patient);
+
+#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)      // Macro introduced in 1.3.1
+#  if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4)
+    // New primitive since Orthanc 1.5.4
+    virtual bool LookupResourceAndParent(int64_t& id,
+                                         OrthancPluginResourceType& type,
+                                         std::string& parentPublicId,
+                                         const char* publicId);
+#  endif
+#endif
+
+#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)      // Macro introduced in 1.3.1
+#  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);
+#  endif
+#endif
   };
 }


=====================================
Framework/Plugins/OrthancCppDatabasePlugin.h
=====================================
@@ -82,7 +82,8 @@ namespace OrthancPlugins
       AllowedAnswers_DicomTag,
       AllowedAnswers_ExportedResource,
       AllowedAnswers_MatchingResource,
-      AllowedAnswers_String
+      AllowedAnswers_String,
+      AllowedAnswers_Metadata
     };
 
     OrthancPluginContext*         context_;
@@ -534,6 +535,23 @@ namespace OrthancPlugins
     virtual int64_t GetLastChangeIndex() = 0;
 
     virtual void TagMostRecentPatient(int64_t patientId) = 0;
+
+#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)      // Macro introduced in 1.3.1
+#  if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4)
+    // NB: "parentPublicId" must be cleared if the resource has no parent
+    virtual bool LookupResourceAndParent(int64_t& id,
+      OrthancPluginResourceType& type,
+      std::string& parentPublicId,
+      const char* publicId) = 0;
+#  endif
+#endif
+
+#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)      // Macro introduced in 1.3.1
+#  if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4)
+  virtual void GetAllMetadata(std::map<int32_t, std::string>& result,
+                              int64_t id) = 0;
+#  endif
+#endif
   };
 
 
@@ -1650,6 +1668,77 @@ namespace OrthancPlugins
     }
    
 
+#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)      // Macro introduced in 1.3.1
+#  if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4)
+    // New primitive since Orthanc 1.5.4
+    static OrthancPluginErrorCode GetAllMetadata(OrthancPluginDatabaseContext* context,
+                                                 void* payload,
+                                                 int64_t resourceId)
+    {
+      IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
+      backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_Metadata);
+
+      try
+      {
+        std::map<int32_t, std::string> result;
+        backend->GetAllMetadata(result, resourceId);
+
+        for (std::map<int32_t, std::string>::const_iterator
+               it = result.begin(); it != result.end(); ++it)
+        {
+          OrthancPluginDatabaseAnswerMetadata(backend->GetOutput().context_,
+                                            backend->GetOutput().database_,
+                                            resourceId, it->first, it->second.c_str());
+        }
+        
+        return OrthancPluginErrorCode_Success;
+      }
+      ORTHANC_PLUGINS_DATABASE_CATCH      
+    }
+#  endif
+#endif
+   
+
+#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)      // Macro introduced in 1.3.1
+#  if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4)
+    // New primitive since Orthanc 1.5.4
+    static OrthancPluginErrorCode LookupResourceAndParent(OrthancPluginDatabaseContext* context,
+                                                          uint8_t* isExisting,
+                                                          int64_t* id,
+                                                          OrthancPluginResourceType* type,
+                                                          void* payload,
+                                                          const char* publicId)
+    {
+      IDatabaseBackend* backend = reinterpret_cast<IDatabaseBackend*>(payload);
+      backend->GetOutput().SetAllowedAnswers(DatabaseBackendOutput::AllowedAnswers_String);
+
+      try
+      {
+        std::string parent;
+        if (backend->LookupResourceAndParent(*id, *type, parent, publicId))
+        {
+          *isExisting = 1;
+
+          if (!parent.empty())
+          {
+            OrthancPluginDatabaseAnswerString(backend->GetOutput().context_,
+                                              backend->GetOutput().database_,
+                                              parent.c_str());
+          }
+        }
+        else
+        {
+          *isExisting = 0;
+        }
+        
+        return OrthancPluginErrorCode_Success;
+      }
+      ORTHANC_PLUGINS_DATABASE_CATCH      
+    }
+#  endif
+#endif
+   
+
   public:
     /**
      * Register a custom database back-end written in C++.
@@ -1741,17 +1830,24 @@ namespace OrthancPlugins
       {
         extensions.createInstance = CreateInstance;          // Fast creation of resources
       }
-      
-      performanceWarning = false;
 #endif      
 
+#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)      // Macro introduced in 1.3.1
+#  if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 5, 4)
+      // Optimizations brought by Orthanc 1.5.4
+      extensions.lookupResourceAndParent = LookupResourceAndParent;
+      extensions.getAllMetadata = GetAllMetadata;
+      performanceWarning = false;
+#  endif
+#endif
+
       if (performanceWarning)
       {
         char info[1024];
         sprintf(info, 
                 "Performance warning: The database index plugin was compiled "
                 "against an old version of the Orthanc SDK (%d.%d.%d): "
-                "Consider upgrading to version 1.5.2 of the Orthanc SDK",
+                "Consider upgrading to version 1.5.4 of the Orthanc SDK",
                 ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER,
                 ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER,
                 ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER);


=====================================
Framework/Plugins/PluginInitialization.cpp
=====================================
@@ -65,7 +65,7 @@ namespace OrthancDatabases
       return false;
     }
 
-    if (OrthancPluginCheckVersionAdvanced(context, 1, 4, 0) == 1)
+    if (OrthancPluginCheckVersionAdvanced(context, 1, 5, 4) == 1)
     {
       ImplicitTransaction::SetErrorOnDoubleExecution(true);
       isOptimal = true;
@@ -111,8 +111,8 @@ namespace OrthancDatabases
         int revision = boost::lexical_cast<int>(tokens[2]);
 
         isOptimal = (major > 1 ||
-                     (major == 1 && minor > 4) ||
-                     (major == 1 && minor == 4 && revision >= 0));
+                     (major == 1 && minor > 5) ||
+                     (major == 1 && minor == 5 && revision >= 4));
       }
     }
 
@@ -121,7 +121,7 @@ namespace OrthancDatabases
     {
       LOG(WARNING) << "Performance warning in " << dbms
                    << " index: Your version of Orthanc (" 
-                   << context->orthancVersion << ") should be upgraded to 1.4.0 "
+                   << context->orthancVersion << ") should be upgraded to 1.5.4 "
                    << "to benefit from best performance";
     }
 


=====================================
Framework/PostgreSQL/PostgreSQLDatabase.cpp
=====================================
@@ -19,6 +19,7 @@
  **/
 
 
+#include "PostgreSQLIncludes.h"  // Must be the first
 #include "PostgreSQLDatabase.h"
 
 #include "PostgreSQLResult.h"
@@ -26,23 +27,11 @@
 #include "PostgreSQLTransaction.h"
 #include "../Common/ImplicitTransaction.h"
 
-#include <pg_config.h>
-
-#if PG_VERSION_NUM >= 110000
-#  include <postgres.h>
-#  undef LOG  // This one comes from <postgres.h>, and conflicts with <Core/Logging.h>
-#endif
-
 #include <Core/Logging.h>
 #include <Core/OrthancException.h>
 
 #include <boost/lexical_cast.hpp>
 
-// PostgreSQL includes
-#include <libpq-fe.h>
-#include <c.h>
-#include <catalog/pg_type.h>
-
 
 namespace OrthancDatabases
 {


=====================================
Framework/PostgreSQL/PostgreSQLIncludes.h
=====================================
@@ -0,0 +1,50 @@
+/**
+ * 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 Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * 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
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+// These includes are necessary for compilation on OS X
+#include <unistd.h>
+#include <vector>
+#include <map>
+#include <cmath>
+#include <Core/Enumerations.h>
+
+/**
+ * This include must be before including "c.h" from PostgreSQL,
+ * otherwise the function "static bool
+ * boost::date_time::special_values_parser<date_type,
+ * charT>::__builtin_expect()" from Boost clashes with macro
+ * "__builtin_expect()" used by PostgreSQL 11.
+ **/
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+// PostgreSQL includes
+#include <pg_config.h>
+
+#if PG_VERSION_NUM >= 110000
+#  include <postgres.h>
+#  undef LOG  // This one comes from <postgres.h>, and conflicts with <Core/Logging.h>
+#endif
+
+#include <libpq-fe.h>
+#include <c.h>
+#include <catalog/pg_type.h>


=====================================
Framework/PostgreSQL/PostgreSQLLargeObject.cpp
=====================================
@@ -21,6 +21,7 @@
 
 // http://www.postgresql.org/docs/9.1/static/lo-interfaces.html#AEN33102
 
+#include "PostgreSQLIncludes.h"  // Must be the first
 #include "PostgreSQLLargeObject.h"
 
 #include <Core/Logging.h>


=====================================
Framework/PostgreSQL/PostgreSQLResult.cpp
=====================================
@@ -19,6 +19,7 @@
  **/
 
 
+#include "PostgreSQLIncludes.h"  // Must be the first
 #include "PostgreSQLResult.h"
 
 #include "../Common/BinaryStringValue.h"
@@ -27,26 +28,13 @@
 #include "../Common/NullValue.h"
 #include "../Common/Utf8StringValue.h"
 
-#include <pg_config.h>
-
-#if PG_VERSION_NUM >= 110000
-#  include <postgres.h>
-#  undef LOG  // This one comes from <postgres.h>, and conflicts with <Core/Logging.h>
-#endif
-
 #include <Core/OrthancException.h>
 #include <Core/Logging.h>
+#include <Core/Endianness.h>
 
 #include <cassert>
 #include <boost/lexical_cast.hpp>
 
-// PostgreSQL includes
-#include <libpq-fe.h>
-#include <c.h>
-#include <catalog/pg_type.h>
-
-#include <Core/Endianness.h>
-
 
 namespace OrthancDatabases
 {


=====================================
Framework/PostgreSQL/PostgreSQLStatement.cpp
=====================================
@@ -19,6 +19,7 @@
  **/
 
 
+#include "PostgreSQLIncludes.h"  // Must be the first
 #include "PostgreSQLStatement.h"
 
 #include "../Common/BinaryStringValue.h"
@@ -29,26 +30,13 @@
 #include "../Common/Utf8StringValue.h"
 #include "PostgreSQLResult.h"
 
-#include <pg_config.h>
-
-#if PG_VERSION_NUM >= 110000
-#  include <postgres.h>
-#  undef LOG  // This one comes from <postgres.h>, and conflicts with <Core/Logging.h>
-#endif
-
 #include <Core/Logging.h>
 #include <Core/OrthancException.h>
 #include <Core/Toolbox.h>
+#include <Core/Endianness.h>
 
 #include <cassert>
 
-// PostgreSQL includes
-#include <libpq-fe.h>
-#include <c.h>
-#include <catalog/pg_type.h>
-
-#include <Core/Endianness.h>
-
 
 namespace OrthancDatabases
 {


=====================================
Framework/PostgreSQL/PostgreSQLTransaction.cpp
=====================================
@@ -108,7 +108,7 @@ namespace OrthancDatabases
       readOnly_ = false;
     }
 
-  return result.release();
+    return result.release();
   }
 
 


=====================================
PostgreSQL/CMakeLists.txt
=====================================
@@ -1,13 +1,13 @@
 cmake_minimum_required(VERSION 2.8)
 project(OrthancPostgreSQL)
 
-set(ORTHANC_PLUGIN_VERSION "3.0")
+set(ORTHANC_PLUGIN_VERSION "3.1")
 
 if (ORTHANC_PLUGIN_VERSION STREQUAL "mainline")
   set(ORTHANC_FRAMEWORK_VERSION "mainline")
   set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg")
 else()
-  set(ORTHANC_FRAMEWORK_VERSION "1.5.2")
+  set(ORTHANC_FRAMEWORK_VERSION "1.5.4")
   set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web")
 endif()
 


=====================================
PostgreSQL/NEWS
=====================================
@@ -2,6 +2,15 @@ Pending changes in the mainline
 ===============================
 
 
+Release 3.1 (2019-02-08)
+========================
+
+* Fix build on Debian Buster
+* Remove "ASSERT" in SQL for compatibility with older releases of PostgreSQL
+* Implementation of new extensions: LookupResourceAndParent and GetAllMetadata
+* Performance: Defining option "TCP_NODELAY" if libpq is linked statically
+
+
 Release 3.0 (2019-01-21)
 ========================
 


=====================================
PostgreSQL/Plugins/CreateInstance.sql
=====================================
@@ -29,40 +29,51 @@ BEGIN
 
     IF patientKey IS NULL THEN
       -- Must create a new patient
-      ASSERT studyKey IS NULL;
-      ASSERT seriesKey IS NULL;
-      ASSERT instanceKey IS NULL;
+      IF NOT (studyKey IS NULL AND seriesKey IS NULL AND instanceKey IS NULL) THEN
+         RAISE EXCEPTION 'Broken invariant';
+      END IF;
+
       INSERT INTO Resources VALUES (DEFAULT, 0, patient, NULL) RETURNING internalId INTO patientKey;
       isNewPatient := 1;
     ELSE
       isNewPatient := 0;
     END IF;
   
-    ASSERT NOT patientKey IS NULL;
+    IF (patientKey IS NULL) THEN
+       RAISE EXCEPTION 'Broken invariant';
+    END IF;
 
     IF studyKey IS NULL THEN
       -- Must create a new study
-      ASSERT seriesKey IS NULL;
-      ASSERT instanceKey IS NULL;
+      IF NOT (seriesKey IS NULL AND instanceKey IS NULL) THEN
+         RAISE EXCEPTION 'Broken invariant';
+      END IF;
+
       INSERT INTO Resources VALUES (DEFAULT, 1, study, patientKey) RETURNING internalId INTO studyKey;
       isNewStudy := 1;
     ELSE
       isNewStudy := 0;
     END IF;
 
-    ASSERT NOT studyKey IS NULL;
-    
+    IF (studyKey IS NULL) THEN
+       RAISE EXCEPTION 'Broken invariant';
+    END IF;
+
     IF seriesKey IS NULL THEN
       -- Must create a new series
-      ASSERT instanceKey IS NULL;
+      IF NOT (instanceKey IS NULL) THEN
+         RAISE EXCEPTION 'Broken invariant';
+      END IF;
+
       INSERT INTO Resources VALUES (DEFAULT, 2, series, studyKey) RETURNING internalId INTO seriesKey;
       isNewSeries := 1;
     ELSE
       isNewSeries := 0;
     END IF;
   
-    ASSERT NOT seriesKey IS NULL;
-    ASSERT instanceKey IS NULL;
+    IF (seriesKey IS NULL OR NOT instanceKey IS NULL) THEN
+       RAISE EXCEPTION 'Broken invariant';
+    END IF;
 
     INSERT INTO Resources VALUES (DEFAULT, 3, instance, seriesKey) RETURNING internalId INTO instanceKey;
     isNewInstance := 1;


=====================================
Resources/CMake/DatabasesPluginConfiguration.cmake
=====================================
@@ -29,6 +29,8 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_ORTHANC_SDK)
     include_directories(${ORTHANC_DATABASES_ROOT}/Resources/Orthanc/Sdk-1.4.0)
   elseif (ORTHANC_SDK_VERSION STREQUAL "1.5.2")
     include_directories(${ORTHANC_DATABASES_ROOT}/Resources/Orthanc/Sdk-1.5.2)
+  elseif (ORTHANC_SDK_VERSION STREQUAL "1.5.4")
+    include_directories(${ORTHANC_DATABASES_ROOT}/Resources/Orthanc/Sdk-1.5.4)
   elseif (ORTHANC_SDK_VERSION STREQUAL "framework")
     include_directories(${ORTHANC_ROOT}/Plugins/Include)
   else()


=====================================
Resources/CMake/DatabasesPluginParameters.cmake
=====================================
@@ -25,7 +25,7 @@ set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory
 
 # Advanced parameters to fine-tune linking against system libraries
 set(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK")
-set(ORTHANC_SDK_VERSION "1.5.2" CACHE STRING "Version of the Orthanc plugin SDK to use, if not using the system version (can be \"0.9.5\", \"1.4.0\", \"1.5.2\" or \"framework\")")
+set(ORTHANC_SDK_VERSION "1.5.4" CACHE STRING "Version of the Orthanc plugin SDK to use, if not using the system version (can be \"0.9.5\", \"1.4.0\", \"1.5.2\", \"1.5.4\" or \"framework\")")
 
 include(${CMAKE_CURRENT_LIST_DIR}/DatabasesFrameworkParameters.cmake)
 


=====================================
Resources/CMake/FindPostgreSQL.cmake deleted
=====================================
@@ -1,172 +0,0 @@
-# - Find the PostgreSQL installation.
-# In Windows, we make the assumption that, if the PostgreSQL files are installed, the default directory
-# will be C:\Program Files\PostgreSQL.
-#
-# This module defines
-#  PostgreSQL_LIBRARIES - the PostgreSQL libraries needed for linking
-#  PostgreSQL_INCLUDE_DIRS - the directories of the PostgreSQL headers
-#  PostgreSQL_VERSION_STRING - the version of PostgreSQL found (since CMake 2.8.8)
-
-#=============================================================================
-# Copyright 2004-2009 Kitware, Inc.
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-# (To distribute this file outside of CMake, substitute the full
-#  License text for the above reference.)
-
-# ----------------------------------------------------------------------------
-# History:
-# This module is derived from the module originally found in the VTK source tree.
-#
-# ----------------------------------------------------------------------------
-# Note:
-# PostgreSQL_ADDITIONAL_VERSIONS is a variable that can be used to set the
-# version mumber of the implementation of PostgreSQL.
-# In Windows the default installation of PostgreSQL uses that as part of the path.
-# E.g C:\Program Files\PostgreSQL\8.4.
-# Currently, the following version numbers are known to this module:
-# "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0"
-#
-# To use this variable just do something like this:
-# set(PostgreSQL_ADDITIONAL_VERSIONS "9.2" "8.4.4")
-# before calling find_package(PostgreSQL) in your CMakeLists.txt file.
-# This will mean that the versions you set here will be found first in the order
-# specified before the default ones are searched.
-#
-# ----------------------------------------------------------------------------
-# You may need to manually set:
-#  PostgreSQL_INCLUDE_DIR  - the path to where the PostgreSQL include files are.
-#  PostgreSQL_LIBRARY_DIR  - The path to where the PostgreSQL library files are.
-# If FindPostgreSQL.cmake cannot find the include files or the library files.
-#
-# ----------------------------------------------------------------------------
-# The following variables are set if PostgreSQL is found:
-#  PostgreSQL_FOUND         - Set to true when PostgreSQL is found.
-#  PostgreSQL_INCLUDE_DIRS  - Include directories for PostgreSQL
-#  PostgreSQL_LIBRARY_DIRS  - Link directories for PostgreSQL libraries
-#  PostgreSQL_LIBRARIES     - The PostgreSQL libraries.
-#
-# ----------------------------------------------------------------------------
-# If you have installed PostgreSQL in a non-standard location.
-# (Please note that in the following comments, it is assumed that <Your Path>
-# points to the root directory of the include directory of PostgreSQL.)
-# Then you have three options.
-# 1) After CMake runs, set PostgreSQL_INCLUDE_DIR to <Your Path>/include and
-#    PostgreSQL_LIBRARY_DIR to wherever the library pq (or libpq in windows) is
-# 2) Use CMAKE_INCLUDE_PATH to set a path to <Your Path>/PostgreSQL<-version>. This will allow find_path()
-#    to locate PostgreSQL_INCLUDE_DIR by utilizing the PATH_SUFFIXES option. e.g. In your CMakeLists.txt file
-#    set(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "<Your Path>/include")
-# 3) Set an environment variable called ${PostgreSQL_ROOT} that points to the root of where you have
-#    installed PostgreSQL, e.g. <Your Path>.
-#
-# ----------------------------------------------------------------------------
-
-set(PostgreSQL_INCLUDE_PATH_DESCRIPTION "top-level directory containing the PostgreSQL include directories. E.g /usr/local/include/PostgreSQL/8.4 or C:/Program Files/PostgreSQL/8.4/include")
-set(PostgreSQL_INCLUDE_DIR_MESSAGE "Set the PostgreSQL_INCLUDE_DIR cmake cache entry to the ${PostgreSQL_INCLUDE_PATH_DESCRIPTION}")
-set(PostgreSQL_LIBRARY_PATH_DESCRIPTION "top-level directory containing the PostgreSQL libraries.")
-set(PostgreSQL_LIBRARY_DIR_MESSAGE "Set the PostgreSQL_LIBRARY_DIR cmake cache entry to the ${PostgreSQL_LIBRARY_PATH_DESCRIPTION}")
-set(PostgreSQL_ROOT_DIR_MESSAGE "Set the PostgreSQL_ROOT system variable to where PostgreSQL is found on the machine E.g C:/Program Files/PostgreSQL/8.4")
-
-
-set(PostgreSQL_KNOWN_VERSIONS ${PostgreSQL_ADDITIONAL_VERSIONS}
-    "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0")
-
-# Define additional search paths for root directories.
-if ( WIN32 )
-  foreach (suffix ${PostgreSQL_KNOWN_VERSIONS} )
-    set(PostgreSQL_ADDITIONAL_SEARCH_PATHS ${PostgreSQL_ADDITIONAL_SEARCH_PATHS} "C:/Program Files/PostgreSQL/${suffix}" )
-  endforeach()
-else()
-  foreach (suffix ${PostgreSQL_KNOWN_VERSIONS} )
-    set(PostgreSQL_ADDITIONAL_SEARCH_PATHS ${PostgreSQL_ADDITIONAL_SEARCH_PATHS} "/usr/include/postgresql/${suffix}" "/usr/local/include/postgresql/${suffix}")
-  endforeach()
-endif()
-set( PostgreSQL_ROOT_DIRECTORIES
-   ENV PostgreSQL_ROOT
-   ${PostgreSQL_ROOT}
-   ${PostgreSQL_ADDITIONAL_SEARCH_PATHS}
-)
-
-#
-# Look for an installation.
-#
-find_path(PostgreSQL_INCLUDE_DIR
-  NAMES libpq-fe.h
-  PATHS
-   # Look in other places.
-   ${PostgreSQL_ROOT_DIRECTORIES}
-  PATH_SUFFIXES
-    pgsql
-    postgresql
-    include
-  # Help the user find it if we cannot.
-  DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}"
-)
-
-find_path(PostgreSQL_TYPE_INCLUDE_DIR
-  NAMES catalog/pg_type.h
-  PATHS
-   # Look in other places.
-   ${PostgreSQL_ROOT_DIRECTORIES}
-  PATH_SUFFIXES
-    postgresql
-    pgsql/server
-    postgresql/server
-    include/server
-    server
-  # Help the user find it if we cannot.
-  DOC "The ${PostgreSQL_INCLUDE_DIR_MESSAGE}"
-  )
-
-# The PostgreSQL library.
-set (PostgreSQL_LIBRARY_TO_FIND pq)
-# Setting some more prefixes for the library
-set (PostgreSQL_LIB_PREFIX "")
-if ( WIN32 )
-  set (PostgreSQL_LIB_PREFIX ${PostgreSQL_LIB_PREFIX} "lib")
-  set ( PostgreSQL_LIBRARY_TO_FIND ${PostgreSQL_LIB_PREFIX}${PostgreSQL_LIBRARY_TO_FIND})
-endif()
-
-find_library( PostgreSQL_LIBRARY
- NAMES ${PostgreSQL_LIBRARY_TO_FIND}
- PATHS
-   ${PostgreSQL_ROOT_DIRECTORIES}
- PATH_SUFFIXES
-   lib
-)
-get_filename_component(PostgreSQL_LIBRARY_DIR ${PostgreSQL_LIBRARY} PATH)
-
-if (PostgreSQL_INCLUDE_DIR AND EXISTS "${PostgreSQL_INCLUDE_DIR}/pg_config.h")
-  file(STRINGS "${PostgreSQL_INCLUDE_DIR}/pg_config.h" pgsql_version_str
-       REGEX "^#define[\t ]+PG_VERSION[\t ]+\".*\"")
-
-  string(REGEX REPLACE "^#define[\t ]+PG_VERSION[\t ]+\"([^\"]*)\".*" "\\1"
-         PostgreSQL_VERSION_STRING "${pgsql_version_str}")
-  unset(pgsql_version_str)
-endif()
-
-# Did we find anything?
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(PostgreSQL
-                                  REQUIRED_VARS PostgreSQL_LIBRARY PostgreSQL_INCLUDE_DIR PostgreSQL_TYPE_INCLUDE_DIR
-                                  VERSION_VAR PostgreSQL_VERSION_STRING)
-set( PostgreSQL_FOUND  ${POSTGRESQL_FOUND})
-
-# Now try to get the include and library path.
-if(PostgreSQL_FOUND)
-
-  set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR} ${PostgreSQL_TYPE_INCLUDE_DIR} )
-  set(PostgreSQL_LIBRARY_DIRS ${PostgreSQL_LIBRARY_DIR} )
-  set(PostgreSQL_LIBRARIES ${PostgreSQL_LIBRARY_TO_FIND})
-  #message("Final PostgreSQL include dir: ${PostgreSQL_INCLUDE_DIRS}")
-  #message("Final PostgreSQL library dir: ${PostgreSQL_LIBRARY_DIRS}")
-  #message("Final PostgreSQL libraries:   ${PostgreSQL_LIBRARIES}")
-endif()
-
-mark_as_advanced(PostgreSQL_INCLUDE_DIR PostgreSQL_TYPE_INCLUDE_DIR PostgreSQL_LIBRARY )


=====================================
Resources/CMake/PostgreSQLConfiguration.cmake
=====================================
@@ -276,6 +276,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LIBPQ)
     -DFRONTEND
     -DUNSAFE_STAT_OK
     -DSYSCONFDIR=""
+    -DTCP_NODELAY
     )
 
   include_directories(
@@ -376,7 +377,19 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LIBPQ)
   source_group(ThirdParty\\PostgreSQL REGULAR_EXPRESSION ${LIBPQ_SOURCES_DIR}/.*)
 
 else()
-  include(${CMAKE_CURRENT_LIST_DIR}/FindPostgreSQL.cmake)
+  set(PostgreSQL_ADDITIONAL_VERSIONS
+    "11" "10" "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0")
+  if (NOT WIN32)
+    foreach (suffix ${PostgreSQL_ADDITIONAL_VERSIONS})
+      list(APPEND PostgreSQL_ADDITIONAL_SEARCH_PATHS
+        "/usr/include/postgresql/${suffix}"
+        "/usr/include/postgresql/${suffix}/server"
+        "/usr/local/include/postgresql/${suffix}"
+        )
+    endforeach()
+  endif()
+
+  include(FindPostgreSQL)
   include_directories(
     ${PostgreSQL_INCLUDE_DIR}
     ${PostgreSQL_TYPE_INCLUDE_DIR}


=====================================
Resources/Orthanc/DownloadOrthancFramework.cmake
=====================================
@@ -97,6 +97,10 @@ if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "hg" OR
         set(ORTHANC_FRAMEWORK_MD5 "099671538865e5da96208b37494d6718")
       elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.5.2")
         set(ORTHANC_FRAMEWORK_MD5 "8867050f3e9a1ce6157c1ea7a9433b1b")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.5.3")
+        set(ORTHANC_FRAMEWORK_MD5 "bf2f5ed1adb8b0fc5f10d278e68e1dfe")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.5.4")
+        set(ORTHANC_FRAMEWORK_MD5 "404baef5d4c43e7c5d9410edda8ef5a5")
       endif()
     endif()
   endif()


=====================================
Resources/Orthanc/Sdk-1.5.4/orthanc/OrthancCDatabasePlugin.h
=====================================
@@ -0,0 +1,987 @@
+/**
+ * @ingroup CInterface
+ **/
+
+/**
+ * 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 "OrthancCPlugin.h"
+
+
+/** @{ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+  /**
+   * Opaque structure that represents the context of a custom database engine.
+   * @ingroup Callbacks
+   **/
+  typedef struct _OrthancPluginDatabaseContext_t OrthancPluginDatabaseContext;
+
+
+/*<! @cond Doxygen_Suppress */
+  typedef enum
+  {
+    _OrthancPluginDatabaseAnswerType_None = 0,
+
+    /* Events */
+    _OrthancPluginDatabaseAnswerType_DeletedAttachment = 1,
+    _OrthancPluginDatabaseAnswerType_DeletedResource = 2,
+    _OrthancPluginDatabaseAnswerType_RemainingAncestor = 3,
+
+    /* Return value */
+    _OrthancPluginDatabaseAnswerType_Attachment = 10,
+    _OrthancPluginDatabaseAnswerType_Change = 11,
+    _OrthancPluginDatabaseAnswerType_DicomTag = 12,
+    _OrthancPluginDatabaseAnswerType_ExportedResource = 13,
+    _OrthancPluginDatabaseAnswerType_Int32 = 14,
+    _OrthancPluginDatabaseAnswerType_Int64 = 15,
+    _OrthancPluginDatabaseAnswerType_Resource = 16,
+    _OrthancPluginDatabaseAnswerType_String = 17,
+    _OrthancPluginDatabaseAnswerType_MatchingResource = 18,  /* New in Orthanc 1.5.2 */
+    _OrthancPluginDatabaseAnswerType_Metadata = 19,          /* New in Orthanc 1.5.4 */
+
+    _OrthancPluginDatabaseAnswerType_INTERNAL = 0x7fffffff
+  } _OrthancPluginDatabaseAnswerType;
+
+
+  typedef struct
+  {
+    const char* uuid;
+    int32_t     contentType;
+    uint64_t    uncompressedSize;
+    const char* uncompressedHash;
+    int32_t     compressionType;
+    uint64_t    compressedSize;
+    const char* compressedHash;
+  } OrthancPluginAttachment;
+
+  typedef struct
+  {
+    uint16_t     group;
+    uint16_t     element;
+    const char*  value;
+  } OrthancPluginDicomTag;
+
+  typedef struct
+  {
+    int64_t                    seq;
+    int32_t                    changeType;
+    OrthancPluginResourceType  resourceType;
+    const char*                publicId;
+    const char*                date;
+  } OrthancPluginChange;
+
+  typedef struct
+  {
+    int64_t                    seq;
+    OrthancPluginResourceType  resourceType;
+    const char*                publicId;
+    const char*                modality;
+    const char*                date;
+    const char*                patientId;
+    const char*                studyInstanceUid;
+    const char*                seriesInstanceUid;
+    const char*                sopInstanceUid;
+  } OrthancPluginExportedResource;
+
+  typedef struct   /* New in Orthanc 1.5.2 */
+  {
+    OrthancPluginResourceType    level;
+    uint16_t                     tagGroup;
+    uint16_t                     tagElement;
+    uint8_t                      isIdentifierTag;
+    uint8_t                      isCaseSensitive;
+    uint8_t                      isMandatory;
+    OrthancPluginConstraintType  type;
+    uint32_t                     valuesCount;
+    const char* const*           values;
+  } OrthancPluginDatabaseConstraint;
+
+  typedef struct   /* New in Orthanc 1.5.2 */
+  {
+    const char*  resourceId;
+    const char*  someInstanceId;  /* Can be NULL if not requested */
+  } OrthancPluginMatchingResource;
+
+  typedef struct   /* New in Orthanc 1.5.2 */
+  {
+    /* Mandatory field */
+    uint8_t  isNewInstance;
+    int64_t  instanceId;
+
+    /* The following fields must only be set if "isNewInstance" is "true" */
+    uint8_t  isNewPatient;
+    uint8_t  isNewStudy;
+    uint8_t  isNewSeries;
+    int64_t  patientId;
+    int64_t  studyId;
+    int64_t  seriesId;
+  } OrthancPluginCreateInstanceResult;
+
+  typedef struct  /* New in Orthanc 1.5.2 */
+  {
+    int64_t      resource;
+    uint16_t     group;
+    uint16_t     element;
+    const char*  value;
+  } OrthancPluginResourcesContentTags;
+    
+  typedef struct  /* New in Orthanc 1.5.2 */
+  {
+    int64_t      resource;
+    int32_t      metadata;
+    const char*  value;
+  } OrthancPluginResourcesContentMetadata;
+
+
+  typedef struct
+  {
+    OrthancPluginDatabaseContext* database;
+    _OrthancPluginDatabaseAnswerType  type;
+    int32_t      valueInt32;
+    uint32_t     valueUint32;
+    int64_t      valueInt64;
+    const char  *valueString;
+    const void  *valueGeneric;
+  } _OrthancPluginDatabaseAnswer;
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerString(
+    OrthancPluginContext*          context,
+    OrthancPluginDatabaseContext*  database,
+    const char*                    value)
+  {
+    _OrthancPluginDatabaseAnswer params;
+    memset(&params, 0, sizeof(params));
+    params.database = database;
+    params.type = _OrthancPluginDatabaseAnswerType_String;
+    params.valueString = value;
+    context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, &params);
+  }
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerChange(
+    OrthancPluginContext*          context,
+    OrthancPluginDatabaseContext*  database,
+    const OrthancPluginChange*     change)
+  {
+    _OrthancPluginDatabaseAnswer params;
+    memset(&params, 0, sizeof(params));
+
+    params.database = database;
+    params.type = _OrthancPluginDatabaseAnswerType_Change;
+    params.valueUint32 = 0;
+    params.valueGeneric = change;
+
+    context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, &params);
+  }
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerChangesDone(
+    OrthancPluginContext*          context,
+    OrthancPluginDatabaseContext*  database)
+  {
+    _OrthancPluginDatabaseAnswer params;
+    memset(&params, 0, sizeof(params));
+
+    params.database = database;
+    params.type = _OrthancPluginDatabaseAnswerType_Change;
+    params.valueUint32 = 1;
+    params.valueGeneric = NULL;
+
+    context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, &params);
+  }
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerInt32(
+    OrthancPluginContext*          context,
+    OrthancPluginDatabaseContext*  database,
+    int32_t                        value)
+  {
+    _OrthancPluginDatabaseAnswer params;
+    memset(&params, 0, sizeof(params));
+    params.database = database;
+    params.type = _OrthancPluginDatabaseAnswerType_Int32;
+    params.valueInt32 = value;
+    context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, &params);
+  }
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerInt64(
+    OrthancPluginContext*          context,
+    OrthancPluginDatabaseContext*  database,
+    int64_t                        value)
+  {
+    _OrthancPluginDatabaseAnswer params;
+    memset(&params, 0, sizeof(params));
+    params.database = database;
+    params.type = _OrthancPluginDatabaseAnswerType_Int64;
+    params.valueInt64 = value;
+    context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, &params);
+  }
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerExportedResource(
+    OrthancPluginContext*                 context,
+    OrthancPluginDatabaseContext*         database,
+    const OrthancPluginExportedResource*  exported)
+  {
+    _OrthancPluginDatabaseAnswer params;
+    memset(&params, 0, sizeof(params));
+
+    params.database = database;
+    params.type = _OrthancPluginDatabaseAnswerType_ExportedResource;
+    params.valueUint32 = 0;
+    params.valueGeneric = exported;
+    context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, &params);
+  }
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerExportedResourcesDone(
+    OrthancPluginContext*                 context,
+    OrthancPluginDatabaseContext*         database)
+  {
+    _OrthancPluginDatabaseAnswer params;
+    memset(&params, 0, sizeof(params));
+
+    params.database = database;
+    params.type = _OrthancPluginDatabaseAnswerType_ExportedResource;
+    params.valueUint32 = 1;
+    params.valueGeneric = NULL;
+    context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, &params);
+  }
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerDicomTag(
+    OrthancPluginContext*          context,
+    OrthancPluginDatabaseContext*  database,
+    const OrthancPluginDicomTag*   tag)
+  {
+    _OrthancPluginDatabaseAnswer params;
+    memset(&params, 0, sizeof(params));
+    params.database = database;
+    params.type = _OrthancPluginDatabaseAnswerType_DicomTag;
+    params.valueGeneric = tag;
+    context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, &params);
+  }
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerAttachment(
+    OrthancPluginContext*          context,
+    OrthancPluginDatabaseContext*  database,
+    const OrthancPluginAttachment* attachment)
+  {
+    _OrthancPluginDatabaseAnswer params;
+    memset(&params, 0, sizeof(params));
+    params.database = database;
+    params.type = _OrthancPluginDatabaseAnswerType_Attachment;
+    params.valueGeneric = attachment;
+    context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, &params);
+  }
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerResource(
+    OrthancPluginContext*          context,
+    OrthancPluginDatabaseContext*  database,
+    int64_t                        id,
+    OrthancPluginResourceType      resourceType)
+  {
+    _OrthancPluginDatabaseAnswer params;
+    memset(&params, 0, sizeof(params));
+    params.database = database;
+    params.type = _OrthancPluginDatabaseAnswerType_Resource;
+    params.valueInt64 = id;
+    params.valueInt32 = (int32_t) resourceType;
+    context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, &params);
+  }
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerMatchingResource(
+    OrthancPluginContext*                 context,
+    OrthancPluginDatabaseContext*         database,
+    const OrthancPluginMatchingResource*  match)
+  {
+    _OrthancPluginDatabaseAnswer params;
+    memset(&params, 0, sizeof(params));
+    params.database = database;
+    params.type = _OrthancPluginDatabaseAnswerType_MatchingResource;
+    params.valueGeneric = match;
+    context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, &params);
+  }
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseAnswerMetadata(
+    OrthancPluginContext*          context,
+    OrthancPluginDatabaseContext*  database,
+    int64_t                        resourceId,
+    int32_t                        type,
+    const char*                    value)
+  {
+    OrthancPluginResourcesContentMetadata metadata;
+    _OrthancPluginDatabaseAnswer params;
+    metadata.resource = resourceId;
+    metadata.metadata = type;
+    metadata.value = value;
+    memset(&params, 0, sizeof(params));
+    params.database = database;
+    params.type = _OrthancPluginDatabaseAnswerType_Metadata;
+    params.valueGeneric = &metadata;
+    context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, &params);
+  }
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseSignalDeletedAttachment(
+    OrthancPluginContext*          context,
+    OrthancPluginDatabaseContext*  database,
+    const OrthancPluginAttachment* attachment)
+  {
+    _OrthancPluginDatabaseAnswer params;
+    memset(&params, 0, sizeof(params));
+    params.database = database;
+    params.type = _OrthancPluginDatabaseAnswerType_DeletedAttachment;
+    params.valueGeneric = attachment;
+    context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, &params);
+  }
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseSignalDeletedResource(
+    OrthancPluginContext*          context,
+    OrthancPluginDatabaseContext*  database,
+    const char*                    publicId,
+    OrthancPluginResourceType      resourceType)
+  {
+    _OrthancPluginDatabaseAnswer params;
+    memset(&params, 0, sizeof(params));
+    params.database = database;
+    params.type = _OrthancPluginDatabaseAnswerType_DeletedResource;
+    params.valueString = publicId;
+    params.valueInt32 = (int32_t) resourceType;
+    context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, &params);
+  }
+
+  ORTHANC_PLUGIN_INLINE void OrthancPluginDatabaseSignalRemainingAncestor(
+    OrthancPluginContext*          context,
+    OrthancPluginDatabaseContext*  database,
+    const char*                    ancestorId,
+    OrthancPluginResourceType      ancestorType)
+  {
+    _OrthancPluginDatabaseAnswer params;
+    memset(&params, 0, sizeof(params));
+    params.database = database;
+    params.type = _OrthancPluginDatabaseAnswerType_RemainingAncestor;
+    params.valueString = ancestorId;
+    params.valueInt32 = (int32_t) ancestorType;
+    context->InvokeService(context, _OrthancPluginService_DatabaseAnswer, &params);
+  }
+
+
+
+
+
+  typedef struct
+  {
+    OrthancPluginErrorCode  (*addAttachment) (
+      /* inputs */
+      void* payload,
+      int64_t id,
+      const OrthancPluginAttachment* attachment);
+                             
+    OrthancPluginErrorCode  (*attachChild) (
+      /* inputs */
+      void* payload,
+      int64_t parent,
+      int64_t child);
+                             
+    OrthancPluginErrorCode  (*clearChanges) (
+      /* inputs */
+      void* payload);
+                             
+    OrthancPluginErrorCode  (*clearExportedResources) (
+      /* inputs */
+      void* payload);
+
+    OrthancPluginErrorCode  (*createResource) (
+      /* outputs */
+      int64_t* id, 
+      /* inputs */
+      void* payload,
+      const char* publicId,
+      OrthancPluginResourceType resourceType);           
+                   
+    OrthancPluginErrorCode  (*deleteAttachment) (
+      /* inputs */
+      void* payload,
+      int64_t id,
+      int32_t contentType);
+   
+    OrthancPluginErrorCode  (*deleteMetadata) (
+      /* inputs */
+      void* payload,
+      int64_t id,
+      int32_t metadataType);
+   
+    OrthancPluginErrorCode  (*deleteResource) (
+      /* inputs */
+      void* payload,
+      int64_t id);    
+
+    /* Output: Use OrthancPluginDatabaseAnswerString() */
+    OrthancPluginErrorCode  (*getAllPublicIds) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      OrthancPluginResourceType resourceType);
+
+    /* Output: Use OrthancPluginDatabaseAnswerChange() and
+     * OrthancPluginDatabaseAnswerChangesDone() */
+    OrthancPluginErrorCode  (*getChanges) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      int64_t since,
+      uint32_t maxResult);
+
+    /* Output: Use OrthancPluginDatabaseAnswerInt64() */
+    OrthancPluginErrorCode  (*getChildrenInternalId) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      int64_t id);
+                   
+    /* Output: Use OrthancPluginDatabaseAnswerString() */
+    OrthancPluginErrorCode  (*getChildrenPublicId) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      int64_t id);
+
+    /* Output: Use OrthancPluginDatabaseAnswerExportedResource() and
+     * OrthancPluginDatabaseAnswerExportedResourcesDone() */
+    OrthancPluginErrorCode  (*getExportedResources) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      int64_t  since,
+      uint32_t  maxResult);
+                   
+    /* Output: Use OrthancPluginDatabaseAnswerChange() */
+    OrthancPluginErrorCode  (*getLastChange) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload);
+
+    /* Output: Use OrthancPluginDatabaseAnswerExportedResource() */
+    OrthancPluginErrorCode  (*getLastExportedResource) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload);
+                   
+    /* Output: Use OrthancPluginDatabaseAnswerDicomTag() */
+    OrthancPluginErrorCode  (*getMainDicomTags) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      int64_t id);
+                   
+    /* Output: Use OrthancPluginDatabaseAnswerString() */
+    OrthancPluginErrorCode  (*getPublicId) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      int64_t id);
+
+    OrthancPluginErrorCode  (*getResourceCount) (
+      /* outputs */
+      uint64_t* target,
+      /* inputs */
+      void* payload,
+      OrthancPluginResourceType  resourceType);
+                   
+    OrthancPluginErrorCode  (*getResourceType) (
+      /* outputs */
+      OrthancPluginResourceType* resourceType,
+      /* inputs */
+      void* payload,
+      int64_t id);
+
+    OrthancPluginErrorCode  (*getTotalCompressedSize) (
+      /* outputs */
+      uint64_t* target,
+      /* inputs */
+      void* payload);
+                   
+    OrthancPluginErrorCode  (*getTotalUncompressedSize) (
+      /* outputs */
+      uint64_t* target,
+      /* inputs */
+      void* payload);
+                   
+    OrthancPluginErrorCode  (*isExistingResource) (
+      /* outputs */
+      int32_t* existing,
+      /* inputs */
+      void* payload,
+      int64_t id);
+
+    OrthancPluginErrorCode  (*isProtectedPatient) (
+      /* outputs */
+      int32_t* isProtected,
+      /* inputs */
+      void* payload,
+      int64_t id);
+
+    /* Output: Use OrthancPluginDatabaseAnswerInt32() */
+    OrthancPluginErrorCode  (*listAvailableMetadata) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      int64_t id);
+                   
+    /* Output: Use OrthancPluginDatabaseAnswerInt32() */
+    OrthancPluginErrorCode  (*listAvailableAttachments) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      int64_t id);
+
+    OrthancPluginErrorCode  (*logChange) (
+      /* inputs */
+      void* payload,
+      const OrthancPluginChange* change);
+                   
+    OrthancPluginErrorCode  (*logExportedResource) (
+      /* inputs */
+      void* payload,
+      const OrthancPluginExportedResource* exported);
+                   
+    /* Output: Use OrthancPluginDatabaseAnswerAttachment() */
+    OrthancPluginErrorCode  (*lookupAttachment) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      int64_t id,
+      int32_t contentType);
+
+    /* Output: Use OrthancPluginDatabaseAnswerString() */
+    OrthancPluginErrorCode  (*lookupGlobalProperty) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      int32_t property);
+
+    /* Use "OrthancPluginDatabaseExtensions::lookupIdentifier3" 
+       instead of this function as of Orthanc 0.9.5 (db v6), can be set to NULL.
+       Output: Use OrthancPluginDatabaseAnswerInt64() */
+    OrthancPluginErrorCode  (*lookupIdentifier) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      const OrthancPluginDicomTag* tag);
+
+    /* Unused starting with Orthanc 0.9.5 (db v6), can be set to NULL.
+       Output: Use OrthancPluginDatabaseAnswerInt64() */
+    OrthancPluginErrorCode  (*lookupIdentifier2) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      const char* value);
+
+    /* Output: Use OrthancPluginDatabaseAnswerString() */
+    OrthancPluginErrorCode  (*lookupMetadata) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      int64_t id,
+      int32_t metadata);
+
+    /* Output: Use OrthancPluginDatabaseAnswerInt64() */
+    OrthancPluginErrorCode  (*lookupParent) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      int64_t id);
+
+    /* Output: Use OrthancPluginDatabaseAnswerResource() */
+    OrthancPluginErrorCode  (*lookupResource) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      const char* publicId);
+
+    /* Output: Use OrthancPluginDatabaseAnswerInt64() */
+    OrthancPluginErrorCode  (*selectPatientToRecycle) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload);
+
+    /* Output: Use OrthancPluginDatabaseAnswerInt64() */
+    OrthancPluginErrorCode  (*selectPatientToRecycle2) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      int64_t patientIdToAvoid);
+
+    OrthancPluginErrorCode  (*setGlobalProperty) (
+      /* inputs */
+      void* payload,
+      int32_t property,
+      const char* value);
+
+    OrthancPluginErrorCode  (*setMainDicomTag) (
+      /* inputs */
+      void* payload,
+      int64_t id,
+      const OrthancPluginDicomTag* tag);
+
+    OrthancPluginErrorCode  (*setIdentifierTag) (
+      /* inputs */
+      void* payload,
+      int64_t id,
+      const OrthancPluginDicomTag* tag);
+
+    OrthancPluginErrorCode  (*setMetadata) (
+      /* inputs */
+      void* payload,
+      int64_t id,
+      int32_t metadata,
+      const char* value);
+
+    OrthancPluginErrorCode  (*setProtectedPatient) (
+      /* inputs */
+      void* payload,
+      int64_t id,
+      int32_t isProtected);
+
+    OrthancPluginErrorCode  (*startTransaction) (
+      /* inputs */
+      void* payload);
+
+    OrthancPluginErrorCode  (*rollbackTransaction) (
+      /* inputs */
+      void* payload);
+
+    OrthancPluginErrorCode  (*commitTransaction) (
+      /* inputs */
+      void* payload);
+
+    OrthancPluginErrorCode  (*open) (
+      /* inputs */
+      void* payload);
+
+    OrthancPluginErrorCode  (*close) (
+      /* inputs */
+      void* payload);
+
+  } OrthancPluginDatabaseBackend;
+
+
+  typedef struct
+  {
+    /**
+     * Base extensions since Orthanc 1.0.0
+     **/
+    
+    /* Output: Use OrthancPluginDatabaseAnswerString() */
+    OrthancPluginErrorCode  (*getAllPublicIdsWithLimit) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      OrthancPluginResourceType resourceType,
+      uint64_t since,
+      uint64_t limit);
+
+    OrthancPluginErrorCode  (*getDatabaseVersion) (
+      /* outputs */
+      uint32_t* version,
+      /* inputs */
+      void* payload);
+
+    OrthancPluginErrorCode  (*upgradeDatabase) (
+      /* inputs */
+      void* payload,
+      uint32_t targetVersion,
+      OrthancPluginStorageArea* storageArea);
+ 
+    OrthancPluginErrorCode  (*clearMainDicomTags) (
+      /* inputs */
+      void* payload,
+      int64_t id);
+
+    /* Output: Use OrthancPluginDatabaseAnswerInt64() */
+    OrthancPluginErrorCode  (*getAllInternalIds) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      OrthancPluginResourceType resourceType);
+
+    /* Output: Use OrthancPluginDatabaseAnswerInt64() */
+    OrthancPluginErrorCode  (*lookupIdentifier3) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      OrthancPluginResourceType resourceType,
+      const OrthancPluginDicomTag* tag,
+      OrthancPluginIdentifierConstraint constraint);
+
+
+    /**
+     * Extensions since Orthanc 1.4.0
+     **/
+    
+    /* Output: Use OrthancPluginDatabaseAnswerInt64() */
+    OrthancPluginErrorCode  (*lookupIdentifierRange) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      OrthancPluginResourceType resourceType,
+      uint16_t group,
+      uint16_t element,
+      const char* start,
+      const char* end);
+
+    
+    /**
+     * Extensions since Orthanc 1.5.2
+     **/
+    
+    /* Ouput: Use OrthancPluginDatabaseAnswerMatchingResource */
+    OrthancPluginErrorCode  (*lookupResources) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      uint32_t constraintsCount,
+      const OrthancPluginDatabaseConstraint* constraints,
+      OrthancPluginResourceType queryLevel,
+      uint32_t limit,
+      uint8_t requestSomeInstance);
+    
+    OrthancPluginErrorCode  (*createInstance) (
+      /* output */
+      OrthancPluginCreateInstanceResult* output,
+      /* inputs */
+      void* payload,
+      const char* hashPatient,
+      const char* hashStudy,
+      const char* hashSeries,
+      const char* hashInstance);
+
+    OrthancPluginErrorCode  (*setResourcesContent) (
+      /* inputs */
+      void* payload,
+      uint32_t countIdentifierTags,
+      const OrthancPluginResourcesContentTags* identifierTags,
+      uint32_t countMainDicomTags,
+      const OrthancPluginResourcesContentTags* mainDicomTags,
+      uint32_t countMetadata,
+      const OrthancPluginResourcesContentMetadata* metadata);
+
+    /* Ouput: Use OrthancPluginDatabaseAnswerString */
+    OrthancPluginErrorCode  (*getChildrenMetadata) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      int64_t resourceId,
+      int32_t metadata);
+
+    OrthancPluginErrorCode  (*getLastChangeIndex) (
+      /* outputs */
+      int64_t* target,
+      /* inputs */
+      void* payload);
+                   
+    OrthancPluginErrorCode  (*tagMostRecentPatient) (
+      /* inputs */
+      void* payload,
+      int64_t patientId);
+                   
+    
+    /**
+     * Extensions since Orthanc 1.5.4
+     **/
+
+    /* Ouput: Use OrthancPluginDatabaseAnswerMetadata */
+    OrthancPluginErrorCode  (*getAllMetadata) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      /* inputs */
+      void* payload,
+      int64_t resourceId);
+    
+    /* Ouput: Use OrthancPluginDatabaseAnswerString to send 
+       the public ID of the parent (if the resource is not a patient) */
+    OrthancPluginErrorCode  (*lookupResourceAndParent) (
+      /* outputs */
+      OrthancPluginDatabaseContext* context,
+      uint8_t* isExisting,
+      int64_t* id,
+      OrthancPluginResourceType* type,
+      
+      /* inputs */
+      void* payload,
+      const char* publicId);
+
+  } OrthancPluginDatabaseExtensions;
+
+/*<! @endcond */
+
+
+  typedef struct
+  {
+    OrthancPluginDatabaseContext**       result;
+    const OrthancPluginDatabaseBackend*  backend;
+    void*                                payload;
+  } _OrthancPluginRegisterDatabaseBackend;
+
+  /**
+   * Register a custom database back-end (for legacy plugins).
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param backend The callbacks of the custom database engine.
+   * @param payload Pointer containing private information for the database engine.
+   * @return The context of the database engine (it must not be manually freed).
+   * @ingroup Callbacks
+   * @deprecated
+   * @see OrthancPluginRegisterDatabaseBackendV2
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginDatabaseContext* OrthancPluginRegisterDatabaseBackend(
+    OrthancPluginContext*                context,
+    const OrthancPluginDatabaseBackend*  backend,
+    void*                                payload)
+  {
+    OrthancPluginDatabaseContext* result = NULL;
+    _OrthancPluginRegisterDatabaseBackend params;
+
+    if (sizeof(int32_t) != sizeof(_OrthancPluginDatabaseAnswerType))
+    {
+      return NULL;
+    }
+
+    memset(&params, 0, sizeof(params));
+    params.backend = backend;
+    params.result = &result;
+    params.payload = payload;
+
+    if (context->InvokeService(context, _OrthancPluginService_RegisterDatabaseBackend, &params) ||
+        result == NULL)
+    {
+      /* Error */
+      return NULL;
+    }
+    else
+    {
+      return result;
+    }
+  }
+
+
+  typedef struct
+  {
+    OrthancPluginDatabaseContext**          result;
+    const OrthancPluginDatabaseBackend*     backend;
+    void*                                   payload;
+    const OrthancPluginDatabaseExtensions*  extensions;
+    uint32_t                                extensionsSize;
+  } _OrthancPluginRegisterDatabaseBackendV2;
+
+
+  /**
+   * Register a custom database back-end.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param backend The callbacks of the custom database engine.
+   * @param payload Pointer containing private information for the database engine.
+   * @param extensions Extensions to the base database SDK that was shipped until Orthanc 0.9.3.
+   * @return The context of the database engine (it must not be manually freed).
+   * @ingroup Callbacks
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginDatabaseContext* OrthancPluginRegisterDatabaseBackendV2(
+    OrthancPluginContext*                   context,
+    const OrthancPluginDatabaseBackend*     backend,
+    const OrthancPluginDatabaseExtensions*  extensions,
+    void*                                   payload)
+  {
+    OrthancPluginDatabaseContext* result = NULL;
+    _OrthancPluginRegisterDatabaseBackendV2 params;
+
+    if (sizeof(int32_t) != sizeof(_OrthancPluginDatabaseAnswerType))
+    {
+      return NULL;
+    }
+
+    memset(&params, 0, sizeof(params));
+    params.backend = backend;
+    params.result = &result;
+    params.payload = payload;
+    params.extensions = extensions;
+    params.extensionsSize = sizeof(OrthancPluginDatabaseExtensions);
+
+    if (context->InvokeService(context, _OrthancPluginService_RegisterDatabaseBackendV2, &params) ||
+        result == NULL)
+    {
+      /* Error */
+      return NULL;
+    }
+    else
+    {
+      return result;
+    }
+  }
+
+
+#ifdef  __cplusplus
+}
+#endif
+
+
+/** @} */
+


=====================================
Resources/Orthanc/Sdk-1.5.4/orthanc/OrthancCPlugin.h
=====================================
The diff for this file was not included because it is too large.

=====================================
Resources/SyncOrthancFolder.py
=====================================
@@ -11,7 +11,7 @@ import stat
 import urllib2
 
 TARGET = os.path.join(os.path.dirname(__file__), 'Orthanc')
-PLUGIN_SDK_VERSION = [ '0.9.5', '1.4.0', '1.5.2' ]
+PLUGIN_SDK_VERSION = [ '0.9.5', '1.4.0', '1.5.2', '1.5.4' ]
 REPOSITORY = 'https://bitbucket.org/sjodogne/orthanc/raw'
 
 FILES = [



View it on GitLab: https://salsa.debian.org/med-team/orthanc-postgresql/commit/ed942e11f2de275f7afc176299c436cd968b00da

-- 
View it on GitLab: https://salsa.debian.org/med-team/orthanc-postgresql/commit/ed942e11f2de275f7afc176299c436cd968b00da
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20190209/867f94ff/attachment-0001.html>


More information about the debian-med-commit mailing list