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