# HG changeset patch # User Sebastien Jodogne # Date 1616163105 -3600 # Node ID d9ef3f16e6a227b2766f42819d52c492f8c00883 # Parent 6dcf57074dd4006ee88559a253b94b197bdc114f wrapping transactions in API v3 diff -r 6dcf57074dd4 -r d9ef3f16e6a2 Framework/Common/DatabaseManager.cpp --- a/Framework/Common/DatabaseManager.cpp Fri Mar 19 10:11:17 2021 +0100 +++ b/Framework/Common/DatabaseManager.cpp Fri Mar 19 15:11:45 2021 +0100 @@ -212,8 +212,10 @@ } - void DatabaseManager::StartTransaction() + void DatabaseManager::StartTransaction(TransactionType type) { + // TODO - Deal with TransactionType + boost::recursive_mutex::scoped_lock lock(mutex_); try @@ -284,13 +286,14 @@ } - DatabaseManager::Transaction::Transaction(DatabaseManager& manager) : + DatabaseManager::Transaction::Transaction(DatabaseManager& manager, + TransactionType type) : lock_(manager.mutex_), manager_(manager), database_(manager.GetDatabase()), committed_(false) { - manager_.StartTransaction(); + manager_.StartTransaction(type); } diff -r 6dcf57074dd4 -r d9ef3f16e6a2 Framework/Common/DatabaseManager.h --- a/Framework/Common/DatabaseManager.h Fri Mar 19 10:11:17 2021 +0100 +++ b/Framework/Common/DatabaseManager.h Fri Mar 19 15:11:45 2021 +0100 @@ -77,7 +77,7 @@ void Close(); - void StartTransaction(); + void StartTransaction(TransactionType type); void CommitTransaction(); @@ -94,7 +94,8 @@ bool committed_; public: - explicit Transaction(DatabaseManager& manager); + explicit Transaction(DatabaseManager& manager, + TransactionType type); ~Transaction(); diff -r 6dcf57074dd4 -r d9ef3f16e6a2 Framework/Common/DatabasesEnumerations.h --- a/Framework/Common/DatabasesEnumerations.h Fri Mar 19 10:11:17 2021 +0100 +++ b/Framework/Common/DatabasesEnumerations.h Fri Mar 19 15:11:45 2021 +0100 @@ -39,4 +39,10 @@ Dialect_PostgreSQL, Dialect_SQLite }; + + enum TransactionType + { + TransactionType_ReadOnly, + TransactionType_ReadWrite + }; } diff -r 6dcf57074dd4 -r d9ef3f16e6a2 Framework/Plugins/DatabaseBackendAdapterV2.cpp --- a/Framework/Plugins/DatabaseBackendAdapterV2.cpp Fri Mar 19 10:11:17 2021 +0100 +++ b/Framework/Plugins/DatabaseBackendAdapterV2.cpp Fri Mar 19 15:11:45 2021 +0100 @@ -1109,7 +1109,7 @@ try { - backend->StartTransaction(); + backend->StartTransaction(TransactionType_ReadWrite); return OrthancPluginErrorCode_Success; } ORTHANC_PLUGINS_DATABASE_CATCH; @@ -1426,8 +1426,7 @@ } - void DatabaseBackendAdapterV2::Register(OrthancPluginContext* context, - IDatabaseBackend& backend) + void DatabaseBackendAdapterV2::Register(IDatabaseBackend& backend) { OrthancPluginDatabaseBackend params; memset(¶ms, 0, sizeof(params)); @@ -1520,6 +1519,8 @@ # endif #endif + OrthancPluginContext* context = backend.GetContext(); + if (performanceWarning) { char info[1024]; @@ -1539,7 +1540,7 @@ OrthancPluginDatabaseContext* database = OrthancPluginRegisterDatabaseBackendV2(context, ¶ms, &extensions, &backend); - if (!context) + if (database == NULL) { throw std::runtime_error("Unable to register the database backend"); } diff -r 6dcf57074dd4 -r d9ef3f16e6a2 Framework/Plugins/DatabaseBackendAdapterV2.h --- a/Framework/Plugins/DatabaseBackendAdapterV2.h Fri Mar 19 10:11:17 2021 +0100 +++ b/Framework/Plugins/DatabaseBackendAdapterV2.h Fri Mar 19 15:11:45 2021 +0100 @@ -78,7 +78,6 @@ * @param backend Your custom database engine. **/ - static void Register(OrthancPluginContext* context, - IDatabaseBackend& backend); + static void Register(IDatabaseBackend& backend); }; } diff -r 6dcf57074dd4 -r d9ef3f16e6a2 Framework/Plugins/IDatabaseBackend.h --- a/Framework/Plugins/IDatabaseBackend.h Fri Mar 19 10:11:17 2021 +0100 +++ b/Framework/Plugins/IDatabaseBackend.h Fri Mar 19 15:11:45 2021 +0100 @@ -23,6 +23,7 @@ #pragma once #include "IDatabaseBackendOutput.h" +#include "../Common/DatabasesEnumerations.h" #include @@ -189,7 +190,7 @@ virtual void SetProtectedPatient(int64_t internalId, bool isProtected) = 0; - virtual void StartTransaction() = 0; + virtual void StartTransaction(TransactionType type) = 0; virtual void RollbackTransaction() = 0; diff -r 6dcf57074dd4 -r d9ef3f16e6a2 Framework/Plugins/IndexBackend.h --- a/Framework/Plugins/IndexBackend.h Fri Mar 19 10:11:17 2021 +0100 +++ b/Framework/Plugins/IndexBackend.h Fri Mar 19 15:11:45 2021 +0100 @@ -242,9 +242,9 @@ virtual void SetProtectedPatient(int64_t internalId, bool isProtected) ORTHANC_OVERRIDE; - virtual void StartTransaction() ORTHANC_OVERRIDE + virtual void StartTransaction(TransactionType type) ORTHANC_OVERRIDE { - manager_.StartTransaction(); + manager_.StartTransaction(type); } diff -r 6dcf57074dd4 -r d9ef3f16e6a2 Framework/Plugins/IndexUnitTests.h --- a/Framework/Plugins/IndexUnitTests.h Fri Mar 19 10:11:17 2021 +0100 +++ b/Framework/Plugins/IndexUnitTests.h Fri Mar 19 15:11:45 2021 +0100 @@ -424,7 +424,7 @@ // A transaction is needed here for MySQL, as it was not possible // to implement recursive deletion of resources using pure SQL // statements - db.StartTransaction(); + db.StartTransaction(TransactionType_ReadWrite); db.DeleteResource(*output, c); db.CommitTransaction(); } diff -r 6dcf57074dd4 -r d9ef3f16e6a2 Framework/Plugins/StorageBackend.cpp --- a/Framework/Plugins/StorageBackend.cpp Fri Mar 19 10:11:17 2021 +0100 +++ b/Framework/Plugins/StorageBackend.cpp Fri Mar 19 15:11:45 2021 +0100 @@ -161,7 +161,7 @@ { try { - DatabaseManager::Transaction transaction(backend_->GetManager()); + DatabaseManager::Transaction transaction(backend_->GetManager(), TransactionType_ReadWrite); backend_->Create(transaction, uuid, content, static_cast(size), type); transaction.Commit(); return OrthancPluginErrorCode_Success; @@ -180,7 +180,7 @@ StorageAreaBuffer buffer(context_); { - DatabaseManager::Transaction transaction(backend_->GetManager()); + DatabaseManager::Transaction transaction(backend_->GetManager(), TransactionType_ReadOnly); backend_->Read(buffer, transaction, uuid, type); transaction.Commit(); } @@ -222,7 +222,7 @@ { try { - DatabaseManager::Transaction transaction(backend_->GetManager()); + DatabaseManager::Transaction transaction(backend_->GetManager(), TransactionType_ReadWrite); backend_->Remove(transaction, uuid, type); transaction.Commit(); return OrthancPluginErrorCode_Success; diff -r 6dcf57074dd4 -r d9ef3f16e6a2 MySQL/Plugins/IndexPlugin.cpp --- a/MySQL/Plugins/IndexPlugin.cpp Fri Mar 19 10:11:17 2021 +0100 +++ b/MySQL/Plugins/IndexPlugin.cpp Fri Mar 19 15:11:45 2021 +0100 @@ -71,7 +71,7 @@ backend_.reset(new OrthancDatabases::MySQLIndex(context, parameters)); /* Register the MySQL index into Orthanc */ - OrthancDatabases::DatabaseBackendAdapterV2::Register(context, *backend_); + OrthancDatabases::DatabaseBackendAdapterV2::Register(*backend_); } catch (Orthanc::OrthancException& e) { diff -r 6dcf57074dd4 -r d9ef3f16e6a2 MySQL/UnitTests/UnitTestsMain.cpp --- a/MySQL/UnitTests/UnitTestsMain.cpp Fri Mar 19 10:11:17 2021 +0100 +++ b/MySQL/UnitTests/UnitTestsMain.cpp Fri Mar 19 15:11:45 2021 +0100 @@ -150,7 +150,7 @@ storageArea.SetClearAll(true); { - OrthancDatabases::DatabaseManager::Transaction transaction(storageArea.GetManager()); + OrthancDatabases::DatabaseManager::Transaction transaction(storageArea.GetManager(), OrthancDatabases::TransactionType_ReadWrite); OrthancDatabases::MySQLDatabase& db = dynamic_cast(transaction.GetDatabase()); diff -r 6dcf57074dd4 -r d9ef3f16e6a2 PostgreSQL/Plugins/IndexPlugin.cpp --- a/PostgreSQL/Plugins/IndexPlugin.cpp Fri Mar 19 10:11:17 2021 +0100 +++ b/PostgreSQL/Plugins/IndexPlugin.cpp Fri Mar 19 15:11:45 2021 +0100 @@ -65,7 +65,7 @@ backend_.reset(new OrthancDatabases::PostgreSQLIndex(context, parameters)); /* Register the PostgreSQL index into Orthanc */ - OrthancDatabases::DatabaseBackendAdapterV2::Register(context, *backend_); + OrthancDatabases::DatabaseBackendAdapterV2::Register(*backend_); } catch (Orthanc::OrthancException& e) { diff -r 6dcf57074dd4 -r d9ef3f16e6a2 PostgreSQL/UnitTests/PostgreSQLTests.cpp --- a/PostgreSQL/UnitTests/PostgreSQLTests.cpp Fri Mar 19 10:11:17 2021 +0100 +++ b/PostgreSQL/UnitTests/PostgreSQLTests.cpp Fri Mar 19 15:11:45 2021 +0100 @@ -343,7 +343,7 @@ storageArea.SetClearAll(true); { - DatabaseManager::Transaction transaction(storageArea.GetManager()); + DatabaseManager::Transaction transaction(storageArea.GetManager(), TransactionType_ReadWrite); PostgreSQLDatabase& db = dynamic_cast(transaction.GetDatabase()); diff -r 6dcf57074dd4 -r d9ef3f16e6a2 SQLite/Plugins/IndexPlugin.cpp --- a/SQLite/Plugins/IndexPlugin.cpp Fri Mar 19 10:11:17 2021 +0100 +++ b/SQLite/Plugins/IndexPlugin.cpp Fri Mar 19 15:11:45 2021 +0100 @@ -32,24 +32,54 @@ #if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in Orthanc 1.3.1 # if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 10, 0) + +#define ORTHANC_PLUGINS_DATABASE_CATCH(context) \ + catch (::Orthanc::OrthancException& e) \ + { \ + return static_cast(e.GetErrorCode()); \ + } \ + catch (::std::runtime_error& e) \ + { \ + const std::string message = "Exception in database back-end: " + std::string(e.what()); \ + OrthancPluginLogError(context, message.c_str()); \ + return OrthancPluginErrorCode_DatabasePlugin; \ + } \ + catch (...) \ + { \ + OrthancPluginLogError(context, "Native exception"); \ + return OrthancPluginErrorCode_DatabasePlugin; \ + } + + namespace OrthancDatabases { class Output : public IDatabaseBackendOutput { private: + struct Metadata + { + int32_t metadata; + const char* value; + }; + _OrthancPluginDatabaseAnswerType answerType_; - std::list strings_; + std::list stringsStore_; std::vector attachments_; std::vector changes_; std::vector tags_; std::vector exported_; std::vector events_; + std::vector integers32_; + std::vector integers64_; + std::vector matches_; + std::vector metadata_; + std::vector stringAnswers_; const char* StoreString(const std::string& s) { - strings_.push_back(s); - return strings_.back().c_str(); + stringsStore_.push_back(s); + return stringsStore_.back().c_str(); } void SetupAnswerType(_OrthancPluginDatabaseAnswerType type) @@ -74,13 +104,18 @@ void Clear() { answerType_ = _OrthancPluginDatabaseAnswerType_None; - strings_.clear(); + stringsStore_.clear(); attachments_.clear(); changes_.clear(); tags_.clear(); exported_.clear(); events_.clear(); + integers32_.clear(); + integers64_.clear(); + matches_.clear(); + metadata_.clear(); + stringAnswers_.clear(); } @@ -113,6 +148,26 @@ size = that.exported_.size(); break; + case _OrthancPluginDatabaseAnswerType_Int32: + size = that.integers32_.size(); + break; + + case _OrthancPluginDatabaseAnswerType_Int64: + size = that.integers64_.size(); + break; + + case _OrthancPluginDatabaseAnswerType_MatchingResource: + size = that.matches_.size(); + break; + + case _OrthancPluginDatabaseAnswerType_Metadata: + size = that.metadata_.size(); + break; + + case _OrthancPluginDatabaseAnswerType_String: + size = that.stringAnswers_.size(); + break; + default: return OrthancPluginErrorCode_InternalError; } @@ -199,6 +254,99 @@ } + static OrthancPluginErrorCode ReadAnswerInt32(OrthancPluginDatabaseTransaction* transaction, + int32_t* target, + uint32_t index) + { + const Output& that = *reinterpret_cast(transaction); + + if (index < that.integers32_.size()) + { + *target = that.integers32_[index]; + return OrthancPluginErrorCode_Success; + } + else + { + return OrthancPluginErrorCode_ParameterOutOfRange; + } + } + + + static OrthancPluginErrorCode ReadAnswerInt64(OrthancPluginDatabaseTransaction* transaction, + int64_t* target, + uint32_t index) + { + const Output& that = *reinterpret_cast(transaction); + + if (index < that.integers64_.size()) + { + *target = that.integers64_[index]; + return OrthancPluginErrorCode_Success; + } + else + { + return OrthancPluginErrorCode_ParameterOutOfRange; + } + } + + + static OrthancPluginErrorCode ReadAnswerMatchingResource(OrthancPluginDatabaseTransaction* transaction, + OrthancPluginMatchingResource* target, + uint32_t index) + { + const Output& that = *reinterpret_cast(transaction); + + if (index < that.matches_.size()) + { + *target = that.matches_[index]; + return OrthancPluginErrorCode_Success; + } + else + { + return OrthancPluginErrorCode_ParameterOutOfRange; + } + } + + + static OrthancPluginErrorCode ReadAnswerMetadata(OrthancPluginDatabaseTransaction* transaction, + int32_t* metadata, + const char** value, + uint32_t index) + { + const Output& that = *reinterpret_cast(transaction); + + if (index < that.metadata_.size()) + { + const Metadata& tmp = that.metadata_[index]; + *metadata = tmp.metadata; + *value = tmp.value; + return OrthancPluginErrorCode_Success; + } + else + { + return OrthancPluginErrorCode_ParameterOutOfRange; + } + } + + + static OrthancPluginErrorCode ReadAnswerString(OrthancPluginDatabaseTransaction* transaction, + const char** target, + uint32_t index) + { + const Output& that = *reinterpret_cast(transaction); + + if (index < that.stringAnswers_.size()) + { + *target = that.stringAnswers_[index].c_str(); + return OrthancPluginErrorCode_Success; + } + else + { + return OrthancPluginErrorCode_ParameterOutOfRange; + } + } + + static OrthancPluginErrorCode ReadEventsCount(OrthancPluginDatabaseTransaction* transaction, uint32_t* target /* out */) { @@ -358,14 +506,57 @@ virtual void AnswerMatchingResource(const std::string& resourceId) ORTHANC_OVERRIDE { + SetupAnswerType(_OrthancPluginDatabaseAnswerType_MatchingResource); + OrthancPluginMatchingResource match; + match.resourceId = StoreString(resourceId); + match.someInstanceId = NULL; + + matches_.push_back(match); } virtual void AnswerMatchingResource(const std::string& resourceId, const std::string& someInstanceId) ORTHANC_OVERRIDE { + SetupAnswerType(_OrthancPluginDatabaseAnswerType_MatchingResource); + OrthancPluginMatchingResource match; + match.resourceId = StoreString(resourceId); + match.someInstanceId = StoreString(someInstanceId); + + matches_.push_back(match); + } + + + void AnswerIntegers32(const std::list& values) + { + SetupAnswerType(_OrthancPluginDatabaseAnswerType_Int32); + + integers32_.reserve(values.size()); + std::copy(std::begin(values), std::end(values), std::back_inserter(integers32_)); + } + + + void AnswerIntegers64(const std::list& values) + { + SetupAnswerType(_OrthancPluginDatabaseAnswerType_Int64); + + integers64_.reserve(values.size()); + std::copy(std::begin(values), std::end(values), std::back_inserter(integers64_)); + } + + + void AnswerMetadata(int32_t metadata, + const std::string& value) + { + SetupAnswerType(_OrthancPluginDatabaseAnswerType_Metadata); + + Metadata tmp; + tmp.metadata = metadata; + tmp.value = StoreString(value); + + metadata_.push_back(tmp); } }; @@ -383,20 +574,235 @@ } }; + + class Transaction : public boost::noncopyable + { + private: + IDatabaseBackend& backend_; + std::unique_ptr output_; + + public: + Transaction(IDatabaseBackend& backend) : + backend_(backend), + output_(new Output) + { + } + + IDatabaseBackend& GetBackend() const + { + return backend_; + } + + Output& GetOutput() const + { + return *output_; + } + + OrthancPluginContext* GetContext() const + { + return backend_.GetContext(); + } + }; + - static void Register() + static OrthancPluginErrorCode Open(void* database) + { + IDatabaseBackend* backend = reinterpret_cast(database); + + try + { + backend->Open(); + return OrthancPluginErrorCode_Success; + } + ORTHANC_PLUGINS_DATABASE_CATCH(backend->GetContext()); + } + + + static OrthancPluginErrorCode Close(void* database) { - OrthancPluginDatabaseBackendV3 backend; - memset(&backend, 0, sizeof(backend)); + IDatabaseBackend* backend = reinterpret_cast(database); + + try + { + backend->Close(); + return OrthancPluginErrorCode_Success; + } + ORTHANC_PLUGINS_DATABASE_CATCH(backend->GetContext()); + } + + + static OrthancPluginErrorCode DestructDatabase(void* database) + { + // Nothing to delete, as this plugin uses a singleton to store backend + if (database == NULL) + { + return OrthancPluginErrorCode_InternalError; + } + else + { + return OrthancPluginErrorCode_Success; + } + } + + + static OrthancPluginErrorCode GetDatabaseVersion(void* database, + uint32_t* version) + { + IDatabaseBackend* backend = reinterpret_cast(database); + + try + { + *version = backend->GetDatabaseVersion(); + return OrthancPluginErrorCode_Success; + } + ORTHANC_PLUGINS_DATABASE_CATCH(backend->GetContext()); + } + + + static OrthancPluginErrorCode UpgradeDatabase(void* database, + OrthancPluginStorageArea* storageArea, + uint32_t targetVersion) + { + IDatabaseBackend* backend = reinterpret_cast(database); + + try + { + backend->UpgradeDatabase(targetVersion, storageArea); + return OrthancPluginErrorCode_Success; + } + ORTHANC_PLUGINS_DATABASE_CATCH(backend->GetContext()); + } + - backend.readAnswersCount = Output::ReadAnswersCount; - backend.readAnswerAttachment = Output::ReadAnswerAttachment; - backend.readAnswerChange = Output::ReadAnswerChange; - backend.readAnswerDicomTag = Output::ReadAnswerDicomTag; - backend.readAnswerExportedResource = Output::ReadAnswerExportedResource; + static OrthancPluginErrorCode StartTransaction(void* database, + OrthancPluginDatabaseTransaction** target /* out */, + OrthancPluginDatabaseTransactionType type) + { + IDatabaseBackend* backend = reinterpret_cast(database); + + try + { + std::unique_ptr transaction(new Transaction(*backend)); + + switch (type) + { + case OrthancPluginDatabaseTransactionType_ReadOnly: + backend->StartTransaction(TransactionType_ReadOnly); + break; + + case OrthancPluginDatabaseTransactionType_ReadWrite: + backend->StartTransaction(TransactionType_ReadWrite); + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + *target = reinterpret_cast(transaction.release()); + + return OrthancPluginErrorCode_Success; + } + ORTHANC_PLUGINS_DATABASE_CATCH(backend->GetContext()); + } + + + static OrthancPluginErrorCode DestructTransaction(OrthancPluginDatabaseTransaction* transaction) + { + if (transaction == NULL) + { + return OrthancPluginErrorCode_NullPointer; + } + else + { + delete reinterpret_cast(transaction); + return OrthancPluginErrorCode_Success; + } + } + + + static OrthancPluginErrorCode Rollback(OrthancPluginDatabaseTransaction* transaction) + { + Transaction* t = reinterpret_cast(transaction); + + try + { + t->GetBackend().RollbackTransaction(); + return OrthancPluginErrorCode_Success; + } + ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); + } + + + static OrthancPluginErrorCode Commit(OrthancPluginDatabaseTransaction* transaction, + int64_t fileSizeDelta /* TODO - not used? */) + { + Transaction* t = reinterpret_cast(transaction); + + try + { + t->GetBackend().CommitTransaction(); + return OrthancPluginErrorCode_Success; + } + ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); + } + + + static OrthancPluginErrorCode AddAttachment(OrthancPluginDatabaseTransaction* transaction, + int64_t id, + const OrthancPluginAttachment* attachment) + { + Transaction* t = reinterpret_cast(transaction); + + try + { + t->GetOutput().Clear(); + t->GetBackend().AddAttachment(id, *attachment); + return OrthancPluginErrorCode_Success; + } + ORTHANC_PLUGINS_DATABASE_CATCH(t->GetContext()); + } + + + + static void RegisterV3(IDatabaseBackend& database) + { + OrthancPluginDatabaseBackendV3 params; + memset(¶ms, 0, sizeof(params)); + + params.readAnswersCount = Output::ReadAnswersCount; + params.readAnswerAttachment = Output::ReadAnswerAttachment; + params.readAnswerChange = Output::ReadAnswerChange; + params.readAnswerDicomTag = Output::ReadAnswerDicomTag; + params.readAnswerExportedResource = Output::ReadAnswerExportedResource; + params.readAnswerInt32 = Output::ReadAnswerInt32; + params.readAnswerInt64 = Output::ReadAnswerInt64; + params.readAnswerMatchingResource = Output::ReadAnswerMatchingResource; + params.readAnswerMetadata = Output::ReadAnswerMetadata; + params.readAnswerString = Output::ReadAnswerString; - backend.readEventsCount = Output::ReadEventsCount; - backend.readEvent = Output::ReadEvent; + params.readEventsCount = Output::ReadEventsCount; + params.readEvent = Output::ReadEvent; + + params.open = Open; + params.close = Close; + params.destructDatabase = DestructDatabase; + params.getDatabaseVersion = GetDatabaseVersion; + params.upgradeDatabase = UpgradeDatabase; + params.startTransaction = StartTransaction; + params.destructTransaction = DestructTransaction; + params.rollback = Rollback; + params.commit = Commit; + + params.addAttachment = AddAttachment; + + OrthancPluginContext* context = database.GetContext(); + + if (OrthancPluginRegisterDatabaseBackendV3(context, ¶ms, sizeof(params), &database) != OrthancPluginErrorCode_Success) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Unable to register the database backend"); + } + + database.SetOutputFactory(new Factory); } } @@ -442,7 +848,23 @@ backend_.reset(new OrthancDatabases::SQLiteIndex(context, "index.db")); // TODO parameter /* Register the SQLite index into Orthanc */ - OrthancDatabases::DatabaseBackendAdapterV2::Register(context, *backend_); + + bool hasLoadedV3 = false; + +#if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) // Macro introduced in Orthanc 1.3.1 +# if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 10, 0) + if (OrthancPluginCheckVersionAdvanced(context, 1, 10, 0) == 1) + { + RegisterV3(*backend_); + hasLoadedV3 = true; + } +# endif +#endif + + if (!hasLoadedV3) + { + OrthancDatabases::DatabaseBackendAdapterV2::Register(*backend_); + } } catch (Orthanc::OrthancException& e) {