1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

MDEV-23722 InnoDB: Assertion: result != FTS_INVALID in fts_trx_row_get_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ä
This commit is contained in:
Thirunarayanan Balathandayuthapani
2020-09-29 16:18:43 +05:30
parent 874942a0f9
commit 6504d3d229
10 changed files with 212 additions and 70 deletions

View File

@ -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;

View File

@ -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
#

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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&

View File

@ -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(
@ -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
@ -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;
@ -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(
@ -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

View File

@ -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;
}

View File

@ -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&

View File

@ -516,7 +516,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(
@ -637,16 +637,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
@ -983,7 +973,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;
@ -1197,7 +1186,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(
@ -1206,32 +1195,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