Mercurial > hg > orthanc-databases
changeset 240:c82c2cf84ae8
added handling of CR_COMMANDS_OUT_OF_SYNC
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 12 Apr 2021 17:07:06 +0200 |
parents | e9ba888f371b |
children | a063bbf10a3e |
files | Framework/MySQL/MySQLDatabase.cpp Framework/MySQL/MySQLDatabase.h Framework/MySQL/MySQLResult.cpp Framework/Plugins/GlobalProperties.cpp |
diffstat | 4 files changed, 39 insertions(+), 298 deletions(-) [+] |
line wrap: on
line diff
--- 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(); } }
--- 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();
--- 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(); }
--- 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 <http://www.gnu.org/licenses/>. - **/ - - -#include "GlobalProperties.h" - -#include "../Common/Utf8StringValue.h" - -#include <Compatibility.h> // For std::unique_ptr<> -#include <Logging.h> -#include <OrthancException.h> - -#include <boost/lexical_cast.hpp> - -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<IPrecompiledStatement> statement(db.Compile(query)); - - Dictionary args; - args.SetIntegerValue("property", property); - - std::unique_ptr<IResult> 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<const Utf8StringValue&>(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<const Utf8StringValue&>(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<IPrecompiledStatement> statement(db.Compile(query)); - - Dictionary args; - args.SetIntegerValue("property", static_cast<int>(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<IPrecompiledStatement> statement(db.Compile(query)); - - Dictionary args; - args.SetIntegerValue("property", static_cast<int>(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<IPrecompiledStatement> statement(db.Compile(query)); - - Dictionary args; - args.SetIntegerValue("property", static_cast<int>(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<int>(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<int>(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<int>(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<std::string>(value)); - } -}