changeset 16:9e419261f1c9

mysql storage area working
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 10 Jul 2018 10:10:35 +0200
parents dfc7002add9c
children 54ea251aed70
files Framework/MySQL/MySQLDatabase.cpp Framework/MySQL/MySQLDatabase.h Framework/MySQL/MySQLResult.cpp Framework/MySQL/MySQLTransaction.cpp Framework/Plugins/OrthancCppDatabasePlugin.h Framework/Plugins/StorageBackend.cpp Framework/Plugins/StorageBackend.h MySQL/Plugins/MySQLIndex.cpp MySQL/Plugins/PrepareIndex.sql MySQL/Plugins/StoragePlugin.cpp MySQL/UnitTests/UnitTestsMain.cpp PostgreSQL/Plugins/PostgreSQLIndex.cpp PostgreSQL/Plugins/PostgreSQLStorageArea.cpp PostgreSQL/Plugins/PostgreSQLStorageArea.h PostgreSQL/Plugins/StoragePlugin.cpp
diffstat 15 files changed, 385 insertions(+), 328 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/MySQL/MySQLDatabase.cpp	Tue Jul 10 07:15:13 2018 +0200
+++ b/Framework/MySQL/MySQLDatabase.cpp	Tue Jul 10 10:10:35 2018 +0200
@@ -145,38 +145,127 @@
       Close();
       throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);        
     }
+  }
 
-    if (parameters_.HasLock())
-    {
-      try
-      {
-        Query query("SELECT GET_LOCK('Lock', 0);", false);
-        MySQLStatement statement(*this, query);
 
-        MySQLTransaction t(*this);
-        Dictionary args;
-
-        std::auto_ptr<IResult> result(t.Execute(statement, args));
+  namespace
+  {
+    class ResultWrapper : public boost::noncopyable
+    {
+    private:
+      MYSQL_RES *result_;
 
-        if (result->IsDone() ||
-            result->GetField(0).GetType() != ValueType_Integer64 ||
-            dynamic_cast<const Integer64Value&>(result->GetField(0)).GetValue() != 1)
+    public:
+      ResultWrapper(MySQLDatabase& mysql,
+                    const std::string& sql) :
+        result_(NULL)
+      {
+        if (mysql_real_query(mysql.GetObject(), sql.c_str(), sql.size()))
         {
+          mysql.LogError();
           throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);
         }
 
-        t.Commit();
+        result_ = mysql_use_result(mysql.GetObject());
+        if (result_ == NULL)
+        {
+          mysql.LogError();
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);
+        }
       }
-      catch (Orthanc::OrthancException&)
+
+      ~ResultWrapper()
+      {
+        if (result_ != NULL)
+        {
+          mysql_free_result(result_);
+          result_ = NULL;
+        }
+      }
+
+      MYSQL_RES *GetObject()
       {
-        LOG(ERROR) << "The MySQL database is locked by another instance of Orthanc";
-        Close();
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);
+        return result_;
       }
+    };
+  }
+
+
+  bool MySQLDatabase::LookupGlobalStringVariable(std::string& value,
+                                                 const std::string& variable)
+  {
+    ResultWrapper result(*this, "SELECT @@global." + variable);
+
+    MYSQL_ROW row = mysql_fetch_row(result.GetObject());
+    if (mysql_errno(mysql_) == 0 &&
+        row &&
+        row[0])
+    {
+      value = std::string(row[0]);
+      return true;
+    }
+    else
+    {
+      return false;
     }
   }
 
   
+  bool MySQLDatabase::LookupGlobalIntegerVariable(int64_t& value,
+                                                  const std::string& variable)
+  {
+    std::string s;
+    
+    if (LookupGlobalStringVariable(s, variable))
+    {
+      try
+      {
+        value = boost::lexical_cast<int64_t>(s);
+        return true;
+      }
+      catch (boost::bad_lexical_cast&)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);
+      }
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+  void MySQLDatabase::AdvisoryLock(int32_t lock)
+  {
+    try
+    {
+      Query query("SELECT GET_LOCK('Lock" +
+                  boost::lexical_cast<std::string>(lock) + "', 0);", false);
+      MySQLStatement statement(*this, query);
+
+      MySQLTransaction t(*this);
+      Dictionary args;
+
+      std::auto_ptr<IResult> result(t.Execute(statement, args));
+
+      if (result->IsDone() ||
+          result->GetField(0).GetType() != ValueType_Integer64 ||
+          dynamic_cast<const Integer64Value&>(result->GetField(0)).GetValue() != 1)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);
+      }
+
+      t.Commit();
+    }
+    catch (Orthanc::OrthancException&)
+    {
+      LOG(ERROR) << "The MySQL database is locked by another instance of Orthanc";
+      Close();
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);
+    }
+  }
+  
+
   bool MySQLDatabase::DoesTableExist(MySQLTransaction& transaction,
                                      const std::string& name)
   {
@@ -212,7 +301,8 @@
   }
 
 
