From 46badf17c4fa8ffe1a13bf147ba492dcc984a57b Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 21 Dec 2016 05:57:00 +0000 Subject: [PATCH] IB: FK cascade delete when parent versioned [fixes #101] --- mysql-test/suite/versioning/r/foreign.result | 26 ++++++++++++++++-- mysql-test/suite/versioning/t/foreign.test | 29 ++++++++++++++++++-- storage/innobase/row/row0ins.cc | 23 ++++++++++------ 3 files changed, 63 insertions(+), 15 deletions(-) diff --git a/mysql-test/suite/versioning/r/foreign.result b/mysql-test/suite/versioning/r/foreign.result index b9c49778c5e..ee9e726a29a 100644 --- a/mysql-test/suite/versioning/r/foreign.result +++ b/mysql-test/suite/versioning/r/foreign.result @@ -52,21 +52,41 @@ insert into child values(1); delete from parent where id = 1; select * from child; parent_id -select * from child for system_time from timestamp '1-1-1' to timestamp now(6); +select * from child for system_time all; parent_id 1 insert into parent values(1); insert into child values(1); -update parent set id=id+1; +update parent set id = id + 1; select * from child; parent_id 2 -select * from child for system_time from timestamp '1-1-1' to timestamp now(6); +select * from child for system_time all; parent_id 1 2 drop table child; drop table parent; +create or replace table parent ( +id int primary key +) with system versioning +engine innodb; +create or replace table child ( +x int, +parent_id int not null, +constraint `parent-fk` + foreign key (parent_id) references parent (id) +on delete cascade +on update restrict +) +engine innodb; +insert into parent (id) values (1); +insert into child (x, parent_id) values (1, 1); +delete from parent; +select * from child; +x parent_id +drop table child; +drop table parent; create table parent( id int unique key ) engine innodb; diff --git a/mysql-test/suite/versioning/t/foreign.test b/mysql-test/suite/versioning/t/foreign.test index 3f1a14e58aa..2a1bca3af60 100644 --- a/mysql-test/suite/versioning/t/foreign.test +++ b/mysql-test/suite/versioning/t/foreign.test @@ -76,13 +76,36 @@ insert into child values(1); delete from parent where id = 1; select * from child; -select * from child for system_time from timestamp '1-1-1' to timestamp now(6); +select * from child for system_time all; insert into parent values(1); insert into child values(1); -update parent set id=id+1; +update parent set id = id + 1; +select * from child; +select * from child for system_time all; + +drop table child; +drop table parent; + +create or replace table parent ( + id int primary key +) with system versioning +engine innodb; + +create or replace table child ( + x int, + parent_id int not null, + constraint `parent-fk` + foreign key (parent_id) references parent (id) + on delete cascade + on update restrict +) +engine innodb; + +insert into parent (id) values (1); +insert into child (x, parent_id) values (1, 1); +delete from parent; select * from child; -select * from child for system_time from timestamp '1-1-1' to timestamp now(6); drop table child; drop table parent; diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 40d3eccdc34..f3fc7422ffe 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -430,7 +430,8 @@ row_ins_cascade_ancestor_updates_table( upd_node = static_cast(parent); - if (upd_node->table == table && upd_node->is_delete == FALSE) { + if (upd_node->table == table && upd_node->is_delete == FALSE + && !upd_node->vers_delete) { return(TRUE); } @@ -977,6 +978,8 @@ row_ins_foreign_fill_virtual( innobase_init_vc_templ(index->table); } + bool is_delete = node->is_delete || node->vers_delete; + for (ulint i = 0; i < n_v_fld; i++) { dict_v_col_t* col = dict_table_get_nth_v_col( @@ -1008,14 +1011,14 @@ row_ins_foreign_fill_virtual( upd_field_set_v_field_no(upd_field, i, index); - if (node->is_delete + if (is_delete ? (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) : (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)) { dfield_set_null(&upd_field->new_val); } - if (!node->is_delete + if (!is_delete && (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)) { dfield_t* new_vfield = innobase_get_computed_value( @@ -1108,7 +1111,9 @@ row_ins_foreign_check_on_constraint( node = static_cast(thr->run_node); - if (node->is_delete && 0 == (foreign->type + bool is_delete = node->is_delete || node->vers_delete; + + if (is_delete && 0 == (foreign->type & (DICT_FOREIGN_ON_DELETE_CASCADE | DICT_FOREIGN_ON_DELETE_SET_NULL))) { @@ -1119,7 +1124,7 @@ row_ins_foreign_check_on_constraint( DBUG_RETURN(DB_ROW_IS_REFERENCED); } - if (!node->is_delete && 0 == (foreign->type + if (!is_delete && 0 == (foreign->type & (DICT_FOREIGN_ON_UPDATE_CASCADE | DICT_FOREIGN_ON_UPDATE_SET_NULL))) { @@ -1148,7 +1153,7 @@ row_ins_foreign_check_on_constraint( cascade->foreign = foreign; - if (node->is_delete + if (is_delete && (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)) { cascade->is_delete = TRUE; } else { @@ -1285,7 +1290,7 @@ row_ins_foreign_check_on_constraint( clust_index, tmp_heap); } - if (node->is_delete + if (is_delete ? (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) : (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)) { @@ -1365,7 +1370,7 @@ row_ins_foreign_check_on_constraint( } } - if (!node->is_delete + if (!is_delete && (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)) { /* Build the appropriate update vector which sets changing @@ -1690,7 +1695,7 @@ row_ins_check_foreign_constraint( if (que_node_get_type(thr->run_node) == QUE_NODE_UPDATE) { upd_node = static_cast(thr->run_node); - if (!(upd_node->is_delete) && upd_node->foreign == foreign) { + if (!(upd_node->is_delete) && !(upd_node->vers_delete) && upd_node->foreign == foreign) { /* If a cascaded update is done as defined by a foreign key constraint, do not check that constraint for the child row. In ON UPDATE CASCADE