diff MySQL/Plugins/MySQLStorageArea.cpp @ 242:b97a537f4613

MySQL: Support of range reads for the storage area
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 13 Apr 2021 17:00:02 +0200
parents 35598014f140
children 29ac6f4a0f45
line wrap: on
line diff
--- a/MySQL/Plugins/MySQLStorageArea.cpp	Tue Apr 13 12:07:30 2021 +0200
+++ b/MySQL/Plugins/MySQLStorageArea.cpp	Tue Apr 13 17:00:02 2021 +0200
@@ -21,6 +21,7 @@
 
 #include "MySQLStorageArea.h"
 
+#include "../../Framework/Common/BinaryStringValue.h"
 #include "../../Framework/MySQL/MySQLDatabase.h"
 #include "../../Framework/MySQL/MySQLTransaction.h"
 #include "MySQLDefinitions.h"
@@ -98,4 +99,94 @@
     ConfigureDatabase(*database, parameters, clearAll);
     SetDatabase(database.release());
   }
+
+
+  class MySQLStorageArea::Accessor : public StorageBackend::AccessorBase
+  {
+  public:
+    Accessor(MySQLStorageArea& backend) :
+      AccessorBase(backend)
+    {
+    }
+
+    virtual void ReadRange(IFileContentVisitor& visitor,
+                           const std::string& uuid,
+                           OrthancPluginContentType type,
+                           uint64_t start,
+                           uint64_t length) ORTHANC_OVERRIDE
+    {
+      DatabaseManager::Transaction transaction(GetManager(), TransactionType_ReadOnly);
+
+      {
+        // https://stackoverflow.com/a/6545557/881731
+        DatabaseManager::CachedStatement statement(
+          STATEMENT_FROM_HERE, GetManager(),
+          "SELECT SUBSTRING(content, ${start}, ${length}) FROM StorageArea WHERE uuid=${uuid} AND type=${type}");
+     
+        statement.SetParameterType("uuid", ValueType_Utf8String);
+        statement.SetParameterType("type", ValueType_Integer64);
+        statement.SetParameterType("start", ValueType_Integer64);
+        statement.SetParameterType("length", ValueType_Integer64);
+
+        Dictionary args;
+        args.SetUtf8Value("uuid", uuid);
+        args.SetIntegerValue("type", type);
+        args.SetIntegerValue("length", length);
+
+        /**
+         * "For all forms of SUBSTRING(), the position of the first
+         * character in the string from which the substring is to be
+         * extracted is reckoned as 1." => hence the "+ 1"
+         * https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_substring
+         **/
+        args.SetIntegerValue("start", start + 1);
+     
+        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);
+      
+          if (value.GetType() == ValueType_BinaryString)
+          {
+            const std::string& content = dynamic_cast<const BinaryStringValue&>(value).GetContent();
+
+            if (static_cast<uint64_t>(content.size()) == length)
+            {
+              visitor.Assign(content);
+            }
+            else
+            {
+              throw Orthanc::OrthancException(Orthanc::ErrorCode_BadRange);
+            }
+          }
+          else
+          {
+            throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);        
+          }
+        }
+      }
+
+      transaction.Commit();
+
+      if (!visitor.IsSuccess())
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_Database, "Could not read range from the storage area");
+      }
+    }
+  };
+  
+
+  StorageBackend::IAccessor* MySQLStorageArea::CreateAccessor()
+  {
+    return new Accessor(*this);
+  }
 }