Skip to content

Commit

Permalink
MDEV-23722 InnoDB: Assertion: result != FTS_INVALID in fts_trx_row_ge…
Browse files Browse the repository at this point in the history
…t_new_state

Marking of deletion of row in fts index happens twice in
self-referential foreign key relation. So while performing
referential checks of foreign key, InnoDB can avoid updating
of fts index if the foreign key has self-referential relationship.

Reviewed-by: Marko Mäkelä
  • Loading branch information
Thirunarayanan committed Oct 8, 2020
1 parent 874942a commit 6504d3d
Show file tree
Hide file tree
Showing 10 changed files with 212 additions and 70 deletions.
35 changes: 35 additions & 0 deletions mysql-test/suite/innodb/r/foreign_key.result
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,38 @@ ERROR HY000: Lock wait timeout exceeded; try restarting transaction
XA END 'xid';
XA ROLLBACK 'xid';
DROP TABLE t1;
CREATE TABLE t1 (pk INT PRIMARY KEY,
f1 VARCHAR(10), f2 VARCHAR(10),
f3 VARCHAR(10), f4 VARCHAR(10),
f5 VARCHAR(10), f6 VARCHAR(10),
f7 VARCHAR(10), f8 VARCHAR(10),
INDEX(f1), INDEX(f2), INDEX(f3), INDEX(f4),
INDEX(f5), INDEX(f6), INDEX(f7), INDEX(f8)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1, 'mariadb', 'mariadb', 'mariadb', 'mariadb',
'mariadb', 'mariadb', 'mariadb', 'mariadb'),
(2, 'mariadb', 'mariadb', 'mariadb', 'mariadb',
'mariadb', 'mariadb', 'mariadb', 'mariadb'),
(3, 'innodb', 'innodb', 'innodb', 'innodb',
'innodb', 'innodb', 'innodb', 'innodb');
ALTER TABLE t1 ADD FOREIGN KEY (f1) REFERENCES t1 (f2) ON DELETE SET NULL;
START TRANSACTION;
DELETE FROM t1 where f1='mariadb';
SELECT * FROM t1;
pk f1 f2 f3 f4 f5 f6 f7 f8
2 NULL mariadb mariadb mariadb mariadb mariadb mariadb mariadb
3 innodb innodb innodb innodb innodb innodb innodb innodb
ROLLBACK;
ALTER TABLE t1 ADD FOREIGN KEY (f3) REFERENCES t1 (f4) ON DELETE CASCADE;
START TRANSACTION;
DELETE FROM t1 where f3='mariadb';
SELECT * FROM t1;
pk f1 f2 f3 f4 f5 f6 f7 f8
3 innodb innodb innodb innodb innodb innodb innodb innodb
ROLLBACK;
ALTER TABLE t1 ADD FOREIGN KEY (f5) REFERENCES t1 (f6) ON UPDATE SET NULL;
UPDATE t1 SET f6='update';
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_3` FOREIGN KEY (`f5`) REFERENCES `t1` (`f6`) ON UPDATE SET NULL)
ALTER TABLE t1 ADD FOREIGN KEY (f7) REFERENCES t1 (f8) ON UPDATE CASCADE;
UPDATE t1 SET f6='cascade';
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_3` FOREIGN KEY (`f5`) REFERENCES `t1` (`f6`) ON UPDATE SET NULL)
DROP TABLE t1;
35 changes: 35 additions & 0 deletions mysql-test/suite/innodb/t/foreign_key.test
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,41 @@ ALTER TABLE t1 ADD FOREIGN KEY f (a) REFERENCES t1 (pk), LOCK=EXCLUSIVE;# Cleanu
XA END 'xid';
XA ROLLBACK 'xid';
DROP TABLE t1;

