Browse Source

* implemented update methods for mariadb driver

master
bergmann 5 years ago
parent
commit
2d7489241d
9 changed files with 808 additions and 26 deletions
  1. +1
    -1
      include/cpphibernate/driver/mariadb/impl/create_update.h
  2. +8
    -0
      include/cpphibernate/driver/mariadb/impl/read.h
  3. +7
    -0
      include/cpphibernate/driver/mariadb/mariadb.h
  4. +23
    -0
      include/cpphibernate/driver/mariadb/schema/field.h
  5. +15
    -0
      include/cpphibernate/driver/mariadb/schema/field.inl
  6. +7
    -3
      include/cpphibernate/driver/mariadb/schema/table.h
  7. +113
    -1
      src/driver/mariadb/schema/field.cpp
  8. +109
    -21
      src/driver/mariadb/schema/table.cpp
  9. +525
    -0
      test/cpphibernate_update.cpp

+ 1
- 1
include/cpphibernate/driver/mariadb/impl/create_update.h View File

@@ -32,7 +32,7 @@ beg_namespace_cpphibernate_driver_mariadb
if (!strict)
{
auto update_context = context;
update_context.is_update = true;
update_context.is_update = !update_context.is_update;
ret = table.create_update(update_context);
}
else if (context.is_update)


+ 8
- 0
include/cpphibernate/driver/mariadb/impl/read.h View File

@@ -12,6 +12,8 @@ beg_namespace_cpphibernate_driver_mariadb
namespace __impl
{

/* declaration */

template<typename T, typename = void>
struct make_read_context_impl
{
@@ -20,6 +22,8 @@ beg_namespace_cpphibernate_driver_mariadb
{ static_assert(sizeof...(args) == -1, "Invalid parameters for mariadb::make_read_context(...)!"); }
};

/* normal datasets */

template<typename T_dataset, typename... T_args>
struct make_read_context_impl<
mp::list<T_dataset, T_args...>,
@@ -69,6 +73,8 @@ beg_namespace_cpphibernate_driver_mariadb
{ return context_impl(dataset, std::forward<T_args>(args)...); }
};

/* nullable datasets */

template<typename T_dataset, typename... T_args>
struct make_read_context_impl<
mp::list<T_dataset, T_args...>,
@@ -131,6 +137,8 @@ beg_namespace_cpphibernate_driver_mariadb
{ return context_impl(dataset, std::forward<T_args>(args)...); }
};

/* container datasets */

template<typename T_dataset, typename... T_args>
struct make_read_context_impl<
mp::list<T_dataset, T_args...>,


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

@@ -58,6 +58,13 @@ beg_namespace_cpphibernate_driver_mariadb
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));
}
};

}

+ 23
- 0
include/cpphibernate/driver/mariadb/schema/field.h View File

@@ -17,6 +17,7 @@ beg_namespace_cpphibernate_driver_mariadb

struct field_t
{
public:
size_t id { 0 }; // unique id of the field
size_t dataset_id { 0 }; // unique id of the dataset type
size_t real_dataset_id { 0 }; // unique id of the real/unwrapped dataset type
@@ -86,6 +87,16 @@ beg_namespace_cpphibernate_driver_mariadb
virtual void set (const data_context& context, const value_t&) const;
virtual bool is_default (const data_context& context) const;
virtual std::string generate_value (::cppmariadb::connection& connection) const;

/* statements */
virtual ::cppmariadb::statement& get_statement_foreign_one_delete(bool key_known) const;
virtual ::cppmariadb::statement& get_statement_foreign_many_update() const;

protected:
using statement_ptr = std::unique_ptr<::cppmariadb::statement>;

::cppmariadb::statement& get_statement_foreign_one_delete_impl(bool key_known, statement_ptr& known, statement_ptr& unknown) const;
::cppmariadb::statement& get_statement_foreign_many_update_impl(statement_ptr& statement) const;
};

/* simple_field_t */
@@ -181,8 +192,20 @@ beg_namespace_cpphibernate_driver_mariadb
using base_type::base_type;

public:
/* CRUD */
virtual value_t foreign_create_update(const create_update_context& context) const override;
virtual read_context_ptr foreign_read (const read_context& context, bool fake_context) const override;

/* statements */
virtual ::cppmariadb::statement& get_statement_foreign_one_delete(bool key_known) const override;
virtual ::cppmariadb::statement& get_statement_foreign_many_update() const override;

private:
using statement_ptr = std::unique_ptr<::cppmariadb::statement>;

mutable statement_ptr _statement_foreign_one_delete_key_known;
mutable statement_ptr _statement_foreign_one_delete_key_unknown;
mutable statement_ptr _statement_foreign_many_update;
};

}

