Procházet zdrojové kódy

* fixed table cleanup after a table that contains a sub-table was deleted

master
bergmann před 7 roky
rodič
revize
bdf9c5499f
6 změnil soubory, kde provedl 145 přidání a 17 odebrání
  1. +3
    -1
      include/cpphibernate/driver/mariadb/schema/table.h
  2. +20
    -8
      src/cpphibernate/driver/mariadb/schema/table.cpp
  3. +2
    -8
      test/cpphibernate_destroy.cpp
  4. +18
    -0
      test/cpphibernate_init.cpp
  5. +89
    -0
      test/cpphibernate_update.cpp
  6. +13
    -0
      test/test_schema.h

+ 3
- 1
include/cpphibernate/driver/mariadb/schema/table.h Zobrazit soubor

@@ -130,6 +130,8 @@ beg_namespace_cpphibernate_driver_mariadb
virtual std::string create_update_base(const create_update_context& context) const;

protected:
using table_set = std::set<const table_t*>;

void init_stage1_exec (const init_context& context) const;
void init_stage2_exec (const init_context& context) const;

@@ -140,7 +142,7 @@ beg_namespace_cpphibernate_driver_mariadb

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;
void destroy_cleanup (const base_context& context, table_set& processed, bool check_derived, bool check_base) const;
};

/* table_simple_t */


+ 20
- 8
src/cpphibernate/driver/mariadb/schema/table.cpp Zobrazit soubor

@@ -1253,6 +1253,9 @@ std::string table_t::execute_create_update(
delete_statement.set(1, *key);
cpphibernate_debug_log("execute DELETE old foreign one query: " << delete_statement.query(connection));
connection.execute(delete_statement);

table_set processed;
field.referenced_table->destroy_cleanup(context, processed, true, true);
}
}

@@ -1397,7 +1400,8 @@ std::string table_t::execute_create_update(
/* delete non referenced elements */
if (context.is_update)
{
ref_table.destroy_cleanup(context, true, true);
table_set processed;
ref_table.destroy_cleanup(context, processed, true, true);
}
}

@@ -1778,30 +1782,38 @@ void table_t::destroy_exec(const destroy_context& context) const
cpphibernate_debug_log("execute DELETE query: " << statement.query(connection));
connection.execute(statement);

for (auto& ptr : foreign_table_many_fields)
table_set processed;
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 (ref_table.is_used_in_container)
ref_table.destroy_cleanup(context, processed, true, true);
}
}

void table_t::destroy_cleanup(const base_context& context, bool check_derived, bool check_base) const
void table_t::destroy_cleanup(const base_context& context, table_set& processed, bool check_derived, bool check_base) const
{
if (processed.count(this))
return;

processed.emplace(this);

execute_foreign_many_delete(context);

for (auto ptr : foreign_table_many_fields)
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 (ref_table.is_used_in_container)
ref_table.destroy_cleanup(context, processed, true, true);
}

if (check_base && base_table)
{
base_table->destroy_cleanup(context, false, true);
base_table->destroy_cleanup(context, processed, false, true);
}

if (check_derived)
@@ -1809,7 +1821,7 @@ void table_t::destroy_cleanup(const base_context& context, bool check_derived, b
for (auto ptr : derived_tables)
{
assert(ptr);
ptr->destroy_cleanup(context, true, false);
ptr->destroy_cleanup(context, processed, true, false);
}
}
}

+ 2
- 8
test/cpphibernate_destroy.cpp Zobrazit soubor

@@ -221,13 +221,6 @@ TEST(CppHibernateTests, destroy_derived3)
"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(
@@ -289,4 +282,5 @@ TEST(CppHibernateTests, destroy_double_usage)
::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
auto context = make_context<driver::mariadb>(test_schema, connection);
context.destroy(d);
}
}


+ 18
- 0
test/cpphibernate_init.cpp Zobrazit soubor

@@ -197,6 +197,17 @@ TEST(CppHibernateTests, init)
"ENGINE = InnoDB\n"
"DEFAULT CHARACTER SET = utf8");

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_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"
" INDEX `index_tbl_double_usage_id_double_usage` ( `tbl_double_usage_id_double_usage` ASC )\n"
")\n"
"ENGINE = InnoDB\n"
"DEFAULT CHARACTER SET = utf8");

expect_query(mock, "ALTER TABLE `tbl_test3`\n"
" ADD CONSTRAINT `fk_tbl_test3_to_tbl_derived3_id_test3_list`\n"
" FOREIGN KEY IF NOT EXISTS (`tbl_derived3_id_test3_list`)\n"
@@ -269,6 +280,13 @@ TEST(CppHibernateTests, init)
" ON DELETE SET NULL\n"
" ON UPDATE NO ACTION");