-  void MySQLDatabase::Execute(const std::string& sql)
+  void MySQLDatabase::Execute(const std::string& sql,
+                              bool arobaseSeparator)
   {
     if (mysql_ == NULL)
     {
@@ -231,8 +321,11 @@
 
       if (!s.empty())
       {
-        // Replace the escape character "@" by a semicolon
-        std::replace(s.begin(), s.end(), '@', ';');
+        if (arobaseSeparator)
+        {
+          // Replace the escape character "@" by a semicolon
+          std::replace(s.begin(), s.end(), '@', ';');
+        }
       
         LOG(TRACE) << "MySQL: " << s;
         CheckErrorCode(mysql_query(mysql_, s.c_str()));
--- a/Framework/MySQL/MySQLDatabase.h	Tue Jul 10 07:15:13 2018 +0200
+++ b/Framework/MySQL/MySQLDatabase.h	Tue Jul 10 10:10:35 2018 +0200
@@ -58,7 +58,16 @@
 
     void Open();
 
-    void Execute(const std::string& sql);
+    bool LookupGlobalStringVariable(std::string& value,
+                                    const std::string& variable);
+    
+    bool LookupGlobalIntegerVariable(int64_t& value,
+                                     const std::string& variable);
+
+    void AdvisoryLock(int32_t lock);
+
+    void Execute(const std::string& sql,
+                 bool arobaseSeparator);
 
     bool DoesTableExist(MySQLTransaction& transaction,
                         const std::string& name);
--- a/Framework/MySQL/MySQLResult.cpp	Tue Jul 10 07:15:13 2018 +0200
+++ b/Framework/MySQL/MySQLResult.cpp	Tue Jul 10 10:10:35 2018 +0200
@@ -36,9 +36,11 @@
     if (code == 1)
     {
       unsigned int error = mysql_errno(database_.GetObject());
+
       if (error == 0)
       {
-        // This case can occur if the SQL request is not a SELECT
+        // This case occurs in requests without a result (e.g. if the
+        // SQL request is not a SELECT)
         done_ = true;
       }
       else if (error == CR_SERVER_GONE_ERROR ||
--- a/Framework/MySQL/MySQLTransaction.cpp	Tue Jul 10 07:15:13 2018 +0200
+++ b/Framework/MySQL/MySQLTransaction.cpp	Tue Jul 10 10:10:35 2018 +0200
@@ -35,7 +35,7 @@
     readOnly_(true),
     active_(false)
   {
-    db_.Execute("START TRANSACTION");
+    db_.Execute("START TRANSACTION", false);
     active_ = true;
   }
 
@@ -48,7 +48,7 @@
 
       try
       {
-        db_.Execute("ROLLBACK");
+        db_.Execute("ROLLBACK", false);
       }
       catch (Orthanc::OrthancException&)
       {
@@ -61,7 +61,7 @@
   {
     if (active_)
     {
-      db_.Execute("ROLLBACK");
+      db_.Execute("ROLLBACK", false);
       active_ = false;
       readOnly_ = true;
     }
@@ -77,7 +77,7 @@
   {
     if (active_)
     {
-      db_.Execute("COMMIT");
+      db_.Execute("COMMIT", false);
       active_ = false;
       readOnly_ = true;
     }
--- a/Framework/Plugins/OrthancCppDatabasePlugin.h	Tue Jul 10 07:15:13 2018 +0200
+++ b/Framework/Plugins/OrthancCppDatabasePlugin.h	Tue Jul 10 10:10:35 2018 +0200
@@ -1504,7 +1504,7 @@
 
       if (performanceWarning)
       {
-        OrthancPluginLogWarning(context, "Performance warning: The database plugin was compiled "
+        OrthancPluginLogWarning(context, "Performance warning: The database index plugin was compiled "
                                 "against an old version of the Orthanc SDK, consider upgrading");
       }
 
--- a/Framework/Plugins/StorageBackend.cpp	Tue Jul 10 07:15:13 2018 +0200
+++ b/Framework/Plugins/StorageBackend.cpp	Tue Jul 10 10:10:35 2018 +0200
@@ -25,6 +25,9 @@
 #  error HAS_ORTHANC_EXCEPTION must be set to 1
 #endif
 
+#include "../../Framework/Common/BinaryStringValue.h"
+#include "../../Framework/Common/FileValue.h"
+
 #include <Core/OrthancException.h>
 
 
@@ -111,6 +114,99 @@
   }
 
 
+  void StorageBackend::Create(DatabaseManager::Transaction& transaction,
+                              const std::string& uuid,
+                              const void* content,
+                              size_t size,
+                              OrthancPluginContentType type)
+  {
+    DatabaseManager::CachedStatement statement(
+      STATEMENT_FROM_HERE, GetManager(),
+      "INSERT INTO StorageArea VALUES (${uuid}, ${content}, ${type})");
+     
+    statement.SetParameterType("uuid", ValueType_Utf8String);
+    statement.SetParameterType("content", ValueType_File);
+    statement.SetParameterType("type", ValueType_Integer64);
+
+    Dictionary args;
+    args.SetUtf8Value("uuid", uuid);
+    args.SetFileValue("content", content, size);
+    args.SetIntegerValue("type", type);
+     
+    statement.Execute(args);
+  }
+
+
+  void StorageBackend::Read(void*& content,
+                            size_t& size,
+                            DatabaseManager::Transaction& transaction, 
+                            const std::string& uuid,
+                            OrthancPluginContentType type) 
+  {
+    DatabaseManager::CachedStatement statement(
+      STATEMENT_FROM_HERE, GetManager(),
+      "SELECT content FROM StorageArea WHERE uuid=${uuid} AND type=${type}");
+     
+    statement.SetParameterType("uuid", ValueType_Utf8String);
+    statement.SetParameterType("type", ValueType_Integer64);
+
+    Dictionary args;
+    args.SetUtf8Value("uuid", uuid);
+    args.SetIntegerValue("type", type);
+     
+    statement.Execute(args);
+
+    if (statement.IsDone())
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
+    }
+    else if (statement.GetResultFieldsCount() != 1)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);        
+    }
+    else
+    {
+      const IValue& value = statement.GetResultField(0);
+      
+      switch (value.GetType())
+      {
+        case ValueType_File:
+          ReadFromString(content, size,
+                         dynamic_cast<const FileValue&>(value).GetContent());
+          break;
+
+        case ValueType_BinaryString:
+          ReadFromString(content, size,
+                         dynamic_cast<const BinaryStringValue&>(value).GetContent());
+          break;
+
+        default:
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);        
+      }
+    }
+  }
+
+
+  void StorageBackend::Remove(DatabaseManager::Transaction& transaction,
+                              const std::string& uuid,
+                              OrthancPluginContentType type)
+  {
+    DatabaseManager::CachedStatement statement(
+      STATEMENT_FROM_HERE, GetManager(),
+      "DELETE FROM StorageArea WHERE uuid=${uuid} AND type=${type}");
+     
+    statement.SetParameterType("uuid", ValueType_Utf8String);
+    statement.SetParameterType("type", ValueType_Integer64);
+
+    Dictionary args;
+    args.SetUtf8Value("uuid", uuid);
+    args.SetIntegerValue("type", type);
+     
+    statement.Execute(args);
+  }
+
+
+
   static OrthancPluginContext* context_ = NULL;
   static std::auto_ptr<StorageBackend>  backend_;
     
@@ -182,6 +278,7 @@
     {
       context_ = context;
       backend_.reset(backend);
+      backend_->GetManager().Open();
 
       OrthancPluginRegisterStorageArea(context_, StorageCreate, StorageRead, StorageRemove);
     }
--- a/Framework/Plugins/StorageBackend.h	Tue Jul 10 07:15:13 2018 +0200
+++ b/Framework/Plugins/StorageBackend.h	Tue Jul 10 10:10:35 2018 +0200
@@ -56,17 +56,17 @@
                         const std::string& uuid,
                         const void* content,
                         size_t size,
-                        OrthancPluginContentType type) = 0;
+                        OrthancPluginContentType type);
 
     virtual void Read(void*& content,
                       size_t& size,
                       DatabaseManager::Transaction& transaction, 
                       const std::string& uuid,
-                      OrthancPluginContentType type) = 0;
+                      OrthancPluginContentType type);
 
     virtual void Remove(DatabaseManager::Transaction& transaction,
                         const std::string& uuid,
-                        OrthancPluginContentType type) = 0;
+                        OrthancPluginContentType type);
 
     static void Register(OrthancPluginContext* context,
                          StorageBackend* backend);   // Takes ownership
