Commit 7a98d232 authored by Nikita Malyavin's avatar Nikita Malyavin

MDEV-30378 Versioned REPLACE succeeds with ON DELETE RESTRICT constraint

node->is_delete was incorrectly set to NO_DELETE for a set of operations.

In general we shouldn't rely on sql_command and look for more abstract ways
to control the behavior.

trg_event_map seems to be a suitable way. To mind replica nodes, it is ORed
with slave_fk_event_map, which stores trg_event_map when replica has
triggers disabled.
parent eb145e5a
......@@ -493,3 +493,42 @@ set foreign_key_checks= on;
delete history from t1;
delete from t1;
drop table t1;
#
# MDEV-30378 Versioned REPLACE succeeds with ON DELETE RESTRICT
# constraint
#
create table t0 (pk integer primary key) with system versioning engine=innodb;
create table t1 (pk integer primary key,
foreign key(pk) references t0(pk)
on delete restrict on update cascade) engine=innodb;
create table t2 (pk integer);
insert into t0 (pk) values (1);
insert into t1 (pk) values (1);
insert into t2 (pk) values (1);
delete from t0;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_1` FOREIGN KEY (`pk`) REFERENCES `t0` (`pk`) ON UPDATE CASCADE)
replace t0 values (1);
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_1` FOREIGN KEY (`pk`) REFERENCES `t0` (`pk`) ON UPDATE CASCADE)
select * into outfile 'load_t0' from t0 ;
load data infile 'load_t0' replace into table t0;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_1` FOREIGN KEY (`pk`) REFERENCES `t0` (`pk`) ON UPDATE CASCADE)
delete t0, t2 from t0 join t2;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_1` FOREIGN KEY (`pk`) REFERENCES `t0` (`pk`) ON UPDATE CASCADE)
select pk from t0;
pk
1
# Cleanup
drop table t1, t0, t2;
# create_select for a temporary table didn't set up pos_in_locked_tables.
create table t (a int unique) engine=innodb
replace select 1 as a, 2 as b union select 1 as a, 3 as c;
select * from t;
a b
1 3
drop table t;
create temporary table t (a int unique) engine=innodb
replace select 1 as a, 2 as b union select 1 as a, 3 as c;
select * from t;
a b
1 3
drop table t;
......@@ -527,4 +527,50 @@ delete from t1;
# cleanup
drop table t1;
--echo #
--echo # MDEV-30378 Versioned REPLACE succeeds with ON DELETE RESTRICT
--echo # constraint
--echo #
create table t0 (pk integer primary key) with system versioning engine=innodb;
create table t1 (pk integer primary key,
foreign key(pk) references t0(pk)
on delete restrict on update cascade) engine=innodb;
create table t2 (pk integer);
insert into t0 (pk) values (1);
insert into t1 (pk) values (1);
insert into t2 (pk) values (1);
--error ER_ROW_IS_REFERENCED_2
delete from t0;
--error ER_ROW_IS_REFERENCED_2
replace t0 values (1);
select * into outfile 'load_t0' from t0 ;
--error ER_ROW_IS_REFERENCED_2
load data infile 'load_t0' replace into table t0;
--error ER_ROW_IS_REFERENCED_2
delete t0, t2 from t0 join t2;
select pk from t0;
--echo # Cleanup
drop table t1, t0, t2;
--let $datadir= `select @@datadir`
--remove_file $datadir/test/load_t0
--echo # create_select for a temporary table didn't set up pos_in_locked_tables.
create table t (a int unique) engine=innodb
replace select 1 as a, 2 as b union select 1 as a, 3 as c;
select * from t;
drop table t;
create temporary table t (a int unique) engine=innodb
replace select 1 as a, 2 as b union select 1 as a, 3 as c;
select * from t;
drop table t;
--source suite/versioning/common_finish.inc
......@@ -4396,6 +4396,7 @@ TABLE *select_create::create_table_from_items(THD *thd,
*/
DBUG_ASSERT(0);
}
create_table->table->pos_in_table_list= create_table;
}
}
else
......
......@@ -8957,10 +8957,12 @@ ha_innobase::update_row(
const bool vers_ins_row = vers_set_fields
&& thd_sql_command(m_user_thd) != SQLCOM_ALTER_TABLE;
TABLE_LIST *tl= table->pos_in_table_list;
uint8 op_map= tl->trg_event_map | tl->slave_fk_event_map;
/* This is not a delete */
m_prebuilt->upd_node->is_delete =
(vers_set_fields && !vers_ins_row) ||
(thd_sql_command(m_user_thd) == SQLCOM_DELETE &&
(op_map & trg2bit(TRG_EVENT_DELETE) &&
table->versioned(VERS_TIMESTAMP))
? VERSIONED_DELETE
: NO_DELETE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment