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