@@ -98,6 +98,7 @@ beg_namespace_cpphibernate_driver_mariadb | |||
using map_key = std::tuple<size_t, const field_t*>; | |||
using statement_map = std::map<map_key, ::cppmariadb::statement>; | |||
mutable statement_ptr _statement_key_from_base; | |||
mutable statement_ptr _statement_create_table; | |||
mutable statement_ptr _statement_alter_table; | |||
mutable statement_ptr _statement_insert_into; | |||
@@ -107,6 +108,7 @@ beg_namespace_cpphibernate_driver_mariadb | |||
mutable statement_ptr _statement_foreign_many_delete; | |||
mutable statement_ptr _statement_delete; | |||
::cppmariadb::statement& get_statement_key_from_base() const; | |||
::cppmariadb::statement& get_statement_create_table() const; | |||
::cppmariadb::statement* get_statement_alter_table() const; | |||
::cppmariadb::statement& get_statement_insert_into() const; | |||
@@ -121,6 +123,9 @@ beg_namespace_cpphibernate_driver_mariadb | |||
const create_update_context& context, | |||
::cppmariadb::statement& statement) const; | |||
std::string get_primary_key(const data_context& context) const; | |||
std::string get_key_from_base(const data_context& context) const; | |||
virtual std::string create_update_base(const create_update_context& context) const; | |||
protected: | |||
@@ -1125,7 +1125,7 @@ std::string table_t::execute_create_update( | |||
} | |||
else | |||
{ | |||
primary_key = *primary_key_field->get(context); | |||
primary_key = get_primary_key(context); | |||
} | |||
/* base_key */ | |||
@@ -1397,6 +1397,34 @@ std::string table_t::get_where_primary_key(const data_context& context) const | |||
std::string table_t::build_delete_query(const std::string* where) const | |||
{ return delete_query_builder_t(*this)(where); } | |||
::cppmariadb::statement& table_t::get_statement_key_from_base() const | |||
{ | |||
if (!_statement_key_from_base) | |||
{ | |||
if (!base_table) | |||
throw exception(std::string("table has no base table: ") + table_name); | |||
assert(primary_key_field); | |||
assert(base_table); | |||
assert(base_table->primary_key_field); | |||
auto& key_info = *primary_key_field; | |||
auto& base_key = *base_table->primary_key_field; | |||
std::ostringstream os; | |||
os << "SELECT `" | |||
<< key_info.table_name | |||
<< "`.`" | |||
<< key_info.field_name | |||
<< "` FROM `" | |||
<< key_info.table_name | |||
<< "` WHERE `" | |||
<< key_info.table_name | |||
<< "`.`" | |||
<< base_key.table_name | |||
<< "_id`=?\?"; | |||
_statement_key_from_base.reset(new ::cppmariadb::statement(os.str())); | |||
} | |||
return *_statement_key_from_base; | |||
} | |||
::cppmariadb::statement& table_t::get_statement_create_table() const | |||
{ | |||
if (_statement_create_table) | |||
@@ -1501,6 +1529,37 @@ void table_t::execute_foreign_many_delete(const base_context& context) const | |||
connection.execute(statement); | |||
} | |||
std::string table_t::get_primary_key(const data_context& context) const | |||
{ | |||
assert(primary_key_field); | |||
if (primary_key_field->is_default(context)) | |||
{ | |||
auto key = get_key_from_base(context); | |||
primary_key_field->set(context, key); | |||
return key; | |||
} | |||
else | |||
{ | |||
return *primary_key_field->get(context); | |||
} | |||
} | |||
std::string table_t::get_key_from_base(const data_context& context) const | |||
{ | |||
if (!base_table) | |||
throw exception(std::string("table has no base table: ") + table_name); | |||
auto& statement = get_statement_key_from_base(); | |||
auto base_key = base_table->get_primary_key(context); | |||
statement.set(0, base_key); | |||
auto result = context.connection.execute_stored(statement); | |||
if (!result) | |||
throw exception("unable to fetch key from database: unable to execute query!"); | |||
auto row = result->next(); | |||
if (!row) | |||
throw exception("unable to fetch key from database: result set is empty!"); | |||
return row->at(0).get<std::string>(); | |||
} | |||
std::string table_t::create_update_base(const create_update_context& context) const | |||
{ | |||
throw misc::hibernate_exception(static_cast<std::ostringstream&>(std::ostringstream { } | |||
@@ -26,5 +26,6 @@ If ( __COTIRE_INCLUDED ) | |||
Cotire ( test_cpphibernate ) | |||
EndIf ( ) | |||
If ( __CMAKE_TESTS_INCLUDED ) | |||
Add_CMake_Test ( cpphibernate test_cpphibernate ) | |||
Add_CMake_Test ( NAME cpphibernate | |||
TARGET test_cpphibernate ) | |||
EndIf ( ) |
@@ -540,4 +540,98 @@ TEST(CppHibernateTests, update_derived3) | |||
::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111)); | |||
auto context = make_context<driver::mariadb>(test_schema, connection); | |||
context.update(static_cast<derived2&>(d3)); | |||
} | |||
TEST(CppHibernateTests, update_dynamic_base) | |||
{ | |||
StrictMock<mariadb_mock> mock; | |||
expect_query(mock, "START TRANSACTION"); | |||
expect_query(mock, "SELECT " | |||
"`tbl_derived2`.`tbl_derived2_id` " | |||
"FROM " | |||
"`tbl_derived2` " | |||
"WHERE " | |||
"`tbl_derived2`.`tbl_base_id`='Xf9f13c08-c6e2-11e8-a8d5-f2801f1b9fd1X'", | |||
result_stored({ | |||
{ "ae0e7888-c6e6-11e8-a8d5-f2801f1b9fd1" } | |||
})); | |||
expect_query(mock, "UPDATE " | |||
"`tbl_base` " | |||
"SET " | |||
"`name`='Xdynamic derived 1X' " | |||
"WHERE " | |||
"`tbl_base_id`=UuidToBin('Xf9f13c08-c6e2-11e8-a8d5-f2801f1b9fd1X')", | |||
result_affected_rows(1)); | |||
expect_query(mock, "DELETE " | |||
"`tbl_test2` " | |||
"FROM " | |||
"`tbl_test2` " | |||
"WHERE " | |||
"`tbl_test2_id` IN (" | |||
"SELECT " | |||
"`tbl_test2_id_test2_nullable` " | |||
"FROM " | |||
"`tbl_derived2` " | |||
"WHERE " | |||
"`tbl_derived2_id`=UuidToBin('Xae0e7888-c6e6-11e8-a8d5-f2801f1b9fd1X')" | |||
")"); | |||
expect_query(mock, "DELETE " | |||
"`tbl_test2` " | |||
"FROM " | |||
"`tbl_test2` " | |||
"WHERE " | |||
"`tbl_test2_id` IN (" | |||
"SELECT " | |||
"`tbl_test2_id_test2_ptr_u` " | |||
"FROM " | |||
"`tbl_derived2` " | |||
"WHERE " | |||
"`tbl_derived2_id`=UuidToBin('Xae0e7888-c6e6-11e8-a8d5-f2801f1b9fd1X')" | |||
")"); | |||
expect_query(mock, "DELETE " | |||
"`tbl_test2` " | |||
"FROM " | |||
"`tbl_test2` " | |||
"WHERE " | |||
"`tbl_test2_id` IN (" | |||
"SELECT " | |||
"`tbl_test2_id_test2_ptr_s` " | |||
"FROM " | |||
"`tbl_derived2` " | |||
"WHERE " | |||
"`tbl_derived2_id`=UuidToBin('Xae0e7888-c6e6-11e8-a8d5-f2801f1b9fd1X')" | |||
")"); | |||
expect_query(mock, "UPDATE " | |||
"`tbl_derived2` " | |||
"SET " | |||
"`tbl_base_id`=UuidToBin('Xf9f13c08-c6e2-11e8-a8d5-f2801f1b9fd1X'), " | |||
"`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('Xae0e7888-c6e6-11e8-a8d5-f2801f1b9fd1X')", | |||
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))); | |||
std::unique_ptr<base> b; | |||
b.reset(new derived2()); | |||
auto& d2 = *dynamic_cast<derived2*>(b.get()); | |||
d2.id = uuid("f9f13c08-c6e2-11e8-a8d5-f2801f1b9fd1"); | |||
d2.name = "dynamic derived 1"; | |||
::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111)); | |||
auto context = make_context<driver::mariadb>(test_schema, connection); | |||
context.update(b); | |||
} |