CREATE TABLE t1 (pk INT PRIMARY KEY,
f1 VARCHAR(10), f2 VARCHAR(10),
f3 VARCHAR(10), f4 VARCHAR(10),
f5 VARCHAR(10), f6 VARCHAR(10),
f7 VARCHAR(10), f8 VARCHAR(10),
INDEX(f1), INDEX(f2), INDEX(f3), INDEX(f4),
INDEX(f5), INDEX(f6), INDEX(f7), INDEX(f8)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1, 'mariadb', 'mariadb', 'mariadb', 'mariadb',
'mariadb', 'mariadb', 'mariadb', 'mariadb'),
(2, 'mariadb', 'mariadb', 'mariadb', 'mariadb',
'mariadb', 'mariadb', 'mariadb', 'mariadb'),
(3, 'innodb', 'innodb', 'innodb', 'innodb',
'innodb', 'innodb', 'innodb', 'innodb');
ALTER TABLE t1 ADD FOREIGN KEY (f1) REFERENCES t1 (f2) ON DELETE SET NULL;
START TRANSACTION;
DELETE FROM t1 where f1='mariadb';
SELECT * FROM t1;
ROLLBACK;

ALTER TABLE t1 ADD FOREIGN KEY (f3) REFERENCES t1 (f4) ON DELETE CASCADE;

START TRANSACTION;
DELETE FROM t1 where f3='mariadb';
SELECT * FROM t1;
ROLLBACK;

ALTER TABLE t1 ADD FOREIGN KEY (f5) REFERENCES t1 (f6) ON UPDATE SET NULL;
--error ER_ROW_IS_REFERENCED_2
UPDATE t1 SET f6='update';

ALTER TABLE t1 ADD FOREIGN KEY (f7) REFERENCES t1 (f8) ON UPDATE CASCADE;
--error ER_ROW_IS_REFERENCED_2
UPDATE t1 SET f6='cascade';
DROP TABLE t1;
#
# End of 10.1 tests
#
42 changes: 42 additions & 0 deletions mysql-test/suite/innodb_fts/r/innodb_fts_misc_1.result
Original file line number Diff line number Diff line change
Expand Up @@ -913,4 +913,46 @@ DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
DROP TABLE t4;
#
# InnoDB: Failing assertion: result != FTS_INVALID in
# fts_trx_row_get_new_state
#
SET FOREIGN_KEY_CHECKS=1;
CREATE TABLE t1 (pk INT PRIMARY KEY,
f1 VARCHAR(10), f2 VARCHAR(10),
f3 VARCHAR(10), f4 VARCHAR(10),
f5 VARCHAR(10), f6 VARCHAR(10),
f7 VARCHAR(10), f8 VARCHAR(10),
FULLTEXT(f1), FULLTEXT(f2), FULLTEXT(f3), FULLTEXT(f4),
FULLTEXT(f5), FULLTEXT(f6), FULLTEXT(f7), FULLTEXT(f8),
INDEX(f1), INDEX(f2), INDEX(f3), INDEX(f4),
INDEX(f5), INDEX(f6), INDEX(f7), INDEX(f8)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1, 'mariadb', 'mariadb', 'mariadb', 'mariadb',
'mariadb', 'mariadb', 'mariadb', 'mariadb'),
(2, 'mariadb', 'mariadb', 'mariadb', 'mariadb',
'mariadb', 'mariadb', 'mariadb', 'mariadb'),
(3, 'innodb', 'innodb', 'innodb', 'innodb',
'innodb', 'innodb', 'innodb', 'innodb');
ALTER TABLE t1 ADD FOREIGN KEY (f1) REFERENCES t1 (f2) ON DELETE SET NULL;
START TRANSACTION;
DELETE FROM t1 where f1='mariadb';
SELECT * FROM t1;
pk f1 f2 f3 f4 f5 f6 f7 f8
2 NULL mariadb mariadb mariadb mariadb mariadb mariadb mariadb
3 innodb innodb innodb innodb innodb innodb innodb innodb
ROLLBACK;
ALTER TABLE t1 ADD FOREIGN KEY (f3) REFERENCES t1 (f4) ON DELETE CASCADE;
START TRANSACTION;
DELETE FROM t1 where f3='mariadb';
SELECT * FROM t1;
pk f1 f2 f3 f4 f5 f6 f7 f8
3 innodb innodb innodb innodb innodb innodb innodb innodb
ROLLBACK;
ALTER TABLE t1 ADD FOREIGN KEY (f5) REFERENCES t1 (f6) ON UPDATE SET NULL;
UPDATE t1 SET f6='update';
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_3` FOREIGN KEY (`f5`) REFERENCES `t1` (`f6`) ON UPDATE SET NULL)
ALTER TABLE t1 ADD FOREIGN KEY (f7) REFERENCES t1 (f8) ON UPDATE CASCADE;
UPDATE t1 SET f6='cascade';
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_3` FOREIGN KEY (`f5`) REFERENCES `t1` (`f6`) ON UPDATE SET NULL)
DROP TABLE t1;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
42 changes: 42 additions & 0 deletions mysql-test/suite/innodb_fts/t/innodb_fts_misc_1.test
Original file line number Diff line number Diff line change
Expand Up @@ -907,4 +907,46 @@ DROP TABLE t2;
DROP TABLE t3;
DROP TABLE t4;

