# HG changeset patch # User Sebastien Jodogne # Date 1531210235 -7200 # Node ID 9e419261f1c95b2cb114a9311c01034cd1a98d7f # Parent dfc7002add9c514027f3ea4fc4165cb48d8a5106 mysql storage area working diff -r dfc7002add9c -r 9e419261f1c9 Framework/MySQL/MySQLDatabase.cpp --- 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 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(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(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(lock) + "', 0);", false); + MySQLStatement statement(*this, query); + + MySQLTransaction t(*this); + Dictionary args; + + std::auto_ptr result(t.Execute(statement, args)); + + if (result->IsDone() || + result->GetField(0).GetType() != ValueType_Integer64 || + dynamic_cast(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())); diff -r dfc7002add9c -r 9e419261f1c9 Framework/MySQL/MySQLDatabase.h --- 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); diff -r dfc7002add9c -r 9e419261f1c9 Framework/MySQL/MySQLResult.cpp --- 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 || diff -r dfc7002add9c -r 9e419261f1c9 Framework/MySQL/MySQLTransaction.cpp --- 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; } diff -r dfc7002add9c -r 9e419261f1c9 Framework/Plugins/OrthancCppDatabasePlugin.h --- 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"); } diff -r dfc7002add9c -r 9e419261f1c9 Framework/Plugins/StorageBackend.cpp --- 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 @@ -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(value).GetContent()); + break; + + case ValueType_BinaryString: + ReadFromString(content, size, + dynamic_cast(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 backend_; @@ -182,6 +278,7 @@ { context_ = context; backend_.reset(backend); + backend_->GetManager().Open(); OrthancPluginRegisterStorageArea(context_, StorageCreate, StorageRead, StorageRemove); } diff -r dfc7002add9c -r 9e419261f1c9 Framework/Plugins/StorageBackend.h --- 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 diff -r dfc7002add9c -r 9e419261f1c9 MySQL/Plugins/MySQLIndex.cpp --- 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 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(); diff -r dfc7002add9c -r 9e419261f1c9 MySQL/Plugins/PrepareIndex.sql --- 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, diff -r dfc7002add9c -r 9e419261f1c9 MySQL/Plugins/StoragePlugin.cpp --- 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 #include +#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 + +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 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(size) / + static_cast(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) { diff -r dfc7002add9c -r 9e419261f1c9 MySQL/UnitTests/UnitTestsMain.cpp --- 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] << " " + std::cerr << "Usage (UNIX): " << argv[0] << " " + << std::endl + << "Usage (Windows): " << argv[0] << " " << 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(argv[2])); + globalParameters_.SetUsername(argv[3]); + globalParameters_.SetPassword(argv[4]); + globalParameters_.SetDatabase(argv[5]); + } ::testing::InitGoogleTest(&argc, argv); Orthanc::Logging::Initialize(); diff -r dfc7002add9c -r 9e419261f1c9 PostgreSQL/Plugins/PostgreSQLIndex.cpp --- 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"; } } diff -r dfc7002add9c -r 9e419261f1c9 PostgreSQL/Plugins/PostgreSQLStorageArea.cpp --- 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 @@ -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(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); - } } diff -r dfc7002add9c -r 9e419261f1c9 PostgreSQL/Plugins/PostgreSQLStorageArea.h --- 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); }; } diff -r dfc7002add9c -r 9e419261f1c9 PostgreSQL/Plugins/StoragePlugin.cpp --- 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 -#include - - -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 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 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(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 static bool DisplayPerformanceWarning()