--- a/MySQL/Plugins/MySQLIndex.cpp	Tue Jul 10 07:15:13 2018 +0200
+++ b/MySQL/Plugins/MySQLIndex.cpp	Tue Jul 10 10:10:35 2018 +0200
@@ -82,39 +82,40 @@
       db.Open();
 
       MySQLTransaction t(db);
-      db.Execute("DROP DATABASE IF EXISTS " + database);
-      db.Execute("CREATE DATABASE " + database);
+      db.Execute("DROP DATABASE IF EXISTS " + database, false);
+      db.Execute("CREATE DATABASE " + database, false);
       t.Commit();
     }
     
     std::auto_ptr<MySQLDatabase> db(new MySQLDatabase(parameters_));
 
     db->Open();
-    db->Execute("ALTER DATABASE " + parameters_.GetDatabase() + 
-                " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
-    db->Execute("SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE");
+    
+    db->Execute("SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE", false);
 
+    if (parameters_.HasLock())
+    {
+      db->AdvisoryLock(42 /* some arbitrary constant */);
+    }
+    
     {
       MySQLTransaction t(*db);
 
+      db->Execute("ALTER DATABASE " + parameters_.GetDatabase() + 
+                  " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci", false);
+    
       if (!db->DoesTableExist(t, "Resources"))
       {
         std::string query;
 
         Orthanc::EmbeddedResources::GetFileResource
           (query, Orthanc::EmbeddedResources::MYSQL_PREPARE_INDEX);
-        db->Execute(query);
+        db->Execute(query, true);
 
         SetGlobalIntegerProperty(*db, t, Orthanc::GlobalProperty_DatabaseSchemaVersion, expectedVersion);
         SetGlobalIntegerProperty(*db, t, Orthanc::GlobalProperty_DatabasePatchLevel, 1);
       }
 
-      t.Commit();
-    }
-
-    {
-      MySQLTransaction t(*db);
-
       if (!db->DoesTableExist(t, "Resources"))
       {
         LOG(ERROR) << "Corrupted MySQL database";
@@ -142,7 +143,7 @@
         throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);        
       }
 
-      t.Rollback();
+      t.Commit();
     }
           
     return db.release();
