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:
@ -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;
|
||||
|
@ -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
|
||||
#
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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&
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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&
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user