# HG changeset patch # User Sebastien Jodogne # Date 1618240026 -7200 # Node ID c82c2cf84ae8d7a58e0621227c2391fd7ac8f4e8 # Parent e9ba888f371bc0d46dd2a02b44e39be6d3c0ea77 added handling of CR_COMMANDS_OUT_OF_SYNC diff -r e9ba888f371b -r c82c2cf84ae8 Framework/MySQL/MySQLDatabase.cpp --- a/Framework/MySQL/MySQLDatabase.cpp Thu Apr 08 20:30:15 2021 +0200 +++ b/Framework/MySQL/MySQLDatabase.cpp Mon Apr 12 17:07:06 2021 +0200 @@ -52,6 +52,40 @@ } + void MySQLDatabase::ThrowException() + { + LogError(); + + unsigned int error = mysql_errno(mysql_); + if (error == CR_SERVER_GONE_ERROR || + error == CR_SERVER_LOST || + error == ER_QUERY_INTERRUPTED) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_DatabaseUnavailable); + } + else if (error == CR_COMMANDS_OUT_OF_SYNC) + { +#if !defined(MARIADB_VERSION_ID) + LOG(ERROR) << "TODO - This error seems to be related to the use of libmysqlclient: Try to switch to mariadb-connector"; +#endif + + throw Orthanc::OrthancException(Orthanc::ErrorCode_DatabaseUnavailable); + } + else if (error == ER_LOCK_DEADLOCK) + { +#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 9, 2) + throw Orthanc::OrthancException(Orthanc::ErrorCode_DatabaseCannotSerialize); +#else + throw Orthanc::OrthancException(Orthanc::ErrorCode_Database, "Collision between multiple writers"); +#endif + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); + } + } + + void MySQLDatabase::CheckErrorCode(int code) { if (code == 0) @@ -60,27 +94,7 @@ } else { - LogError(); - - unsigned int error = mysql_errno(mysql_); - if (error == CR_SERVER_GONE_ERROR || - error == CR_SERVER_LOST || - error == ER_QUERY_INTERRUPTED) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_DatabaseUnavailable); - } - else if (error == ER_LOCK_DEADLOCK) - { -#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 9, 2) - throw Orthanc::OrthancException(Orthanc::ErrorCode_DatabaseCannotSerialize); -#else - throw Orthanc::OrthancException(Orthanc::ErrorCode_Database, "Collision between multiple writers"); -#endif - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); - } + ThrowException(); } } diff -r e9ba888f371b -r c82c2cf84ae8 Framework/MySQL/MySQLDatabase.h --- a/Framework/MySQL/MySQLDatabase.h Thu Apr 08 20:30:15 2021 +0200 +++ b/Framework/MySQL/MySQLDatabase.h Mon Apr 12 17:07:06 2021 +0200 @@ -56,6 +56,8 @@ void CheckErrorCode(int code); + void ThrowException(); + MYSQL* GetObject(); void Open(); diff -r e9ba888f371b -r c82c2cf84ae8 Framework/MySQL/MySQLResult.cpp --- a/Framework/MySQL/MySQLResult.cpp Thu Apr 08 20:30:15 2021 +0200 +++ b/Framework/MySQL/MySQLResult.cpp Mon Apr 12 17:07:06 2021 +0200 @@ -43,17 +43,9 @@ // SQL request is not a SELECT) done_ = true; } - else if (error == CR_SERVER_GONE_ERROR || - error == CR_SERVER_LOST || - error == ER_QUERY_INTERRUPTED) - { - database_.LogError(); - throw Orthanc::OrthancException(Orthanc::ErrorCode_DatabaseUnavailable); - } else { - database_.LogError(); - throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); + database_.ThrowException(); } } else @@ -82,7 +74,7 @@ // https://github.com/hholzgra/connector-c-examples/blob/master/mysql_stmt_bind_result.c SetFieldsCount(statement_.GetResultFieldsCount()); - + Step(); } diff -r e9ba888f371b -r c82c2cf84ae8 Framework/Plugins/GlobalProperties.cpp --- a/Framework/Plugins/GlobalProperties.cpp Thu Apr 08 20:30:15 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,267 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2021 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 . - **/ - - -#include "GlobalProperties.h" - -#include "../Common/Utf8StringValue.h" - -#include // For std::unique_ptr<> -#include -#include - -#include - -namespace OrthancDatabases -{ - bool LookupGlobalProperty(std::string& target, - IDatabase& db, - ITransaction& transaction, - const std::string& serverIdentifier, - Orthanc::GlobalProperty property) - { - Query query("SELECT value FROM GlobalProperties WHERE property=${property}", true); - query.SetType("property", ValueType_Integer64); - - std::unique_ptr statement(db.Compile(query)); - - Dictionary args; - args.SetIntegerValue("property", property); - - std::unique_ptr result(transaction.Execute(*statement, args)); - - if (result->IsDone()) - { - return false; - } - - result->SetExpectedType(0, ValueType_Utf8String); - - ValueType type = result->GetField(0).GetType(); - - if (type == ValueType_Null) - { - return false; - } - else if (type != ValueType_Utf8String) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); - } - else - { - target = dynamic_cast(result->GetField(0)).GetContent(); - return true; - } - } - - - bool LookupGlobalProperty(std::string& target /* out */, - DatabaseManager& manager, - const std::string& serverIdentifier, - Orthanc::GlobalProperty property) - { - DatabaseManager::CachedStatement statement( - STATEMENT_FROM_HERE, manager, - "SELECT value FROM GlobalProperties WHERE property=${property}"); - - statement.SetReadOnly(true); - statement.SetParameterType("property", ValueType_Integer64); - - Dictionary args; - args.SetIntegerValue("property", property); - - statement.Execute(args); - statement.SetResultFieldType(0, ValueType_Utf8String); - - if (statement.IsDone()) - { - return false; - } - - ValueType type = statement.GetResultField(0).GetType(); - - if (type == ValueType_Null) - { - return false; - } - else if (type != ValueType_Utf8String) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); - } - else - { - target = dynamic_cast(statement.GetResultField(0)).GetContent(); - return true; - } - } - - - void SetGlobalProperty(IDatabase& db, - ITransaction& transaction, - const std::string& serverIdentifier, - Orthanc::GlobalProperty property, - const std::string& utf8) - { - // This version of "SetGlobalProperty()" (with an explicit - // transaction) is called internally by the plugin to set a global - // property during the initialization of the database. (TODO: - // Could be replaced by the version with an implicit transaction - // to avoid code redundancy). - - if (db.GetDialect() == Dialect_SQLite) - { - Query query("INSERT OR REPLACE INTO GlobalProperties VALUES (${property}, ${value})", false); - query.SetType("property", ValueType_Integer64); - query.SetType("value", ValueType_Utf8String); - - std::unique_ptr statement(db.Compile(query)); - - Dictionary args; - args.SetIntegerValue("property", static_cast(property)); - args.SetUtf8Value("value", utf8); - - transaction.ExecuteWithoutResult(*statement, args); - } - else - { - { - Query query("DELETE FROM GlobalProperties WHERE property=${property}", false); - query.SetType("property", ValueType_Integer64); - - std::unique_ptr statement(db.Compile(query)); - - Dictionary args; - args.SetIntegerValue("property", static_cast(property)); - - transaction.ExecuteWithoutResult(*statement, args); - } - - { - Query query("INSERT INTO GlobalProperties VALUES (${property}, ${value})", false); - query.SetType("property", ValueType_Integer64); - query.SetType("value", ValueType_Utf8String); - - std::unique_ptr statement(db.Compile(query)); - - Dictionary args; - args.SetIntegerValue("property", static_cast(property)); - args.SetUtf8Value("value", utf8); - - transaction.ExecuteWithoutResult(*statement, args); - } - } - } - - - void SetGlobalProperty(DatabaseManager& manager, - const std::string& serverIdentifier, - Orthanc::GlobalProperty property, - const std::string& utf8) - { - // This version of "SetGlobalProperty()" (without an explicit - // transaction) is called by Orthanc during its execution. Orthanc - // manages the transaction at a higher level, but this transaction - // is always present. - - if (manager.GetDialect() == Dialect_SQLite) - { - DatabaseManager::CachedStatement statement( - STATEMENT_FROM_HERE, manager, - "INSERT OR REPLACE INTO GlobalProperties VALUES (${property}, ${value})"); - - statement.SetParameterType("property", ValueType_Integer64); - statement.SetParameterType("value", ValueType_Utf8String); - - Dictionary args; - args.SetIntegerValue("property", static_cast(property)); - args.SetUtf8Value("value", utf8); - - statement.Execute(args); - } - else - { - { - DatabaseManager::CachedStatement statement( - STATEMENT_FROM_HERE, manager, - "DELETE FROM GlobalProperties WHERE property=${property}"); - - statement.SetParameterType("property", ValueType_Integer64); - - Dictionary args; - args.SetIntegerValue("property", property); - - statement.Execute(args); - } - - { - DatabaseManager::CachedStatement statement( - STATEMENT_FROM_HERE, manager, - "INSERT INTO GlobalProperties VALUES (${property}, ${value})"); - - statement.SetParameterType("property", ValueType_Integer64); - statement.SetParameterType("value", ValueType_Utf8String); - - Dictionary args; - args.SetIntegerValue("property", static_cast(property)); - args.SetUtf8Value("value", utf8); - - statement.Execute(args); - } - } - } - - - bool LookupGlobalIntegerProperty(int& target, - IDatabase& db, - ITransaction& transaction, - const std::string& serverIdentifier, - Orthanc::GlobalProperty property) - { - std::string value; - - if (LookupGlobalProperty(value, db, transaction, serverIdentifier, property)) - { - try - { - target = boost::lexical_cast(value); - return true; - } - catch (boost::bad_lexical_cast&) - { - LOG(ERROR) << "Corrupted PostgreSQL database"; - throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); - } - } - else - { - return false; - } - } - - - void SetGlobalIntegerProperty(IDatabase& db, - ITransaction& transaction, - const std::string& serverIdentifier, - Orthanc::GlobalProperty property, - int value) - { - SetGlobalProperty(db, transaction, serverIdentifier, property, boost::lexical_cast(value)); - } -}