expect_query(mock, "ALTER TABLE `tbl_double_usage_wrapper`\n"
" ADD CONSTRAINT `fk_tbl_double_usage_wrapper_to_tbl_double_usage_id_double_usage`\n"
" FOREIGN KEY IF NOT EXISTS (`tbl_double_usage_id_double_usage`)\n"
" REFERENCES `test`.`tbl_double_usage` (`tbl_double_usage_id`)\n"
" ON DELETE SET NULL\n"
" ON UPDATE NO ACTION");

expect_query(mock, "COMMIT");

EXPECT_CALL(


+ 89
- 0
test/cpphibernate_update.cpp Zobrazit soubor

@@ -795,6 +795,95 @@ TEST(CppHibernateTests, update_double_usage)
d.multiple_items.back().id = 1003;
d.multiple_items.back().data = 789;

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

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

expect_query(mock, "START TRANSACTION");
expect_query(mock, "INSERT INTO `tbl_double_usage`",
result_id(101));
expect_query(mock, "INSERT INTO "
"`tbl_double_usage_item` "
"SET "
"`tbl_double_usage_id_single_item`='X101X', "
"`tbl_double_usage_id_multiple_items`=null, "
"`tbl_double_usage_index_multiple_items`='X0X', "
"`data`='X123X'",
result_id(1001));
expect_query(mock, "INSERT INTO "
"`tbl_double_usage_item` "
"SET "
"`tbl_double_usage_id_single_item`=null, "
"`tbl_double_usage_id_multiple_items`='X101X', "
"`tbl_double_usage_index_multiple_items`='X0X', "
"`data`='X456X'",
result_id(1002));
expect_query(mock, "INSERT INTO "
"`tbl_double_usage_item` "
"SET "
"`tbl_double_usage_id_single_item`=null, "
"`tbl_double_usage_id_multiple_items`='X101X', "
"`tbl_double_usage_index_multiple_items`='X1X', "
"`data`='X789X'",
result_id(1003));
expect_query(mock, "DELETE "
"`tbl_double_usage`, `T0` "
"FROM "
"`tbl_double_usage` "
"LEFT JOIN "
"`tbl_double_usage_item` AS `T0` ON `tbl_double_usage`.`tbl_double_usage_id`=`T0`.`tbl_double_usage_id_single_item` "
"WHERE "
"`tbl_double_usage_id` IN ("
"SELECT "
"`tbl_double_usage_id_double_usage` "
"FROM "
"`tbl_double_usage_wrapper` "
"WHERE "
"`tbl_double_usage_wrapper_id`='X1X' "
"AND `tbl_double_usage_id_double_usage`!='X101X'"
")");
expect_query(mock, "DELETE "
"`tbl_double_usage_item` "
"FROM "
"`tbl_double_usage_item` "
"WHERE "
"(`tbl_double_usage_id_single_item` IS NULL) "
"AND (`tbl_double_usage_id_multiple_items` IS NULL)");
expect_query(mock, "UPDATE "
"`tbl_double_usage_wrapper` "
"SET "
"`tbl_double_usage_id_double_usage`='X101X' "
"WHERE "
"`tbl_double_usage_wrapper_id`='X1X'",
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)));

double_usage_wrapper d;
d.id = 1;
d.double_usage.reset(new double_usage());
d.double_usage->single_item.reset(new double_usage_item());
d.double_usage->single_item->data = 123;
d.double_usage->multiple_items.emplace_back();
d.double_usage->multiple_items.back().data = 456;
d.double_usage->multiple_items.emplace_back();
d.double_usage->multiple_items.back().data = 789;

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

+ 13
- 0
test/test_schema.h Zobrazit soubor

@@ -125,6 +125,12 @@ struct double_usage
std::vector<double_usage_item> multiple_items;
};

struct double_usage_wrapper
{
int id { 0 };
std::unique_ptr<double_usage> double_usage;
};

constexpr decltype(auto) test_schema = cpphibernate_make_schema(
test,
cpphibernate_make_table_name(
@@ -219,5 +225,12 @@ constexpr decltype(auto) test_schema = cpphibernate_make_schema(
cpphibernate_make_id (&double_usage::id),
cpphibernate_make_field (double_usage, single_item),
cpphibernate_make_field (double_usage, multiple_items)
),
cpphibernate_make_table_name(
tbl_double_usage_wrapper,
double_usage_wrapper,
18,
cpphibernate_make_id (&double_usage_wrapper::id),
cpphibernate_make_field (double_usage_wrapper, double_usage)
)
);

Načítá se…
Zrušit
Uložit