--- a/MySQL/Plugins/PrepareIndex.sql	Tue Jul 10 07:15:13 2018 +0200
+++ b/MySQL/Plugins/PrepareIndex.sql	Tue Jul 10 10:10:35 2018 +0200
@@ -3,9 +3,6 @@
        value TEXT
        );
 
--- Set GlobalProperty_DatabaseSchemaVersion
-INSERT INTO GlobalProperties VALUES (1, '6');
-       
 CREATE TABLE Resources(
        internalId BIGINT NOT NULL AUTO_INCREMENT,
        resourceType INTEGER NOT NULL,
--- a/MySQL/Plugins/StoragePlugin.cpp	Tue Jul 10 07:15:13 2018 +0200
+++ b/MySQL/Plugins/StoragePlugin.cpp	Tue Jul 10 10:10:35 2018 +0200
@@ -19,13 +19,114 @@
  **/
 
 
-#include "../../Framework/MySQL/MySQLDatabase.h"
 #include "../../Framework/Plugins/StorageBackend.h"
 
-#include <Plugins/Samples/Common/OrthancPluginCppWrapper.h>
 #include <Core/Logging.h>
 
 
+#include "../../Framework/Common/Integer64Value.h"
+#include "../../Framework/MySQL/MySQLDatabase.h"
+#include "../../Framework/MySQL/MySQLResult.h"
+#include "../../Framework/MySQL/MySQLStatement.h"
+#include "../../Framework/MySQL/MySQLTransaction.h"
+
+#include <boost/math/special_functions/round.hpp>
+
+namespace OrthancDatabases
+{
+  class MySQLStorageArea : public StorageBackend
+  {
+  private:
+    class Factory : public IDatabaseFactory
+    {
+    private:
+      MySQLStorageArea&  that_;
+
+    public:
+      Factory(MySQLStorageArea& that) :
+        that_(that)
+      {
+      }
+
+      virtual Dialect GetDialect() const
+      {
+        return Dialect_MySQL;
+      }
+
+      virtual IDatabase* Open()
+      {
+        return that_.OpenInternal();
+      }
+    };
+
+    OrthancPluginContext*  context_;
+    MySQLParameters        parameters_;
+    bool                   clearAll_;
+
+    IDatabase* OpenInternal()
+    {
+      std::auto_ptr<MySQLDatabase> db(new MySQLDatabase(parameters_));
+
+      db->Open();
+
+      if (parameters_.HasLock())
+      {
+        db->AdvisoryLock(43 /* some arbitrary constant */);
+      }
+
+      {
+        MySQLTransaction t(*db);
+
+        int64_t size;
+        if (db->LookupGlobalIntegerVariable(size, "max_allowed_packet"))
+        {
+          int mb = boost::math::iround(static_cast<double>(size) /
+                                       static_cast<double>(1024 * 1024));
+          LOG(WARNING) << "Your MySQL server cannot "
+                       << "store DICOM files larger than " << mb << "MB";
+          LOG(WARNING) << "  => Consider increasing \"max_allowed_packet\" "
+                       << "in \"my.cnf\" if this limit is insufficient for your use";
+        }
+        else
+        {
+          LOG(WARNING) << "Unable to auto-detect the maximum size of DICOM "
+                       << "files that can be stored in this MySQL server";
+        }
+               
+        if (clearAll_)
+        {
+          db->Execute("DROP TABLE IF EXISTS StorageArea", false);
+        }
+
+        db->Execute("CREATE TABLE IF NOT EXISTS StorageArea("
+                    "uuid VARCHAR(64) NOT NULL PRIMARY KEY,"
+                    "content LONGBLOB NOT NULL,"
+                    "type INTEGER NOT NULL)", false);
+
+        t.Commit();
+      }
+
+      return db.release();
+    }
+
+  public:
+    MySQLStorageArea(const MySQLParameters& parameters) :
+      StorageBackend(new Factory(*this)),
+      parameters_(parameters),
+      clearAll_(false)
+    {
+    }
+
+    void SetClearAll(bool clear)
+    {
+      clearAll_ = clear;
+    }
+  };
+}
+
+
+
+
 static bool DisplayPerformanceWarning()
 {
   (void) DisplayPerformanceWarning;   // Disable warning about unused function
@@ -80,8 +181,9 @@
 
     try
     {
-      // TODO
-      //OrthancDatabases::StorageBackend::Register();
+      OrthancDatabases::MySQLParameters parameters(mysql);
+      OrthancDatabases::StorageBackend::Register
+        (context, new OrthancDatabases::MySQLStorageArea(parameters));
     }
     catch (Orthanc::OrthancException& e)
     {
--- a/MySQL/UnitTests/UnitTestsMain.cpp	Tue Jul 10 07:15:13 2018 +0200
+++ b/MySQL/UnitTests/UnitTestsMain.cpp	Tue Jul 10 10:10:35 2018 +0200
@@ -60,17 +60,34 @@
 {
   if (argc < 5)
   {
-    std::cerr << "Usage: " << argv[0] << " <socket> <username> <password> <database>"
+    std::cerr << "Usage (UNIX):    " << argv[0] << " <socket> <username> <password> <database>"
+              << std::endl
+              << "Usage (Windows): " << argv[0] << " <host> <port> <username> <password> <database>"
               << std::endl << std::endl
-              << "Example: " << argv[0] << " /var/run/mysqld/mysqld.sock root root orthanctest"
+              << "Example (UNIX):    " << argv[0] << " /var/run/mysqld/mysqld.sock root root orthanctest"
+              << std::endl
+              << "Example (Windows): " << argv[0] << " localhost 3306 root root orthanctest"
               << std::endl << std::endl;
     return -1;
   }
 
-  globalParameters_.SetUnixSocket(argv[1]);
-  globalParameters_.SetUsername(argv[2]);
-  globalParameters_.SetPassword(argv[3]);
-  globalParameters_.SetDatabase(argv[4]);
+  if (argc == 5)
+  {
+    // UNIX
+    globalParameters_.SetUnixSocket(argv[1]);
+    globalParameters_.SetUsername(argv[2]);
+    globalParameters_.SetPassword(argv[3]);
+    globalParameters_.SetDatabase(argv[4]);
+  }
+  else
+  {
+    // Windows
+    globalParameters_.SetHost(argv[1]);
+    globalParameters_.SetPort(boost::lexical_cast<unsigned int>(argv[2]));
+    globalParameters_.SetUsername(argv[3]);
+    globalParameters_.SetPassword(argv[4]);
+    globalParameters_.SetDatabase(argv[5]);
+  }
 
   ::testing::InitGoogleTest(&argc, argv);
   Orthanc::Logging::Initialize();
--- a/PostgreSQL/Plugins/PostgreSQLIndex.cpp	Tue Jul 10 07:15:13 2018 +0200
+++ b/PostgreSQL/Plugins/PostgreSQLIndex.cpp	Tue Jul 10 10:10:35 2018 +0200
@@ -129,7 +129,10 @@
          **/
         try
         {
-          LOG(INFO) << "Trying to enable trigram matching on the PostgreSQL database to speed up wildcard searches.  This may take several minutes";  // we've observed 9 minutes on DB with 100000 studies
+          // We've observed 9 minutes on DB with 100000 studies
+          LOG(INFO) << "Trying to enable trigram matching on the PostgreSQL database "
+                    << "to speed up wildcard searches. This may take several minutes";
+
           db->Execute(
             "CREATE EXTENSION pg_trgm; "
             "CREATE INDEX DicomIdentifiersIndexValues2 ON DicomIdentifiers USING gin(value gin_trgm_ops);");
@@ -138,8 +141,10 @@
         }
         catch (Orthanc::OrthancException&)
         {
-          LOG(WARNING) << "Performance warning: Your PostgreSQL server does not support trigram matching";
-          LOG(WARNING) << "-> Consider installing the \"pg_trgm\" extension on the PostgreSQL server, e.g. on Debian: sudo apt install postgresql-contrib";
+          LOG(WARNING) << "Performance warning: Your PostgreSQL server does "
+                       << "not support trigram matching";
+          LOG(WARNING) << "-> Consider installing the \"pg_trgm\" extension on the "
+                       << "PostgreSQL server, e.g. on Debian: sudo apt install postgresql-contrib";
         }
       }
 
--- a/PostgreSQL/Plugins/PostgreSQLStorageArea.cpp	Tue Jul 10 07:15:13 2018 +0200
+++ b/PostgreSQL/Plugins/PostgreSQLStorageArea.cpp	Tue Jul 10 10:10:35 2018 +0200
@@ -21,7 +21,6 @@
 
 #include "PostgreSQLStorageArea.h"
 
-#include "../../Framework/Common/FileValue.h"
 #include "../../Framework/PostgreSQL/PostgreSQLTransaction.h"
 
 #include <Plugins/Samples/Common/OrthancPluginCppWrapper.h>
@@ -74,82 +73,4 @@
     clearAll_(false)
   {
   }
-
-
-  void PostgreSQLStorageArea::Create(DatabaseManager::Transaction& transaction,
-                                     const std::string& uuid,
-                                     const void* content,
-                                     size_t size,
-                                     OrthancPluginContentType type)
-  {
-    DatabaseManager::CachedStatement statement(
-      STATEMENT_FROM_HERE, GetManager(),
-      "INSERT INTO StorageArea VALUES (${uuid}, ${content}, ${type})");
-     
-    statement.SetParameterType("uuid", ValueType_Utf8String);
-    statement.SetParameterType("content", ValueType_File);
-    statement.SetParameterType("type", ValueType_Integer64);
-
-    Dictionary args;
-    args.SetUtf8Value("uuid", uuid);
-    args.SetFileValue("content", content, size);
-    args.SetIntegerValue("type", type);
-     
-    statement.Execute(args);
-  }
-
-
-  void PostgreSQLStorageArea::Read(void*& content,
-                                   size_t& size,
-                                   DatabaseManager::Transaction& transaction, 
-                                   const std::string& uuid,
-                                   OrthancPluginContentType type) 
-  {
-    DatabaseManager::CachedStatement statement(
-      STATEMENT_FROM_HERE, GetManager(),
-      "SELECT content FROM StorageArea WHERE uuid=${uuid} AND type=${type}");
-     
-    statement.SetParameterType("uuid", ValueType_Utf8String);
-    statement.SetParameterType("type", ValueType_Integer64);
-
-    Dictionary args;
-    args.SetUtf8Value("uuid", uuid);
-    args.SetIntegerValue("type", type);
-     
-    statement.Execute(args);
-
-    if (statement.IsDone())
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
-    }
-    else if (statement.GetResultFieldsCount() != 1 ||
-             statement.GetResultField(0).GetType() != ValueType_File)
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);        
-    }
-    else
-    {
-      const FileValue& value = dynamic_cast<const FileValue&>(statement.GetResultField(0));
-      ReadFromString(content, size, value.GetContent());
-    }
-  }
-
-
-  void PostgreSQLStorageArea::Remove(DatabaseManager::Transaction& transaction,
-                                     const std::string& uuid,
-                                     OrthancPluginContentType type)
-  {
-    DatabaseManager::CachedStatement statement(
-      STATEMENT_FROM_HERE, GetManager(),
-      "DELETE FROM StorageArea WHERE uuid=${uuid} AND type=${type}");
-     
-    statement.SetParameterType("uuid", ValueType_Utf8String);
-    statement.SetParameterType("type", ValueType_Integer64);
-
-    Dictionary args;
-    args.SetUtf8Value("uuid", uuid);
-    args.SetIntegerValue("type", type);
-     
-    statement.Execute(args);
-  }
 }
