Browse Source

* Refactored mariadb driver init operation

refactoring
bergmann 4 years ago
parent
commit
da248fdcc7
36 changed files with 942 additions and 162 deletions
  1. +34
    -0
      cmake/config.h.in
  2. +6
    -0
      cmake/cpphibernate-options.cmake
  3. +0
    -12
      include/cpphibernate/config.h
  4. +12
    -10
      include/cpphibernate/context/context.inl
  5. +11
    -5
      include/cpphibernate/driver/mariadb.h
  6. +7
    -0
      include/cpphibernate/driver/mariadb/classes/forward.h
  7. +6
    -0
      include/cpphibernate/driver/mariadb/classes/schema/schema.h
  8. +28
    -0
      include/cpphibernate/driver/mariadb/classes/tables/table.h
  9. +4
    -0
      include/cpphibernate/driver/mariadb/context.h
  10. +29
    -0
      include/cpphibernate/driver/mariadb/context/base_context.h
  11. +17
    -0
      include/cpphibernate/driver/mariadb/context/base_context.inl
  12. +26
    -0
      include/cpphibernate/driver/mariadb/context/init_context.h
  13. +18
    -0
      include/cpphibernate/driver/mariadb/context/init_context.inl
  14. +23
    -5
      include/cpphibernate/driver/mariadb/driver.h
  15. +12
    -2
      include/cpphibernate/driver/mariadb/driver.inl
  16. +1
    -1
      include/cpphibernate/driver/mariadb/helper.h
  17. +0
    -93
      include/cpphibernate/driver/mariadb/helper/transaction_lock.h
  18. +0
    -0
      include/cpphibernate/driver/mariadb/impl/_create_update.h
  19. +0
    -0
      include/cpphibernate/driver/mariadb/impl/_destroy.h
  20. +0
    -0
      include/cpphibernate/driver/mariadb/impl/_limit.h
  21. +0
    -0
      include/cpphibernate/driver/mariadb/impl/_modifier_tags.h
  22. +0
    -0
      include/cpphibernate/driver/mariadb/impl/_order_by.h
  23. +0
    -0
      include/cpphibernate/driver/mariadb/impl/_read.h
  24. +0
    -0
      include/cpphibernate/driver/mariadb/impl/_where.h
  25. +29
    -19
      include/cpphibernate/driver/mariadb/impl/context.h
  26. +17
    -6
      include/cpphibernate/driver/mariadb/impl/context.inl
  27. +99
    -0
      include/cpphibernate/driver/mariadb/impl/driver_impl.h
  28. +27
    -0
      include/cpphibernate/driver/mariadb/impl/driver_impl.inl
  29. +1
    -0
      include/cpphibernate/misc/type_helper.inl
  30. +27
    -0
      src/CMakeLists.txt
  31. +0
    -0
      src/cpphibernate/driver/mariadb/classes/fields/misc.cpp
  32. +89
    -0
      src/cpphibernate/driver/mariadb/classes/schema/init.cpp
  33. +0
    -0
      src/cpphibernate/driver/mariadb/classes/schema/misc.cpp
  34. +413
    -0
      src/cpphibernate/driver/mariadb/classes/tables/init.cpp
  35. +0
    -0
      src/cpphibernate/driver/mariadb/classes/tables/misc.cpp
  36. +6
    -9
      test/cpphibernate/cpphibernate_init.cpp

+ 34
- 0
cmake/config.h.in View File

@@ -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

+ 6
- 0
cmake/cpphibernate-options.cmake View File

@@ -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
"Install headers of cpphibernate."
ON )
@@ -13,3 +16,6 @@ Option ( CPPHIBERNATE_INSTALL_DEBUG
Option ( CPPHIBERNATE_NO_STRIP
"Do not strip debug symbols from binary."
OFF )
Option ( CPPHIBERNATE_DEBUG
"Write extra debug output to the console/logger."
OFF )

+ 0
- 12
include/cpphibernate/config.h View File

@@ -1,12 +0,0 @@
#pragma once

#include <cppmp.h>
#include <boost/hana.hpp>

namespace cpphibernate
{

namespace mp = ::cppmp;
namespace hana = ::boost::hana;

}

+ 12
- 10
include/cpphibernate/context/context.inl View File

@@ -18,15 +18,17 @@ namespace cpphibernate
{ 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)
{ return impl.init(recreate); }
};
#endif

