| @@ -195,5 +195,24 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| using read_context_ptr = std::unique_ptr<read_context>; | using read_context_ptr = std::unique_ptr<read_context>; | ||||
| /* destroy_context */ | |||||
| struct destroy_context | |||||
| : public data_context | |||||
| { | |||||
| std::string where; | |||||
| template<typename T_data> | |||||
| inline destroy_context( | |||||
| T_data& p_data, | |||||
| const schema_t& p_schema, | |||||
| ::cppmariadb::connection& p_connection) | |||||
| : data_context( | |||||
| p_data, | |||||
| p_schema, | |||||
| p_connection) | |||||
| { } | |||||
| }; | |||||
| } | } | ||||
| end_namespace_cpphibernate_driver_mariadb | end_namespace_cpphibernate_driver_mariadb | ||||
| @@ -1,6 +1,7 @@ | |||||
| #pragma once | #pragma once | ||||
| #include <cpphibernate/driver/mariadb/impl/create_update.h> | #include <cpphibernate/driver/mariadb/impl/create_update.h> | ||||
| #include <cpphibernate/driver/mariadb/impl/destroy.h> | |||||
| #include <cpphibernate/driver/mariadb/impl/limit.h> | #include <cpphibernate/driver/mariadb/impl/limit.h> | ||||
| #include <cpphibernate/driver/mariadb/impl/order_by.h> | #include <cpphibernate/driver/mariadb/impl/order_by.h> | ||||
| #include <cpphibernate/driver/mariadb/impl/read.h> | #include <cpphibernate/driver/mariadb/impl/read.h> | ||||
| @@ -0,0 +1,96 @@ | |||||
| #pragma once | |||||
| #include <cppmariadb.h> | |||||
| #include <cpphibernate/misc.h> | |||||
| #include <cpphibernate/config.h> | |||||
| #include <cpphibernate/driver/mariadb/helper.h> | |||||
| #include <cpphibernate/driver/mariadb/schema/schema.h> | |||||
| beg_namespace_cpphibernate_driver_mariadb | |||||
| { | |||||
| /* destroy_impl_t */ | |||||
| template<typename T_dataset, typename = void> | |||||
| struct destroy_impl_t | |||||
| { | |||||
| using dataset_type = T_dataset; | |||||
| static inline void apply(const destroy_context& context, bool strict = true) | |||||
| { | |||||
| auto dataset_id = misc::get_type_id(hana::type_c<dataset_type>); | |||||
| auto& connection = context.connection; | |||||
| auto& schema = context.schema; | |||||
| auto& table = schema.table(dataset_id); | |||||
| assert(table.primary_key_field); | |||||
| transaction_lock trans(connection); | |||||
| if (!table.primary_key_field->is_default(context)) | |||||
| { | |||||
| table.destroy(context); | |||||
| } | |||||
| else if (strict) | |||||
| { | |||||
| throw misc::hibernate_exception("can not destroy dataset with no primary key assigned!"); | |||||
| } | |||||
| trans.commit(); | |||||
| } | |||||
| }; | |||||
| /* destroy_impl_t - nullable */ | |||||
| template<typename T_dataset> | |||||
| struct destroy_impl_t< | |||||
| T_dataset, | |||||
| mp::enable_if<misc::is_nullable<T_dataset>>> | |||||
| { | |||||
| using dataset_type = T_dataset; | |||||
| using nullable_helper_type = misc::nullable_helper<dataset_type>; | |||||
| static inline void apply(const destroy_context& context, bool strict = true) | |||||
| { | |||||
| auto& dataset = context.get<dataset_type>(); | |||||
| auto* value = nullable_helper_type::get(dataset); | |||||
| if (value) | |||||
| { | |||||
| using new_dataset_type = mp::decay_t<decltype(*value)>; | |||||
| using new_destroy_impl_type = destroy_impl_t<new_dataset_type>; | |||||
| auto new_context = change_context(context, *value); | |||||
| new_destroy_impl_type::apply(new_context, strict); | |||||
| } | |||||
| else if (strict) | |||||
| { | |||||
| throw misc::hibernate_exception("can not destroy nullable type with no value!"); | |||||
| } | |||||
| } | |||||
| }; | |||||
| /* destroy_impl_t - container */ | |||||
| template<typename T_dataset> | |||||
| struct destroy_impl_t< | |||||
| T_dataset, | |||||
| mp::enable_if<misc::is_container<T_dataset>>> | |||||
| { | |||||
| using dataset_type = T_dataset; | |||||
| static inline void apply(const destroy_context& context, bool strict = true) | |||||
| { | |||||
| auto& connection = context.connection; | |||||
| auto& dataset = context.get<dataset_type>(); | |||||
| transaction_lock trans(connection); | |||||
| for (auto& x : dataset) | |||||
| { | |||||
| using new_dataset_type = mp::decay_t<decltype(x)>; | |||||
| using new_destroy_impl_type = destroy_impl_t<new_dataset_type>; | |||||
| auto new_context = change_context(context, x); | |||||
| new_destroy_impl_type::apply(new_context, strict); | |||||
| } | |||||
| trans.commit(); | |||||
| } | |||||
| }; | |||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| @@ -65,6 +65,21 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| create_update_impl_t<T_dataset>::apply( | create_update_impl_t<T_dataset>::apply( | ||||
| create_update_context(dataset, _schema, _connection, _filter, true)); | 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); | |||||
| } | |||||
| }; | }; | ||||
| } | } | ||||
| @@ -67,7 +67,9 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| const table_t* get_derived_by_table_id(size_t id) const; | const table_t* get_derived_by_table_id(size_t id) const; | ||||
| const table_t* get_derived_by_dataset_id(size_t id) const; | const table_t* get_derived_by_dataset_id(size_t id) const; | ||||
| virtual void emplace(const read_context& context) const; | |||||
| virtual void emplace (const read_context& context) const; | |||||
| std::string get_where_primary_key(const data_context& context) const; | |||||
| std::string build_delete_query (const std::string* where) const; | |||||
| /* CRUD */ | /* CRUD */ | ||||
| inline void init_stage1(const init_context& context) const | inline void init_stage1(const init_context& context) const | ||||
| @@ -82,6 +84,9 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| inline void read(const read_context& context) const | inline void read(const read_context& context) const | ||||
| { return read_exec(context); } | { return read_exec(context); } | ||||
| inline void destroy(const destroy_context& context) const | |||||
| { return destroy_intern(context); } | |||||
| private: | private: | ||||
| template<typename T_schema, typename T_table, typename T_base_dataset> | template<typename T_schema, typename T_table, typename T_base_dataset> | ||||
| friend struct table_simple_t; | friend struct table_simple_t; | ||||
| @@ -100,6 +105,7 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| mutable statement_map _statement_select_dynamic; | mutable statement_map _statement_select_dynamic; | ||||
| mutable statement_map _statement_update; | mutable statement_map _statement_update; | ||||
| mutable statement_ptr _statement_foreign_many_delete; | mutable statement_ptr _statement_foreign_many_delete; | ||||
| mutable statement_ptr _statement_delete; | |||||
| ::cppmariadb::statement& get_statement_create_table() const; | ::cppmariadb::statement& get_statement_create_table() const; | ||||
| ::cppmariadb::statement* get_statement_alter_table() const; | ::cppmariadb::statement* get_statement_alter_table() const; | ||||
| @@ -107,6 +113,9 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| ::cppmariadb::statement& get_statement_select(const read_context& context) 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_update(const filter_t& filter, const field_t* owner) const; | ||||
| ::cppmariadb::statement& get_statement_foreign_many_delete() const; | ::cppmariadb::statement& get_statement_foreign_many_delete() const; | ||||
| ::cppmariadb::statement& get_statement_delete() const; | |||||
| void execute_foreign_many_delete(const base_context& context) const; | |||||
| std::string execute_create_update( | std::string execute_create_update( | ||||
| const create_update_context& context, | const create_update_context& context, | ||||
| @@ -122,6 +131,10 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| std::string create_update_exec (const create_update_context& context) const; | std::string create_update_exec (const create_update_context& context) const; | ||||
| void read_exec (const read_context& context) const; | void read_exec (const read_context& context) const; | ||||
| virtual void destroy_intern (const destroy_context& context) const; | |||||
| void destroy_exec (const destroy_context& context) const; | |||||
| void destroy_cleanup (const base_context& context, bool check_derived, bool check_base) const; | |||||
| }; | }; | ||||
| /* table_simple_t */ | /* table_simple_t */ | ||||
| @@ -177,6 +190,7 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| protected: | protected: | ||||
| virtual std::string create_update_intern(const create_update_context& context) const override; | virtual std::string create_update_intern(const create_update_context& context) const override; | ||||
| virtual void destroy_intern (const destroy_context& context) const override; | |||||
| private: | private: | ||||
| virtual std::string create_update_base(const create_update_context& context) const override; | virtual std::string create_update_base(const create_update_context& context) const override; | ||||
| @@ -64,6 +64,36 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| : this->create_update_exec(context); | : this->create_update_exec(context); | ||||
| } | } | ||||
| template<typename T_schema, typename T_table, typename T_base_dataset> | |||||
| void table_polymorphic_t<T_schema, T_table, T_base_dataset> | |||||
| ::destroy_intern(const destroy_context& context) const | |||||
| { | |||||
| bool done = false; | |||||
| auto& dataset = context.get<dataset_type>(); | |||||
| for_each_derived(dataset, hana::false_c, [&](auto& derived_dataset){ | |||||
| if (!done) | |||||
| { | |||||
| using derived_dataset_type = mp::decay_t<decltype(derived_dataset)>; | |||||
| auto derived_dataset_id = misc::get_type_id(hana::type_c<derived_dataset_type>); | |||||
| auto derived_table = this->get_derived_by_dataset_id(derived_dataset_id); | |||||
| if (!derived_table) | |||||
| { | |||||
| throw misc::hibernate_exception(static_cast<std::ostringstream&>(std::ostringstream { } | |||||
| << "unable to find derived table info for dataset '" | |||||
| << utl::type_helper<derived_dataset_type>::name() << "'!").str()); | |||||
| } | |||||
| auto new_context = change_context(context, derived_dataset); | |||||
| derived_table->destroy(new_context); | |||||
| done = true; | |||||
| } | |||||
| }); | |||||
| if (!done) | |||||
| { | |||||
| this->destroy_exec(context); | |||||
| } | |||||
| } | |||||
| template<typename T_schema, typename T_table, typename T_base_dataset> | template<typename T_schema, typename T_table, typename T_base_dataset> | ||||
| std::string table_polymorphic_t<T_schema, T_table, T_base_dataset> | std::string table_polymorphic_t<T_schema, T_table, T_base_dataset> | ||||
| ::create_update_base(const create_update_context& context) const | ::create_update_base(const create_update_context& context) const | ||||
| @@ -176,13 +176,12 @@ throw_not_implemented(::cppmariadb::statement&, get_statement_foreign_many_updat | |||||
| { | { | ||||
| if (!known) | if (!known) | ||||
| { | { | ||||
| auto& ref_table = *referenced_table; | |||||
| auto& key_info = *table->primary_key_field; | auto& key_info = *table->primary_key_field; | ||||
| auto& ref_key_info = *referenced_table->primary_key_field; | |||||
| auto& ref_key_info = *ref_table.primary_key_field; | |||||
| std::ostringstream os; | std::ostringstream os; | ||||
| os << "DELETE FROM `" | |||||
| << ref_key_info.table_name | |||||
| << "` WHERE `" | |||||
| os << "WHERE `" | |||||
| << ref_key_info.field_name | << ref_key_info.field_name | ||||
| << "` IN (SELECT `" | << "` IN (SELECT `" | ||||
| << ref_key_info.table_name | << ref_key_info.table_name | ||||
| @@ -205,7 +204,10 @@ throw_not_implemented(::cppmariadb::statement&, get_statement_foreign_many_updat | |||||
| << "?\?" | << "?\?" | ||||
| << ref_key_info.convert_to_close | << ref_key_info.convert_to_close | ||||
| << ")"; | << ")"; | ||||
| known.reset(new ::cppmariadb::statement(os.str())); | |||||
| auto where = os.str(); | |||||
| auto query = ref_table.build_delete_query(&where); | |||||
| known.reset(new ::cppmariadb::statement(query)); | |||||
| } | } | ||||
| return *known; | return *known; | ||||
| } | } | ||||
| @@ -213,13 +215,12 @@ throw_not_implemented(::cppmariadb::statement&, get_statement_foreign_many_updat | |||||
| { | { | ||||
| if (!unknown) | if (!unknown) | ||||
| { | { | ||||
| auto& ref_table = *referenced_table; | |||||
| auto& key_info = *table->primary_key_field; | auto& key_info = *table->primary_key_field; | ||||
| auto& ref_key_info = *referenced_table->primary_key_field; | |||||
| auto& ref_key_info = *ref_table.primary_key_field; | |||||
| std::ostringstream os; | std::ostringstream os; | ||||
| os << "DELETE FROM `" | |||||
| << ref_key_info.table_name | |||||
| << "` WHERE `" | |||||
| os << "WHERE `" | |||||
| << ref_key_info.field_name | << ref_key_info.field_name | ||||
| << "` IN (SELECT `" | << "` IN (SELECT `" | ||||
| << ref_key_info.table_name | << ref_key_info.table_name | ||||
| @@ -234,7 +235,10 @@ throw_not_implemented(::cppmariadb::statement&, get_statement_foreign_many_updat | |||||
| << "?\?" | << "?\?" | ||||
| << key_info.convert_to_close | << key_info.convert_to_close | ||||
| << ")"; | << ")"; | ||||
| unknown.reset(new ::cppmariadb::statement(os.str())); | |||||
| auto where = os.str(); | |||||
| auto query = ref_table.build_delete_query(&where); | |||||
| unknown.reset(new ::cppmariadb::statement(query)); | |||||
| } | } | ||||
| return *unknown; | return *unknown; | ||||
| } | } | ||||
| @@ -443,6 +443,160 @@ struct select_query_builder_t | |||||
| } | } | ||||
| }; | }; | ||||
| /* delete_query_builder_t */ | |||||
| struct delete_query_builder_t | |||||
| { | |||||
| const table_t& _table; | |||||
| size_t alias_id { 0 }; | |||||
| std::ostringstream os; | |||||
| std::list<std::string> names; | |||||
| delete_query_builder_t( | |||||
| const table_t& p_table) | |||||
| : _table (p_table) | |||||
| { } | |||||
| inline std::string make_alias() | |||||
| { return std::string("T") + std::to_string(alias_id++); } | |||||
| inline void add_table(const table_t& table, const std::string& alias, bool add_base, bool add_derived) | |||||
| { | |||||
| auto has_alias = !alias.empty(); | |||||
| auto real_alias = has_alias ? alias : table.table_name; | |||||
| if (table.base_table && add_base) | |||||
| { | |||||
| assert(table.base_table->primary_key_field); | |||||
| auto& base_table = *table.base_table; | |||||
| auto& base_key = *base_table.primary_key_field; | |||||
| auto base_alias = has_alias ? make_alias() : std::string(); | |||||
| auto real_base_alias = has_alias ? base_alias : base_table.table_name; | |||||
| os << " LEFT JOIN `" | |||||
| << base_table.table_name; | |||||
| if (has_alias) | |||||
| { | |||||
| os << "` AS `" | |||||
| << base_alias; | |||||
| } | |||||
| os << "` ON `" | |||||
| << real_alias | |||||
| << "`.`" | |||||
| << base_key.field_name | |||||
| << "`=`" | |||||
| << real_base_alias | |||||
| << "`.`" | |||||
| << base_key.field_name | |||||
| << "`"; | |||||
| add_table(base_table, base_alias, true, false); | |||||
| } | |||||
| names.emplace_back(real_alias); | |||||
| /* foreign table one */ | |||||
| for (auto& ptr : table.foreign_table_one_fields) | |||||
| { | |||||
| assert(ptr); | |||||
| assert(ptr->referenced_table); | |||||
| assert(ptr->referenced_table->primary_key_field); | |||||
| auto& field = *ptr; | |||||
| auto& ref_table = *field.referenced_table; | |||||
| auto& ref_key = *ref_table.primary_key_field; | |||||
| auto new_alias = make_alias(); | |||||
| os << " LEFT JOIN `" | |||||
| << ref_table.table_name | |||||
| << "` AS `" | |||||
| << new_alias | |||||
| << "` ON `" | |||||
| << real_alias | |||||
| << "`.`" | |||||
| << ref_key.table_name | |||||
| << "_id_" | |||||
| << field.field_name | |||||
| << "`=`" | |||||
| << new_alias | |||||
| << "`.`" | |||||
| << ref_key.field_name | |||||
| << "`"; | |||||
| add_table(ref_table, new_alias, true, true); | |||||
| } | |||||
| /* derived tables */ | |||||
| if (add_derived) | |||||
| { | |||||
| for (auto& ptr : table.derived_tables) | |||||
| { | |||||
| assert(ptr); | |||||
| assert(ptr->primary_key_field); | |||||
| auto& derived_table = *ptr; | |||||
| auto& primary_key = *table.primary_key_field; | |||||
| auto derived_alias = has_alias ? make_alias() : std::string(); | |||||
| auto real_derived_alias = has_alias ? derived_alias : derived_table.table_name; | |||||
| os << " LEFT JOIN `" | |||||
| << derived_table.table_name; | |||||
| if (has_alias) | |||||
| { | |||||
| os << "` AS `" | |||||
| << derived_alias; | |||||
| } | |||||
| os << "` ON `" | |||||
| << real_alias | |||||
| << "`.`" | |||||
| << primary_key.field_name | |||||
| << "`=`" | |||||
| << real_derived_alias | |||||
| << "`.`" | |||||
| << primary_key.field_name | |||||
| << "`"; | |||||
| add_table(derived_table, derived_alias, false, true); | |||||
| } | |||||
| } | |||||
| } | |||||
| inline std::string operator()(const std::string* where) | |||||
| { | |||||
| os << " FROM `" | |||||
| << _table.table_name | |||||
| << "`"; | |||||
| add_table(_table, "", true, true); | |||||
| if (where) | |||||
| { | |||||
| os << " " << *where; | |||||
| } | |||||
| else | |||||
| { | |||||
| os << " ?where!"; | |||||
| } | |||||
| std::ostringstream ss; | |||||
| ss << "DELETE "; | |||||
| bool first = true; | |||||
| for (auto& name : names) | |||||
| { | |||||
| if (first) | |||||
| first = false; | |||||
| else | |||||
| ss << ", "; | |||||
| ss << "`" | |||||
| << name | |||||
| << "`"; | |||||
| } | |||||
| ss << os.str(); | |||||
| return ss.str(); | |||||
| } | |||||
| }; | |||||
| /* build queries */ | /* build queries */ | ||||
| std::string build_init_stage1_query(const table_t& table) | std::string build_init_stage1_query(const table_t& table) | ||||
| @@ -686,7 +840,7 @@ std::string build_init_stage2_query(const table_t& table) | |||||
| << indent | << indent | ||||
| << "ON DELETE CASCADE" | << "ON DELETE CASCADE" | ||||
| << indent | << indent | ||||
| << "ON UPDATE NO ACTION" | |||||
| << "ON UPDATE CASCADE" | |||||
| << decindent; | << decindent; | ||||
| } | } | ||||
| @@ -723,7 +877,7 @@ std::string build_init_stage2_query(const table_t& table) | |||||
| << ref_key_info.field_name | << ref_key_info.field_name | ||||
| << "`)" | << "`)" | ||||
| << indent | << indent | ||||
| << "ON DELETE CASCADE" | |||||
| << "ON DELETE SET NULL" | |||||
| << indent | << indent | ||||
| << "ON UPDATE NO ACTION" | << "ON UPDATE NO ACTION" | ||||
| << decindent; | << decindent; | ||||
| @@ -1143,9 +1297,7 @@ std::string table_t::execute_create_update( | |||||
| /* delete non referenced elements */ | /* delete non referenced elements */ | ||||
| if (context.is_update) | 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); | |||||
| ref_table.execute_foreign_many_delete(context); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1220,6 +1372,31 @@ const table_t* table_t::get_derived_by_dataset_id(size_t id) const | |||||
| void table_t::emplace(const read_context& context) const | void table_t::emplace(const read_context& context) const | ||||
| { throw misc::hibernate_exception(std::string("'") + table_name + "' does not implement the emplace() method!"); } | { throw misc::hibernate_exception(std::string("'") + table_name + "' does not implement the emplace() method!"); } | ||||
| std::string table_t::get_where_primary_key(const data_context& context) const | |||||
| { | |||||
| assert(primary_key_field); | |||||
| auto& field = *primary_key_field; | |||||
| auto primary_key = *field.get(context); | |||||
| std::ostringstream os; | |||||
| os << "WHERE `" | |||||
| << field.table_name | |||||
| << "`.`" | |||||
| << field.field_name | |||||
| << "`=" | |||||
| << field.convert_to_open | |||||
| << "'" | |||||
| << context.connection.escape(primary_key) | |||||
| << "'" | |||||
| << field.convert_to_close; | |||||
| return os.str(); | |||||
| } | |||||
| 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_create_table() const | ::cppmariadb::statement& table_t::get_statement_create_table() const | ||||
| { | { | ||||
| if (_statement_create_table) | if (_statement_create_table) | ||||
| @@ -1282,10 +1459,8 @@ void table_t::emplace(const read_context& context) const | |||||
| if (!_statement_foreign_many_delete) | if (!_statement_foreign_many_delete) | ||||
| { | { | ||||
| std::ostringstream os; | std::ostringstream os; | ||||
| os << "DELETE FROM `" | |||||
| << table_name | |||||
| << "` WHERE"; | |||||
| auto first = true; | auto first = true; | ||||
| os << "WHERE"; | |||||
| for (auto ptr : foreign_key_fields) | for (auto ptr : foreign_key_fields) | ||||
| { | { | ||||
| assert(ptr); | assert(ptr); | ||||
| @@ -1300,11 +1475,32 @@ void table_t::emplace(const read_context& context) const | |||||
| << field.field_name | << field.field_name | ||||
| << "` IS NULL)"; | << "` IS NULL)"; | ||||
| } | } | ||||
| _statement_foreign_many_delete.reset(new ::cppmariadb::statement(os.str())); | |||||
| std::string where = os.str(); | |||||
| auto query = delete_query_builder_t(*this)(&where); | |||||
| _statement_foreign_many_delete.reset(new ::cppmariadb::statement(query)); | |||||
| } | } | ||||
| return *_statement_foreign_many_delete; | return *_statement_foreign_many_delete; | ||||
| } | } | ||||
| ::cppmariadb::statement& table_t::get_statement_delete() const | |||||
| { | |||||
| if (!_statement_delete) | |||||
| { | |||||
| auto query = delete_query_builder_t(*this)(nullptr); | |||||
| _statement_delete.reset(new ::cppmariadb::statement(query)); | |||||
| } | |||||
| return *_statement_delete; | |||||
| } | |||||
| void table_t::execute_foreign_many_delete(const base_context& context) const | |||||
| { | |||||
| auto& connection = context.connection; | |||||
| auto& statement = get_statement_foreign_many_delete(); | |||||
| cpphibernate_debug_log("execute DELETE old foreign many query: " << statement.query(connection)); | |||||
| connection.execute(statement); | |||||
| } | |||||
| std::string table_t::create_update_base(const create_update_context& context) const | std::string table_t::create_update_base(const create_update_context& context) const | ||||
| { | { | ||||
| throw misc::hibernate_exception(static_cast<std::ostringstream&>(std::ostringstream { } | throw misc::hibernate_exception(static_cast<std::ostringstream&>(std::ostringstream { } | ||||
| @@ -1328,6 +1524,9 @@ void table_t::init_stage2_exec(const init_context& context) const | |||||
| connection.execute(*statement); | connection.execute(*statement); | ||||
| } | } | ||||
| std::string table_t::create_update_intern(const create_update_context& context) const | |||||
| { return create_update_exec(context); } | |||||
| std::string table_t::create_update_exec(const create_update_context& context) const | std::string table_t::create_update_exec(const create_update_context& context) const | ||||
| { | { | ||||
| auto& statement = context.is_update | auto& statement = context.is_update | ||||
| @@ -1336,9 +1535,6 @@ std::string table_t::create_update_exec(const create_update_context& context) co | |||||
| return execute_create_update(context, statement); | return execute_create_update(context, statement); | ||||
| } | } | ||||
| std::string table_t::create_update_intern(const create_update_context& context) const | |||||
| { return create_update_exec(context); } | |||||
| void table_t::read_exec(const read_context& context) const | void table_t::read_exec(const read_context& context) const | ||||
| { | { | ||||
| auto& statement = get_statement_select(context); | auto& statement = get_statement_select(context); | ||||
| @@ -1401,4 +1597,58 @@ void table_t::read_exec(const read_context& context) const | |||||
| ref_table.read(next_context); | ref_table.read(next_context); | ||||
| } | } | ||||
| } | |||||
| void table_t::destroy_intern(const destroy_context& context) const | |||||
| { return destroy_exec(context); } | |||||
| void table_t::destroy_exec(const destroy_context& context) const | |||||
| { | |||||
| assert(primary_key_field); | |||||
| auto& connection = context.connection; | |||||
| auto& statement = get_statement_delete(); | |||||
| statement.set(0, context.where); | |||||
| cpphibernate_debug_log("execute DELETE query: " << statement.query(connection)); | |||||
| connection.execute(statement); | |||||
| destroy_cleanup(context, false, true); | |||||
| } | |||||
| void table_t::destroy_cleanup(const base_context& context, bool check_derived, bool check_base) const | |||||
| { | |||||
| for (auto ptr : foreign_table_many_fields) | |||||
| { | |||||
| assert(ptr); | |||||
| assert(ptr->referenced_table); | |||||
| auto& ref_table = *ptr->referenced_table; | |||||
| ref_table.execute_foreign_many_delete(context); | |||||
| } | |||||
| for (auto ptr : foreign_table_fields) | |||||
| { | |||||
| assert(ptr); | |||||
| assert(ptr->referenced_table); | |||||
| auto& ref_table = *ptr->referenced_table; | |||||
| ref_table.destroy_cleanup(context, true, true); | |||||
| } | |||||
| if (check_base && base_table) | |||||
| { | |||||
| base_table->destroy_cleanup(context, false, true); | |||||
| } | |||||
| if (check_derived) | |||||
| { | |||||
| for (auto ptr : derived_tables) | |||||
| { | |||||
| assert(ptr); | |||||
| ptr->destroy_cleanup(context, true, false); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -0,0 +1,250 @@ | |||||
| #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, destroy_test1) | |||||
| { | |||||
| StrictMock<mariadb_mock> mock; | |||||
| expect_query(mock, "START TRANSACTION"); | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_test1` " | |||||
| "FROM " | |||||
| "`tbl_test1` " | |||||
| "WHERE " | |||||
| "`tbl_test1`.`tbl_test1_id`=UuidToBin('X3d12697a-abb9-11e8-98d0-529269fb1459X')"); | |||||
| 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"); | |||||
| ::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111)); | |||||
| auto context = make_context<driver::mariadb>(test_schema, connection); | |||||
| context.destroy(t1); | |||||
| } | |||||
| TEST(CppHibernateTests, destroy_test2) | |||||
| { | |||||
| StrictMock<mariadb_mock> mock; | |||||
| expect_query(mock, "START TRANSACTION"); | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_test2` " | |||||
| "FROM " | |||||
| "`tbl_test2` " | |||||
| "WHERE " | |||||
| "`tbl_test2`.`tbl_test2_id`=UuidToBin('X3d1270dc-abb9-11e8-98d0-529269fb1459X')"); | |||||
| 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"); | |||||
| ::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111)); | |||||
| auto context = make_context<driver::mariadb>(test_schema, connection); | |||||
| context.destroy(t2); | |||||
| } | |||||
| TEST(CppHibernateTests, destroy_test3) | |||||
| { | |||||
| StrictMock<mariadb_mock> mock; | |||||
| expect_query(mock, "START TRANSACTION"); | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_test3` " | |||||
| "FROM " | |||||
| "`tbl_test3` " | |||||
| "WHERE " | |||||
| "`tbl_test3`.`tbl_test3_id`=UuidToBin('X3d12737a-abb9-11e8-98d0-529269fb1459X')"); | |||||
| 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"); | |||||
| ::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111)); | |||||
| auto context = make_context<driver::mariadb>(test_schema, connection); | |||||
| context.destroy(t3); | |||||
| } | |||||
| TEST(CppHibernateTests, destroy_derived1) | |||||
| { | |||||
| StrictMock<mariadb_mock> mock; | |||||
| expect_query(mock, "START TRANSACTION"); | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_base`, " | |||||
| "`tbl_derived1`, " | |||||
| "`T0` " | |||||
| "FROM " | |||||
| "`tbl_derived1` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_base` ON `tbl_derived1`.`tbl_base_id`=`tbl_base`.`tbl_base_id` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_test1` AS `T0` ON `tbl_derived1`.`tbl_test1_id_test1_data`=`T0`.`tbl_test1_id` " | |||||
| "WHERE " | |||||
| "`tbl_base`.`tbl_base_id`=UuidToBin('X3d12778a-abb9-11e8-98d0-529269fb1459X')"); | |||||
| 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"); | |||||
| ::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111)); | |||||
| auto context = make_context<driver::mariadb>(test_schema, connection); | |||||
| context.destroy(static_cast<base&>(d1)); | |||||
| } | |||||
| TEST(CppHibernateTests, destroy_derived2) | |||||
| { | |||||
| StrictMock<mariadb_mock> mock; | |||||
| expect_query(mock, "START TRANSACTION"); | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_base`, " | |||||
| "`tbl_derived2`, " | |||||
| "`T0`, " | |||||
| "`T1`, " | |||||
| "`T2`, " | |||||
| "`tbl_derived3` " | |||||
| "FROM " | |||||
| "`tbl_derived2` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_base` ON `tbl_derived2`.`tbl_base_id`=`tbl_base`.`tbl_base_id` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_test2` AS `T0` ON `tbl_derived2`.`tbl_test2_id_test2_nullable`=`T0`.`tbl_test2_id` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_test2` AS `T1` ON `tbl_derived2`.`tbl_test2_id_test2_ptr_u`=`T1`.`tbl_test2_id` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_test2` AS `T2` ON `tbl_derived2`.`tbl_test2_id_test2_ptr_s`=`T2`.`tbl_test2_id` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_derived3` ON `tbl_derived2`.`tbl_derived2_id`=`tbl_derived3`.`tbl_derived2_id` " | |||||
| "WHERE " | |||||
| "`tbl_base`.`tbl_base_id`=UuidToBin('X3d127db6-abb9-11e8-98d0-529269fb1459X')"); | |||||
| 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"); | |||||
| ::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111)); | |||||
| auto context = make_context<driver::mariadb>(test_schema, connection); | |||||
| context.destroy(static_cast<base&>(d2)); | |||||
| } | |||||
| TEST(CppHibernateTests, destroy_derived3) | |||||
| { | |||||
| StrictMock<mariadb_mock> mock; | |||||
| expect_query(mock, "START TRANSACTION"); | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_base`, " | |||||
| "`tbl_derived2`, " | |||||
| "`T0`, " | |||||
| "`T1`, " | |||||
| "`T2`, " | |||||
| "`tbl_derived3` " | |||||
| "FROM " | |||||
| "`tbl_derived3` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_derived2` ON `tbl_derived3`.`tbl_derived2_id`=`tbl_derived2`.`tbl_derived2_id` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_base` ON `tbl_derived2`.`tbl_base_id`=`tbl_base`.`tbl_base_id` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_test2` AS `T0` ON `tbl_derived2`.`tbl_test2_id_test2_nullable`=`T0`.`tbl_test2_id` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_test2` AS `T1` ON `tbl_derived2`.`tbl_test2_id_test2_ptr_u`=`T1`.`tbl_test2_id` " | |||||
| "LEFT JOIN " | |||||
| "`tbl_test2` AS `T2` ON `tbl_derived2`.`tbl_test2_id_test2_ptr_s`=`T2`.`tbl_test2_id` " | |||||
| "WHERE " | |||||
| "`tbl_derived2`.`tbl_derived2_id`=UuidToBin('X3d1287a2-abb9-11e8-98d0-529269fb1459X')"); | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_test3` " | |||||
| "FROM " | |||||
| "`tbl_test3` " | |||||
| "WHERE " | |||||
| "(`tbl_derived3_id_test3_list` IS NULL) AND " | |||||
| "(`tbl_derived3_id_test3_vector` IS NULL)"); | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_test3` " | |||||
| "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.derived2_id = uuid("3d1287a2-abb9-11e8-98d0-529269fb1459"); | |||||
| ::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111)); | |||||
| auto context = make_context<driver::mariadb>(test_schema, connection); | |||||
| context.destroy(static_cast<derived2&>(d3)); | |||||
| } | |||||
| @@ -168,11 +168,11 @@ TEST(CppHibernateTests, init) | |||||
| " FOREIGN KEY (`tbl_base_id`)\n" | " FOREIGN KEY (`tbl_base_id`)\n" | ||||
| " REFERENCES `test`.`tbl_base` (`tbl_base_id`)\n" | " REFERENCES `test`.`tbl_base` (`tbl_base_id`)\n" | ||||
| " ON DELETE CASCADE\n" | " ON DELETE CASCADE\n" | ||||
| " ON UPDATE NO ACTION,\n" | |||||
| " ON UPDATE CASCADE,\n" | |||||
| " ADD CONSTRAINT `fk_tbl_derived1_to_tbl_test1_id_test1_data`\n" | " ADD CONSTRAINT `fk_tbl_derived1_to_tbl_test1_id_test1_data`\n" | ||||
| " FOREIGN KEY (`tbl_test1_id_test1_data`)\n" | " FOREIGN KEY (`tbl_test1_id_test1_data`)\n" | ||||
| " REFERENCES `test`.`tbl_test1` (`tbl_test1_id`)\n" | " REFERENCES `test`.`tbl_test1` (`tbl_test1_id`)\n" | ||||
| " ON DELETE CASCADE\n" | |||||
| " ON DELETE SET NULL\n" | |||||
| " ON UPDATE NO ACTION"); | " ON UPDATE NO ACTION"); | ||||
| expect_query(mock, "ALTER TABLE `tbl_derived2`\n" | expect_query(mock, "ALTER TABLE `tbl_derived2`\n" | ||||
| @@ -180,21 +180,21 @@ TEST(CppHibernateTests, init) | |||||
| " FOREIGN KEY (`tbl_base_id`)\n" | " FOREIGN KEY (`tbl_base_id`)\n" | ||||
| " REFERENCES `test`.`tbl_base` (`tbl_base_id`)\n" | " REFERENCES `test`.`tbl_base` (`tbl_base_id`)\n" | ||||
| " ON DELETE CASCADE\n" | " ON DELETE CASCADE\n" | ||||
| " ON UPDATE NO ACTION,\n" | |||||
| " ON UPDATE CASCADE,\n" | |||||
| " ADD CONSTRAINT `fk_tbl_derived2_to_tbl_test2_id_test2_nullable`\n" | " ADD CONSTRAINT `fk_tbl_derived2_to_tbl_test2_id_test2_nullable`\n" | ||||
| " FOREIGN KEY (`tbl_test2_id_test2_nullable`)\n" | " FOREIGN KEY (`tbl_test2_id_test2_nullable`)\n" | ||||
| " REFERENCES `test`.`tbl_test2` (`tbl_test2_id`)\n" | " REFERENCES `test`.`tbl_test2` (`tbl_test2_id`)\n" | ||||
| " ON DELETE CASCADE\n" | |||||
| " ON DELETE SET NULL\n" | |||||
| " ON UPDATE NO ACTION,\n" | " ON UPDATE NO ACTION,\n" | ||||
| " ADD CONSTRAINT `fk_tbl_derived2_to_tbl_test2_id_test2_ptr_u`\n" | " ADD CONSTRAINT `fk_tbl_derived2_to_tbl_test2_id_test2_ptr_u`\n" | ||||
| " FOREIGN KEY (`tbl_test2_id_test2_ptr_u`)\n" | " FOREIGN KEY (`tbl_test2_id_test2_ptr_u`)\n" | ||||
| " REFERENCES `test`.`tbl_test2` (`tbl_test2_id`)\n" | " REFERENCES `test`.`tbl_test2` (`tbl_test2_id`)\n" | ||||
| " ON DELETE CASCADE\n" | |||||
| " ON DELETE SET NULL\n" | |||||
| " ON UPDATE NO ACTION,\n" | " ON UPDATE NO ACTION,\n" | ||||
| " ADD CONSTRAINT `fk_tbl_derived2_to_tbl_test2_id_test2_ptr_s`\n" | " ADD CONSTRAINT `fk_tbl_derived2_to_tbl_test2_id_test2_ptr_s`\n" | ||||
| " FOREIGN KEY (`tbl_test2_id_test2_ptr_s`)\n" | " FOREIGN KEY (`tbl_test2_id_test2_ptr_s`)\n" | ||||
| " REFERENCES `test`.`tbl_test2` (`tbl_test2_id`)\n" | " REFERENCES `test`.`tbl_test2` (`tbl_test2_id`)\n" | ||||
| " ON DELETE CASCADE\n" | |||||
| " ON DELETE SET NULL\n" | |||||
| " ON UPDATE NO ACTION"); | " ON UPDATE NO ACTION"); | ||||
| expect_query(mock, "ALTER TABLE `tbl_derived3`\n" | expect_query(mock, "ALTER TABLE `tbl_derived3`\n" | ||||
| @@ -202,7 +202,7 @@ TEST(CppHibernateTests, init) | |||||
| " FOREIGN KEY (`tbl_derived2_id`)\n" | " FOREIGN KEY (`tbl_derived2_id`)\n" | ||||
| " REFERENCES `test`.`tbl_derived2` (`tbl_derived2_id`)\n" | " REFERENCES `test`.`tbl_derived2` (`tbl_derived2_id`)\n" | ||||
| " ON DELETE CASCADE\n" | " ON DELETE CASCADE\n" | ||||
| " ON UPDATE NO ACTION"); | |||||
| " ON UPDATE CASCADE"); | |||||
| expect_query(mock, "COMMIT"); | expect_query(mock, "COMMIT"); | ||||
| @@ -153,7 +153,9 @@ TEST(CppHibernateTests, update_derived1) | |||||
| "`u32_ptr_u`=null, " | "`u32_ptr_u`=null, " | ||||
| "`u32_ptr_s`='X789X'", | "`u32_ptr_s`='X789X'", | ||||
| result_affected_rows(1)); | result_affected_rows(1)); | ||||
| expect_query(mock, "DELETE FROM " | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_test1` " | |||||
| "FROM " | |||||
| "`tbl_test1` " | "`tbl_test1` " | ||||
| "WHERE " | "WHERE " | ||||
| "`tbl_test1_id` IN (" | "`tbl_test1_id` IN (" | ||||
| @@ -224,7 +226,9 @@ TEST(CppHibernateTests, update_derived2) | |||||
| "WHERE " | "WHERE " | ||||
| "`tbl_test2_id`=UuidToBin('X3d1283a6-abb9-11e8-98d0-529269fb1459X')", | "`tbl_test2_id`=UuidToBin('X3d1283a6-abb9-11e8-98d0-529269fb1459X')", | ||||
| result_affected_rows(1)); | result_affected_rows(1)); | ||||
| expect_query(mock, "DELETE FROM " | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_test2` " | |||||
| "FROM " | |||||
| "`tbl_test2` " | "`tbl_test2` " | ||||
| "WHERE " | "WHERE " | ||||
| "`tbl_test2_id` IN (" | "`tbl_test2_id` IN (" | ||||
| @@ -249,7 +253,9 @@ TEST(CppHibernateTests, update_derived2) | |||||
| "`u16_data`='X22X', " | "`u16_data`='X22X', " | ||||
| "`i16_data`='X23X'", | "`i16_data`='X23X'", | ||||
| result_affected_rows(1)); | result_affected_rows(1)); | ||||
| expect_query(mock, "DELETE FROM " | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_test2` " | |||||
| "FROM " | |||||
| "`tbl_test2` " | "`tbl_test2` " | ||||
| "WHERE " | "WHERE " | ||||
| "`tbl_test2_id` IN (" | "`tbl_test2_id` IN (" | ||||
| @@ -261,7 +267,9 @@ TEST(CppHibernateTests, update_derived2) | |||||
| "`tbl_derived2_id`=UuidToBin('X3d127bcc-abb9-11e8-98d0-529269fb1459X') AND " | "`tbl_derived2_id`=UuidToBin('X3d127bcc-abb9-11e8-98d0-529269fb1459X') AND " | ||||
| "`tbl_test2_id_test2_ptr_u`!= UuidToBin('Xec0f0aac-b8b9-11e8-96f8-529269fb1459X')" | "`tbl_test2_id_test2_ptr_u`!= UuidToBin('Xec0f0aac-b8b9-11e8-96f8-529269fb1459X')" | ||||
| ")"); | ")"); | ||||
| expect_query(mock, "DELETE FROM " | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_test2` " | |||||
| "FROM " | |||||
| "`tbl_test2` " | "`tbl_test2` " | ||||
| "WHERE " | "WHERE " | ||||
| "`tbl_test2_id` IN (" | "`tbl_test2_id` IN (" | ||||
| @@ -328,7 +336,9 @@ TEST(CppHibernateTests, update_derived3) | |||||
| "WHERE " | "WHERE " | ||||
| "`tbl_base_id`=UuidToBin('X3d1288ce-abb9-11e8-98d0-529269fb1459X')", | "`tbl_base_id`=UuidToBin('X3d1288ce-abb9-11e8-98d0-529269fb1459X')", | ||||
| result_affected_rows(1)); | result_affected_rows(1)); | ||||
| expect_query(mock, "DELETE FROM " | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_test2` " | |||||
| "FROM " | |||||
| "`tbl_test2` " | "`tbl_test2` " | ||||
| "WHERE " | "WHERE " | ||||
| "`tbl_test2_id` IN (" | "`tbl_test2_id` IN (" | ||||
| @@ -339,7 +349,9 @@ TEST(CppHibernateTests, update_derived3) | |||||
| "WHERE " | "WHERE " | ||||
| "`tbl_derived2_id`=UuidToBin('X3d1287a2-abb9-11e8-98d0-529269fb1459X')" | "`tbl_derived2_id`=UuidToBin('X3d1287a2-abb9-11e8-98d0-529269fb1459X')" | ||||
| ")"); | ")"); | ||||
| expect_query(mock, "DELETE FROM " | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_test2` " | |||||
| "FROM " | |||||
| "`tbl_test2` " | "`tbl_test2` " | ||||
| "WHERE " | "WHERE " | ||||
| "`tbl_test2_id` IN (" | "`tbl_test2_id` IN (" | ||||
| @@ -350,7 +362,9 @@ TEST(CppHibernateTests, update_derived3) | |||||
| "WHERE " | "WHERE " | ||||
| "`tbl_derived2_id`=UuidToBin('X3d1287a2-abb9-11e8-98d0-529269fb1459X')" | "`tbl_derived2_id`=UuidToBin('X3d1287a2-abb9-11e8-98d0-529269fb1459X')" | ||||
| ")"); | ")"); | ||||
| expect_query(mock, "DELETE FROM " | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_test2` " | |||||
| "FROM " | |||||
| "`tbl_test2` " | "`tbl_test2` " | ||||
| "WHERE " | "WHERE " | ||||
| "`tbl_test2_id` IN (" | "`tbl_test2_id` IN (" | ||||
| @@ -414,7 +428,9 @@ TEST(CppHibernateTests, update_derived3) | |||||
| "`u64_data`='X112X', " | "`u64_data`='X112X', " | ||||
| "`i64_data`='X113X'", | "`i64_data`='X113X'", | ||||
| result_affected_rows(1)); | result_affected_rows(1)); | ||||
| expect_query(mock, "DELETE FROM " | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_test3` " | |||||
| "FROM " | |||||
| "`tbl_test3` " | "`tbl_test3` " | ||||
| "WHERE " | "WHERE " | ||||
| "(`tbl_derived3_id_test3_list` IS NULL) AND " | "(`tbl_derived3_id_test3_list` IS NULL) AND " | ||||
| @@ -467,7 +483,9 @@ TEST(CppHibernateTests, update_derived3) | |||||
| "WHERE " | "WHERE " | ||||
| "`tbl_test3_id`=UuidToBin('X3d129134-abb9-11e8-98d0-529269fb1459X')", | "`tbl_test3_id`=UuidToBin('X3d129134-abb9-11e8-98d0-529269fb1459X')", | ||||
| result_affected_rows(1)); | result_affected_rows(1)); | ||||
| expect_query(mock, "DELETE FROM " | |||||
| expect_query(mock, "DELETE " | |||||
| "`tbl_test3` " | |||||
| "FROM " | |||||
| "`tbl_test3` " | "`tbl_test3` " | ||||
| "WHERE " | "WHERE " | ||||
| "(`tbl_derived3_id_test3_list` IS NULL) AND " | "(`tbl_derived3_id_test3_list` IS NULL) AND " | ||||
| @@ -64,8 +64,8 @@ struct result_data | |||||
| inline MYSQL_RES* next_result() | inline MYSQL_RES* next_result() | ||||
| { | { | ||||
| static MYSQL_RES* value = reinterpret_cast<MYSQL_RES*>(0x1000); | |||||
| return ++value; | |||||
| static size_t value = 0x2000; | |||||
| return reinterpret_cast<MYSQL_RES*>(value++); | |||||
| } | } | ||||
| inline const result_data::data_type& empty_result_data() | inline const result_data::data_type& empty_result_data() | ||||