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));
-  }
-}