# HG changeset patch # User Sebastien Jodogne # Date 1618382551 -7200 # Node ID 483af3f35a4b950a22a6e85ea59e878f4d28cfe0 # Parent 9d00e5e073e828cf46dca7965a693afda12d09d5 turning ResultFileValue into a base class, and implement its primitives for PostgreSQL diff -r 9d00e5e073e8 -r 483af3f35a4b Framework/Common/ResultFileValue.cpp --- a/Framework/Common/ResultFileValue.cpp Tue Apr 13 18:50:44 2021 +0200 +++ b/Framework/Common/ResultFileValue.cpp Wed Apr 14 08:42:31 2021 +0200 @@ -35,7 +35,11 @@ switch (target) { case ValueType_BinaryString: - return new BinaryStringValue(content_); + { + std::string content; + ReadWhole(content); + return new BinaryStringValue(content); + } default: throw Orthanc::OrthancException(Orthanc::ErrorCode_BadParameterType); diff -r 9d00e5e073e8 -r 483af3f35a4b Framework/Common/ResultFileValue.h --- a/Framework/Common/ResultFileValue.h Tue Apr 13 18:50:44 2021 +0200 +++ b/Framework/Common/ResultFileValue.h Wed Apr 14 08:42:31 2021 +0200 @@ -27,36 +27,19 @@ namespace OrthancDatabases { + /** + * This class is not used for MySQL, as MySQL uses BLOB columns to + * store files. + **/ class ResultFileValue : public IValue { - private: - std::string content_; - public: - ResultFileValue() - { - } - - std::string& GetContent() - { - return content_; - } - - const std::string& GetContent() const - { - return content_; - } - - const void* GetBuffer() const - { - return (content_.empty() ? NULL : content_.c_str()); - } - - size_t GetSize() const - { - return content_.size(); - } - + virtual void ReadWhole(std::string& target) const = 0; + + virtual void ReadRange(std::string& target, + uint64_t start, + size_t length) const = 0; + virtual ValueType GetType() const ORTHANC_OVERRIDE { return ValueType_ResultFile; diff -r 9d00e5e073e8 -r 483af3f35a4b Framework/Plugins/StorageBackend.cpp --- a/Framework/Plugins/StorageBackend.cpp Tue Apr 13 18:50:44 2021 +0200 +++ b/Framework/Plugins/StorageBackend.cpp Wed Apr 14 08:42:31 2021 +0200 @@ -148,8 +148,12 @@ switch (value.GetType()) { case ValueType_ResultFile: - visitor.Assign(dynamic_cast(value).GetContent()); + { + std::string content; + dynamic_cast(value).ReadWhole(content); + visitor.Assign(content); break; + } case ValueType_BinaryString: visitor.Assign(dynamic_cast(value).GetContent()); @@ -174,9 +178,60 @@ const std::string& uuid, OrthancPluginContentType type, uint64_t start, - uint64_t length) + size_t length) { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + /** + * This is a generic implementation, that will only work if + * "ResultFileValue" is implemented by the database backend. For + * instance, this will *not* work with MySQL, as the latter uses + * BLOB columns to store files. + **/ + DatabaseManager::Transaction transaction(manager_, TransactionType_ReadOnly); + + { + DatabaseManager::CachedStatement statement( + STATEMENT_FROM_HERE, manager_, + "SELECT content FROM StorageArea WHERE uuid=${uuid} AND type=${type}"); + + statement.SetParameterType("uuid", ValueType_Utf8String); + statement.SetParameterType("type", ValueType_Integer64); + + Dictionary args; + args.SetUtf8Value("uuid", uuid); + args.SetIntegerValue("type", type); + + 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_ResultFile) + { + std::string content; + dynamic_cast(value).ReadRange(content, start, length); + visitor.Assign(content); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); + } + } + } + + transaction.Commit(); + + if (!visitor.IsSuccess()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_Database, "Could not read attachment from the storage area"); + } } @@ -598,7 +653,7 @@ const std::string& uuid, OrthancPluginContentType type, uint64_t start, - uint64_t length) + size_t length) { StringVisitor visitor(target); accessor.ReadRange(visitor, uuid, type, start, length); diff -r 9d00e5e073e8 -r 483af3f35a4b Framework/Plugins/StorageBackend.h --- a/Framework/Plugins/StorageBackend.h Tue Apr 13 18:50:44 2021 +0200 +++ b/Framework/Plugins/StorageBackend.h Wed Apr 14 08:42:31 2021 +0200 @@ -65,7 +65,7 @@ const std::string& uuid, OrthancPluginContentType type, uint64_t start, - uint64_t length) = 0; + size_t length) = 0; virtual void Remove(const std::string& uuid, OrthancPluginContentType type) = 0; @@ -111,7 +111,7 @@ const std::string& uuid, OrthancPluginContentType type, uint64_t start, - uint64_t length); + size_t length); virtual void Remove(const std::string& uuid, OrthancPluginContentType type); @@ -148,6 +148,6 @@ const std::string& uuid, OrthancPluginContentType type, uint64_t start, - uint64_t length); + size_t length); }; } diff -r 9d00e5e073e8 -r 483af3f35a4b Framework/PostgreSQL/PostgreSQLResult.cpp --- a/Framework/PostgreSQL/PostgreSQLResult.cpp Tue Apr 13 18:50:44 2021 +0200 +++ b/Framework/PostgreSQL/PostgreSQLResult.cpp Wed Apr 14 08:42:31 2021 +0200 @@ -170,8 +170,7 @@ } - void PostgreSQLResult::GetLargeObject(std::string& result, - unsigned int column) const + std::string PostgreSQLResult::GetLargeObjectOid(unsigned int column) const { CheckColumn(column, OIDOID); @@ -185,24 +184,44 @@ oid = *(const Oid*) PQgetvalue(reinterpret_cast(result_), position_, column); oid = ntohl(oid); - PostgreSQLLargeObject::Read(result, database_, boost::lexical_cast(oid)); + return boost::lexical_cast(oid); + } + + + void PostgreSQLResult::GetLargeObjectContent(std::string& content, + unsigned int column) const + { + PostgreSQLLargeObject::Read(content, database_, GetLargeObjectOid(column)); } - void PostgreSQLResult::GetLargeObject(void*& result, - size_t& size, - unsigned int column) const + class PostgreSQLResult::LargeObjectResult : public ResultFileValue { - CheckColumn(column, OIDOID); + private: + PostgreSQLDatabase& database_; + std::string oid_; + + public: + LargeObjectResult(PostgreSQLDatabase& database, + const std::string& oid) : + database_(database), + oid_(oid) + { + } - Oid oid; - assert(PQfsize(reinterpret_cast(result_), column) == sizeof(oid)); + virtual void ReadWhole(std::string& target) const ORTHANC_OVERRIDE + { + PostgreSQLLargeObject::Read(target, database_, oid_); - oid = *(const Oid*) PQgetvalue(reinterpret_cast(result_), position_, column); - oid = ntohl(oid); - - PostgreSQLLargeObject::Read(result, size, database_, boost::lexical_cast(oid)); - } + } + + virtual void ReadRange(std::string& target, + uint64_t start, + size_t length) const ORTHANC_OVERRIDE + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + }; IValue* PostgreSQLResult::GetValue(unsigned int column) const @@ -234,11 +253,7 @@ return new BinaryStringValue(GetString(column)); case OIDOID: - { - std::unique_ptr value(new ResultFileValue); - GetLargeObject(value->GetContent(), column); - return value.release(); - } + return new LargeObjectResult(database_, GetLargeObjectOid(column)); default: throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); diff -r 9d00e5e073e8 -r 483af3f35a4b Framework/PostgreSQL/PostgreSQLResult.h --- a/Framework/PostgreSQL/PostgreSQLResult.h Tue Apr 13 18:50:44 2021 +0200 +++ b/Framework/PostgreSQL/PostgreSQLResult.h Wed Apr 14 08:42:31 2021 +0200 @@ -32,6 +32,8 @@ class PostgreSQLResult : public boost::noncopyable { private: + class LargeObjectResult; + void *result_; /* Object of type "PGresult*" */ int position_; PostgreSQLDatabase& database_; @@ -70,12 +72,10 @@ std::string GetString(unsigned int column) const; - void GetLargeObject(std::string& result, - unsigned int column) const; + std::string GetLargeObjectOid(unsigned int column) const; - void GetLargeObject(void*& result, - size_t& size, - unsigned int column) const; + void GetLargeObjectContent(std::string& content, + unsigned int column) const; IValue* GetValue(unsigned int column) const; }; diff -r 9d00e5e073e8 -r 483af3f35a4b PostgreSQL/UnitTests/PostgreSQLTests.cpp --- a/PostgreSQL/UnitTests/PostgreSQLTests.cpp Tue Apr 13 18:50:44 2021 +0200 +++ b/PostgreSQL/UnitTests/PostgreSQLTests.cpp Wed Apr 14 08:42:31 2021 +0200 @@ -326,7 +326,7 @@ ASSERT_EQ("Index 9", r.GetString(0)); std::string data; - r.GetLargeObject(data, 1); + r.GetLargeObjectContent(data, 1); ASSERT_EQ("Value 18", data); r.Next();