@@ -0,0 +1,34 @@ | |||||
#pragma once | |||||
#include <cppmp.h> | |||||
#include <boost/hana.hpp> | |||||
namespace cpphibernate | |||||
{ | |||||
namespace mp = ::cppmp; | |||||
namespace hana = ::boost::hana; | |||||
} | |||||
#cmakedefine CPPHIBERNATE_DEBUG | |||||
#cmakedefine CPPHIBERNATE_HAS_CPPLOGGING | |||||
#cmakedefine CPPHIBERNATE_HAS_CPPMARIADB | |||||
#ifdef CPPHIBERNATE_HAS_CPPLOGGING | |||||
#include <cpplogging/interface.h> | |||||
#define cpphibernate_log(p_level) \ | |||||
cpplogging_global_log(p_level) | |||||
#else | |||||
#include <iostream> | |||||
#define cpphibernate_log(p_level) \ | |||||
::std::cout << #p_level << ' ' << __FILE__ << ':' << __LINE__ << " - " | |||||
#endif | |||||
#ifdef CPPHIBERNATE_DEBUG | |||||
#define cpphibernate_log_debug(...) \ | |||||
cpphibernate_log(debug) << __VA_ARGS__ | |||||
#else | |||||
#define cpphibernate_log_debug(...) \ | |||||
do { } while (0) | |||||
#endif |
@@ -1,3 +1,6 @@ | |||||
Option ( CPPHIBERNATE_USE_CPPLOGGING | |||||
"Try to find the cpplogging library and use it as logger instead of logging to std::cout." | |||||
OFF ) | |||||
Option ( CPPHIBERNATE_INSTALL_HEADER | Option ( CPPHIBERNATE_INSTALL_HEADER | ||||
"Install headers of cpphibernate." | "Install headers of cpphibernate." | ||||
ON ) | ON ) | ||||
@@ -13,3 +16,6 @@ Option ( CPPHIBERNATE_INSTALL_DEBUG | |||||
Option ( CPPHIBERNATE_NO_STRIP | Option ( CPPHIBERNATE_NO_STRIP | ||||
"Do not strip debug symbols from binary." | "Do not strip debug symbols from binary." | ||||
OFF ) | OFF ) | ||||
Option ( CPPHIBERNATE_DEBUG | |||||
"Write extra debug output to the console/logger." | |||||
OFF ) |
@@ -1,12 +0,0 @@ | |||||
#pragma once | |||||
#include <cppmp.h> | |||||
#include <boost/hana.hpp> | |||||
namespace cpphibernate | |||||
{ | |||||
namespace mp = ::cppmp; | |||||
namespace hana = ::boost::hana; | |||||
} |
@@ -18,15 +18,17 @@ namespace cpphibernate | |||||
{ static_assert(sizeof...(T_args) == -1, "Invalid parameters for context::init(...)!"); } | { static_assert(sizeof...(T_args) == -1, "Invalid parameters for context::init(...)!"); } | ||||
}; | }; | ||||
constexpr decltype(auto) init = mp::generic_predicate<init_builder> { }; | |||||
#if 0 | |||||
template<typename T_impl> | |||||
struct init_builder<mp::list<T_impl, bool>, void> | |||||
template<typename T_impl, typename T_bool> | |||||
struct init_builder< | |||||
mp::list<T_impl, T_bool>, | |||||
mp::enable_if_t<mp::is_same_v<bool, mp::decay_t<T_bool>>>> | |||||
{ | { | ||||
static constexpr decltype(auto) apply(T_impl& impl, bool recreate) | static constexpr decltype(auto) apply(T_impl& impl, bool recreate) | ||||
{ return impl.init(recreate); } | { return impl.init(recreate); } | ||||
}; | }; | ||||
#endif | |||||
constexpr decltype(auto) init = mp::generic_predicate<init_builder> { }; | |||||
/* create_builder */ | /* create_builder */ | ||||
template<typename X, typename = void> | template<typename X, typename = void> | ||||
@@ -120,27 +122,27 @@ namespace cpphibernate | |||||
template<typename T_driver, typename T_schema> | template<typename T_driver, typename T_schema> | ||||
template<typename... T_args> | template<typename... T_args> | ||||
constexpr decltype(auto) context<T_driver, T_schema>::init(T_args&&... args) | constexpr decltype(auto) context<T_driver, T_schema>::init(T_args&&... args) | ||||
{ return __impl::init(*this, std::forward<T_args>(args)...); } | |||||
{ return __impl::init(this->impl(), std::forward<T_args>(args)...); } | |||||
template<typename T_driver, typename T_schema> | template<typename T_driver, typename T_schema> | ||||
template<typename... T_args> | template<typename... T_args> | ||||
constexpr decltype(auto) context<T_driver, T_schema>::create(T_args&&... args) | constexpr decltype(auto) context<T_driver, T_schema>::create(T_args&&... args) | ||||
{ return __impl::create(*this, std::forward<T_args>(args)...); } | |||||
{ return __impl::create(this->impl(), std::forward<T_args>(args)...); } | |||||
template<typename T_driver, typename T_schema> | template<typename T_driver, typename T_schema> | ||||
template<typename... T_args> | template<typename... T_args> | ||||
constexpr decltype(auto) context<T_driver, T_schema>::read(T_args&&... args) | constexpr decltype(auto) context<T_driver, T_schema>::read(T_args&&... args) | ||||
{ return __impl::read(*this, std::forward<T_args>(args)...); } | |||||
{ return __impl::read(this->impl(), std::forward<T_args>(args)...); } | |||||
template<typename T_driver, typename T_schema> | template<typename T_driver, typename T_schema> | ||||
template<typename... T_args> | template<typename... T_args> | ||||
constexpr decltype(auto) context<T_driver, T_schema>::update(T_args&&... args) | constexpr decltype(auto) context<T_driver, T_schema>::update(T_args&&... args) | ||||
{ return __impl::update(*this, std::forward<T_args>(args)...); } | |||||
{ return __impl::update(this->impl(), std::forward<T_args>(args)...); } | |||||
template<typename T_driver, typename T_schema> | template<typename T_driver, typename T_schema> | ||||
template<typename... T_args> | template<typename... T_args> | ||||
constexpr decltype(auto) context<T_driver, T_schema>::destroy(T_args&&... args) | constexpr decltype(auto) context<T_driver, T_schema>::destroy(T_args&&... args) | ||||
{ return __impl::destroy(*this, std::forward<T_args>(args)...); } | |||||
{ return __impl::destroy(this->impl(), std::forward<T_args>(args)...); } | |||||
#if 0 | #if 0 | ||||
@@ -1,8 +1,14 @@ | |||||
#pragma once | #pragma once | ||||
#include <cpphibernate/driver/mariadb/driver.h> | |||||
#include <cpphibernate/config.h> | |||||
namespace cpphibernate | |||||
{ | |||||
using mariadb_driver = ::cpphibernate::mariadb::driver_t; | |||||
} | |||||
#ifdef CPPHIBERNATE_HAS_CPPMARIADB | |||||
#include <cpphibernate/driver/mariadb/driver.h> | |||||
namespace cpphibernate | |||||
{ | |||||
using mariadb_driver = ::cpphibernate::mariadb::driver_t; | |||||
} | |||||
#else | |||||
#error "cppmariadb library was not found!" | |||||
#endif |
@@ -6,6 +6,13 @@ | |||||
namespace cpphibernate { | namespace cpphibernate { | ||||
namespace mariadb { | namespace mariadb { | ||||
enum init_stage | |||||
{ | |||||
unknown = 0, | |||||
stage1, | |||||
stage2, | |||||
}; | |||||
enum class attribute_t; | enum class attribute_t; | ||||
struct attributes_t; | struct attributes_t; | ||||
struct field_t; | struct field_t; | ||||
@@ -4,6 +4,7 @@ | |||||
#include "../forward.h" | #include "../forward.h" | ||||
#include "../tables/tables.h" | #include "../tables/tables.h" | ||||
#include "../../context.h" | |||||
namespace cpphibernate { | namespace cpphibernate { | ||||
namespace mariadb { | namespace mariadb { | ||||
@@ -52,6 +53,11 @@ namespace mariadb { | |||||
*/ | */ | ||||
std::ostream& print(std::ostream& os) const; | std::ostream& print(std::ostream& os) const; | ||||
/** | |||||
* @brief Initialize the whole schema using the passed context. | |||||
*/ | |||||
void init(const init_context& context) const; | |||||
private: | private: | ||||
/** | /** | ||||
* @brief Initialize the field. | * @brief Initialize the field. | ||||
@@ -6,6 +6,7 @@ | |||||
#include "../forward.h" | #include "../forward.h" | ||||
#include "../fields/fields.h" | #include "../fields/fields.h" | ||||
#include "../../context.h" | |||||
namespace cpphibernate { | namespace cpphibernate { | ||||
namespace mariadb { | namespace mariadb { | ||||
@@ -87,11 +88,38 @@ namespace mariadb { | |||||
*/ | */ | ||||
std::ostream& print(std::ostream& os) const; | std::ostream& print(std::ostream& os) const; | ||||
/** | |||||
* @brief Initialize the table using the passed context. | |||||
* | |||||
* The initialization is splitted into two stages. In the first stage the | |||||
* table is created. In the second stage the table contraints are added. | |||||
* The first stage must be completed for all tables before stage two of | |||||
* any table is executed. | |||||
*/ | |||||
void init(const init_context& context, init_stage stage) const; | |||||
private: | private: | ||||
/** | /** | ||||
* @brief Initialize the field. | * @brief Initialize the field. | ||||
*/ | */ | ||||
void init(); | void init(); | ||||
private: | |||||
using statement_ptr_u = std::unique_ptr<::cppmariadb::statement>; | |||||
mutable statement_ptr_u _statement_init_stage1; //!< Statement for init stage 1 (create table). | |||||
mutable statement_ptr_u _statement_init_stage2; //!< Statement for init stage 2 (alter table). | |||||
/** | |||||
* @brief Get or create the mariadb statement for init stage 1. | |||||
*/ | |||||
::cppmariadb::statement& get_statement_init_stage1() const; | |||||
/** | |||||
* @brief Get or create the mariadb statement for init stage 2. | |||||
*/ | |||||
::cppmariadb::statement* get_statement_init_stage2() const; | |||||
}; | }; | ||||
namespace __impl | namespace __impl | ||||
@@ -0,0 +1,4 @@ | |||||
#pragma once | |||||
#include "context/base_context.h" | |||||
#include "context/init_context.h" |
@@ -0,0 +1,29 @@ | |||||
#pragma once | |||||
#include <cppmariadb.h> | |||||
#include <cpphibernate/config.h> | |||||
namespace cpphibernate { | |||||
namespace mariadb { | |||||
struct schema_t; | |||||
/** | |||||
* @brief Base class for all mariadb driver context classes. | |||||
*/ | |||||
struct base_context | |||||
{ | |||||
const schema_t& schema; //!< schema to use for the operation | |||||
::cppmariadb::connection& connection; //!< mariadb connection to use for executing queries | |||||
/** | |||||
* @brief Constructor. | |||||
*/ | |||||
inline base_context( | |||||
const schema_t& p_schema, | |||||
::cppmariadb::connection& p_connection); | |||||
}; | |||||
} } | |||||
#include "base_context.inl" |
@@ -0,0 +1,17 @@ | |||||
#pragma once | |||||
#include "base_context.h" | |||||
namespace cpphibernate { | |||||
namespace mariadb { | |||||
/* base_context */ | |||||
base_context::base_context( | |||||
const schema_t& p_schema, | |||||
::cppmariadb::connection& p_connection) | |||||
: schema (p_schema) | |||||
, connection(p_connection) | |||||
{ } | |||||
} } |
@@ -0,0 +1,26 @@ | |||||
#pragma once | |||||
#include <cppmariadb.h> | |||||
#include <cpphibernate/config.h> | |||||
#include "base_context.h" | |||||
namespace cpphibernate { | |||||
namespace mariadb { | |||||
/** | |||||
* @brief Mariadb driver context for initializing the database. | |||||
*/ | |||||
struct init_context | |||||
: public base_context | |||||
{ | |||||
bool recreate; | |||||
inline init_context( | |||||
const schema_t& p_schema, | |||||
::cppmariadb::connection& p_connection, | |||||
bool p_recreate); | |||||
}; | |||||
} } | |||||
#include "init_context.inl" |
@@ -0,0 +1,18 @@ | |||||
#pragma once | |||||
#include "init_context.h" | |||||
namespace cpphibernate { | |||||
namespace mariadb { | |||||
/* init_context */ | |||||
init_context::init_context( | |||||
const schema_t& p_schema, | |||||
::cppmariadb::connection& p_connection, | |||||
bool p_recreate) | |||||
: base_context (p_schema, p_connection) | |||||
, recreate (p_recreate) | |||||
{ } | |||||
} } |
@@ -3,21 +3,22 @@ | |||||
#include <cppmariadb.h> | #include <cppmariadb.h> | ||||
#include "classes.h" | #include "classes.h" | ||||
// #include <cpphibernate/config.h> | |||||
// #include <cpphibernate/driver/mariadb/impl.h> | |||||
// #include <cpphibernate/driver/mariadb/schema.h> | |||||
// #include <cpphibernate/driver/mariadb/schema/filter.h> | |||||
#include "impl/driver_impl.h" | |||||
namespace cpphibernate { | namespace cpphibernate { | ||||
namespace mariadb { | namespace mariadb { | ||||
/** | /** | ||||
* @brief Mariadb driver. | * @brief Mariadb driver. | ||||
* | |||||
* The normal cpphibernate context will be inherited from this class. So all methods | |||||
* defined here will be part of the context class. | |||||
*/ | */ | ||||
struct driver_t | struct driver_t | ||||
{ | { | ||||
private: | private: | ||||
schema_ptr_u _schema; | |||||
driver_impl_t _impl; //!< Driver implementation. | |||||
::cppmariadb::connection * _connection; //!< Mariadb connection to use for queries. | |||||
public: | public: | ||||
/** | /** | ||||
@@ -31,6 +32,23 @@ namespace mariadb { | |||||
*/ | */ | ||||
inline std::ostream& print(std::ostream& os) const; | inline std::ostream& print(std::ostream& os) const; | ||||
/** | |||||
* @brief Get the connection currently assigned to the driver. | |||||
*/ | |||||
inline ::cppmariadb::connection * connection() const; | |||||
/** | |||||
* @brief Set the connection to use for queries. | |||||
* This will invalidate all cached queries and strings. | |||||
*/ | |||||
inline void connection(::cppmariadb::connection * p_connection); | |||||
protected: | |||||
/** | |||||
* @brief Get the imlementation object of the driver. | |||||
*/ | |||||
inline auto& impl() const; | |||||
/* | /* | ||||
public: | public: | ||||
using lock_type = std::unique_ptr<transaction_lock>; | using lock_type = std::unique_ptr<transaction_lock>; | ||||
@@ -1,16 +1,26 @@ | |||||
#pragma once | #pragma once | ||||
#include "driver.h" | #include "driver.h" | ||||
#include "impl/driver_impl.inl" | |||||
namespace cpphibernate { | namespace cpphibernate { | ||||
namespace mariadb { | namespace mariadb { | ||||
template<typename T_schema> | template<typename T_schema> | ||||
driver_t::driver_t(T_schema&& p_schema) | driver_t::driver_t(T_schema&& p_schema) | ||||
: _schema(make_schema(std::forward<T_schema>(p_schema))) | |||||
: _impl(*this, std::forward<T_schema>(p_schema)) | |||||
{ } | { } | ||||
std::ostream& driver_t::print(std::ostream& os) const | std::ostream& driver_t::print(std::ostream& os) const | ||||
{ return _schema->print(os); } | |||||
{ return _impl.schema->print(os); } | |||||
::cppmariadb::connection* driver_t::connection() const | |||||
{ return _connection; } | |||||
void driver_t::connection(::cppmariadb::connection * p_connection) | |||||
{ _connection = p_connection; } | |||||
auto& driver_t::impl() const | |||||
{ return _impl; } | |||||
} } | } } |
@@ -1,7 +1,7 @@ | |||||
#pragma once | #pragma once | ||||
#include "helper/key_properties.h" | |||||
#include "helper/type_properties.h" | #include "helper/type_properties.h" | ||||
#include "helper/key_properties.h" | #include "helper/key_properties.h" | ||||
#include "helper/nullable_helper.h" | |||||
#include "helper/transaction_lock.h" | #include "helper/transaction_lock.h" | ||||
#include "helper/type_properties.h" | #include "helper/type_properties.h" |
@@ -1,93 +0,0 @@ | |||||
#pragma once | |||||
#include <memory> | |||||
#include <iomanip> | |||||
#include <cppmariadb.h> | |||||
#include <cpphibernate/config.h> | |||||
#include <cpputils/misc/type_helper.h> | |||||
beg_namespace_cpphibernate_driver_mariadb | |||||
{ | |||||
struct transaction_lock final | |||||
{ | |||||
public: | |||||
inline transaction_lock(::cppmariadb::connection& con) | |||||
{ begin_transaction(*this, con); } | |||||
inline ~transaction_lock() | |||||
{ close_transaction(*this); } | |||||
inline bool commit() | |||||
{ return commit_transaction(*this); } | |||||
private: | |||||
using transaction_ptr_type = std::unique_ptr<::cppmariadb::transaction>; | |||||
#ifdef CPPHIBERNATE_DEBUG | |||||
# define debug_log(str) cpphibernate_debug_log( \ | |||||
"transaction (id=" << std::setw(8) << std::setfill(' ') << lock.id << \ | |||||
", counter=" << std::setw(2) << std::setfill(' ') << counter << ") " str) | |||||
struct counter { }; | |||||
size_t id { utl::unique_counter<counter>::next() }; | |||||
#else | |||||
# define debug_log(str) do { } while(0) | |||||
#endif | |||||
static size_t& ref_counter() | |||||
{ | |||||
static size_t value = 0; | |||||
return value; | |||||
} | |||||
static transaction_ptr_type& ref_transaction_ptr() | |||||
{ | |||||
static transaction_ptr_type value; | |||||
return value; | |||||
} | |||||
static void begin_transaction(const transaction_lock& lock, ::cppmariadb::connection& con) | |||||
{ | |||||
auto& counter = ref_counter(); | |||||
++counter; | |||||
debug_log("+++"); | |||||
if (counter == 1) | |||||
{ | |||||
debug_log("begin"); | |||||
ref_transaction_ptr().reset(new ::cppmariadb::transaction(con)); | |||||
} | |||||
} | |||||
static bool commit_transaction(const transaction_lock& lock) | |||||
{ | |||||
auto& counter = ref_counter(); | |||||
if (counter == 1) | |||||
{ | |||||
debug_log("commit"); | |||||
ref_transaction_ptr()->commit(); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
static void close_transaction(const transaction_lock& lock) | |||||
{ | |||||
auto& counter = ref_counter(); | |||||
debug_log("---"); | |||||
if (counter <= 1) | |||||
{ | |||||
debug_log("close"); | |||||
counter = 0; | |||||
ref_transaction_ptr().reset(); | |||||
} | |||||
else | |||||
{ | |||||
--counter; | |||||
} | |||||
} | |||||
}; | |||||
#undef debug_log | |||||
} | |||||
end_namespace_cpphibernate_driver_mariadb |
@@ -1,32 +1,43 @@ | |||||
#pragma once | #pragma once | ||||
#include <cppmariadb.h> | #include <cppmariadb.h> | ||||
#include <cpphibernate/misc.h> | |||||
#include <cpphibernate/config.h> | #include <cpphibernate/config.h> | ||||
#include <cpphibernate/driver/mariadb/schema/field.fwd.h> | |||||
#include <cpphibernate/driver/mariadb/schema/table.fwd.h> | |||||
#include <cpphibernate/driver/mariadb/schema/filter.fwd.h> | |||||
#include <cpphibernate/driver/mariadb/schema/schema.fwd.h> | |||||
#include "../classes.h" | |||||
beg_namespace_cpphibernate_driver_mariadb | |||||
{ | |||||
/* base_context */ | |||||
namespace cpphibernate { | |||||
namespace mariadb { | |||||
/** | |||||
* @brief Base class for all mariadb driver context classes. | |||||
*/ | |||||
struct base_context | struct base_context | ||||
{ | { | ||||
const schema_t& schema; | |||||
::cppmariadb::connection& connection; | |||||
const schema_t& schema; //!< schema to use for the operation | |||||
::cppmariadb::connection& connection; //!< mariadb connection to use for executing queries | |||||
/** | |||||
* @brief Constructor. | |||||
*/ | |||||
inline base_context( | inline base_context( | ||||
const schema_t& p_schema, | |||||
::cppmariadb::connection& p_connection) | |||||
: schema (p_schema) | |||||
, connection(p_connection) | |||||
{ } | |||||
const schema_t& p_schema, | |||||
::cppmariadb::connection& p_connection); | |||||
}; | }; | ||||
/** | |||||
* @brief Mariadb driver context for initializing the database. | |||||
*/ | |||||
struct init_context | |||||
: public base_context | |||||
{ | |||||
bool recreate; | |||||
inline init_context( | |||||
const schema_t& p_schema, | |||||
::cppmariadb::connection& p_connection, | |||||
bool p_recreate); | |||||
}; | |||||
#if 0 | |||||
/* init_context */ | /* init_context */ | ||||
struct init_context | struct init_context | ||||
@@ -213,6 +224,5 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
p_connection) | p_connection) | ||||
{ } | { } | ||||
}; | }; | ||||
} | |||||
end_namespace_cpphibernate_driver_mariadb | |||||
#endif | |||||
} } |
@@ -1,10 +1,22 @@ | |||||
#pragma once | #pragma once | ||||
#include <cpphibernate/driver/mariadb/helper/context.h> | |||||
#include "context.h" | |||||
beg_namespace_cpphibernate_driver_mariadb | |||||
{ | |||||
namespace cpphibernate { | |||||
namespace mariadb { | |||||
/* base_context */ | |||||
base_context::base_context( | |||||
const schema_t& p_schema, | |||||
::cppmariadb::connection& p_connection) | |||||
: schema (p_schema) | |||||
, connection(p_connection) | |||||
{ } | |||||
#if 0 | |||||
/* data_context */ | /* data_context */ | ||||
template<typename T_dataset> | template<typename T_dataset> | ||||
@@ -86,6 +98,5 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
ptr.release(); | ptr.release(); | ||||
return *static_cast<dataset_type*>(data); | return *static_cast<dataset_type*>(data); | ||||
} | } | ||||
} | |||||
end_namespace_cpphibernate_driver_mariadb | |||||
#endif | |||||
} } |
@@ -0,0 +1,99 @@ | |||||
#pragma once | |||||
#include <cppmariadb.h> | |||||
#include "../classes.h" | |||||
namespace cpphibernate { | |||||
namespace mariadb { | |||||
struct driver_t; | |||||
/** | |||||
* @brief Actual implementation of the mariadb driver. | |||||
* | |||||
* This class is used/owner by the mariadb driver class (as a member). | |||||
* The public interface of this class will not be part of the cpphibernate context. | |||||
*/ | |||||
struct driver_impl_t | |||||
{ | |||||
driver_t& owner; | |||||
schema_ptr_u schema; | |||||
/** | |||||
* @brief Constructor. | |||||
* @param[in] p_owner Object the driver implementation is owned by. | |||||
* @param[in] p_schema Cpphibernate schema to use with the driver. | |||||
*/ | |||||
template<typename T_schema> | |||||
inline driver_impl_t(driver_t& p_owner, T_schema&& p_schema); | |||||
/** | |||||
* @brief Initialize the schema in the database. | |||||
* | |||||
* @param[in] recreate Recreate the whole schema (this will drop all existing data). | |||||
*/ | |||||
inline void init(bool recreate) const; | |||||
/* | |||||
} | |||||
protected: | |||||
inline void init_impl(bool recreate) const | |||||
{ | |||||
transaction_lock trans(*_connection); | |||||
_schema.init(init_context(_schema, *_connection, recreate)); | |||||
trans.commit(); | |||||
} | |||||
template<typename T_dataset> | |||||
inline void create_impl(T_dataset& dataset) const | |||||
{ | |||||
create_update_impl_t<T_dataset>::apply( | |||||
create_update_context(dataset, _schema, *_connection, _filter, false)); | |||||
} | |||||
template<typename T_dataset, typename T_modifiers> | |||||
inline void read_impl(T_dataset& dataset, T_modifiers&& modifiers) const | |||||
{ | |||||
using dataset_type = mp::decay_t<T_dataset>; | |||||
using real_dataset_type = misc::real_dataset_t<dataset_type>; | |||||
auto dataset_id = misc::get_type_id(hana::type_c<real_dataset_type>); | |||||
auto& table = _schema.table(dataset_id); | |||||
auto context = make_read_context(dataset, _schema, *_connection, _filter); | |||||
context.where = build_where(_schema, modifiers).query(*_connection); | |||||
context.limit = build_limit(modifiers).query(*_connection); | |||||
context.order_by = build_order_by(_schema, modifiers).query(*_connection); | |||||
transaction_lock trans(*_connection); | |||||
table.read(context); | |||||
trans.commit(); | |||||
} | |||||
template<typename T_dataset> | |||||
inline void update_impl(T_dataset& dataset) const | |||||
{ | |||||
create_update_impl_t<T_dataset>::apply( | |||||
create_update_context(dataset, _schema, *_connection, _filter, true)); | |||||
} | |||||
template<typename T_dataset> | |||||
inline void destroy_impl(T_dataset& dataset) const | |||||
{ | |||||
using dataset_type = mp::decay_t<T_dataset>; | |||||
using real_dataset_type = misc::real_dataset_t<dataset_type>; | |||||
auto dataset_id = misc::get_type_id(hana::type_c<real_dataset_type>); | |||||
auto& table = _schema.table(dataset_id); | |||||
destroy_context context(dataset, _schema, *_connection); | |||||
context.where = table.get_where_primary_key(context); | |||||
destroy_impl_t<T_dataset>::apply(context); | |||||
} | |||||
*/ | |||||
}; | |||||
} } |
@@ -0,0 +1,27 @@ | |||||
#pragma once | |||||
#include "driver_impl.h" | |||||
#include "../driver.h" | |||||
namespace cpphibernate { | |||||
namespace mariadb { | |||||
/* driver_impl_t */ | |||||
template<typename T_schema> | |||||
driver_impl_t::driver_impl_t(driver_t& p_owner, T_schema&& p_schema) | |||||
: owner (p_owner) | |||||
, schema(make_schema(std::forward<T_schema>(p_schema))) | |||||
{ } | |||||
void driver_impl_t::init(bool recreate) const | |||||
{ | |||||
auto * connection = owner.connection(); | |||||
if (!connection) | |||||
throw exception("Cpphibernate mariadb driver is not connected to any database!"); | |||||
::cppmariadb::transaction_lock trans(*connection); | |||||
schema->init(init_context(*schema, *connection, recreate)); | |||||
trans.commit(); | |||||
} | |||||
} } |
@@ -6,6 +6,7 @@ | |||||
#include <vector> | #include <vector> | ||||
#include <memory> | #include <memory> | ||||
#include <cppcore/misc/type_helper.h> | |||||
#include <cppcore/misc/nullable.h> | #include <cppcore/misc/nullable.h> | ||||
#include <cpphibernate/config.h> | #include <cpphibernate/config.h> | ||||
@@ -11,11 +11,20 @@ Find_Package ( cppmariadb REQUIRED ) | |||||
If ( cppmariadb_FOUND ) | If ( cppmariadb_FOUND ) | ||||
Set ( CPPHIBERNATE_HAS_CPPMARIADB true ) | Set ( CPPHIBERNATE_HAS_CPPMARIADB true ) | ||||
EndIf ( ) | EndIf ( ) | ||||
If ( CPPHIBERNATE_USE_CPPLOGGING ) | |||||
Find_Package ( cpplogging ) | |||||
If ( cpplogging_FOUND ) | |||||
Set ( CPPHIBERNATE_HAS_CPPLOGGING true ) | |||||
EndIf ( ) | |||||
EndIf ( ) | |||||
# Object Library ################################################################################## | # Object Library ################################################################################## | ||||
Set ( CMAKE_POSITION_INDEPENDENT_CODE ON ) | Set ( CMAKE_POSITION_INDEPENDENT_CODE ON ) | ||||
Set ( CPPHIBERNATE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) | Set ( CPPHIBERNATE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) | ||||
Set ( CPPHIBERNATE_GENERATED_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated/include ) | |||||
Configure_File ( ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/config.h.in | |||||
${CPPHIBERNATE_GENERATED_INCLUDE_DIR}/cpphibernate/config.h ) | |||||
File ( GLOB_RECURSE CPPHIBERNATE_HEADER_FILES ${CPPHIBERNATE_INCLUDE_DIR}/*.h ) | File ( GLOB_RECURSE CPPHIBERNATE_HEADER_FILES ${CPPHIBERNATE_INCLUDE_DIR}/*.h ) | ||||
File ( GLOB_RECURSE CPPHIBERNATE_INLINE_FILES ${CPPHIBERNATE_INCLUDE_DIR}/*.inl ) | File ( GLOB_RECURSE CPPHIBERNATE_INLINE_FILES ${CPPHIBERNATE_INCLUDE_DIR}/*.inl ) | ||||
File ( GLOB_RECURSE CPPHIBERNATE_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) | File ( GLOB_RECURSE CPPHIBERNATE_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) | ||||
@@ -27,6 +36,7 @@ Add_Library ( cpphibernate-objects | |||||
Target_Include_Directories ( cpphibernate-objects | Target_Include_Directories ( cpphibernate-objects | ||||
PUBLIC | PUBLIC | ||||
$<BUILD_INTERFACE:${CPPHIBERNATE_INCLUDE_DIR}> | $<BUILD_INTERFACE:${CPPHIBERNATE_INCLUDE_DIR}> | ||||
$<BUILD_INTERFACE:${CPPHIBERNATE_GENERATED_INCLUDE_DIR}> | |||||
$<INSTALL_INTERFACE:${CPPHIBERNATE_INSTALL_DIR_INCLUDE}> ) | $<INSTALL_INTERFACE:${CPPHIBERNATE_INSTALL_DIR_INCLUDE}> ) | ||||
Target_Link_Libraries ( cpphibernate-objects | Target_Link_Libraries ( cpphibernate-objects | ||||
PUBLIC | PUBLIC | ||||
@@ -38,6 +48,11 @@ If ( CPPHIBERNATE_HAS_CPPMARIADB ) | |||||
PUBLIC | PUBLIC | ||||
cppmariadb::cppmariadb-shared ) | cppmariadb::cppmariadb-shared ) | ||||
EndIf ( ) | EndIf ( ) | ||||
If ( CPPHIBERNATE_HAS_CPPLOGGING ) | |||||
Target_Link_Libraries ( cpphibernate-objects | |||||
PUBLIC | |||||
cpplogging::cpplogging-shared ) | |||||
EndIf ( ) | |||||
# Static Library ################################################################################## | # Static Library ################################################################################## | ||||
@@ -49,12 +64,18 @@ Set_Target_Properties ( cpphibernate-static | |||||
Target_Include_Directories ( cpphibernate-static | Target_Include_Directories ( cpphibernate-static | ||||
PUBLIC | PUBLIC | ||||
$<BUILD_INTERFACE:${CPPHIBERNATE_INCLUDE_DIR}> | $<BUILD_INTERFACE:${CPPHIBERNATE_INCLUDE_DIR}> | ||||
$<BUILD_INTERFACE:${CPPHIBERNATE_GENERATED_INCLUDE_DIR}> | |||||
$<INSTALL_INTERFACE:${CPPHIBERNATE_INSTALL_DIR_INCLUDE}> ) | $<INSTALL_INTERFACE:${CPPHIBERNATE_INSTALL_DIR_INCLUDE}> ) | ||||
If ( CPPHIBERNATE_HAS_CPPMARIADB ) | If ( CPPHIBERNATE_HAS_CPPMARIADB ) | ||||
Target_Link_Libraries ( cpphibernate-static | Target_Link_Libraries ( cpphibernate-static | ||||
PUBLIC | PUBLIC | ||||
cppmariadb::cppmariadb-static ) | cppmariadb::cppmariadb-static ) | ||||
EndIf ( ) | EndIf ( ) | ||||
If ( CPPHIBERNATE_HAS_CPPLOGGING ) | |||||
Target_Link_Libraries ( cpphibernate-objects | |||||
PUBLIC | |||||
cpplogging::cpplogging-static ) | |||||
EndIf ( ) | |||||
# Shared Library ################################################################################## | # Shared Library ################################################################################## | ||||
@@ -67,12 +88,18 @@ Set_Target_Properties ( cpphibernate-shared | |||||
Target_Include_Directories ( cpphibernate-shared | Target_Include_Directories ( cpphibernate-shared | ||||
PUBLIC | PUBLIC | ||||
$<BUILD_INTERFACE:${CPPHIBERNATE_INCLUDE_DIR}> | $<BUILD_INTERFACE:${CPPHIBERNATE_INCLUDE_DIR}> | ||||
$<BUILD_INTERFACE:${CPPHIBERNATE_GENERATED_INCLUDE_DIR}> | |||||
$<INSTALL_INTERFACE:${CPPHIBERNATE_INSTALL_DIR_INCLUDE}> ) | $<INSTALL_INTERFACE:${CPPHIBERNATE_INSTALL_DIR_INCLUDE}> ) | ||||
If ( CPPHIBERNATE_HAS_CPPMARIADB ) | If ( CPPHIBERNATE_HAS_CPPMARIADB ) | ||||
Target_Link_Libraries ( cpphibernate-shared | Target_Link_Libraries ( cpphibernate-shared | ||||
PUBLIC | PUBLIC | ||||
cppmariadb::cppmariadb-shared ) | cppmariadb::cppmariadb-shared ) | ||||
EndIf ( ) | EndIf ( ) | ||||
If ( CPPHIBERNATE_HAS_CPPLOGGING ) | |||||
Target_Link_Libraries ( cpphibernate-objects | |||||
PUBLIC | |||||
cpplogging::cpplogging-shared ) | |||||
EndIf ( ) | |||||
# Optimization #################################################################################### | # Optimization #################################################################################### | ||||
@@ -0,0 +1,89 @@ | |||||
#include <cpphibernate/driver/mariadb/classes/schema/schema.h> | |||||
using namespace ::cpphibernate; | |||||
using namespace ::cpphibernate::mariadb; | |||||
#define exec_query() \ | |||||
do { \ | |||||
connection.execute(ss.str()); \ | |||||
ss.str(std::string()); \ | |||||
ss.clear(); \ | |||||
} while(0) | |||||
void schema_t::init(const init_context& context) const | |||||
{ | |||||
std::ostringstream ss; | |||||
auto& connection = context.connection; | |||||
if (context.recreate) | |||||
{ | |||||
ss << "DROP DATABASE IF EXISTS `" | |||||
<< name | |||||
<< "`"; | |||||
exec_query(); | |||||
} | |||||
/* create schema */ | |||||
ss << "CREATE SCHEMA IF NOT EXISTS `" | |||||
<< name | |||||
<< "` DEFAULT CHARACTER SET utf8"; | |||||
exec_query(); | |||||
/* use schema */ | |||||
ss << "USE `" | |||||
<< name | |||||
<< "`"; | |||||
exec_query(); | |||||
/* UuidToBin */ | |||||
ss << "CREATE FUNCTION IF NOT EXISTS UuidToBin(_uuid CHAR(36))\n" | |||||
" RETURNS BINARY(16)\n" | |||||
" LANGUAGE SQL\n" | |||||
" DETERMINISTIC\n" | |||||
" CONTAINS SQL\n" | |||||
" SQL SECURITY INVOKER\n" | |||||
"RETURN\n" | |||||
" UNHEX(CONCAT(\n" | |||||
" SUBSTR(_uuid, 25, 12),\n" // node id | |||||
" SUBSTR(_uuid, 20, 4),\n" // clock sequence | |||||
" SUBSTR(_uuid, 15, 4),\n" // time high and version | |||||
" SUBSTR(_uuid, 10, 4),\n" // time mid | |||||
" SUBSTR(_uuid, 1, 8)\n" // time low | |||||
" )\n" | |||||
")"; | |||||
exec_query(); | |||||
/* BinToUuid */ | |||||
ss << "CREATE FUNCTION IF NOT EXISTS BinToUuid(_bin BINARY(16))\n" | |||||
" RETURNS CHAR(36)\n" | |||||
" LANGUAGE SQL\n" | |||||
" DETERMINISTIC\n" | |||||
" CONTAINS SQL\n" | |||||
" SQL SECURITY INVOKER\n" | |||||
"RETURN\n" | |||||
" IF(\n" | |||||
" _bin IS NULL,\n" | |||||
" NULL,\n" | |||||
" LCASE(CONCAT_WS('-',\n" | |||||
" HEX(SUBSTR(_bin, 13, 4)),\n" // time low | |||||
" HEX(SUBSTR(_bin, 11, 2)),\n" // time mid | |||||
" HEX(SUBSTR(_bin, 9, 2)),\n" // time high and version | |||||
" HEX(SUBSTR(_bin, 7, 2)),\n" // clock sequence | |||||
" HEX(SUBSTR(_bin, 1, 6))\n" // node id | |||||
" )\n" | |||||
" )\n" | |||||
")"; | |||||
exec_query(); | |||||
/* initialize tables */ | |||||
for (auto& table : tables) | |||||
{ | |||||
assert(static_cast<bool>(table)); | |||||
table->init(context, init_stage::stage1); | |||||
} | |||||
for (auto& table : tables) | |||||
{ | |||||
assert(static_cast<bool>(table)); | |||||
table->init(context, init_stage::stage2); | |||||
} | |||||
} |
@@ -0,0 +1,413 @@ | |||||
#include <cppcore/misc/indent.h> | |||||
#include <cpphibernate/driver/mariadb/classes/tables/table.h> | |||||
#include <cpphibernate/driver/mariadb/classes/schema/schema.h> | |||||
using namespace ::cpphibernate; | |||||
using namespace ::cpphibernate::mariadb; | |||||
void table_t::init(const init_context& context, init_stage stage) const | |||||
{ | |||||
switch (stage) | |||||
{ | |||||
case init_stage::stage1: | |||||
{ | |||||
auto& statement = get_statement_init_stage1(); | |||||
auto& connection = context.connection; | |||||
cpphibernate_log_debug("execute CREATE TABLE query: " << statement.query(connection)); | |||||
connection.execute(statement); | |||||
} | |||||
break; | |||||
case init_stage::stage2: | |||||
{ | |||||
auto* statement = get_statement_init_stage2(); | |||||
auto& connection = context.connection; | |||||
if (!statement) | |||||
return; | |||||
cpphibernate_log_debug("execute ALTER TABLE query: " << statement->query(connection)); | |||||
connection.execute(*statement); | |||||
} | |||||
break; | |||||
case init_stage::unknown: | |||||
throw exception("Unkown or invalid init stage!"); | |||||
break; | |||||
} | |||||
} | |||||
::cppmariadb::statement& table_t::get_statement_init_stage1() const | |||||
{ | |||||
using namespace ::cppcore; | |||||
if (_statement_init_stage1) | |||||
return *_statement_init_stage1; | |||||
std::ostringstream os; | |||||
/* CREATE TABLE */ | |||||
os << "CREATE TABLE IF NOT EXISTS `" | |||||
<< name | |||||
<< "`" | |||||
<< indent | |||||
<< "(" | |||||
<< incindent; | |||||
/* primary key */ | |||||
{ | |||||
assert(primary_key_field); | |||||
auto& key_info = *primary_key_field; | |||||
auto args = key_info.create_arguments; | |||||
os << indent | |||||
<< "`" | |||||
<< key_info.name | |||||
<< "` " | |||||
<< key_info.type | |||||
<< " NOT NULL" | |||||
<< (args.empty() ? "" : " ") | |||||
<< args | |||||
<< ","; | |||||
} | |||||
/* base table key fields */ | |||||
if (static_cast<bool>(base_table)) | |||||
{ | |||||
auto& base_table_info = *base_table; | |||||
assert(base_table_info.primary_key_field); | |||||
auto& key_info = *base_table_info.primary_key_field; | |||||
os << indent | |||||
<< "`" | |||||
<< key_info.name | |||||
<< "` " | |||||
<< key_info.type | |||||
<< " NOT NULL,"; | |||||
} | |||||
/* foreign table one fields */ | |||||
for (auto& ptr : foreign_table_one_fields) | |||||
{ | |||||
assert(static_cast<bool>(ptr)); | |||||
auto& field_info = *ptr; | |||||
assert(field_info.referenced_table); | |||||
auto& referenced_table = *field_info.referenced_table; | |||||
if (referenced_table.is_used_in_container) | |||||
continue; | |||||
assert(referenced_table.primary_key_field); | |||||
auto& ref_key_info = *referenced_table.primary_key_field; | |||||
os << indent | |||||
<< "`" | |||||
<< ref_key_info.table.name | |||||
<< "_id_" | |||||
<< field_info.name | |||||
<< "` " | |||||
<< ref_key_info.type | |||||
<< (field_info.value_is_nullable | |||||
? " NULL DEFAULT NULL," | |||||
: " NOT NULL,"); | |||||
} | |||||
/* foreign fields */ | |||||
for (auto& ptr : foreign_key_fields) | |||||
{ | |||||
assert(static_cast<bool>(ptr)); | |||||
auto& field_info = *ptr; | |||||
assert(field_info.table.primary_key_field); | |||||
auto& ref_key_info = *field_info.table.primary_key_field; | |||||
os << indent | |||||
<< "`" | |||||
<< field_info.table.name | |||||
<< "_id_" | |||||
<< field_info.name | |||||
<< "` " | |||||
<< ref_key_info.type | |||||
<< " NULL DEFAULT NULL,"; | |||||
if (field_info.value_is_ordered) | |||||
{ | |||||
os << indent | |||||
<< "`" | |||||
<< field_info.table.name | |||||
<< "_index_" | |||||
<< field_info.name | |||||
<< "` INT UNSIGNED NOT NULL,"; | |||||
} | |||||
} | |||||
/* data fields */ | |||||
for (auto& ptr : data_fields) | |||||
{ | |||||
assert(static_cast<bool>(ptr)); | |||||
auto& field_info = *ptr; | |||||
os << indent | |||||
<< "`" | |||||
<< field_info.name | |||||
<< "` " | |||||
<< field_info.type | |||||
<< (field_info.value_is_nullable | |||||
? " NULL DEFAULT NULL," | |||||
: " NOT NULL,"); | |||||
} | |||||
/* type field for derived tables */ | |||||
if (!derived_tables.empty() && | |||||
!base_table) | |||||
{ | |||||
os << indent | |||||
<< "`__type` INT UNSIGNED NOT NULL,"; | |||||
} | |||||
/* PRIMARY KEY */ | |||||
{ | |||||
assert(primary_key_field); | |||||
auto& key_info = *primary_key_field; | |||||
os << indent | |||||
<< "PRIMARY KEY ( `" | |||||
<< key_info.name | |||||
<< "` )"; | |||||
} | |||||
/* UNIQUE INDEX primary key */ | |||||
{ | |||||
assert(primary_key_field); | |||||
auto& key_info = *primary_key_field; | |||||
os << ',' | |||||
<< indent | |||||
<< "UNIQUE INDEX `index_" | |||||
<< key_info.name | |||||
<< "` ( `" | |||||
<< key_info.name | |||||
<< "` ASC )"; | |||||
} | |||||
/* UNIQUE INDEX base table keys */ | |||||
if (base_table) | |||||
{ | |||||
auto& table_info = *base_table; | |||||
assert(table_info.primary_key_field); | |||||
auto& key_info = *table_info.primary_key_field; | |||||
os << ',' | |||||
<< indent | |||||
<< "UNIQUE INDEX `index_" | |||||
<< key_info.name | |||||
<< "` ( `" | |||||
<< key_info.name | |||||
<< "` ASC )"; | |||||
} | |||||
/* INDEX foreign table one fields */ | |||||
for (auto& ptr : foreign_table_one_fields) | |||||
{ | |||||
assert(static_cast<bool>(ptr)); | |||||
auto& field_info = *ptr; | |||||
assert(field_info.referenced_table); | |||||
auto& referenced_table = *field_info.referenced_table; | |||||
if (referenced_table.is_used_in_container) | |||||
continue; | |||||
assert(referenced_table.primary_key_field); | |||||
auto& ref_key_info = *referenced_table.primary_key_field; | |||||
os << "," | |||||
<< indent | |||||
<< "INDEX `index_" | |||||
<< ref_key_info.table.name | |||||
<< "_id_" | |||||
<< field_info.name | |||||
<< "` ( `" | |||||
<< ref_key_info.table.name | |||||
<< "_id_" | |||||
<< field_info.name | |||||
<< "` ASC )"; | |||||
} | |||||
/* INDEX foreign fields */ | |||||
for (auto& ptr : foreign_key_fields) | |||||
{ | |||||
assert(static_cast<bool>(ptr)); | |||||
auto& field_info = *ptr; | |||||
os << "," | |||||
<< indent | |||||
<< "INDEX `index_" | |||||
<< field_info.table.name | |||||
<< "_id_" | |||||
<< field_info.name | |||||
<< "` ( `" | |||||
<< field_info.table.name | |||||
<< "_id_" | |||||
<< field_info.name | |||||
<< "` ASC )"; | |||||
} | |||||
/* CREATE TABLE end */ | |||||
os << decindent | |||||
<< indent | |||||
<< ")" | |||||
<< indent | |||||
<< "ENGINE = InnoDB" | |||||
<< indent | |||||
<< "DEFAULT CHARACTER SET = utf8"; | |||||
_statement_init_stage1.reset(new ::cppmariadb::statement(os.str())); | |||||
return *_statement_init_stage1; | |||||
} | |||||
::cppmariadb::statement* table_t::get_statement_init_stage2() const | |||||
{ | |||||
using namespace ::cppcore; | |||||
if (_statement_init_stage2) | |||||
return _statement_init_stage2->empty() | |||||
? nullptr | |||||
: _statement_init_stage2.get(); | |||||
std::ostringstream os; | |||||
/* ALTER TABLE */ | |||||
os << "ALTER TABLE `" | |||||
<< name | |||||
<< "`" | |||||
<< incindent; | |||||
size_t index = 0; | |||||
/* CONSTRAINT base table */ | |||||
if (base_table) | |||||
{ | |||||
assert(base_table->primary_key_field); | |||||
auto& ref_key_info = *base_table->primary_key_field; | |||||
if (index++) os << ","; | |||||
os << indent | |||||
<< "ADD CONSTRAINT `fk_" | |||||
<< name | |||||
<< "_" | |||||
<< ref_key_info.name | |||||
<< "`" | |||||
<< incindent | |||||
<< indent | |||||
<< "FOREIGN KEY IF NOT EXISTS (`" | |||||
<< ref_key_info.name | |||||
<< "`)" | |||||
<< indent | |||||
<< "REFERENCES `" | |||||
<< ref_key_info.table.schema.name | |||||
<< "`.`" | |||||
<< ref_key_info.table.name | |||||
<< "` (`" | |||||
<< ref_key_info.name | |||||
<< "`)" | |||||
<< indent | |||||
<< "ON DELETE CASCADE" | |||||
<< indent | |||||
<< "ON UPDATE CASCADE" | |||||
<< decindent; | |||||
} | |||||
/* CONSTRAINT foreign table one fields */ | |||||
for (auto& ptr : foreign_table_one_fields) | |||||
{ | |||||
assert(static_cast<bool>(ptr)); | |||||
auto& field_info = *ptr; | |||||
assert(field_info.referenced_table); | |||||
auto& referenced_table = *field_info.referenced_table; | |||||
if (referenced_table.is_used_in_container) | |||||
continue; | |||||
assert(referenced_table.primary_key_field); | |||||
auto& ref_key_info = *referenced_table.primary_key_field; | |||||
if (index++) os << ","; | |||||
os << indent | |||||
<< "ADD CONSTRAINT `fk_" | |||||
<< name | |||||
<< "_" | |||||
<< ref_key_info.table.name | |||||
<< "_" | |||||
<< field_info.name | |||||
<< "`" | |||||
<< incindent | |||||
<< indent | |||||
<< "FOREIGN KEY IF NOT EXISTS (`" | |||||
<< ref_key_info.table.name | |||||
<< "_id_" | |||||
<< field_info.name | |||||
<< "`)" | |||||
<< indent | |||||
<< "REFERENCES `" | |||||
<< ref_key_info.table.schema.name | |||||
<< "`.`" | |||||
<< ref_key_info.table.name | |||||
<< "` (`" | |||||
<< ref_key_info.name | |||||
<< "`)" | |||||
<< indent; | |||||
if (field_info.value_is_nullable) | |||||
os << "ON DELETE SET NULL"; | |||||
else | |||||
os << "ON DELETE CASCADE"; | |||||
os << indent | |||||
<< "ON UPDATE NO ACTION" | |||||
<< decindent; | |||||
} | |||||
/* CONSTRAINT foreign fields */ | |||||
for (auto& ptr : foreign_key_fields) | |||||
{ | |||||
assert(static_cast<bool>(ptr)); | |||||
auto& field_info = *ptr; | |||||
assert(field_info.table.primary_key_field); | |||||
auto& ref_key_info = *field_info.table.primary_key_field; | |||||
if (index++) os << ","; | |||||
os << indent | |||||
<< "ADD CONSTRAINT `fk_" | |||||
<< name | |||||
<< "_" | |||||
<< field_info.table.name | |||||
<< "_" | |||||
<< field_info.name | |||||
<< "`" | |||||
<< incindent | |||||
<< indent | |||||
<< "FOREIGN KEY IF NOT EXISTS (`" | |||||
<< field_info.table.name | |||||
<< "_id_" | |||||
<< field_info.name | |||||
<< "`)" | |||||
<< indent | |||||
<< "REFERENCES `" | |||||
<< ref_key_info.table.schema.name | |||||
<< "`.`" | |||||
<< ref_key_info.table.name | |||||
<< "` (`" | |||||
<< ref_key_info.name | |||||
<< "`)" | |||||
<< indent | |||||
<< "ON DELETE SET NULL" | |||||
<< indent | |||||
<< "ON UPDATE NO ACTION" | |||||
<< decindent; | |||||
} | |||||
_statement_init_stage2.reset(new ::cppmariadb::statement(index == 0 | |||||
? std::string { } | |||||
: os.str())); | |||||
return _statement_init_stage2->empty() | |||||
? nullptr | |||||
: _statement_init_stage2.get(); | |||||
} |
@@ -11,7 +11,6 @@ namespace hana = ::boost::hana; | |||||
TEST(CppHibernateTests, init) | TEST(CppHibernateTests, init) | ||||
{ | { | ||||
/* | |||||
StrictMock<mariadb_mock> mock; | StrictMock<mariadb_mock> mock; | ||||
expect_query(mock, "START TRANSACTION"); | expect_query(mock, "START TRANSACTION"); | ||||
@@ -178,7 +177,7 @@ TEST(CppHibernateTests, init) | |||||
expect_query(mock, "CREATE TABLE IF NOT EXISTS `tbl_double_usage_item`\n" | expect_query(mock, "CREATE TABLE IF NOT EXISTS `tbl_double_usage_item`\n" | ||||
"(\n" | "(\n" | ||||
" `tbl_double_usage_item_id` INT UNSIGNED NOT NULL,\n" | |||||
" `tbl_double_usage_item_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,\n" | |||||
" `tbl_double_usage_id_single_item` INT NULL DEFAULT NULL,\n" | " `tbl_double_usage_id_single_item` INT NULL DEFAULT NULL,\n" | ||||
" `tbl_double_usage_id_multiple_items` INT NULL DEFAULT NULL,\n" | " `tbl_double_usage_id_multiple_items` INT NULL DEFAULT NULL,\n" | ||||
" `tbl_double_usage_index_multiple_items` INT UNSIGNED NOT NULL,\n" | " `tbl_double_usage_index_multiple_items` INT UNSIGNED NOT NULL,\n" | ||||
@@ -193,7 +192,7 @@ TEST(CppHibernateTests, init) | |||||
expect_query(mock, "CREATE TABLE IF NOT EXISTS `tbl_double_usage`\n" | expect_query(mock, "CREATE TABLE IF NOT EXISTS `tbl_double_usage`\n" | ||||
"(\n" | "(\n" | ||||
" `tbl_double_usage_id` INT NOT NULL,\n" | |||||
" `tbl_double_usage_id` INT NOT NULL AUTO_INCREMENT,\n" | |||||
" PRIMARY KEY ( `tbl_double_usage_id` ),\n" | " PRIMARY KEY ( `tbl_double_usage_id` ),\n" | ||||
" UNIQUE INDEX `index_tbl_double_usage_id` ( `tbl_double_usage_id` ASC )\n" | " UNIQUE INDEX `index_tbl_double_usage_id` ( `tbl_double_usage_id` ASC )\n" | ||||
")\n" | ")\n" | ||||
@@ -202,7 +201,7 @@ TEST(CppHibernateTests, init) | |||||
expect_query(mock, "CREATE TABLE IF NOT EXISTS `tbl_double_usage_wrapper`\n" | expect_query(mock, "CREATE TABLE IF NOT EXISTS `tbl_double_usage_wrapper`\n" | ||||
"(\n" | "(\n" | ||||
" `tbl_double_usage_wrapper_id` INT NOT NULL,\n" | |||||
" `tbl_double_usage_wrapper_id` INT NOT NULL AUTO_INCREMENT,\n" | |||||
" `tbl_double_usage_id_double_usage` INT NULL DEFAULT NULL,\n" | " `tbl_double_usage_id_double_usage` INT NULL DEFAULT NULL,\n" | ||||
" PRIMARY KEY ( `tbl_double_usage_wrapper_id` ),\n" | " PRIMARY KEY ( `tbl_double_usage_wrapper_id` ),\n" | ||||
" UNIQUE INDEX `index_tbl_double_usage_wrapper_id` ( `tbl_double_usage_wrapper_id` ASC ),\n" | " UNIQUE INDEX `index_tbl_double_usage_wrapper_id` ( `tbl_double_usage_wrapper_id` ASC ),\n" | ||||
@@ -296,11 +295,9 @@ TEST(CppHibernateTests, init) | |||||
mock, | mock, | ||||
mysql_close( | mysql_close( | ||||
reinterpret_cast<MYSQL*>(0x1111))); | reinterpret_cast<MYSQL*>(0x1111))); | ||||
*/ | |||||
::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111)); | ::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111)); | ||||
auto context = make_context<mariadb_driver>(test_schema); | auto context = make_context<mariadb_driver>(test_schema); | ||||
(void)context; | |||||
context.print(std::cout) << std::endl << std::endl; | |||||
// context.init(true); | |||||
context.connection(&connection); | |||||
context.init(true); | |||||
} | } |