Skip to content
Commits on Source (10)
repo: 1d7c4b96183115894767b40ed485045665f2c75c
node: 8994bbdbc6d09f0824f789bb02e3d5b1b44e60e2
branch: OrthancPostgreSQL-2.1
repo: 7cea966b682978aa285eb9b3a7a9cff81df464b3
node: 4b2dab49b6ea1f3369e769b0ce94e00c4ea32f1f
branch: OrthancPostgreSQL-2.2
latesttag: null
latesttagdistance: 166
changessincelatesttag: 178
latesttagdistance: 34
changessincelatesttag: 36
build*
PostgreSQL/CMakeLists.txt.user
PostgreSQL/ThirdPartyDownloads/
PostgreSQL plugin for Orthanc
=============================
Database plugins for Orthanc
============================
Authors
......
# Orthanc - A Lightweight, RESTful DICOM Store
# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
# Department, University Hospital of Liege, Belgium
# Copyright (C) 2017-2018 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/>.
cmake_minimum_required(VERSION 2.8)
project(OrthancPostgreSQL)
set(ORTHANC_POSTGRESQL_VERSION "2.1")
if (ORTHANC_POSTGRESQL_VERSION STREQUAL "mainline")
set(ORTHANC_FRAMEWORK_VERSION "mainline")
set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg")
else()
set(ORTHANC_FRAMEWORK_VERSION "1.3.2")
set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web")
endif()
# Parameters of the build
set(STATIC_BUILD OFF CACHE BOOL "Static build of the third-party libraries (necessary for Windows)")
set(ALLOW_DOWNLOADS OFF CACHE BOOL "Allow CMake to download packages")
set(BUILD_UNIT_TESTS ON CACHE BOOL "Build UnitTests")
set(ORTHANC_FRAMEWORK_SOURCE "${ORTHANC_FRAMEWORK_DEFAULT_SOURCE}" CACHE STRING "Source of the Orthanc source code (can be \"hg\", \"archive\", \"web\" or \"path\")")
set(ORTHANC_FRAMEWORK_ARCHIVE "" CACHE STRING "Path to the Orthanc archive, if ORTHANC_FRAMEWORK_SOURCE is \"archive\"")
set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory, if ORTHANC_FRAMEWORK_SOURCE is \"path\"")
# Advanced parameters to fine-tune linking against system libraries
set(USE_SYSTEM_LIBPQ ON CACHE BOOL "Use the system version of the PostgreSQL client library")
set(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK")
# Download and setup the Orthanc framework
include(${CMAKE_SOURCE_DIR}/Resources/Orthanc/DownloadOrthancFramework.cmake)
set(ORTHANC_FRAMEWORK_PLUGIN ON)
include(${ORTHANC_ROOT}/Resources/CMake/OrthancFrameworkParameters.cmake)
set(ENABLE_LOCALE OFF) # Disable support for locales (notably in Boost)
set(ENABLE_GOOGLE_TEST ON)
include(${ORTHANC_ROOT}/Resources/CMake/OrthancFrameworkConfiguration.cmake)
include_directories(${ORTHANC_ROOT})
# The CMake script in "Graveyard" was used up to release 2.0. The new
# script makes auto-configuration of the variables.
include(${CMAKE_SOURCE_DIR}/Resources/CMake/PostgreSQLConfiguration.cmake)
#include(${CMAKE_SOURCE_DIR}/Resources/Graveyard/PostgreSQLConfiguration.cmake)
if (STATIC_BUILD OR NOT USE_SYSTEM_ORTHANC_SDK)
include_directories(${CMAKE_SOURCE_DIR}/Resources/Orthanc/Sdk-0.9.5)
else ()
CHECK_INCLUDE_FILE_CXX(orthanc/OrthancCppDatabasePlugin.h HAVE_ORTHANC_H)
if (NOT HAVE_ORTHANC_H)
message(FATAL_ERROR "Please install the headers of the Orthanc plugins SDK")
endif()
endif()
if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
link_libraries(secur32)
execute_process(
COMMAND
${PYTHON_EXECUTABLE} ${ORTHANC_ROOT}/Resources/WindowsResources.py
${ORTHANC_POSTGRESQL_VERSION} "PostgreSQL storage plugin" OrthancPostgreSQLStorage.dll
"PostgreSQL as a database back-end to Orthanc (storage area)"
ERROR_VARIABLE Failure
OUTPUT_FILE ${AUTOGENERATED_DIR}/StorageVersion.rc
)
if (Failure)
message(FATAL_ERROR "Error while computing the version information: ${Failure}")
endif()
execute_process(
COMMAND
${PYTHON_EXECUTABLE} ${ORTHANC_ROOT}/Resources/WindowsResources.py
${ORTHANC_POSTGRESQL_VERSION} "PostgreSQL index plugin" OrthancPostgreSQLIndex.dll
"PostgreSQL as a database back-end to Orthanc (index area)"
ERROR_VARIABLE Failure
OUTPUT_FILE ${AUTOGENERATED_DIR}/IndexVersion.rc
)
if (Failure)
message(FATAL_ERROR "Error while computing the version information: ${Failure}")
endif()
set(INDEX_RESOURCES ${AUTOGENERATED_DIR}/IndexVersion.rc)
set(STORAGE_RESOURCES ${AUTOGENERATED_DIR}/StorageVersion.rc)
endif()
# Embed the SQL files into the binaries
EmbedResources(
--system-exception
--namespace=OrthancPlugins
POSTGRESQL_PREPARE ${CMAKE_CURRENT_SOURCE_DIR}/IndexPlugin/PostgreSQLPrepare.sql
POSTGRESQL_PREPARE_V5 ${CMAKE_CURRENT_SOURCE_DIR}/IndexPlugin/PostgreSQLVersion5.sql
POSTGRESQL_PREPARE_V6 ${CMAKE_CURRENT_SOURCE_DIR}/IndexPlugin/PostgreSQLVersion6.sql
)
set(CORE_SOURCES
${CMAKE_SOURCE_DIR}/Core/PostgreSQLConnection.cpp
${CMAKE_SOURCE_DIR}/Core/PostgreSQLLargeObject.cpp
${CMAKE_SOURCE_DIR}/Core/PostgreSQLResult.cpp
${CMAKE_SOURCE_DIR}/Core/PostgreSQLStatement.cpp
${CMAKE_SOURCE_DIR}/Core/PostgreSQLTransaction.cpp
${CMAKE_SOURCE_DIR}/Core/Configuration.cpp
${CMAKE_SOURCE_DIR}/Core/GlobalProperties.cpp
${AUTOGENERATED_DIR}/EmbeddedResources.cpp
${ORTHANC_CORE_SOURCES}
${LIBPQ_SOURCES}
)
add_library(OrthancPostgreSQLStorage
SHARED
${CORE_SOURCES}
${CMAKE_SOURCE_DIR}/StoragePlugin/PostgreSQLStorageArea.cpp
${CMAKE_SOURCE_DIR}/StoragePlugin/Plugin.cpp
${STORAGE_RESOURCES}
)
add_library(OrthancPostgreSQLIndex
SHARED
${CORE_SOURCES}
${CMAKE_SOURCE_DIR}/IndexPlugin/PostgreSQLWrapper.cpp
${CMAKE_SOURCE_DIR}/IndexPlugin/Plugin.cpp
${INDEX_RESOURCES}
)
message("Setting the version of the libraries to ${ORTHANC_POSTGRESQL_VERSION}")
add_definitions(-DORTHANC_POSTGRESQL_VERSION="${ORTHANC_POSTGRESQL_VERSION}")
set_target_properties(OrthancPostgreSQLStorage PROPERTIES
VERSION ${ORTHANC_POSTGRESQL_VERSION}
SOVERSION ${ORTHANC_POSTGRESQL_VERSION}
)
set_target_properties(OrthancPostgreSQLIndex PROPERTIES
VERSION ${ORTHANC_POSTGRESQL_VERSION}
SOVERSION ${ORTHANC_POSTGRESQL_VERSION}
)
install(
TARGETS OrthancPostgreSQLStorage OrthancPostgreSQLIndex
RUNTIME DESTINATION lib # Destination for Windows
LIBRARY DESTINATION share/orthanc/plugins # Destination for Linux
)
if (BUILD_UNIT_TESTS)
add_executable(UnitTests
${CORE_SOURCES}
${CMAKE_SOURCE_DIR}/IndexPlugin/PostgreSQLWrapper.cpp
${CMAKE_SOURCE_DIR}/StoragePlugin/PostgreSQLStorageArea.cpp
${CMAKE_SOURCE_DIR}/UnitTestsSources/UnitTestsMain.cpp
${CMAKE_SOURCE_DIR}/UnitTestsSources/PostgreSQLTests.cpp
${CMAKE_SOURCE_DIR}/UnitTestsSources/PostgreSQLWrapperTests.cpp
${GOOGLE_TEST_SOURCES}
)
target_link_libraries(UnitTests ${GOOGLE_TEST_LIBRARIES})
endif()
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 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 "Configuration.h"
#include "PostgreSQLException.h"
#include <fstream>
#include <json/reader.h>
#include <memory>
// For UUID generation
extern "C"
{
#ifdef WIN32
#include <rpc.h>
#else
#include <uuid/uuid.h>
#endif
}
namespace OrthancPlugins
{
bool ReadConfiguration(Json::Value& configuration,
OrthancPluginContext* context)
{
std::string s;
{
char* tmp = OrthancPluginGetConfiguration(context);
if (tmp == NULL)
{
OrthancPluginLogError(context, "Error while retrieving the configuration from Orthanc");
return false;
}
s.assign(tmp);
OrthancPluginFreeString(context, tmp);
}
Json::Reader reader;
if (reader.parse(s, configuration))
{
return true;
}
else
{
OrthancPluginLogError(context, "Unable to parse the configuration");
return false;
}
}
std::string GetStringValue(const Json::Value& configuration,
const std::string& key,
const std::string& defaultValue)
{
if (configuration.type() != Json::objectValue ||
!configuration.isMember(key) ||
configuration[key].type() != Json::stringValue)
{
return defaultValue;
}
else
{
return configuration[key].asString();
}
}
int GetIntegerValue(const Json::Value& configuration,
const std::string& key,
int defaultValue)
{
if (configuration.type() != Json::objectValue ||
!configuration.isMember(key) ||
configuration[key].type() != Json::intValue)
{
return defaultValue;
}
else
{
return configuration[key].asInt();
}
}
bool GetBooleanValue(const Json::Value& configuration,
const std::string& key,
bool defaultValue)
{
if (configuration.type() != Json::objectValue ||
!configuration.isMember(key) ||
configuration[key].type() != Json::booleanValue)
{
return defaultValue;
}
else
{
return configuration[key].asBool();
}
}
PostgreSQLConnection* CreateConnection(bool& useLock,
OrthancPluginContext* context,
const Json::Value& configuration)
{
useLock = true; // Use locking by default
std::auto_ptr<PostgreSQLConnection> connection(new PostgreSQLConnection);
if (configuration.isMember("PostgreSQL"))
{
Json::Value c = configuration["PostgreSQL"];
if (c.isMember("ConnectionUri"))
{
connection->SetConnectionUri(c["ConnectionUri"].asString());
}
else
{
connection->SetHost(GetStringValue(c, "Host", "localhost"));
connection->SetPortNumber(GetIntegerValue(c, "Port", 5432));
connection->SetDatabase(GetStringValue(c, "Database", "orthanc"));
connection->SetUsername(GetStringValue(c, "Username", "orthanc"));
connection->SetPassword(GetStringValue(c, "Password", "orthanc"));
}
useLock = GetBooleanValue(c, "Lock", useLock);
}
if (!useLock)
{
OrthancPluginLogWarning(context, "Locking of the PostgreSQL database is disabled");
}
connection->Open();
return connection.release();
}
std::string GenerateUuid()
{
#ifdef WIN32
UUID uuid;
UuidCreate ( &uuid );
unsigned char * str;
UuidToStringA ( &uuid, &str );
std::string s( ( char* ) str );
RpcStringFreeA ( &str );
#else
uuid_t uuid;
uuid_generate_random ( uuid );
char s[37];
uuid_unparse ( uuid, s );
#endif
return s;
}
bool IsFlagInCommandLineArguments(OrthancPluginContext* context,
const std::string& flag)
{
uint32_t count = OrthancPluginGetCommandLineArgumentsCount(context);
for (uint32_t i = 0; i < count; i++)
{
char* tmp = OrthancPluginGetCommandLineArgument(context, i);
std::string arg(tmp);
OrthancPluginFreeString(context, tmp);
if (arg == flag)
{
return true;
}
}
return false;
}
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 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 "Configuration.h"
#include "PostgreSQLException.h"
#include "PostgreSQLResult.h"
#include "PostgreSQLTransaction.h"
#define USE_ADVISORY_LOCK 1
namespace OrthancPlugins
{
GlobalProperties::GlobalProperties(PostgreSQLConnection& connection,
bool useLock,
int32_t lockKey) :
connection_(connection),
useLock_(useLock),
lockKey_(lockKey)
{
PostgreSQLTransaction transaction(connection_);
if (!connection_.DoesTableExist("GlobalProperties"))
{
connection_.Execute("CREATE TABLE GlobalProperties("
"property INTEGER PRIMARY KEY,"
"value TEXT)");
}
transaction.Commit();
}
void GlobalProperties::Lock(bool allowUnlock)
{
if (useLock_)
{
PostgreSQLTransaction transaction(connection_);
#if USE_ADVISORY_LOCK == 1
PostgreSQLStatement s(connection_, "select pg_try_advisory_lock($1);");
s.DeclareInputInteger(0);
s.BindInteger(0, lockKey_);
PostgreSQLResult result(s);
if (result.IsDone() ||
!result.GetBoolean(0))
{
throw PostgreSQLException("The database is locked by another instance of Orthanc.");
}
#else
PostgreSQLTransaction transaction(connection_);
// Check the lock
if (!allowUnlock)
{
std::string lock = "0";
if (LookupGlobalProperty(lock, lockKey_) &&
lock != "0")
{
throw PostgreSQLException("The database is locked by another instance of Orthanc. "
"Use \"" + FLAG_UNLOCK + "\" to manually remove the lock.");
}
}
// Lock the database
SetGlobalProperty(lockKey_, "1");
#endif
transaction.Commit();
}
}
bool GlobalProperties::LookupGlobalProperty(std::string& target,
int32_t property)
{
if (lookupGlobalProperty_.get() == NULL)
{
lookupGlobalProperty_.reset
(new PostgreSQLStatement
(connection_, "SELECT value FROM GlobalProperties WHERE property=$1"));
lookupGlobalProperty_->DeclareInputInteger(0);
}
lookupGlobalProperty_->BindInteger(0, static_cast<int>(property));
PostgreSQLResult result(*lookupGlobalProperty_);
if (result.IsDone())
{
return false;
}
else
{
target = result.GetString(0);
return true;
}
}
void GlobalProperties::SetGlobalProperty(int32_t property,
const char* value)
{
if (setGlobalProperty1_.get() == NULL ||
setGlobalProperty2_.get() == NULL)
{
setGlobalProperty1_.reset
(new PostgreSQLStatement
(connection_, "DELETE FROM GlobalProperties WHERE property=$1"));
setGlobalProperty1_->DeclareInputInteger(0);
setGlobalProperty2_.reset
(new PostgreSQLStatement
(connection_, "INSERT INTO GlobalProperties VALUES ($1, $2)"));
setGlobalProperty2_->DeclareInputInteger(0);
setGlobalProperty2_->DeclareInputString(1);
}
setGlobalProperty1_->BindInteger(0, property);
setGlobalProperty1_->Run();
setGlobalProperty2_->BindInteger(0, property);
setGlobalProperty2_->BindString(1, value);
setGlobalProperty2_->Run();
}
void GlobalProperties::Unlock()
{
if (useLock_)
{
#if USE_ADVISORY_LOCK == 1
// Nothing to do, the lock is released after the connection is closed
#else
// Remove the lock
PostgreSQLTransaction transaction(connection_);
SetGlobalProperty(lockKey_, "0");
transaction.Commit();
#endif
}
}
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 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 "BinaryStringValue.h"
#include "FileValue.h"
#include "NullValue.h"
#include <Core/OrthancException.h>
#include <boost/lexical_cast.hpp>
namespace OrthancDatabases
{
IValue* BinaryStringValue::Convert(ValueType target) const
{
switch (target)
{
case ValueType_File:
return new FileValue(content_);
case ValueType_Null:
return new NullValue;
default:
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadParameterType);
}
}
std::string BinaryStringValue::Format() const
{
return "(binary - " + boost::lexical_cast<std::string>(content_.size()) + " bytes)";
}
}
......@@ -19,64 +19,60 @@
**/
#include "PostgreSQLTransaction.h"
#pragma once
#include "PostgreSQLException.h"
#include "IValue.h"
namespace OrthancPlugins
namespace OrthancDatabases
{
PostgreSQLTransaction::PostgreSQLTransaction(PostgreSQLConnection& connection,
bool open) :
connection_(connection),
isOpen_(false)
class BinaryStringValue : public IValue
{
if (open)
private:
std::string content_;
public:
explicit BinaryStringValue()
{
Begin();
}
}
PostgreSQLTransaction::~PostgreSQLTransaction()
{
if (isOpen_)
explicit BinaryStringValue(const std::string& content) :
content_(content)
{
connection_.Execute("ABORT");
}
}
void PostgreSQLTransaction::Begin()
{
if (isOpen_)
BinaryStringValue(const void* content,
size_t size)
{
throw PostgreSQLException("PostgreSQL: Beginning a transaction twice!");
content_.assign(reinterpret_cast<const char*>(content), size);
}
connection_.Execute("BEGIN");
connection_.Execute("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
isOpen_ = true;
}
std::string& GetContent()
{
return content_;
}
void PostgreSQLTransaction::Rollback()
{
if (!isOpen_)
const std::string& GetContent() const
{
throw PostgreSQLException("Attempting to rollback a nonexistent transaction. "
"Did you remember to call Begin()?");
return content_;
}
connection_.Execute("ABORT");
isOpen_ = false;
}
const void* GetBuffer() const
{
return (content_.empty() ? NULL : content_.c_str());
}
void PostgreSQLTransaction::Commit()
{
if (!isOpen_)
size_t GetSize() const
{
return content_.size();
}
virtual ValueType GetType() const
{
throw PostgreSQLException("Attempting to roll back a nonexistent transaction. "
"Did you remember to call Begin()?");
return ValueType_BinaryString;
}
virtual IValue* Convert(ValueType target) const;
connection_.Execute("COMMIT");
isOpen_ = false;
}
virtual std::string Format() const;
};
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 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 "DatabaseManager.h"
#include <Core/Logging.h>
#include <Core/OrthancException.h>
#include <boost/thread.hpp>
namespace OrthancDatabases
{
IDatabase& DatabaseManager::GetDatabase()
{
static const unsigned int MAX_CONNECTION_ATTEMPTS = 10; // TODO: Parameter
unsigned int count = 0;
while (database_.get() == NULL)
{
transaction_.reset(NULL);
try
{
database_.reset(factory_->Open());
}
catch (Orthanc::OrthancException& e)
{
if (e.GetErrorCode() == Orthanc::ErrorCode_DatabaseUnavailable)
{
count ++;
if (count <= MAX_CONNECTION_ATTEMPTS)
{
LOG(WARNING) << "Database is currently unavailable, retrying...";
boost::this_thread::sleep(boost::posix_time::seconds(1));
continue;
}
else
{
LOG(ERROR) << "Timeout when connecting to the database, giving up";
}
}
throw;
}
}
if (database_.get() == NULL ||
database_->GetDialect() != dialect_)
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
}
else
{
return *database_;
}
}
void DatabaseManager::Close()
{
LOG(TRACE) << "Closing the connection to the database";
// Rollback active transaction, if any
transaction_.reset(NULL);
// Delete all the cached statements (must occur before closing
// the database)
for (CachedStatements::iterator it = cachedStatements_.begin();
it != cachedStatements_.end(); ++it)
{
assert(it->second != NULL);
delete it->second;
}
cachedStatements_.clear();
// Close the database
database_.reset(NULL);
LOG(TRACE) << "Connection to the database is closed";
}
void DatabaseManager::CloseIfUnavailable(Orthanc::ErrorCode e)
{
if (e != Orthanc::ErrorCode_Success)
{
transaction_.reset(NULL);
}
if (e == Orthanc::ErrorCode_DatabaseUnavailable)
{
LOG(ERROR) << "The database is not available, closing the connection";
Close();
}
}
IPrecompiledStatement* DatabaseManager::LookupCachedStatement(const StatementLocation& location) const
{
CachedStatements::const_iterator found = cachedStatements_.find(location);
if (found == cachedStatements_.end())
{
return NULL;
}
else
{
assert(found->second != NULL);
return found->second;
}
}
IPrecompiledStatement& DatabaseManager::CacheStatement(const StatementLocation& location,
const Query& query)
{
LOG(TRACE) << "Caching statement from " << location.GetFile() << ":" << location.GetLine();
std::auto_ptr<IPrecompiledStatement> statement(GetDatabase().Compile(query));
IPrecompiledStatement* tmp = statement.get();
if (tmp == NULL)
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
}
assert(cachedStatements_.find(location) == cachedStatements_.end());
cachedStatements_[location] = statement.release();
return *tmp;
}
ITransaction& DatabaseManager::GetTransaction()
{
if (transaction_.get() == NULL)
{
LOG(TRACE) << "Automatically creating an implicit database transaction";
try
{
transaction_.reset(GetDatabase().CreateTransaction(true));
}
catch (Orthanc::OrthancException& e)
{
CloseIfUnavailable(e.GetErrorCode());
throw;
}
}
assert(transaction_.get() != NULL);
return *transaction_;
}
void DatabaseManager::ReleaseImplicitTransaction()
{
if (transaction_.get() != NULL &&
transaction_->IsImplicit())
{
LOG(TRACE) << "Committing an implicit database transaction";
try
{
transaction_->Commit();
transaction_.reset(NULL);
}
catch (Orthanc::OrthancException& e)
{
// Don't throw the exception, as we are in CachedStatement destructor
LOG(ERROR) << "Error while committing an implicit database transaction: " << e.What();
}
}
}
DatabaseManager::DatabaseManager(IDatabaseFactory* factory) : // Takes ownership
factory_(factory)
{
if (factory == NULL)
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
}
dialect_ = factory->GetDialect();
}
void DatabaseManager::StartTransaction()
{
boost::recursive_mutex::scoped_lock lock(mutex_);
try
{
if (transaction_.get() != NULL)
{
LOG(ERROR) << "Cannot start another transaction while there is an uncommitted transaction";
throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);
}
transaction_.reset(GetDatabase().CreateTransaction(false));
}
catch (Orthanc::OrthancException& e)
{
CloseIfUnavailable(e.GetErrorCode());
throw;
}
}
void DatabaseManager::CommitTransaction()
{
boost::recursive_mutex::scoped_lock lock(mutex_);
if (transaction_.get() == NULL)
{
LOG(ERROR) << "Cannot commit a non-existing transaction";
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
}
else
{
try
{
transaction_->Commit();
transaction_.reset(NULL);
}
catch (Orthanc::OrthancException& e)
{
CloseIfUnavailable(e.GetErrorCode());
throw;
}
}
}
void DatabaseManager::RollbackTransaction()
{
boost::recursive_mutex::scoped_lock lock(mutex_);
if (transaction_.get() == NULL)
{
LOG(ERROR) << "Cannot rollback a non-existing transaction";
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
}
else
{
try
{
transaction_->Rollback();
transaction_.reset(NULL);
}
catch (Orthanc::OrthancException& e)
{
CloseIfUnavailable(e.GetErrorCode());
throw;
}
}
}
IResult& DatabaseManager::CachedStatement::GetResult() const
{
if (result_.get() == NULL)
{
LOG(ERROR) << "Accessing the results of a statement without having executed it";
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
}
return *result_;
}
void DatabaseManager::CachedStatement::Setup(const char* sql)
{
statement_ = manager_.LookupCachedStatement(location_);
if (statement_ == NULL)
{
query_.reset(new Query(sql));
}
else
{
LOG(TRACE) << "Reusing cached statement from "
<< location_.GetFile() << ":" << location_.GetLine();
}
}
DatabaseManager::Transaction::Transaction(DatabaseManager& manager) :
lock_(manager.mutex_),
manager_(manager),
database_(manager.GetDatabase()),
committed_(false)
{
manager_.StartTransaction();
}
DatabaseManager::Transaction::~Transaction()
{
if (!committed_)
{
try
{
manager_.RollbackTransaction();
}
catch (Orthanc::OrthancException& e)
{
// Don't rethrow the exception as we are in a destructor
LOG(ERROR) << "Uncatched error during some transaction rollback: " << e.What();
}
}
}
void DatabaseManager::Transaction::Commit()
{
if (committed_)
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
}
else
{
manager_.CommitTransaction();
committed_ = true;
}
}
DatabaseManager::CachedStatement::CachedStatement(const StatementLocation& location,
DatabaseManager& manager,
const char* sql) :
manager_(manager),
lock_(manager_.mutex_),
database_(manager_.GetDatabase()),
location_(location),
transaction_(manager_.GetTransaction())
{
Setup(sql);
}
DatabaseManager::CachedStatement::CachedStatement(const StatementLocation& location,
Transaction& transaction,
const char* sql) :
manager_(transaction.GetManager()),
lock_(manager_.mutex_),
database_(manager_.GetDatabase()),
location_(location),
transaction_(manager_.GetTransaction())
{
Setup(sql);
}
DatabaseManager::CachedStatement::~CachedStatement()
{
manager_.ReleaseImplicitTransaction();
}
void DatabaseManager::CachedStatement::SetReadOnly(bool readOnly)
{
if (query_.get() != NULL)
{
query_->SetReadOnly(readOnly);
}
}
void DatabaseManager::CachedStatement::SetParameterType(const std::string& parameter,
ValueType type)
{
if (query_.get() != NULL)
{
query_->SetType(parameter, type);
}
}
void DatabaseManager::CachedStatement::Execute()
{
Dictionary parameters;
Execute(parameters);
}
void DatabaseManager::CachedStatement::Execute(const Dictionary& parameters)
{
if (result_.get() != NULL)
{
LOG(ERROR) << "Cannot execute twice a statement";
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
}
try
{
if (query_.get() != NULL)
{
// Register the newly-created statement
assert(statement_ == NULL);
statement_ = &manager_.CacheStatement(location_, *query_);
query_.reset(NULL);
}
assert(statement_ != NULL);
result_.reset(transaction_.Execute(*statement_, parameters));
}
catch (Orthanc::OrthancException& e)
{
manager_.CloseIfUnavailable(e.GetErrorCode());
throw;
}
}
bool DatabaseManager::CachedStatement::IsDone() const
{
try
{
return GetResult().IsDone();
}
catch (Orthanc::OrthancException& e)
{
manager_.CloseIfUnavailable(e.GetErrorCode());
throw;
}
}
void DatabaseManager::CachedStatement::Next()
{
try
{
GetResult().Next();
}
catch (Orthanc::OrthancException& e)
{
manager_.CloseIfUnavailable(e.GetErrorCode());
throw;
}
}
size_t DatabaseManager::CachedStatement::GetResultFieldsCount() const
{
try
{
return GetResult().GetFieldsCount();
}
catch (Orthanc::OrthancException& e)
{
manager_.CloseIfUnavailable(e.GetErrorCode());
throw;
}
}
void DatabaseManager::CachedStatement::SetResultFieldType(size_t field,
ValueType type)
{
try
{
if (!GetResult().IsDone())
{
GetResult().SetExpectedType(field, type);
}
}
catch (Orthanc::OrthancException& e)
{
manager_.CloseIfUnavailable(e.GetErrorCode());
throw;
}
}
const IValue& DatabaseManager::CachedStatement::GetResultField(size_t index) const
{
try
{
return GetResult().GetField(index);
}
catch (Orthanc::OrthancException& e)
{
manager_.CloseIfUnavailable(e.GetErrorCode());
throw;
}
}
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 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/>.
**/
#pragma once
#include "IDatabaseFactory.h"
#include "StatementLocation.h"
#include <Core/Enumerations.h>
#include <boost/thread/recursive_mutex.hpp>
#include <memory>
namespace OrthancDatabases
{
class DatabaseManager : public boost::noncopyable
{
private:
typedef std::map<StatementLocation, IPrecompiledStatement*> CachedStatements;
boost::recursive_mutex mutex_;
std::auto_ptr<IDatabaseFactory> factory_;
std::auto_ptr<IDatabase> database_;
std::auto_ptr<ITransaction> transaction_;
CachedStatements cachedStatements_;
Dialect dialect_;
IDatabase& GetDatabase();
void CloseIfUnavailable(Orthanc::ErrorCode e);
IPrecompiledStatement* LookupCachedStatement(const StatementLocation& location) const;
IPrecompiledStatement& CacheStatement(const StatementLocation& location,
const Query& query);
ITransaction& GetTransaction();
void ReleaseImplicitTransaction();
public:
explicit DatabaseManager(IDatabaseFactory* factory); // Takes ownership
~DatabaseManager()
{
Close();
}
Dialect GetDialect() const
{
return dialect_;
}
void Open()
{
GetDatabase();
}
void Close();
void StartTransaction();
void CommitTransaction();
void RollbackTransaction();
// This class is only used in the "StorageBackend"
class Transaction : public boost::noncopyable
{
private:
boost::recursive_mutex::scoped_lock lock_;
DatabaseManager& manager_;
IDatabase& database_;
bool committed_;
public:
explicit Transaction(DatabaseManager& manager);
~Transaction();
void Commit();
DatabaseManager& GetManager()
{
return manager_;
}
IDatabase& GetDatabase()
{
return database_;
}
};
class CachedStatement : public boost::noncopyable
{
private:
DatabaseManager& manager_;
boost::recursive_mutex::scoped_lock lock_;
IDatabase& database_;
StatementLocation location_;
ITransaction& transaction_;
IPrecompiledStatement* statement_;
std::auto_ptr<Query> query_;
std::auto_ptr<IResult> result_;
void Setup(const char* sql);
IResult& GetResult() const;
public:
CachedStatement(const StatementLocation& location,
DatabaseManager& manager,
const char* sql);
CachedStatement(const StatementLocation& location,
Transaction& transaction,
const char* sql);
~CachedStatement();
IDatabase& GetDatabase()
{
return database_;
}
void SetReadOnly(bool readOnly);
void SetParameterType(const std::string& parameter,
ValueType type);
void Execute();
void Execute(const Dictionary& parameters);
bool IsDone() const;
void Next();
size_t GetResultFieldsCount() const;
void SetResultFieldType(size_t field,
ValueType type);
const IValue& GetResultField(size_t index) const;
};
};
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 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/>.
**/
#pragma once
namespace OrthancDatabases
{
enum ValueType
{
ValueType_BinaryString,
ValueType_File,
ValueType_Integer64,
ValueType_Null,
ValueType_Utf8String
};
enum Dialect
{
Dialect_MySQL,
Dialect_PostgreSQL,
Dialect_SQLite
};
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 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 "Dictionary.h"
#include "BinaryStringValue.h"
#include "FileValue.h"
#include "Integer64Value.h"
#include "NullValue.h"
#include "Utf8StringValue.h"
#include <Core/Logging.h>
#include <Core/OrthancException.h>
#include <cassert>
namespace OrthancDatabases
{
Dictionary::~Dictionary()
{
for (Values::iterator it = values_.begin();
it != values_.end(); ++it)
{
assert(it->second != NULL);
delete it->second;
}
}
bool Dictionary::HasKey(const std::string& key) const
{
return values_.find(key) != values_.end();
}
void Dictionary::Remove(const std::string& key)
{
Values::iterator found = values_.find(key);
if (found != values_.end())
{
assert(found->second != NULL);
delete found->second;
values_.erase(found);
}
}
void Dictionary::SetValue(const std::string& key,
IValue* value) // Takes ownership
{
if (value == NULL)
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
}
Values::iterator found = values_.find(key);
if (found == values_.end())
{
values_[key] = value;
}
else
{
assert(found->second != NULL);
delete found->second;
found->second = value;
}
}
void Dictionary::SetUtf8Value(const std::string& key,
const std::string& utf8)
{
SetValue(key, new Utf8StringValue(utf8));
}
void Dictionary::SetBinaryValue(const std::string& key,
const std::string& binary)
{
SetValue(key, new BinaryStringValue(binary));
}
void Dictionary::SetFileValue(const std::string& key,
const std::string& file)
{
SetValue(key, new FileValue(file));
}
void Dictionary::SetFileValue(const std::string& key,
const void* content,
size_t size)
{
SetValue(key, new FileValue(content, size));
}
void Dictionary::SetIntegerValue(const std::string& key,
int64_t value)
{
SetValue(key, new Integer64Value(value));
}
void Dictionary::SetNullValue(const std::string& key)
{
SetValue(key, new NullValue);
}
const IValue& Dictionary::GetValue(const std::string& key) const
{
Values::const_iterator found = values_.find(key);
if (found == values_.end())
{
LOG(ERROR) << "Inexistent value in a dictionary: " << key;
throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem);
}
else
{
assert(found->second != NULL);
return *found->second;
}
}
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 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/>.
**/
#pragma once
#include "IValue.h"
#include <map>
#include <stdint.h>
namespace OrthancDatabases
{
class Dictionary : public boost::noncopyable
{
private:
typedef std::map<std::string, IValue*> Values;
Values values_;
public:
~Dictionary();
bool HasKey(const std::string& key) const;
void Remove(const std::string& key);
void SetValue(const std::string& key,
IValue* value); // Takes ownership
void SetUtf8Value(const std::string& key,
const std::string& utf8);
void SetBinaryValue(const std::string& key,
const std::string& binary);
void SetFileValue(const std::string& key,
const std::string& file);
void SetFileValue(const std::string& key,
const void* content,
size_t size);
void SetIntegerValue(const std::string& key,
int64_t value);
void SetNullValue(const std::string& key);
const IValue& GetValue(const std::string& key) const;
};
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 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 "FileValue.h"
#include "BinaryStringValue.h"
#include "NullValue.h"
#include <Core/OrthancException.h>
#include <boost/lexical_cast.hpp>
namespace OrthancDatabases
{
IValue* FileValue::Convert(ValueType target) const
{
switch (target)
{
case ValueType_BinaryString:
return new BinaryStringValue(content_);
case ValueType_Null:
return new NullValue;
default:
throw Orthanc::OrthancException(Orthanc::ErrorCode_BadParameterType);
}
}
std::string FileValue::Format() const
{
return "(file - " + boost::lexical_cast<std::string>(content_.size()) + " bytes)";
}
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 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/>.
**/
#pragma once
#include "IValue.h"
namespace OrthancDatabases
{
class FileValue : public IValue
{
private:
std::string content_;
public:
FileValue()
{
}
explicit FileValue(const std::string& content) :
content_(content)
{
}
FileValue(const void* buffer,
size_t size)
{
content_.assign(reinterpret_cast<const char*>(buffer), size);
}
void SwapContent(std::string& content)
{
content_.swap(content);
}
void SetContent(const std::string& content)
{
content_ = content;
}
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 ValueType GetType() const
{
return ValueType_File;
}
virtual IValue* Convert(ValueType target) const;
virtual std::string Format() const;
};
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 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 "GenericFormatter.h"
#include <Core/OrthancException.h>
#include <boost/lexical_cast.hpp>
namespace OrthancDatabases
{
void GenericFormatter::Format(std::string& target,
const std::string& source,
ValueType type)
{
if (source.empty())
{
// This is the default parameter for INSERT
switch (dialect_)
{
case Dialect_PostgreSQL:
target = "DEFAULT";
break;
case Dialect_MySQL:
case Dialect_SQLite:
target = "NULL";
break;
default:
throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
}
}
else
{
switch (dialect_)
{
case Dialect_PostgreSQL:
target = "$" + boost::lexical_cast<std::string>(parametersName_.size() + 1);
break;
case Dialect_MySQL:
case Dialect_SQLite:
target = "?";
break;
default:
throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
}
parametersName_.push_back(source);
parametersType_.push_back(type);
}
}
const std::string& GenericFormatter::GetParameterName(size_t index) const
{
if (index >= parametersName_.size())
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
}
else
{
return parametersName_[index];
}
}
ValueType GenericFormatter::GetParameterType(size_t index) const
{
if (index >= parametersType_.size())
{
throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
}
else
{
return parametersType_[index];
}
}
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 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/>.
**/
#pragma once
#include "Query.h"
namespace OrthancDatabases
{
class GenericFormatter : public Query::IParameterFormatter
{
private:
Dialect dialect_;
std::vector<std::string> parametersName_;
std::vector<ValueType> parametersType_;
public:
explicit GenericFormatter(Dialect dialect) :
dialect_(dialect)
{
}
void Format(std::string& target,
const std::string& source,
ValueType type);
size_t GetParametersCount() const
{
return parametersName_.size();
}
const std::string& GetParameterName(size_t index) const;
ValueType GetParameterType(size_t index) const;
};
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 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/>.
**/
#pragma once
#include "IPrecompiledStatement.h"
#include "ITransaction.h"
#include "Query.h"
namespace OrthancDatabases
{
class IDatabase : public boost::noncopyable
{
public:
virtual ~IDatabase()
{
}
virtual Dialect GetDialect() const = 0;
virtual IPrecompiledStatement* Compile(const Query& query) = 0;
virtual ITransaction* CreateTransaction(bool isImplicit) = 0;
};
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 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/>.
**/
#pragma once
#include "IDatabase.h"
namespace OrthancDatabases
{
class IDatabaseFactory : public boost::noncopyable
{
public:
virtual ~IDatabaseFactory()
{
}
virtual Dialect GetDialect() const = 0;
virtual IDatabase* Open() = 0;
};
}
/**
* Orthanc - A Lightweight, RESTful DICOM Store
* Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
* Department, University Hospital of Liege, Belgium
* Copyright (C) 2017-2018 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/>.
**/
#pragma once
#include <boost/noncopyable.hpp>
namespace OrthancDatabases
{
class IPrecompiledStatement : public boost::noncopyable
{
public:
virtual ~IPrecompiledStatement()
{
}
virtual bool IsReadOnly() const = 0;
};
}