--- a/PostgreSQL/Plugins/PostgreSQLStorageArea.h	Tue Jul 10 07:15:13 2018 +0200
+++ b/PostgreSQL/Plugins/PostgreSQLStorageArea.h	Tue Jul 10 10:10:35 2018 +0200
@@ -64,21 +64,5 @@
     {
       clearAll_ = clear;
     }
-
-    virtual void Create(DatabaseManager::Transaction& transaction,
-                        const std::string& uuid,
-                        const void* content,
-                        size_t size,
-                        OrthancPluginContentType type);
-
-    virtual void Read(void*& content,
-                      size_t& size,
-                      DatabaseManager::Transaction& transaction, 
-                      const std::string& uuid,
-                      OrthancPluginContentType type);
-
-    virtual void Remove(DatabaseManager::Transaction& transaction,
-                        const std::string& uuid,
-                        OrthancPluginContentType type);
   };
 }
--- a/PostgreSQL/Plugins/StoragePlugin.cpp	Tue Jul 10 07:15:13 2018 +0200
+++ b/PostgreSQL/Plugins/StoragePlugin.cpp	Tue Jul 10 10:10:35 2018 +0200
@@ -20,180 +20,9 @@
 
 
 #include "../../Framework/Plugins/StorageBackend.h"
-
-#include "../../Framework/Common/FileValue.h"
-#include "../../Framework/PostgreSQL/PostgreSQLDatabase.h"
-#include "../../Framework/PostgreSQL/PostgreSQLLargeObject.h"
-#include "../../Framework/PostgreSQL/PostgreSQLTransaction.h"
-
-#include <Plugins/Samples/Common/OrthancPluginCppWrapper.h>
-#include <Core/Logging.h>
-
-
-namespace OrthancDatabases
-{
-  class PostgreSQLStorageArea : public StorageBackend
-  {
-  private:
-    class Factory : public IDatabaseFactory
-    {
-    private:
-      PostgreSQLStorageArea&  that_;
-
-    public:
-      Factory(PostgreSQLStorageArea& that) :
-      that_(that)
-      {
-      }
-
-      virtual Dialect GetDialect() const
-      {
-        return Dialect_PostgreSQL;
-      }
-
-      virtual IDatabase* Open()
-      {
-        return that_.OpenInternal();
-      }
-    };
-
-    OrthancPluginContext*  context_;
-    PostgreSQLParameters   parameters_;
-    bool                   clearAll_;
-
-    IDatabase* OpenInternal()
-    {
-      std::auto_ptr<PostgreSQLDatabase> db(new PostgreSQLDatabase(parameters_));
-
-      db->Open();
-
-      if (parameters_.HasLock())
-      {
-        db->AdvisoryLock(43 /* some arbitrary constant */);
-      }
-
-      if (clearAll_)
-      {
-        db->ClearAll();
-      }
-
-      {
-        PostgreSQLTransaction t(*db);
-
-        if (!db->DoesTableExist("StorageArea"))
-        {
-          db->Execute("CREATE TABLE IF NOT EXISTS StorageArea("
-                      "uuid VARCHAR NOT NULL PRIMARY KEY,"
-                      "content OID NOT NULL,"
-                      "type INTEGER NOT NULL)");
-
-          // Automatically remove the large objects associated with the table
-          db->Execute("CREATE OR REPLACE RULE StorageAreaDelete AS ON DELETE "
-                      "TO StorageArea DO SELECT lo_unlink(old.content);");
-        }
-
-        t.Commit();
-      }
-
-      return db.release();
-    }
-
-  public:
-    PostgreSQLStorageArea(const PostgreSQLParameters& parameters) :
-    StorageBackend(new Factory(*this)),
-    parameters_(parameters),
-    clearAll_(false)
-    {
-    }
+#include "PostgreSQLStorageArea.h"
 
-    void SetClearAll(bool clear)
-    {
-      clearAll_ = clear;
-    }
-
-
-    virtual void Create(DatabaseManager::Transaction& transaction,
-                        const std::string& uuid,
-                        const void* content,
-                        size_t size,
-                        OrthancPluginContentType type)
-    {
-      std::auto_ptr<FileValue> file(new FileValue(content, size));
-      
-      {
-        DatabaseManager::CachedStatement statement(
-          STATEMENT_FROM_HERE, GetManager(),
-          "INSERT INTO StorageArea VALUES (${uuid}, ${content}, ${type})");
-     
-        statement.SetParameterType("uuid", ValueType_Utf8String);
-        statement.SetParameterType("content", ValueType_File);
-        statement.SetParameterType("type", ValueType_Integer64);
-
-        Dictionary args;
-        args.SetUtf8Value("uuid", uuid);
-        args.SetValue("content", file.release());
-        args.SetIntegerValue("type", type);
-     
-        statement.Execute(args);
-      }
-    }
-
-
-    virtual void Read(void*& content,
-                      size_t& size,
-                      DatabaseManager::Transaction& transaction, 
-                      const std::string& uuid,
-                      OrthancPluginContentType type) 
-    {
-      DatabaseManager::CachedStatement statement(
-        STATEMENT_FROM_HERE, GetManager(),
-        "SELECT content FROM StorageArea WHERE uuid=$1 AND type=$2");
-     
-      statement.SetParameterType("uuid", ValueType_Utf8String);
-      statement.SetParameterType("type", ValueType_Integer64);
-
-      Dictionary args;
-      args.SetUtf8Value("uuid", uuid);
-      args.SetIntegerValue("type", type);
-     
-      statement.Execute(args);
-
-      if (statement.IsDone())
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
-      }
-      else if (statement.GetResultFieldsCount() != 1 ||
-               statement.GetResultField(0).GetType() != ValueType_File)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);        
-      }
-      else
-      {
-        const FileValue& value = dynamic_cast<const FileValue&>(statement.GetResultField(0));
-        ReadFromString(content, size, value.GetContent());
-      }
-    }
-
-
-    virtual void Remove(DatabaseManager::Transaction& transaction,
-                        const std::string& uuid,
-                        OrthancPluginContentType type)
-    {
-      DatabaseManager::CachedStatement statement(
-        STATEMENT_FROM_HERE, GetManager(),
-        "DELETE FROM StorageArea WHERE uuid=${uuid} AND type=${type}");
-     
-      statement.SetParameterType("uuid", ValueType_Utf8String);
-      statement.SetParameterType("type", ValueType_Integer64);
-
-      Dictionary args;
-      args.SetUtf8Value("uuid", uuid);
-      args.SetIntegerValue("type", type);
-     
-      statement.Execute(args);
-    }
-  };
-}
+#include <Core/Logging.h>
 
 
 static bool DisplayPerformanceWarning()