+ 15
- 0
include/cpphibernate/driver/mariadb/schema/field.inl View File

@@ -108,6 +108,21 @@ beg_namespace_cpphibernate_driver_mariadb
}
}

template<typename T_field>
::cppmariadb::statement& foreign_table_field_t<T_field>
::get_statement_foreign_one_delete(bool key_known) const
{
return base_type::get_statement_foreign_one_delete_impl(
key_known,
_statement_foreign_one_delete_key_known,
_statement_foreign_one_delete_key_unknown);
}

template<typename T_field>
::cppmariadb::statement& foreign_table_field_t<T_field>
::get_statement_foreign_many_update() const
{ return base_type::get_statement_foreign_many_update_impl(_statement_foreign_many_update); }

namespace __impl
{



+ 7
- 3
include/cpphibernate/driver/mariadb/schema/table.h View File

@@ -90,23 +90,27 @@ beg_namespace_cpphibernate_driver_mariadb
friend struct table_polymorphic_t;

using statement_ptr = std::unique_ptr<::cppmariadb::statement>;
using statement_map = std::map<size_t, ::cppmariadb::statement>;
using map_key = std::tuple<size_t, const field_t*>;
using statement_map = std::map<map_key, ::cppmariadb::statement>;

mutable statement_ptr _statement_create_table;
mutable statement_ptr _statement_alter_table;
mutable statement_ptr _statement_insert_into;
mutable statement_map _statement_select_static;
mutable statement_map _statement_select_dynamic;
mutable statement_map _statement_update;
mutable statement_ptr _statement_foreign_many_delete;

::cppmariadb::statement& get_statement_create_table() const;
::cppmariadb::statement* get_statement_alter_table() const;
::cppmariadb::statement& get_statement_insert_into() const;
::cppmariadb::statement& get_statement_select(const read_context& context) const;
::cppmariadb::statement& get_statement_update(const filter_t& filter, const field_t* owner) const;
::cppmariadb::statement& get_statement_foreign_many_delete() const;

std::string execute_create_update(
const create_update_context& context,
::cppmariadb::statement& statement,
const filter_t* filter) const;
::cppmariadb::statement& statement) const;

virtual std::string create_update_base(const create_update_context& context) const;



+ 113
- 1
src/driver/mariadb/schema/field.cpp View File

