changeset 1:d17b2631bb67

starting StorageBackend
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 04 Jul 2018 18:05:24 +0200
parents 7cea966b6829
children 17bce6a07b2b
files Framework/Plugins/IndexBackend.cpp Framework/Plugins/IndexBackend.h Framework/Plugins/OrthancCppDatabasePlugin.h Framework/Plugins/StorageBackend.cpp Framework/Plugins/StorageBackend.h Framework/PostgreSQL/PostgreSQLLargeObject.cpp Resources/CMake/DatabasesPluginConfiguration.cmake
diffstat 7 files changed, 287 insertions(+), 184 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/Plugins/IndexBackend.cpp	Wed Jul 04 08:16:29 2018 +0200
+++ b/Framework/Plugins/IndexBackend.cpp	Wed Jul 04 18:05:24 2018 +0200
@@ -419,7 +419,7 @@
     
   void IndexBackend::DeleteResource(int64_t id)
   {
-    assert(GetDialect() != Dialect_MySQL);
+    assert(manager_.GetDialect() != Dialect_MySQL);
     
     ClearDeletedFiles();
     ClearDeletedResources();
@@ -692,7 +692,7 @@
   {
     std::auto_ptr<DatabaseManager::CachedStatement> statement;
 
-    switch (GetDialect())
+    switch (manager_.GetDialect())
     {
       case Dialect_MySQL:
         statement.reset(new DatabaseManager::CachedStatement(
@@ -759,7 +759,7 @@
 
     // NB: "COALESCE" is used to replace "NULL" by "0" if the number of rows is empty
 
-    switch (GetDialect())
+    switch (manager_.GetDialect())
     {
       case Dialect_MySQL:
         statement.reset(new DatabaseManager::CachedStatement(
@@ -796,7 +796,7 @@
 
     // NB: "COALESCE" is used to replace "NULL" by "0" if the number of rows is empty
 
-    switch (GetDialect())
+    switch (manager_.GetDialect())
     {
       case Dialect_MySQL:
         statement.reset(new DatabaseManager::CachedStatement(
@@ -1307,7 +1307,7 @@
                                  int32_t metadataType,
                                  const char* value)
   {
-    if (GetDialect() == Dialect_SQLite)
+    if (manager_.GetDialect() == Dialect_SQLite)
     {
       DatabaseManager::CachedStatement statement(
         STATEMENT_FROM_HERE, manager_,
@@ -1465,7 +1465,7 @@
   {
     std::auto_ptr<DatabaseManager::CachedStatement> statement;
 
-    switch (GetDialect())
+    switch (manager_.GetDialect())
     {
       case Dialect_MySQL:
         statement.reset(new DatabaseManager::CachedStatement(
@@ -1501,7 +1501,7 @@
   {
     std::auto_ptr<DatabaseManager::CachedStatement> statement;
 
-    switch (GetDialect())
+    switch (manager_.GetDialect())
     {
       case Dialect_MySQL:
         statement.reset(new DatabaseManager::CachedStatement(
--- a/Framework/Plugins/IndexBackend.h	Wed Jul 04 08:16:29 2018 +0200
+++ b/Framework/Plugins/IndexBackend.h	Wed Jul 04 18:05:24 2018 +0200
@@ -78,11 +78,6 @@
   public:
     IndexBackend(IDatabaseFactory* factory);
     
-    Dialect GetDialect() const
-    {
-      return manager_.GetDialect();
-    }
-    
     virtual void Open()
     {
       manager_.Open();
--- a/Framework/Plugins/OrthancCppDatabasePlugin.h	Wed Jul 04 08:16:29 2018 +0200
+++ b/Framework/Plugins/OrthancCppDatabasePlugin.h	Wed Jul 04 18:05:24 2018 +0200
@@ -28,34 +28,30 @@
 
 #pragma once
 
-#include <orthanc/OrthancCDatabasePlugin.h>
+#if HAS_ORTHANC_EXCEPTION != 1
+#  error HAS_ORTHANC_EXCEPTION must be set to 1
+#endif
+
 
-#define ORTHANC_PLUGINS_DATABASE_CATCH_COMMON           \
-  catch (::std::runtime_error& e)                       \
-  {                                                     \
-    LogError(backend, e);                               \
-    return OrthancPluginErrorCode_DatabasePlugin;       \
-  }                                                     \
-  catch (::OrthancPlugins::DatabaseException& e)        \
-  {                                                     \
-    return e.GetErrorCode();                            \
-  }                                                     \
-  catch (...)                                           \
-  {                                                     \
-    backend->GetOutput().LogError("Native exception");  \
-    return OrthancPluginErrorCode_DatabasePlugin;       \
-  }
+#include <orthanc/OrthancCDatabasePlugin.h>
+#include <Core/OrthancException.h>
 
-#if HAS_ORTHANC_EXCEPTION == 1
-#  include <Core/OrthancException.h>
-#  define ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC                  \
+
+#define ORTHANC_PLUGINS_DATABASE_CATCH                            \
   catch (::Orthanc::OrthancException& e)                          \
   {                                                               \
     return static_cast<OrthancPluginErrorCode>(e.GetErrorCode()); \
+  }                                                               \
+  catch (::std::runtime_error& e)                                 \
+  {                                                               \
+    LogError(backend, e);                                         \
+    return OrthancPluginErrorCode_DatabasePlugin;                 \
+  }                                                               \
+  catch (...)                                                     \
+  {                                                               \
+    backend->GetOutput().LogError("Native exception");            \
+    return OrthancPluginErrorCode_DatabasePlugin;                 \
   }
-#else
-#  define ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-#endif
 
 
 #include <stdexcept>
@@ -64,55 +60,10 @@
 
 namespace OrthancPlugins
 {
-//! @cond Doxygen_Suppress
-  // This class mimics "boost::noncopyable"
-  class NonCopyable
-  {
-  private:
-    NonCopyable(const NonCopyable&);
-
-    NonCopyable& operator= (const NonCopyable&);
-
-  protected:
-    NonCopyable()
-    {
-    }
-
-    ~NonCopyable()
-    {
-    }
-  };
-//! @endcond
-
-
   /**
    * @ingroup Callbacks
    **/
-  class DatabaseException
-  {
-  private:
-    OrthancPluginErrorCode  code_;
-
-  public:
-    DatabaseException() : code_(OrthancPluginErrorCode_DatabasePlugin)
-    {
-    }
-
-    DatabaseException(OrthancPluginErrorCode code) : code_(code)
-    {
-    }
-
-    OrthancPluginErrorCode  GetErrorCode() const
-    {
-      return code_;
-    }
-  };
-
-
-  /**
-   * @ingroup Callbacks
-   **/
-  class DatabaseBackendOutput : public NonCopyable
+  class DatabaseBackendOutput : public boost::noncopyable
   {
     friend class DatabaseBackendAdapter;
 
@@ -298,7 +249,7 @@
   /**
    * @ingroup Callbacks
    **/
-  class IDatabaseBackend : public NonCopyable
+  class IDatabaseBackend : public boost::noncopyable
   {
     friend class DatabaseBackendAdapter;
 
@@ -536,8 +487,7 @@
         backend->AddAttachment(id, *attachment);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
                              
@@ -553,8 +503,7 @@
         backend->AttachChild(parent, child);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
           
                    
@@ -568,8 +517,7 @@
         backend->ClearChanges();
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
                              
 
@@ -583,8 +531,7 @@
         backend->ClearExportedResources();
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -601,8 +548,7 @@
         *id = backend->CreateResource(publicId, resourceType);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
           
          
@@ -618,8 +564,7 @@
         backend->DeleteAttachment(id, contentType);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
    
 
@@ -635,8 +580,7 @@
         backend->DeleteMetadata(id, metadataType);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
    
 
@@ -651,8 +595,7 @@
         backend->DeleteResource(id);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -677,8 +620,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -704,8 +646,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -733,8 +674,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -759,8 +699,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -785,8 +724,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
           
          
@@ -812,8 +750,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -837,8 +774,7 @@
         }
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
           
          
@@ -853,8 +789,7 @@
         backend->GetLastChange();
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -869,8 +804,7 @@
         backend->GetLastExportedResource();
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
     
                
@@ -886,8 +820,7 @@
         backend->GetMainDicomTags(id);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
           
          
@@ -907,8 +840,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -924,8 +856,7 @@
         *target = backend->GetResourceCount(resourceType);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
                    
 
@@ -941,8 +872,7 @@
         *resourceType = backend->GetResourceType(id);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -957,8 +887,7 @@
         *target = backend->GetTotalCompressedSize();
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
           
          
@@ -973,8 +902,7 @@
         *target = backend->GetTotalUncompressedSize();
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
                    
 
@@ -990,8 +918,7 @@
         *existing = backend->IsExistingResource(id);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1007,8 +934,7 @@
         *isProtected = backend->IsProtectedPatient(id);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1034,8 +960,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
           
          
@@ -1061,8 +986,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1077,8 +1001,7 @@
         backend->LogChange(*change);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
           
          
@@ -1093,8 +1016,7 @@
         backend->LogExportedResource(*exported);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
           
          
@@ -1111,8 +1033,7 @@
         backend->LookupAttachment(id, contentType);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1135,8 +1056,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1163,8 +1083,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1193,8 +1112,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1217,8 +1135,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1240,8 +1157,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1265,8 +1181,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1287,8 +1202,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1310,8 +1224,7 @@
 
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1327,8 +1240,7 @@
         backend->SetGlobalProperty(property, value);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1344,8 +1256,7 @@
         backend->SetMainDicomTag(id, tag->group, tag->element, tag->value);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1361,8 +1272,7 @@
         backend->SetIdentifierTag(id, tag->group, tag->element, tag->value);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1379,8 +1289,7 @@
         backend->SetMetadata(id, metadata, value);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1396,8 +1305,7 @@
         backend->SetProtectedPatient(id, (isProtected != 0));
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1411,8 +1319,7 @@
         backend->StartTransaction();
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1426,8 +1333,7 @@
         backend->RollbackTransaction();
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1441,8 +1347,7 @@
         backend->CommitTransaction();
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1456,8 +1361,7 @@
         backend->Open();
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1471,8 +1375,7 @@
         backend->Close();
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1486,8 +1389,7 @@
         *version = backend->GetDatabaseVersion();
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
 
@@ -1502,8 +1404,7 @@
         backend->UpgradeDatabase(targetVersion, storageArea);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
     
@@ -1517,8 +1418,7 @@
         backend->ClearMainDicomTags(internalId);
         return OrthancPluginErrorCode_Success;
       }
-      ORTHANC_PLUGINS_DATABASE_CATCH_ORTHANC
-      ORTHANC_PLUGINS_DATABASE_CATCH_COMMON
+      ORTHANC_PLUGINS_DATABASE_CATCH
     }
 
     
@@ -1608,7 +1508,8 @@
                                 "against an old version of the Orthanc SDK, consider upgrading");
       }
 
-      OrthancPluginDatabaseContext* database = OrthancPluginRegisterDatabaseBackendV2(context, &params, &extensions, &backend);
+      OrthancPluginDatabaseContext* database =
+        OrthancPluginRegisterDatabaseBackendV2(context, &params, &extensions, &backend);
       if (!context)
       {
         throw std::runtime_error("Unable to register the database backend");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Plugins/StorageBackend.cpp	Wed Jul 04 18:05:24 2018 +0200
@@ -0,0 +1,133 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 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/>.
+ **/
+
+
+#include "StorageBackend.h"
+
+#if HAS_ORTHANC_EXCEPTION != 1
+#  error HAS_ORTHANC_EXCEPTION must be set to 1
+#endif
+
+#include <Core/OrthancException.h>
+
+
+#define ORTHANC_PLUGINS_DATABASE_CATCH                                  \
+  catch (::Orthanc::OrthancException& e)                                \
+  {                                                                     \
+    return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());       \
+  }                                                                     \
+  catch (::std::runtime_error& e)                                       \
+  {                                                                     \
+    std::string s = "Exception in storage area back-end: " + std::string(e.what()); \
+    OrthancPluginLogError(context_, s.c_str());                         \
+    return OrthancPluginErrorCode_DatabasePlugin;                       \
+  }                                                                     \
+  catch (...)                                                           \
+  {                                                                     \
+    OrthancPluginLogError(context_, "Native exception");                \
+    return OrthancPluginErrorCode_DatabasePlugin;                       \
+  }
+
+
+namespace OrthancDatabases
+{
+  StorageBackend::StorageBackend(IDatabaseFactory* factory) :
+    manager_(factory)
+  {
+  }
+
+
+
+  static OrthancPluginContext* context_ = NULL;
+  static std::auto_ptr<StorageBackend>  backend_;
+    
+  static OrthancPluginErrorCode StorageCreate(const char* uuid,
+                                              const void* content,
+                                              int64_t size,
+                                              OrthancPluginContentType type)
+  {
+    try
+    {
+      backend_->Create(uuid, content, static_cast<size_t>(size), type);
+      return OrthancPluginErrorCode_Success;
+    }
+    ORTHANC_PLUGINS_DATABASE_CATCH;
+  }
+
+
+  static OrthancPluginErrorCode StorageRead(void** content,
+                                            int64_t* size,
+                                            const char* uuid,
+                                            OrthancPluginContentType type)
+  {
+    try
+    {
+      size_t tmp;
+      backend_->Read(*content, tmp, uuid, type);
+      *size = static_cast<int64_t>(tmp);
+      return OrthancPluginErrorCode_Success;
+    }
+    ORTHANC_PLUGINS_DATABASE_CATCH;
+  }
+
+
+  static OrthancPluginErrorCode StorageRemove(const char* uuid,
+                                              OrthancPluginContentType type)
+  {
+    try
+    {
+      backend_->Remove(uuid, type);
+      return OrthancPluginErrorCode_Success;
+    }
+    ORTHANC_PLUGINS_DATABASE_CATCH;
+  }
+
+  
+  void StorageBackend::Register(OrthancPluginContext* context,
+                                StorageBackend* backend)
+  {
+    if (context == NULL ||
+        backend == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+    }
+    
+    if (context_ != NULL ||
+        backend_.get() != NULL)
+    {
+      // This function can only be invoked once in the plugin
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    else
+    {
+      context_ = context;
+      backend_.reset(backend);
+
+      OrthancPluginRegisterStorageArea(context_, StorageCreate, StorageRead, StorageRemove);
+    }
+  }
+
+
+  void StorageBackend::Finalize()
+  {
+    backend_.reset(NULL);
+    context_ = NULL;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Plugins/StorageBackend.h	Wed Jul 04 18:05:24 2018 +0200
@@ -0,0 +1,68 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 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
+
+#include "../Common/DatabaseManager.h"
+#include <orthanc/OrthancCDatabasePlugin.h>
+
+
+namespace OrthancDatabases
+{
+  class StorageBackend : public boost::noncopyable
+  {
+  private:
+    DatabaseManager   manager_;
+
+  protected:
+    DatabaseManager& GetManager()
+    {
+      return manager_;
+    }
+    
+  public:
+    StorageBackend(IDatabaseFactory* factory);
+
+    virtual ~StorageBackend()
+    {
+    }
+    
+    // WARNING: These methods can possibly be invoked simultaneously
+    // (no mutual exclusion in the storage area plugins)
+    virtual void Create(const std::string& uuid,
+                        const void* content,
+                        size_t size,
+                        OrthancPluginContentType type) = 0;
+
+    virtual void Read(void*& content,
+                      size_t& size,
+                      const std::string& uuid,
+                      OrthancPluginContentType type) = 0;
+
+    virtual void Remove(const std::string& uuid,
+                        OrthancPluginContentType type) = 0;
+
+    static void Register(OrthancPluginContext* context,
+                         StorageBackend* backend);   // Takes ownership
+
+    static void Finalize();
+  };
+}
--- a/Framework/PostgreSQL/PostgreSQLLargeObject.cpp	Wed Jul 04 08:16:29 2018 +0200
+++ b/Framework/PostgreSQL/PostgreSQLLargeObject.cpp	Wed Jul 04 18:05:24 2018 +0200
@@ -200,6 +200,11 @@
     else
     {
       target = malloc(size);
+      if (target == NULL)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NotEnoughMemory);
+      }
+      
       reader.Read(reinterpret_cast<char*>(target));
     }
   }
--- a/Resources/CMake/DatabasesPluginConfiguration.cmake	Wed Jul 04 08:16:29 2018 +0200
+++ b/Resources/CMake/DatabasesPluginConfiguration.cmake	Wed Jul 04 18:05:24 2018 +0200
@@ -42,5 +42,6 @@
   ${ORTHANC_CORE_SOURCES}
   ${ORTHANC_DATABASES_ROOT}/Framework/Plugins/GlobalProperties.cpp
   ${ORTHANC_DATABASES_ROOT}/Framework/Plugins/IndexBackend.cpp
+  ${ORTHANC_DATABASES_ROOT}/Framework/Plugins/StorageBackend.cpp
   ${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
   )