Skip to content

Commit 7fe906a

Browse files
author
Nisha Gopalakrishnan
committed
Bug#36234681: InnoDB: Failing assertion: result != FTS_INVALID
ANALYSIS DELETE operation on a table with self referential foreign key constraint and full text index may trigger an assert. When performing the DELETE operation, marking of deletion of the full text row happens twice due to the self referential foreign key constraint. Hence the state of the row becomes invalid and the assert is triggered. Fix Avoid updating the full text index if the foreign key has self referential constraint. NOTE: This is a 5.7 patch Change-Id: I96d32937e8f50ecb580f3084c9fccd423408575d
1 parent 0fe52ea commit 7fe906a

File tree

3 files changed

+42
-37
lines changed

3 files changed

+42
-37
lines changed

storage/innobase/dict/dict0mem.cc

+27-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*****************************************************************************
22
3-
Copyright (c) 1996, 2023, Oracle and/or its affiliates.
3+
Copyright (c) 1996, 2024, Oracle and/or its affiliates.
44
Copyright (c) 2012, Facebook Inc.
55
66
This program is free software; you can redistribute it and/or modify
@@ -1128,6 +1128,32 @@ dict_foreign_set_validate(
11281128
&& dict_foreign_set_validate(table.referenced_set));
11291129
}
11301130

1131+
bool dict_foreign_t::is_fts_col_affected() const
1132+
{
1133+
/* The check is skipped:
1134+
- if the table has no full text index defined.
1135+
- if it is a self referential foreign constaint. This is because
1136+
in the context of cascading DML operation, only the referenced
1137+
table is relevant for the validation even if the current table
1138+
has FTS index. */
1139+
if (!foreign_table->fts || foreign_table == referenced_table) {
1140+
return false;
1141+
}
1142+
1143+
for (ulint i = 0; i < n_fields; i++)
1144+
{
1145+
const dict_col_t* col = dict_index_get_nth_col(
1146+
foreign_index, i);
1147+
1148+
if (dict_table_is_fts_column(foreign_table->fts->indexes,
1149+
dict_col_get_no(col),
1150+
dict_col_is_virtual(col)) != ULINT_UNDEFINED) {
1151+
return true;
1152+
}
1153+
}
1154+
return false;
1155+
}
1156+
11311157
std::ostream&
11321158
operator<< (std::ostream& out, const dict_foreign_t& foreign)
11331159
{

storage/innobase/include/dict0mem.h

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*****************************************************************************
22
3-
Copyright (c) 1996, 2023, Oracle and/or its affiliates.
3+
Copyright (c) 1996, 2024, Oracle and/or its affiliates.
44
Copyright (c) 2012, Facebook Inc.
55
66
This program is free software; you can redistribute it and/or modify
@@ -1093,6 +1093,14 @@ struct dict_foreign_t{
10931093

10941094
dict_vcol_set* v_cols; /*!< set of virtual columns affected
10951095
by foreign key constraint. */
1096+
/** Check whether foreign key constraint contains a column with a full
1097+
index on it. The function is used in the context of cascading DML
1098+
operations.
1099+
@retval true if the column has FTS index on it.
1100+
@retval false if the FK table has no FTS index or has self referential
1101+
relationship
1102+
*/
1103+
bool is_fts_col_affected() const;
10961104
};
10971105

10981106
std::ostream&

storage/innobase/row/row0ins.cc

+6-35
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ row_ins_cascade_calc_update_vec(
535535

536536
n_fields_updated = 0;
537537

538-
*fts_col_affected = FALSE;
538+
*fts_col_affected = foreign->is_fts_col_affected();
539539

540540
if (table->fts) {
541541
doc_id_pos = dict_table_get_nth_col_pos(
@@ -660,16 +660,6 @@ row_ins_cascade_calc_update_vec(
660660
padded_data, min_size);
661661
}
662662

663-
/* Check whether the current column has
664-
FTS index on it */
665-
if (table->fts
666-
&& dict_table_is_fts_column(
667-
table->fts->indexes,
668-
dict_col_get_no(col),
669-
dict_col_is_virtual(col))
670-
!= ULINT_UNDEFINED) {
671-
*fts_col_affected = TRUE;
672-
}
673663

674664
/* If Doc ID is updated, check whether the
675665
Doc ID is valid */
@@ -1117,7 +1107,6 @@ row_ins_foreign_check_on_constraint(
11171107
trx_t* trx;
11181108
mem_heap_t* tmp_heap = NULL;
11191109
doc_id_t doc_id = FTS_NULL_DOC_ID;
1120-
ibool fts_col_affacted = FALSE;
11211110

11221111
DBUG_ENTER("row_ins_foreign_check_on_constraint");
11231112
ut_a(thr);
@@ -1348,17 +1337,9 @@ row_ins_foreign_check_on_constraint(
13481337
ufield->exp = NULL;
13491338
dfield_set_null(&ufield->new_val);
13501339

1351-
if (table->fts && dict_table_is_fts_column(
1352-
table->fts->indexes,
1353-
dict_index_get_nth_col_no(index, i),
1354-
dict_col_is_virtual(
1355-
dict_index_get_nth_col(index, i)))
1356-
!= ULINT_UNDEFINED) {
1357-
fts_col_affacted = TRUE;
1358-
}
13591340
}
13601341

1361-
if (fts_col_affacted) {
1342+
if (foreign->is_fts_col_affected()) {
13621343
fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL);
13631344
}
13641345

@@ -1375,31 +1356,21 @@ row_ins_foreign_check_on_constraint(
13751356

13761357
} else if (table->fts && cascade->is_delete) {
13771358
/* DICT_FOREIGN_ON_DELETE_CASCADE case */
1378-
for (i = 0; i < foreign->n_fields; i++) {
1379-
if (table->fts && dict_table_is_fts_column(
1380-
table->fts->indexes,
1381-
dict_index_get_nth_col_no(index, i),
1382-
dict_col_is_virtual(
1383-
dict_index_get_nth_col(index, i)))
1384-
!= ULINT_UNDEFINED) {
1385-
fts_col_affacted = TRUE;
1386-
}
1387-
}
1388-
1389-
if (fts_col_affacted) {
1359+
if (foreign->is_fts_col_affected()) {
13901360
fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL);
13911361
}
13921362
}
13931363

13941364
if (!node->is_delete
13951365
&& (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)) {
1366+
ibool fts_col_affected = FALSE;
13961367

13971368
/* Build the appropriate update vector which sets changing
13981369
foreign->n_fields first fields in rec to new values */
13991370

14001371
n_to_update = row_ins_cascade_calc_update_vec(
14011372
node, foreign, tmp_heap,
1402-
trx, &fts_col_affacted);
1373+
trx, &fts_col_affected);
14031374

14041375

14051376
if (foreign->v_cols != NULL
@@ -1440,7 +1411,7 @@ row_ins_foreign_check_on_constraint(
14401411
}
14411412

14421413
/* Mark the old Doc ID as deleted */
1443-
if (fts_col_affacted) {
1414+
if (fts_col_affected) {
14441415
ut_ad(table->fts);
14451416
fts_trx_add_op(trx, table, doc_id, FTS_DELETE, NULL);
14461417
}

0 commit comments

Comments
 (0)