@@ -158,4 +158,116 @@ throw_not_implemented(read_context_ptr, foreign_read, const read_contex
throw_not_implemented(bool, is_default, const data_context& context)
throw_not_implemented(string, generate_value, ::cppmariadb::connection&)
throw_not_implemented(value_t, get, const data_context& context)
throw_not_implemented(void, set, const data_context& context, const value_t&)
throw_not_implemented(void, set, const data_context& context, const value_t&)

/* statements */

throw_not_implemented(::cppmariadb::statement&, get_statement_foreign_one_delete, bool)
throw_not_implemented(::cppmariadb::statement&, get_statement_foreign_many_update)

::cppmariadb::statement& field_t::get_statement_foreign_one_delete_impl(bool key_known, statement_ptr& known, statement_ptr& unknown) const
{
assert(table);
assert(table->primary_key_field);
assert(referenced_table);
assert(referenced_table->primary_key_field);

if (key_known)
{
if (!known)
{
auto& key_info = *table->primary_key_field;
auto& ref_key_info = *referenced_table->primary_key_field;

std::ostringstream os;
os << "DELETE FROM `"
<< ref_key_info.table_name
<< "` WHERE `"
<< ref_key_info.field_name
<< "` IN (SELECT `"
<< ref_key_info.table_name
<< "_id_"
<< field_name
<< "` FROM `"
<< key_info.table_name
<< "` WHERE `"
<< key_info.field_name
<< "`="
<< key_info.convert_to_open
<< "?\?"
<< key_info.convert_to_close
<< " AND `"
<< ref_key_info.table_name
<< "_id_"
<< field_name
<< "`!= "
<< ref_key_info.convert_to_open
<< "?\?"
<< ref_key_info.convert_to_close
<< ")";
known.reset(new ::cppmariadb::statement(os.str()));
}
return *known;
}
else
{
if (!unknown)
{
auto& key_info = *table->primary_key_field;
auto& ref_key_info = *referenced_table->primary_key_field;

std::ostringstream os;
os << "DELETE FROM `"
<< ref_key_info.table_name
<< "` WHERE `"
<< ref_key_info.field_name
<< "` IN (SELECT `"
<< ref_key_info.table_name
<< "_id_"
<< field_name
<< "` FROM `"
<< key_info.table_name
<< "` WHERE `"
<< key_info.field_name
<< "`="
<< key_info.convert_to_open
<< "?\?"
<< key_info.convert_to_close
<< ")";
unknown.reset(new ::cppmariadb::statement(os.str()));
}
return *unknown;
}
}

::cppmariadb::statement& field_t::get_statement_foreign_many_update_impl(statement_ptr& statement) const
{
assert(referenced_table);
assert(referenced_table->primary_key_field);
if (!statement)
{
auto& ref_key_info = *referenced_table->primary_key_field;

std::ostringstream os;
os << "UPDATE `"
<< ref_key_info.table_name
<< "` SET `"
<< ref_key_info.table_name
<< "_id_"
<< field_name
<< "`=NULL, `"
<< ref_key_info.table_name
<< "_index_"
<< field_name
<< "`=0 WHERE `"
<< ref_key_info.table_name
<< "_id_"
<< field_name
<< "`="
<< ref_key_info.convert_to_open
<< "?\?"
<< ref_key_info.convert_to_close;
statement.reset(new ::cppmariadb::statement(os.str()));
}
return *statement;
}

+ 109
- 21
src/driver/mariadb/schema/table.cpp View File

@@ -910,8 +910,9 @@ std::string build_create_update_query(const table_t& table, const filter_t* filt
}

/* type field for derived tables */
if (!table.derived_tables.empty() &&
!table.base_table)
if ( !table.derived_tables.empty()
&& !table.base_table
&& !is_update)
{
if (index++)
os << ", ";
@@ -948,13 +949,13 @@ std::string build_select_query(

std::string table_t::execute_create_update(
const create_update_context& context,
::cppmariadb::statement& statement,
const filter_t* filter) const
::cppmariadb::statement& statement) const
{
auto& connection = context.connection;
auto& filter = context.filter;

size_t index = 0;
bool is_update = static_cast<bool>(filter);
bool is_update = context.is_update;

std::string primary_key;
statement.clear();
@@ -976,7 +977,7 @@ std::string table_t::execute_create_update(
/* base_key */
if ( base_table
&& ( !is_update
|| !filter->is_excluded(*base_table)))
|| !filter.is_excluded(*base_table)))
{
auto new_context = context;
if (!new_context.derived_table)
@@ -986,19 +987,37 @@ std::string table_t::execute_create_update(
++index;
}

if (is_update && filter->is_excluded(*this))
if (is_update && filter.is_excluded(*this))
return primary_key;

/* foreign table one fields */
for (auto& ptr : foreign_table_one_fields)
{
assert(ptr);
if (is_update && filter->is_excluded(*ptr))
auto& field = *ptr;
if (is_update && filter.is_excluded(field))
continue;
value_t key = ptr->foreign_create_update(context);
if (key.has_value()) statement.set(index, std::move(key));
else statement.set_null(index);

/* insert/update dataset */
value_t key = field.foreign_create_update(context);
if (key.has_value())
statement.set(index, std::move(key));
else if (field.value_is_nullable)
statement.set_null(index);
else
throw misc::hibernate_exception("Received null key for non nullable foreign dataset!");
++index;

/* cleanup old dataset (if new one was created) */
if (context.is_update)
{
auto& delete_statement = field.get_statement_foreign_one_delete(key.has_value());
delete_statement.set(0, primary_key);
if (key.has_value())
delete_statement.set(1, *key);
cpphibernate_debug_log("execute DELETE old foreign one query: " << delete_statement.query(connection));
connection.execute(delete_statement);
}
}

/* foreign fields */
@@ -1036,7 +1055,7 @@ std::string table_t::execute_create_update(
for (auto& ptr : data_fields)
{
assert(ptr);
if (is_update && filter->is_excluded(*ptr))
if (is_update && filter.is_excluded(*ptr))
continue;

auto& field_info = *ptr;
@@ -1048,8 +1067,9 @@ std::string table_t::execute_create_update(
}

/* type field for derived tables */
if (!derived_tables.empty() &&
!base_table)
if ( !derived_tables.empty()
&& !base_table
&& !is_update)
{
statement.set(index, context.derived_table
? context.derived_table->table_id
@@ -1084,6 +1104,8 @@ std::string table_t::execute_create_update(
else
{
auto count = connection.execute_rows(statement);
if (count != 1)
throw misc::hibernate_exception("Expected exaclty one row to be inserted/updated!");
cpphibernate_debug_log(count << " rows inserted/updated");
}
primary_key_field->set(context, primary_key);
@@ -1092,16 +1114,39 @@ std::string table_t::execute_create_update(
for (auto& ptr : foreign_table_many_fields)
{
assert(ptr);
assert(ptr->referenced_table);

auto& field = *ptr;
auto& ref_table = *field.referenced_table;

if ( is_update
&& ( filter->is_excluded(*ptr)
|| filter->is_excluded(*ptr->referenced_table)))
&& ( filter.is_excluded(field)
|| filter.is_excluded(ref_table)))
continue;

/* set foreign keys of existing elements to null */
if (context.is_update)
{
auto& update_statement = field.get_statement_foreign_many_update();
update_statement.set(0, primary_key);
cpphibernate_debug_log("execute UPDATE old foreign many query: " << update_statement.query(connection));
connection.execute(update_statement);
}

/* update elements */
auto next_context = context;
next_context.owner_field = ptr;
next_context.owner_key = primary_key;
next_context.derived_table = nullptr;
ptr->foreign_create_update(next_context);
field.foreign_create_update(next_context);

/* delete non referenced elements */
if (context.is_update)
{
auto& delete_statement = ref_table.get_statement_foreign_many_delete();
cpphibernate_debug_log("execute DELETE old foreign many query: " << delete_statement.query(connection));
connection.execute(delete_statement);
}
}

return primary_key;
@@ -1210,15 +1255,56 @@ void table_t::emplace(const read_context& context) const
auto& map = context.is_dynamic
? _statement_select_dynamic
: _statement_select_static;
auto it = map.find(context.filter.cache_id);
auto key = std::make_tuple(context.filter.cache_id, static_cast<const field_t*>(nullptr));
auto it = map.find(key);
if (it == map.end())
{
auto query = build_select_query(*this, context.filter, context.is_dynamic);
it = map.emplace(context.filter.cache_id, ::cppmariadb::statement(query)).first;
it = map.emplace(key, ::cppmariadb::statement(query)).first;
}
return it->second;
}

::cppmariadb::statement& table_t::get_statement_update(const filter_t& filter, const field_t* owner) const
{
auto key = std::make_tuple(filter.cache_id, owner);
auto it = _statement_update.find(key);
if (it == _statement_update.end())
{
auto query = build_create_update_query(*this, &filter, owner);
it = _statement_update.emplace(key, ::cppmariadb::statement(query)).first;
}
return it->second;
}

::cppmariadb::statement& table_t::get_statement_foreign_many_delete() const
{
if (!_statement_foreign_many_delete)
{
std::ostringstream os;
os << "DELETE FROM `"
<< table_name
<< "` WHERE";
auto first = true;
for (auto ptr : foreign_key_fields)
{
assert(ptr);
auto& field = *ptr;
if (first)
first = false;
else
os << " AND";
os << " (`"
<< field.table_name
<< "_id_"
<< field.field_name
<< "` IS NULL)";
}
_statement_foreign_many_delete.reset(new ::cppmariadb::statement(os.str()));
}
return *_statement_foreign_many_delete;
}

std::string table_t::create_update_base(const create_update_context& context) const
{
throw misc::hibernate_exception(static_cast<std::ostringstream&>(std::ostringstream { }
@@ -1244,8 +1330,10 @@ void table_t::init_stage2_exec(const init_context& context) const

std::string table_t::create_update_exec(const create_update_context& context) const
{
auto& statement = get_statement_insert_into();
return execute_create_update(context, statement, nullptr);
auto& statement = context.is_update
? get_statement_update(context.filter, context.owner_field)
: get_statement_insert_into();
return execute_create_update(context, statement);
}

std::string table_t::create_update_intern(const create_update_context& context) const


+ 525
- 0
test/cpphibernate_update.cpp View File

@@ -0,0 +1,525 @@
#include <cpphibernate/driver/mariadb.h>

#include "test_helper.h"
#include "test_schema.h"
#include "mariadb_mock.h"

using namespace ::testing;
using namespace ::cpphibernate;

TEST(CppHibernateTests, update_test1)
{
StrictMock<mariadb_mock> mock;

expect_query(mock, "START TRANSACTION");
expect_query(mock, "UPDATE "
"`tbl_test1` "
"SET "
"`str_data`='Xstr_data of class `test1` object `t1`X', "
"`str64_data`='Xstr64_data of class `test1` object `t1`X', "
"`u32_nullable`=null, "
"`u32_ptr_u`='X456X', "
"`u32_ptr_s`='X789X' "
"WHERE "
"`tbl_test1_id`=UuidToBin('X3d12697a-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "COMMIT");

EXPECT_CALL(
mock,
mysql_real_escape_string(reinterpret_cast<MYSQL*>(0x1111), _, _, _))
.Times(AnyNumber())
.WillRepeatedly(WithArgs<1, 2, 3>(EscapeString()));

EXPECT_CALL(
mock,
mysql_close(
reinterpret_cast<MYSQL*>(0x1111)));

test1 t1;
t1.id = uuid("3d12697a-abb9-11e8-98d0-529269fb1459");
t1.str_data = "str_data of class `test1` object `t1`";
t1.str64_data = "str64_data of class `test1` object `t1`";
t1.u32_ptr_u = std::make_unique<uint32_t>(456);
t1.u32_ptr_s = std::make_shared<uint32_t>(789);

::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
auto context = make_context<driver::mariadb>(test_schema, connection);
context.update(t1);
}

TEST(CppHibernateTests, update_test2)
{
StrictMock<mariadb_mock> mock;

expect_query(mock, "START TRANSACTION");
expect_query(mock, "UPDATE "
"`tbl_test2` "
"SET "
"`u8_data`='X1X', "
"`i8_data`='X2X', "
"`u16_data`='X3X', "
"`i16_data`='X4X' "
"WHERE "
"`tbl_test2_id`=UuidToBin('X3d1270dc-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "COMMIT");

EXPECT_CALL(
mock,
mysql_real_escape_string(reinterpret_cast<MYSQL*>(0x1111), _, _, _))
.Times(AnyNumber())
.WillRepeatedly(WithArgs<1, 2, 3>(EscapeString()));

EXPECT_CALL(
mock,
mysql_close(
reinterpret_cast<MYSQL*>(0x1111)));

test2 t2;
t2.id = uuid("3d1270dc-abb9-11e8-98d0-529269fb1459");
t2.u8_data = 1;
t2.i8_data = 2;
t2.u16_data = 3;
t2.i16_data = 4;

::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
auto context = make_context<driver::mariadb>(test_schema, connection);
context.update(t2);
}

TEST(CppHibernateTests, update_test3)
{
StrictMock<mariadb_mock> mock;

expect_query(mock, "START TRANSACTION");
expect_query(mock, "UPDATE "
"`tbl_test3` "
"SET "
"`u32_data`='X5X', "
"`i32_data`='X6X', "
"`u64_data`='X7X', "
"`i64_data`='X8X' "
"WHERE "
"`tbl_test3_id`=UuidToBin('X3d12737a-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "COMMIT");

EXPECT_CALL(
mock,
mysql_real_escape_string(reinterpret_cast<MYSQL*>(0x1111), _, _, _))
.Times(AnyNumber())
.WillRepeatedly(WithArgs<1, 2, 3>(EscapeString()));

EXPECT_CALL(
mock,
mysql_close(
reinterpret_cast<MYSQL*>(0x1111)));

test3 t3;
t3.id = uuid("3d12737a-abb9-11e8-98d0-529269fb1459");
t3.u32_data = 5;
t3.i32_data = 6;
t3.u64_data = 7;
t3.i64_data = 8;

::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
auto context = make_context<driver::mariadb>(test_schema, connection);
context.update(t3);
}

TEST(CppHibernateTests, update_derived1)
{
StrictMock<mariadb_mock> mock;

expect_query(mock, "START TRANSACTION");
expect_query(mock, "UPDATE "
"`tbl_base` "
"SET "
"`name`='Xderived1X' "
"WHERE "
"`tbl_base_id`=UuidToBin('X3d12778a-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "SELECT Uuid()", result_used({
{ "e2488a64-b843-11e8-96f8-529269fb1459" }
}));
expect_query(mock, "INSERT INTO "
"`tbl_test1` "
"SET "
"`tbl_test1_id`=UuidToBin('Xe2488a64-b843-11e8-96f8-529269fb1459X'), "
"`str_data`='Xstr_data of class `test1` object `d1.test1_data`X', "
"`str64_data`='Xstr64_data of class `test1` object `d1.test1_data`X', "
"`u32_nullable`='X32X', "
"`u32_ptr_u`=null, "
"`u32_ptr_s`='X789X'",
result_affected_rows(1));
expect_query(mock, "DELETE FROM "
"`tbl_test1` "
"WHERE "
"`tbl_test1_id` IN ("
"SELECT "
"`tbl_test1_id_test1_data` "
"FROM "
"`tbl_derived1` "
"WHERE "
"`tbl_derived1_id`=UuidToBin('X3d12758c-abb9-11e8-98d0-529269fb1459X') AND "
"`tbl_test1_id_test1_data`!= UuidToBin('Xe2488a64-b843-11e8-96f8-529269fb1459X')"
")");
expect_query(mock, "UPDATE "
"`tbl_derived1` "
"SET "
"`tbl_base_id`=UuidToBin('X3d12778a-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_test1_id_test1_data`=UuidToBin('Xe2488a64-b843-11e8-96f8-529269fb1459X'), "
"`enum_data`='Xtest2X' "
"WHERE "
"`tbl_derived1_id`=UuidToBin('X3d12758c-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "COMMIT");

EXPECT_CALL(
mock,
mysql_real_escape_string(reinterpret_cast<MYSQL*>(0x1111), _, _, _))
.Times(AnyNumber())
.WillRepeatedly(WithArgs<1, 2, 3>(EscapeString()));

EXPECT_CALL(
mock,
mysql_close(
reinterpret_cast<MYSQL*>(0x1111)));

derived1 d1;
d1.id = uuid("3d12778a-abb9-11e8-98d0-529269fb1459");
d1.name = "derived1";
d1.derived1_id = uuid("3d12758c-abb9-11e8-98d0-529269fb1459");
d1.enum_data = test_enum::test2;
d1.test1_data.str_data = "str_data of class `test1` object `d1.test1_data`";
d1.test1_data.str64_data = "str64_data of class `test1` object `d1.test1_data`";
d1.test1_data.u32_nullable = 32;
d1.test1_data.u32_ptr_s = std::make_shared<uint32_t>(789);

::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
auto context = make_context<driver::mariadb>(test_schema, connection);
context.update(static_cast<base&>(d1));
}

TEST(CppHibernateTests, update_derived2)
{
StrictMock<mariadb_mock> mock;

expect_query(mock, "START TRANSACTION");
expect_query(mock, "UPDATE "
"`tbl_base` "
"SET "
"`name`='Xderived2X' "
"WHERE "
"`tbl_base_id`=UuidToBin('X3d127db6-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "UPDATE "
"`tbl_test2` "
"SET "
"`u8_data`='X10X', "
"`i8_data`='X11X', "
"`u16_data`='X12X', "
"`i16_data`='X13X' "
"WHERE "
"`tbl_test2_id`=UuidToBin('X3d1283a6-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "DELETE FROM "
"`tbl_test2` "
"WHERE "
"`tbl_test2_id` IN ("
"SELECT "
"`tbl_test2_id_test2_nullable` "
"FROM "
"`tbl_derived2` "
"WHERE "
"`tbl_derived2_id`=UuidToBin('X3d127bcc-abb9-11e8-98d0-529269fb1459X') AND "
"`tbl_test2_id_test2_nullable`!= UuidToBin('X3d1283a6-abb9-11e8-98d0-529269fb1459X')"
")");
expect_query(mock, "SELECT Uuid()",
result_used({
{ "ec0f0aac-b8b9-11e8-96f8-529269fb1459" }
}));
expect_query(mock, "INSERT INTO "
"`tbl_test2` "
"SET "
"`tbl_test2_id`=UuidToBin('Xec0f0aac-b8b9-11e8-96f8-529269fb1459X'), "
"`u8_data`='X20X', "
"`i8_data`='X21X', "
"`u16_data`='X22X', "
"`i16_data`='X23X'",
result_affected_rows(1));
expect_query(mock, "DELETE FROM "
"`tbl_test2` "
"WHERE "
"`tbl_test2_id` IN ("
"SELECT "
"`tbl_test2_id_test2_ptr_u` "
"FROM "
"`tbl_derived2` "
"WHERE "
"`tbl_derived2_id`=UuidToBin('X3d127bcc-abb9-11e8-98d0-529269fb1459X') AND "
"`tbl_test2_id_test2_ptr_u`!= UuidToBin('Xec0f0aac-b8b9-11e8-96f8-529269fb1459X')"
")");
expect_query(mock, "DELETE FROM "
"`tbl_test2` "
"WHERE "
"`tbl_test2_id` IN ("
"SELECT "
"`tbl_test2_id_test2_ptr_s` "
"FROM "
"`tbl_derived2` "
"WHERE "
"`tbl_derived2_id`=UuidToBin('X3d127bcc-abb9-11e8-98d0-529269fb1459X')"
")");
expect_query(mock, "UPDATE "
"`tbl_derived2` "
"SET "
"`tbl_base_id`=UuidToBin('X3d127db6-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_test2_id_test2_nullable`=UuidToBin('X3d1283a6-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_test2_id_test2_ptr_u`=UuidToBin('Xec0f0aac-b8b9-11e8-96f8-529269fb1459X'), "
"`tbl_test2_id_test2_ptr_s`=UuidToBin(null) "
"WHERE "
"`tbl_derived2_id`=UuidToBin('X3d127bcc-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "COMMIT");

EXPECT_CALL(
mock,
mysql_real_escape_string(reinterpret_cast<MYSQL*>(0x1111), _, _, _))
.Times(AnyNumber())
.WillRepeatedly(WithArgs<1, 2, 3>(EscapeString()));

EXPECT_CALL(
mock,
mysql_close(
reinterpret_cast<MYSQL*>(0x1111)));

derived2 d2;
d2.id = uuid("3d127db6-abb9-11e8-98d0-529269fb1459");
d2.name = "derived2";
d2.derived2_id = uuid("3d127bcc-abb9-11e8-98d0-529269fb1459");
d2.test2_nullable = test2 { };
d2.test2_nullable->id = uuid("3d1283a6-abb9-11e8-98d0-529269fb1459");
d2.test2_nullable->u8_data = 10;
d2.test2_nullable->i8_data = 11;
d2.test2_nullable->u16_data = 12;
d2.test2_nullable->i16_data = 13;
d2.test2_ptr_u = std::make_unique<test2>();
d2.test2_ptr_u->u8_data = 20;
d2.test2_ptr_u->i8_data = 21;
d2.test2_ptr_u->u16_data = 22;
d2.test2_ptr_u->i16_data = 23;

::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
auto context = make_context<driver::mariadb>(test_schema, connection);
context.update(static_cast<base&>(d2));
}

TEST(CppHibernateTests, update_derived3)
{
StrictMock<mariadb_mock> mock;

expect_query(mock, "START TRANSACTION");
expect_query(mock, "UPDATE "
"`tbl_base` "
"SET "
"`name`='Xderived3X' "
"WHERE "
"`tbl_base_id`=UuidToBin('X3d1288ce-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "DELETE FROM "
"`tbl_test2` "
"WHERE "
"`tbl_test2_id` IN ("
"SELECT "
"`tbl_test2_id_test2_nullable` "
"FROM "
"`tbl_derived2` "
"WHERE "
"`tbl_derived2_id`=UuidToBin('X3d1287a2-abb9-11e8-98d0-529269fb1459X')"
")");
expect_query(mock, "DELETE FROM "
"`tbl_test2` "
"WHERE "
"`tbl_test2_id` IN ("
"SELECT "
"`tbl_test2_id_test2_ptr_u` "
"FROM "
"`tbl_derived2` "
"WHERE "
"`tbl_derived2_id`=UuidToBin('X3d1287a2-abb9-11e8-98d0-529269fb1459X')"
")");
expect_query(mock, "DELETE FROM "
"`tbl_test2` "
"WHERE "
"`tbl_test2_id` IN ("
"SELECT "
"`tbl_test2_id_test2_ptr_s` "
"FROM "
"`tbl_derived2` "
"WHERE "
"`tbl_derived2_id`=UuidToBin('X3d1287a2-abb9-11e8-98d0-529269fb1459X')"
")");
expect_query(mock, "UPDATE "
"`tbl_derived2` "
"SET "
"`tbl_base_id`=UuidToBin('X3d1288ce-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_test2_id_test2_nullable`=UuidToBin(null), "
"`tbl_test2_id_test2_ptr_u`=UuidToBin(null), "
"`tbl_test2_id_test2_ptr_s`=UuidToBin(null) "
"WHERE "
"`tbl_derived2_id`=UuidToBin('X3d1287a2-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "UPDATE "
"`tbl_derived3` "
"SET "
"`tbl_derived2_id`=UuidToBin('X3d1287a2-abb9-11e8-98d0-529269fb1459X') "
"WHERE "
"`tbl_derived3_id`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "UPDATE "
"`tbl_test3` "
"SET "
"`tbl_test3_id_test3_list`=NULL, "
"`tbl_test3_index_test3_list`=0 "
"WHERE "
"`tbl_test3_id_test3_list`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X')");
expect_query(mock, "UPDATE "
"`tbl_test3` "
"SET "
"`tbl_derived3_id_test3_list`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_derived3_index_test3_list`='X0X', "
"`u32_data`='X100X', "
"`i32_data`='X101X', "
"`u64_data`='X102X', "
"`i64_data`='X103X' "
"WHERE "
"`tbl_test3_id`=UuidToBin('X3d1289f0-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "SELECT Uuid()",
result_used({
{ "435bd976-b8c3-11e8-96f8-529269fb1459" }
}));
expect_query(mock, "INSERT INTO "
"`tbl_test3` "
"SET "
"`tbl_test3_id`=UuidToBin('X435bd976-b8c3-11e8-96f8-529269fb1459X'), "
"`tbl_derived3_id_test3_list`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_derived3_index_test3_list`='X1X', "
"`tbl_derived3_id_test3_vector`=UuidToBin(null), "
"`tbl_derived3_index_test3_vector`='X0X', "
"`u32_data`='X110X', "
"`i32_data`='X111X', "
"`u64_data`='X112X', "
"`i64_data`='X113X'",
result_affected_rows(1));
expect_query(mock, "DELETE FROM "
"`tbl_test3` "
"WHERE "
"(`tbl_derived3_id_test3_list` IS NULL) AND "
"(`tbl_derived3_id_test3_vector` IS NULL)");
expect_query(mock, "UPDATE "
"`tbl_test3` "
"SET "
"`tbl_test3_id_test3_vector`=NULL, "
"`tbl_test3_index_test3_vector`=0 "
"WHERE "
"`tbl_test3_id_test3_vector`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X')");
expect_query(mock, "UPDATE "
"`tbl_test3` "
"SET "
"`tbl_derived3_id_test3_vector`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_derived3_index_test3_vector`='X0X', "
"`u32_data`='X200X', "
"`i32_data`='X201X', "
"`u64_data`='X202X', "
"`i64_data`='X203X' "
"WHERE "
"`tbl_test3_id`=UuidToBin('X3d128eb4-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "SELECT Uuid()",
result_used({
{ "1c0a3592-b8c4-11e8-96f8-529269fb1459" }
}));
expect_query(mock, "INSERT INTO "
"`tbl_test3` "
"SET "
"`tbl_test3_id`=UuidToBin('X1c0a3592-b8c4-11e8-96f8-529269fb1459X'), "
"`tbl_derived3_id_test3_list`=UuidToBin(null), "
"`tbl_derived3_index_test3_list`='X0X', "
"`tbl_derived3_id_test3_vector`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_derived3_index_test3_vector`='X1X', "
"`u32_data`='X210X', "
"`i32_data`='X211X', "
"`u64_data`='X212X', "
"`i64_data`='X213X'",
result_affected_rows(1));
expect_query(mock, "UPDATE "
"`tbl_test3` "
"SET "
"`tbl_derived3_id_test3_vector`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_derived3_index_test3_vector`='X2X', "
"`u32_data`='X220X', "
"`i32_data`='X221X', "
"`u64_data`='X222X', "
"`i64_data`='X223X' "
"WHERE "
"`tbl_test3_id`=UuidToBin('X3d129134-abb9-11e8-98d0-529269fb1459X')",
result_affected_rows(1));
expect_query(mock, "DELETE FROM "
"`tbl_test3` "
"WHERE "
"(`tbl_derived3_id_test3_list` IS NULL) AND "
"(`tbl_derived3_id_test3_vector` IS NULL)");
expect_query(mock, "COMMIT");

EXPECT_CALL(
mock,
mysql_real_escape_string(reinterpret_cast<MYSQL*>(0x1111), _, _, _))
.Times(AnyNumber())
.WillRepeatedly(WithArgs<1, 2, 3>(EscapeString()));

EXPECT_CALL(
mock,
mysql_close(
reinterpret_cast<MYSQL*>(0x1111)));

derived3 d3;
d3.id = uuid("3d1288ce-abb9-11e8-98d0-529269fb1459");
d3.name = "derived3";
d3.derived2_id = uuid("3d1287a2-abb9-11e8-98d0-529269fb1459");
d3.derived3_id = uuid("3d12866c-abb9-11e8-98d0-529269fb1459");
d3.test3_list.emplace_back();
d3.test3_list.back().id = uuid("3d1289f0-abb9-11e8-98d0-529269fb1459");
d3.test3_list.back().u32_data = 100;
d3.test3_list.back().i32_data = 101;
d3.test3_list.back().u64_data = 102;
d3.test3_list.back().i64_data = 103;
d3.test3_list.emplace_back();
d3.test3_list.back().u32_data = 110;
d3.test3_list.back().i32_data = 111;
d3.test3_list.back().u64_data = 112;
d3.test3_list.back().i64_data = 113;
d3.test3_vector.emplace_back();
d3.test3_vector.back().id = uuid("3d128eb4-abb9-11e8-98d0-529269fb1459");
d3.test3_vector.back().u32_data = 200;
d3.test3_vector.back().i32_data = 201;
d3.test3_vector.back().u64_data = 202;
d3.test3_vector.back().i64_data = 203;
d3.test3_vector.emplace_back();
d3.test3_vector.back().u32_data = 210;
d3.test3_vector.back().i32_data = 211;
d3.test3_vector.back().u64_data = 212;
d3.test3_vector.back().i64_data = 213;
d3.test3_vector.emplace_back();
d3.test3_vector.back().id = uuid("3d129134-abb9-11e8-98d0-529269fb1459");
d3.test3_vector.back().u32_data = 220;
d3.test3_vector.back().i32_data = 221;
d3.test3_vector.back().u64_data = 222;
d3.test3_vector.back().i64_data = 223;

::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
auto context = make_context<driver::mariadb>(test_schema, connection);
context.update(static_cast<derived2&>(d3));
}

Loading…
Cancel
Save