--echo #
--echo # InnoDB: Failing assertion: result != FTS_INVALID in
--echo # fts_trx_row_get_new_state
--echo #
SET FOREIGN_KEY_CHECKS=1;
CREATE TABLE t1 (pk INT PRIMARY KEY,
f1 VARCHAR(10), f2 VARCHAR(10),
f3 VARCHAR(10), f4 VARCHAR(10),
f5 VARCHAR(10), f6 VARCHAR(10),
f7 VARCHAR(10), f8 VARCHAR(10),
FULLTEXT(f1), FULLTEXT(f2), FULLTEXT(f3), FULLTEXT(f4),
FULLTEXT(f5), FULLTEXT(f6), FULLTEXT(f7), FULLTEXT(f8),
INDEX(f1), INDEX(f2), INDEX(f3), INDEX(f4),
INDEX(f5), INDEX(f6), INDEX(f7), INDEX(f8)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1, 'mariadb', 'mariadb', 'mariadb', 'mariadb',
'mariadb', 'mariadb', 'mariadb', 'mariadb'),
(2, 'mariadb', 'mariadb', 'mariadb', 'mariadb',
'mariadb', 'mariadb', 'mariadb', 'mariadb'),
(3, 'innodb', 'innodb', 'innodb', 'innodb',
'innodb', 'innodb', 'innodb', 'innodb');
ALTER TABLE t1 ADD FOREIGN KEY (f1) REFERENCES t1 (f2) ON DELETE SET NULL;
START TRANSACTION;
DELETE FROM t1 where f1='mariadb';
SELECT * FROM t1;
ROLLBACK;

ALTER TABLE t1 ADD FOREIGN KEY (f3) REFERENCES t1 (f4) ON DELETE CASCADE;

START TRANSACTION;
DELETE FROM t1 where f3='mariadb';
SELECT * FROM t1;
ROLLBACK;

ALTER TABLE t1 ADD FOREIGN KEY (f5) REFERENCES t1 (f6) ON UPDATE SET NULL;
--error ER_ROW_IS_REFERENCED_2
UPDATE t1 SET f6='update';

ALTER TABLE t1 ADD FOREIGN KEY (f7) REFERENCES t1 (f8) ON UPDATE CASCADE;
--error ER_ROW_IS_REFERENCED_2
UPDATE t1 SET f6='cascade';
DROP TABLE t1;

SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
19 changes: 19 additions & 0 deletions storage/innobase/dict/dict0mem.cc
Original file line number Diff line number Diff line change
Expand Up @@ -852,3 +852,22 @@ operator<< (std::ostream& out, const dict_foreign_set& fk_set)
return(out);
}

/** Check whether fulltext index gets affected by foreign
key constraint. */
bool dict_foreign_t::affects_fulltext() const
{
if (foreign_table == referenced_table || !foreign_table->fts)
return false;

for (ulint i = 0; i < n_fields; i++)
{
if (dict_table_is_fts_column(
foreign_table->fts->indexes,
dict_index_get_nth_col_no(foreign_index, i))
!= ULINT_UNDEFINED)
return true;
}

return false;
}