constexpr decltype(auto) init = mp::generic_predicate<init_builder> { };

/* create_builder */

template<typename X, typename = void>
@@ -120,27 +122,27 @@ namespace cpphibernate
template<typename T_driver, typename T_schema>
template<typename... T_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_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_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_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_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


+ 11
- 5
include/cpphibernate/driver/mariadb.h View File

@@ -1,8 +1,14 @@
#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

+ 7
- 0
include/cpphibernate/driver/mariadb/classes/forward.h View File

@@ -6,6 +6,13 @@
namespace cpphibernate {
namespace mariadb {

enum init_stage
{
unknown = 0,
stage1,
stage2,
};

enum class attribute_t;
struct attributes_t;
struct field_t;


+ 6
- 0
include/cpphibernate/driver/mariadb/classes/schema/schema.h View File

@@ -4,6 +4,7 @@

#include "../forward.h"
#include "../tables/tables.h"
#include "../../context.h"

namespace cpphibernate {
namespace mariadb {
@@ -52,6 +53,11 @@ namespace mariadb {
*/
std::ostream& print(std::ostream& os) const;

/**
* @brief Initialize the whole schema using the passed context.
*/
void init(const init_context& context) const;

private:
/**
* @brief Initialize the field.


+ 28
- 0
include/cpphibernate/driver/mariadb/classes/tables/table.h View File

@@ -6,6 +6,7 @@

#include "../forward.h"
#include "../fields/fields.h"
#include "../../context.h"

namespace cpphibernate {
namespace mariadb {
@@ -87,11 +88,38 @@ namespace mariadb {
*/
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:

/**
* @brief Initialize the field.
*/
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


+ 4
- 0
include/cpphibernate/driver/mariadb/context.h View File

@@ -0,0 +1,4 @@
#pragma once

#include "context/base_context.h"
#include "context/init_context.h"

+ 29
- 0
include/cpphibernate/driver/mariadb/context/base_context.h View File

@@ -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"

+ 17
- 0
include/cpphibernate/driver/mariadb/context/base_context.inl View File

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

} }

+ 26
- 0
include/cpphibernate/driver/mariadb/context/init_context.h View File

@@ -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"

+ 18
- 0
include/cpphibernate/driver/mariadb/context/init_context.inl View File

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

} }

+ 23
- 5
include/cpphibernate/driver/mariadb/driver.h View File

@@ -3,21 +3,22 @@
#include <cppmariadb.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 mariadb {

/**
* @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
{
private:
schema_ptr_u _schema;
driver_impl_t _impl; //!< Driver implementation.
::cppmariadb::connection * _connection; //!< Mariadb connection to use for queries.

public:
/**
@@ -31,6 +32,23 @@ namespace mariadb {
*/
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:
using lock_type = std::unique_ptr<transaction_lock>;


+ 12
- 2
include/cpphibernate/driver/mariadb/driver.inl View File

@@ -1,16 +1,26 @@
#pragma once

#include "driver.h"
#include "impl/driver_impl.inl"

namespace cpphibernate {
namespace mariadb {

template<typename T_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
{ 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
- 1
include/cpphibernate/driver/mariadb/helper.h View File

@@ -1,7 +1,7 @@
#pragma once

#include "helper/key_properties.h"
#include "helper/type_properties.h"
#include "helper/key_properties.h"
#include "helper/nullable_helper.h"
#include "helper/transaction_lock.h"
#include "helper/type_properties.h"

+ 0
- 93
include/cpphibernate/driver/mariadb/helper/transaction_lock.h View File

@@ -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

include/cpphibernate/driver/mariadb/impl/create_update.h → include/cpphibernate/driver/mariadb/impl/_create_update.h View File


include/cpphibernate/driver/mariadb/impl/destroy.h → include/cpphibernate/driver/mariadb/impl/_destroy.h View File


include/cpphibernate/driver/mariadb/impl/limit.h → include/cpphibernate/driver/mariadb/impl/_limit.h View File


include/cpphibernate/driver/mariadb/impl/modifier_tags.h → include/cpphibernate/driver/mariadb/impl/_modifier_tags.h View File


include/cpphibernate/driver/mariadb/impl/order_by.h → include/cpphibernate/driver/mariadb/impl/_order_by.h View File


include/cpphibernate/driver/mariadb/impl/read.h → include/cpphibernate/driver/mariadb/impl/_read.h View File


include/cpphibernate/driver/mariadb/impl/where.h → include/cpphibernate/driver/mariadb/impl/_where.h View File


include/cpphibernate/driver/mariadb/helper/context.h → include/cpphibernate/driver/mariadb/impl/context.h View File

@@ -1,32 +1,43 @@
#pragma once

#include <cppmariadb.h>
#include <cpphibernate/misc.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
{
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(
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 */

struct init_context
@@ -213,6 +224,5 @@ beg_namespace_cpphibernate_driver_mariadb
p_connection)
{ }
};

}
end_namespace_cpphibernate_driver_mariadb
#endif
} }

include/cpphibernate/driver/mariadb/helper/context.inl → include/cpphibernate/driver/mariadb/impl/context.inl View File

@@ -1,10 +1,22 @@
#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 */

template<typename T_dataset>
@@ -86,6 +98,5 @@ beg_namespace_cpphibernate_driver_mariadb
ptr.release();
return *static_cast<dataset_type*>(data);
}

}
end_namespace_cpphibernate_driver_mariadb
#endif
} }