4 changes: 4 additions & 0 deletions storage/innobase/include/dict0mem.h
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,10 @@ struct dict_foreign_t{
does not generate new indexes
implicitly */
dict_index_t* referenced_index;/*!< referenced index */

/** Check whether the fulltext index gets affected by
foreign key constraint */
bool affects_fulltext() const;
};

std::ostream&
Expand Down
41 changes: 6 additions & 35 deletions storage/innobase/row/row0ins.cc
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ row_ins_cascade_calc_update_vec(

n_fields_updated = 0;

*fts_col_affected = FALSE;
*fts_col_affected = foreign->affects_fulltext();

if (table->fts) {
doc_id_pos = dict_table_get_nth_col_pos(
Expand Down Expand Up @@ -631,16 +631,6 @@ row_ins_cascade_calc_update_vec(
padded_data, min_size);
}

/* Check whether the current column has
FTS index on it */
if (table->fts
&& dict_table_is_fts_column(
table->fts->indexes,
dict_col_get_no(col))
!= ULINT_UNDEFINED) {
*fts_col_affected = TRUE;
}

/* If Doc ID is updated, check whether the
Doc ID is valid */
if (table->fts
Expand Down Expand Up @@ -977,7 +967,6 @@ row_ins_foreign_check_on_constraint(
upd_t* update;
ulint n_to_update;
dberr_t err;
ulint i;
trx_t* trx;
mem_heap_t* tmp_heap = NULL;
doc_id_t doc_id = FTS_NULL_DOC_ID;
Expand Down Expand Up @@ -1191,7 +1180,7 @@ row_ins_foreign_check_on_constraint(
UNIV_MEM_INVALID(update->fields,
update->n_fields * sizeof *update->fields);

for (i = 0; i < foreign->n_fields; i++) {
for (ulint i = 0; i < foreign->n_fields; i++) {
upd_field_t* ufield = &update->fields[i];

ufield->field_no = dict_table_get_nth_col_pos(
Expand All @@ -1200,32 +1189,14 @@ row_ins_foreign_check_on_constraint(
ufield->orig_len = 0;
ufield->exp = NULL;
dfield_set_null(&ufield->new_val);

if (table->fts && dict_table_is_fts_column(
table->fts->indexes,
dict_index_get_nth_col_no(index, i))
!= ULINT_UNDEFINED) {
fts_col_affacted = TRUE;
}
}

if (fts_col_affacted) {
fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL);
}
} else if (table->fts && cascade->is_delete) {
/* DICT_FOREIGN_ON_DELETE_CASCADE case */
for (i = 0; i < foreign->n_fields; i++) {
if (table->fts && dict_table_is_fts_column(
table->fts->indexes,
dict_index_get_nth_col_no(index, i))
!= ULINT_UNDEFINED) {
fts_col_affacted = TRUE;
}
}

if (fts_col_affacted) {
if (foreign->affects_fulltext()) {
fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL);
}
} else if (table->fts && cascade->is_delete
&& foreign->affects_fulltext()) {
fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL);
}

if (!node->is_delete
Expand Down
19 changes: 19 additions & 0 deletions storage/xtradb/dict/dict0mem.cc
Original file line number Diff line number Diff line change
Expand Up @@ -853,3 +853,22 @@ operator<< (std::ostream& out, const dict_foreign_set& fk_set)
return(out);
}

/** Check whether fulltext index gets affected by foreign
key constraint. */
bool dict_foreign_t::affects_fulltext() const
{
if (foreign_table == referenced_table || !foreign_table->fts)
return false;

for (ulint i = 0; i < n_fields; i++)
{
if (dict_table_is_fts_column(
foreign_table->fts->indexes,
dict_index_get_nth_col_no(foreign_index, i))
!= ULINT_UNDEFINED)
return true;
}

return false;
}

4 changes: 4 additions & 0 deletions storage/xtradb/include/dict0mem.h
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,10 @@ struct dict_foreign_t{
does not generate new indexes
implicitly */
dict_index_t* referenced_index;/*!< referenced index */

/** Check whether the fulltext index gets affected by
foreign key constraint */
bool affects_fulltext() const;
};

std::ostream&
Expand Down
Loading

0 comments on commit 6504d3d

Please sign in to comment.