+ 99
- 0
include/cpphibernate/driver/mariadb/impl/driver_impl.h View File

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

} }

+ 27
- 0
include/cpphibernate/driver/mariadb/impl/driver_impl.inl View File

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

} }

+ 1
- 0
include/cpphibernate/misc/type_helper.inl View File

@@ -6,6 +6,7 @@
#include <vector>
#include <memory>

#include <cppcore/misc/type_helper.h>
#include <cppcore/misc/nullable.h>
#include <cpphibernate/config.h>



+ 27
- 0
src/CMakeLists.txt View File

@@ -11,11 +11,20 @@ Find_Package ( cppmariadb REQUIRED )
If ( cppmariadb_FOUND )
Set ( CPPHIBERNATE_HAS_CPPMARIADB true )
EndIf ( )
If ( CPPHIBERNATE_USE_CPPLOGGING )
Find_Package ( cpplogging )
If ( cpplogging_FOUND )
Set ( CPPHIBERNATE_HAS_CPPLOGGING true )
EndIf ( )
EndIf ( )

# Object Library ##################################################################################

Set ( CMAKE_POSITION_INDEPENDENT_CODE ON )
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_INLINE_FILES ${CPPHIBERNATE_INCLUDE_DIR}/*.inl )
File ( GLOB_RECURSE CPPHIBERNATE_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp )
@@ -27,6 +36,7 @@ Add_Library ( cpphibernate-objects
Target_Include_Directories ( cpphibernate-objects
PUBLIC
$<BUILD_INTERFACE:${CPPHIBERNATE_INCLUDE_DIR}>
$<BUILD_INTERFACE:${CPPHIBERNATE_GENERATED_INCLUDE_DIR}>
$<INSTALL_INTERFACE:${CPPHIBERNATE_INSTALL_DIR_INCLUDE}> )
Target_Link_Libraries ( cpphibernate-objects
PUBLIC
@@ -38,6 +48,11 @@ If ( CPPHIBERNATE_HAS_CPPMARIADB )
PUBLIC
cppmariadb::cppmariadb-shared )
EndIf ( )
If ( CPPHIBERNATE_HAS_CPPLOGGING )
Target_Link_Libraries ( cpphibernate-objects
PUBLIC
cpplogging::cpplogging-shared )
EndIf ( )

# Static Library ##################################################################################

@@ -49,12 +64,18 @@ Set_Target_Properties ( cpphibernate-static
Target_Include_Directories ( cpphibernate-static
PUBLIC
$<BUILD_INTERFACE:${CPPHIBERNATE_INCLUDE_DIR}>
$<BUILD_INTERFACE:${CPPHIBERNATE_GENERATED_INCLUDE_DIR}>
$<INSTALL_INTERFACE:${CPPHIBERNATE_INSTALL_DIR_INCLUDE}> )
If ( CPPHIBERNATE_HAS_CPPMARIADB )
Target_Link_Libraries ( cpphibernate-static
PUBLIC
cppmariadb::cppmariadb-static )
EndIf ( )
If ( CPPHIBERNATE_HAS_CPPLOGGING )
Target_Link_Libraries ( cpphibernate-objects
PUBLIC
cpplogging::cpplogging-static )
EndIf ( )

# Shared Library ##################################################################################

@@ -67,12 +88,18 @@ Set_Target_Properties ( cpphibernate-shared
Target_Include_Directories ( cpphibernate-shared
PUBLIC
$<BUILD_INTERFACE:${CPPHIBERNATE_INCLUDE_DIR}>
$<BUILD_INTERFACE:${CPPHIBERNATE_GENERATED_INCLUDE_DIR}>
$<INSTALL_INTERFACE:${CPPHIBERNATE_INSTALL_DIR_INCLUDE}> )
If ( CPPHIBERNATE_HAS_CPPMARIADB )
Target_Link_Libraries ( cpphibernate-shared
PUBLIC
cppmariadb::cppmariadb-shared )
EndIf ( )
If ( CPPHIBERNATE_HAS_CPPLOGGING )
Target_Link_Libraries ( cpphibernate-objects
PUBLIC
cpplogging::cpplogging-shared )
EndIf ( )

# Optimization ####################################################################################



src/cpphibernate/driver/mariadb/classes/fields/field.cpp → src/cpphibernate/driver/mariadb/classes/fields/misc.cpp View File


+ 89
- 0
src/cpphibernate/driver/mariadb/classes/schema/init.cpp View File

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

src/cpphibernate/driver/mariadb/classes/schema/schema.cpp → src/cpphibernate/driver/mariadb/classes/schema/misc.cpp View File


+ 413
- 0
src/cpphibernate/driver/mariadb/classes/tables/init.cpp View File

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

src/cpphibernate/driver/mariadb/classes/tables/table.cpp → src/cpphibernate/driver/mariadb/classes/tables/misc.cpp View File


+ 6
- 9
test/cpphibernate/cpphibernate_init.cpp View File

@@ -11,7 +11,6 @@ namespace hana = ::boost::hana;

TEST(CppHibernateTests, init)
{
/*
StrictMock<mariadb_mock> mock;

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"
"(\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_multiple_items` INT NULL DEFAULT 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"
"(\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"
" UNIQUE INDEX `index_tbl_double_usage_id` ( `tbl_double_usage_id` ASC )\n"
")\n"
@@ -202,7 +201,7 @@ TEST(CppHibernateTests, init)

expect_query(mock, "CREATE TABLE IF NOT EXISTS `tbl_double_usage_wrapper`\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"
" PRIMARY KEY ( `tbl_double_usage_wrapper_id` ),\n"
" UNIQUE INDEX `index_tbl_double_usage_wrapper_id` ( `tbl_double_usage_wrapper_id` ASC ),\n"
@@ -296,11 +295,9 @@ TEST(CppHibernateTests, init)
mock,
mysql_close(
reinterpret_cast<MYSQL*>(0x1111)));
*/
::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
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);
}

Loading…
Cancel
Save