summaryrefslogtreecommitdiff
path: root/storage/innobase/row
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/row')
-rw-r--r--storage/innobase/row/row0ins.c11
-rw-r--r--storage/innobase/row/row0merge.c5
-rw-r--r--storage/innobase/row/row0mysql.c70
-rw-r--r--storage/innobase/row/row0purge.c33
-rw-r--r--storage/innobase/row/row0row.c55
-rw-r--r--storage/innobase/row/row0sel.c116
-rw-r--r--storage/innobase/row/row0uins.c4
-rw-r--r--storage/innobase/row/row0umod.c25
-rw-r--r--storage/innobase/row/row0upd.c7
9 files changed, 234 insertions, 92 deletions
diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c
index e0414cde80d..2925feb2904 100644
--- a/storage/innobase/row/row0ins.c
+++ b/storage/innobase/row/row0ins.c
@@ -118,6 +118,9 @@ ins_node_create_entry_list(
node->entry_sys_heap);
UT_LIST_ADD_LAST(tuple_list, node->entry_list, entry);
+ /* We will include all indexes (include those corrupted
+ secondary indexes) in the entry list. Filteration of
+ these corrupted index will be done in row_ins() */
index = dict_table_get_next_index(index);
}
}
@@ -2045,7 +2048,6 @@ row_ins_index_entry_low(
mtr_start(&mtr);
if (err != DB_SUCCESS) {
-
goto function_exit;
}
@@ -2395,6 +2397,13 @@ row_ins(
node->index = dict_table_get_next_index(node->index);
node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry);
+
+ /* Skip corrupted secondar index and its entry */
+ while (node->index && dict_index_is_corrupted(node->index)) {
+
+ node->index = dict_table_get_next_index(node->index);
+ node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry);
+ }
}
ut_ad(node->entry == NULL);
diff --git a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c
index 5be437add5a..d42f21241ca 100644
--- a/storage/innobase/row/row0merge.c
+++ b/storage/innobase/row/row0merge.c
@@ -2554,8 +2554,9 @@ row_merge_is_index_usable(
const trx_t* trx, /*!< in: transaction */
const dict_index_t* index) /*!< in: index to check */
{
- return(!trx->read_view
- || read_view_sees_trx_id(trx->read_view, index->trx_id));
+ return(!dict_index_is_corrupted(index)
+ && (!trx->read_view
+ || read_view_sees_trx_id(trx->read_view, index->trx_id)));
}
/*********************************************************************//**
diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
index e1ada387729..d0bedd69842 100644
--- a/storage/innobase/row/row0mysql.c
+++ b/storage/innobase/row/row0mysql.c
@@ -576,6 +576,7 @@ handle_new_error:
case DB_DUPLICATE_KEY:
case DB_FOREIGN_DUPLICATE_KEY:
case DB_TOO_BIG_RECORD:
+ case DB_UNDO_RECORD_TOO_BIG:
case DB_ROW_IS_REFERENCED:
case DB_NO_REFERENCED_ROW:
case DB_CANNOT_ADD_CONSTRAINT:
@@ -2015,41 +2016,13 @@ row_create_index_for_mysql(
trx_start_if_not_started(trx);
- /* Check that the same column does not appear twice in the index.
- Starting from 4.0.14, InnoDB should be able to cope with that, but
- safer not to allow them. */
-
- for (i = 0; i < dict_index_get_n_fields(index); i++) {
- ulint j;
-
- for (j = 0; j < i; j++) {
- if (0 == ut_strcmp(
- dict_index_get_nth_field(index, j)->name,
- dict_index_get_nth_field(index, i)->name)) {
- ut_print_timestamp(stderr);
-
- fputs(" InnoDB: Error: column ", stderr);
- ut_print_name(stderr, trx, FALSE,
- dict_index_get_nth_field(
- index, i)->name);
- fputs(" appears twice in ", stderr);
- dict_index_name_print(stderr, trx, index);
- fputs("\n"
- "InnoDB: This is not allowed"
- " in InnoDB.\n", stderr);
-
- err = DB_COL_APPEARS_TWICE_IN_INDEX;
-
- goto error_handling;
- }
- }
-
- /* Check also that prefix_len and actual length
- is less than that from DICT_MAX_FIELD_LEN_BY_FORMAT() */
+ for (i = 0; i < index->n_def; i++) {
+ /* Check that prefix_len and actual length
+ < DICT_MAX_INDEX_COL_LEN */
len = dict_index_get_nth_field(index, i)->prefix_len;
- if (field_lengths) {
+ if (field_lengths && field_lengths[i]) {
len = ut_max(len, field_lengths[i]);
}
@@ -2057,6 +2030,7 @@ row_create_index_for_mysql(
if (len > (ulint) DICT_MAX_FIELD_LEN_BY_FORMAT(table)) {
err = DB_TOO_BIG_INDEX_COL;
+ dict_mem_index_free(index);
goto error_handling;
}
}
@@ -3125,7 +3099,8 @@ row_drop_table_for_mysql(
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
- table = dict_table_get_low_ignore_err(name, DICT_ERR_IGNORE_INDEX_ROOT);
+ table = dict_table_get_low_ignore_err(
+ name, DICT_ERR_IGNORE_INDEX_ROOT | DICT_ERR_IGNORE_CORRUPT);
if (!table) {
err = DB_TABLE_NOT_FOUND;
@@ -3272,6 +3247,19 @@ check_next_foreign:
"index_id CHAR;\n"
"foreign_id CHAR;\n"
"found INT;\n"
+
+ "DECLARE CURSOR cur_fk IS\n"
+ "SELECT ID FROM SYS_FOREIGN\n"
+ "WHERE FOR_NAME = :table_name\n"
+ "AND TO_BINARY(FOR_NAME)\n"
+ " = TO_BINARY(:table_name)\n"
+ "LOCK IN SHARE MODE;\n"
+
+ "DECLARE CURSOR cur_idx IS\n"
+ "SELECT ID FROM SYS_INDEXES\n"
+ "WHERE TABLE_ID = table_id\n"
+ "LOCK IN SHARE MODE;\n"
+
"BEGIN\n"
"SELECT ID INTO table_id\n"
"FROM SYS_TABLES\n"
@@ -3294,13 +3282,9 @@ check_next_foreign:
"IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n"
" found := 0;\n"
"END IF;\n"
+ "OPEN cur_fk;\n"
"WHILE found = 1 LOOP\n"
- " SELECT ID INTO foreign_id\n"
- " FROM SYS_FOREIGN\n"
- " WHERE FOR_NAME = :table_name\n"
- " AND TO_BINARY(FOR_NAME)\n"
- " = TO_BINARY(:table_name)\n"
- " LOCK IN SHARE MODE;\n"
+ " FETCH cur_fk INTO foreign_id;\n"
" IF (SQL % NOTFOUND) THEN\n"
" found := 0;\n"
" ELSE\n"
@@ -3310,12 +3294,11 @@ check_next_foreign:
" WHERE ID = foreign_id;\n"
" END IF;\n"
"END LOOP;\n"
+ "CLOSE cur_fk;\n"
"found := 1;\n"
+ "OPEN cur_idx;\n"
"WHILE found = 1 LOOP\n"
- " SELECT ID INTO index_id\n"
- " FROM SYS_INDEXES\n"
- " WHERE TABLE_ID = table_id\n"
- " LOCK IN SHARE MODE;\n"
+ " FETCH cur_idx INTO index_id;\n"
" IF (SQL % NOTFOUND) THEN\n"
" found := 0;\n"
" ELSE\n"
@@ -3326,6 +3309,7 @@ check_next_foreign:
" AND TABLE_ID = table_id;\n"
" END IF;\n"
"END LOOP;\n"
+ "CLOSE cur_idx;\n"
"DELETE FROM SYS_COLUMNS\n"
"WHERE TABLE_ID = table_id;\n"
"DELETE FROM SYS_TABLES\n"
diff --git a/storage/innobase/row/row0purge.c b/storage/innobase/row/row0purge.c
index 83e7c9e4857..efcfdc3bac5 100644
--- a/storage/innobase/row/row0purge.c
+++ b/storage/innobase/row/row0purge.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
-this program; if not, write to the Free Software Foundation, Inc., 59 Temple
-Place, Suite 330, Boston, MA 02111-1307 USA
+this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -469,6 +469,13 @@ row_purge_del_mark(
heap = mem_heap_create(1024);
while (node->index != NULL) {
+ /* skip corrupted secondary index */
+ dict_table_skip_corrupt_index(node->index);
+
+ if (!node->index) {
+ break;
+ }
+
index = node->index;
/* Build the index entry */
@@ -508,7 +515,8 @@ row_purge_upd_exist_or_extern_func(
ut_ad(node);
- if (node->rec_type == TRX_UNDO_UPD_DEL_REC) {
+ if (node->rec_type == TRX_UNDO_UPD_DEL_REC
+ || (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
goto skip_secondaries;
}
@@ -516,6 +524,12 @@ row_purge_upd_exist_or_extern_func(
heap = mem_heap_create(1024);
while (node->index != NULL) {
+ dict_table_skip_corrupt_index(node->index);
+
+ if (!node->index) {
+ break;
+ }
+
index = node->index;
if (row_upd_changes_ord_field_binary(node->index, node->update,
@@ -632,14 +646,14 @@ row_purge_parse_undo_rec(
roll_ptr_t roll_ptr;
ulint info_bits;
ulint type;
- ulint cmpl_info;
ut_ad(node && thr);
trx = thr_get_trx(thr);
- ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &cmpl_info,
- updated_extern, &undo_no, &table_id);
+ ptr = trx_undo_rec_get_pars(
+ node->undo_rec, &type, &node->cmpl_info,
+ updated_extern, &undo_no, &table_id);
node->rec_type = type;
if (type == TRX_UNDO_UPD_DEL_REC && !(*updated_extern)) {
@@ -652,7 +666,8 @@ row_purge_parse_undo_rec(
node->table = NULL;
if (type == TRX_UNDO_UPD_EXIST_REC
- && cmpl_info & UPD_NODE_NO_ORD_CHANGE && !(*updated_extern)) {
+ && node->cmpl_info & UPD_NODE_NO_ORD_CHANGE
+ && !(*updated_extern)) {
/* Purge requires no changes to indexes: we may return */
@@ -702,7 +717,7 @@ err_exit:
/* Read to the partial row the fields that occur in indexes */
- if (!(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
+ if (!(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
ptr = trx_undo_rec_get_partial_row(
ptr, clust_index, &node->row,
type == TRX_UNDO_UPD_DEL_REC,
diff --git a/storage/innobase/row/row0row.c b/storage/innobase/row/row0row.c
index 3bd0323ddbe..20fd475343e 100644
--- a/storage/innobase/row/row0row.c
+++ b/storage/innobase/row/row0row.c
@@ -101,12 +101,27 @@ row_build_index_entry(
dfield_copy(dfield, dfield2);
- if (dfield_is_null(dfield) || ind_field->prefix_len == 0) {
+ if (dfield_is_null(dfield)) {
continue;
}
- /* If a column prefix index, take only the prefix.
- Prefix-indexed columns may be externally stored. */
+ if (ind_field->prefix_len == 0
+ && (!dfield_is_ext(dfield)
+ || dict_index_is_clust(index))) {
+ /* The dfield_copy() above suffices for
+ columns that are stored in-page, or for
+ clustered index record columns that are not
+ part of a column prefix in the PRIMARY KEY. */
+ continue;
+ }
+
+ /* If the column is stored externally (off-page) in
+ the clustered index, it must be an ordering field in
+ the secondary index. In the Antelope format, only
+ prefix-indexed columns may be stored off-page in the
+ clustered index record. In the Barracuda format, also
+ fully indexed long CHAR or VARCHAR columns may be
+ stored off-page. */
ut_ad(col->ord_part);
if (UNIV_LIKELY_NULL(ext)) {
@@ -119,15 +134,41 @@ row_build_index_entry(
}
dfield_set_data(dfield, buf, len);
}
+
+ if (ind_field->prefix_len == 0) {
+ /* In the Barracuda format
+ (ROW_FORMAT=DYNAMIC or
+ ROW_FORMAT=COMPRESSED), we can have a
+ secondary index on an entire column
+ that is stored off-page in the
+ clustered index. As this is not a
+ prefix index (prefix_len == 0),
+ include the entire off-page column in
+ the secondary index record. */
+ continue;
+ }
} else if (dfield_is_ext(dfield)) {
+ /* This table is either in Antelope format
+ (ROW_FORMAT=REDUNDANT or ROW_FORMAT=COMPACT)
+ or a purge record where the ordered part of
+ the field is not external.
+ In Antelope, the maximum column prefix
+ index length is 767 bytes, and the clustered
+ index record contains a 768-byte prefix of
+ each off-page column. */
ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
len -= BTR_EXTERN_FIELD_REF_SIZE;
+ dfield_set_len(dfield, len);
}
- len = dtype_get_at_most_n_mbchars(
- col->prtype, col->mbminmaxlen,
- ind_field->prefix_len, len, dfield_get_data(dfield));
- dfield_set_len(dfield, len);
+ /* If a column prefix index, take only the prefix. */
+ if (ind_field->prefix_len) {
+ len = dtype_get_at_most_n_mbchars(
+ col->prtype, col->mbminmaxlen,
+ ind_field->prefix_len, len,
+ dfield_get_data(dfield));
+ dfield_set_len(dfield, len);
+ }
}
ut_ad(dtuple_check_typed(entry));
diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c
index 53d0c2ec232..5d8f53f68da 100644
--- a/storage/innobase/row/row0sel.c
+++ b/storage/innobase/row/row0sel.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -99,14 +99,22 @@ row_sel_sec_rec_is_for_blob(
ulint clust_len, /*!< in: length of clust_field */
const byte* sec_field, /*!< in: column in secondary index */
ulint sec_len, /*!< in: length of sec_field */
+ ulint prefix_len, /*!< in: index column prefix length
+ in bytes */
dict_table_t* table) /*!< in: table */
{
ulint len;
byte buf[REC_VERSION_56_MAX_INDEX_COL_LEN];
ulint zip_size = dict_table_flags_to_zip_size(table->flags);
- ulint max_prefix_len = DICT_MAX_FIELD_LEN_BY_FORMAT(table);
+ /* This function should never be invoked on an Antelope format
+ table, because they should always contain enough prefix in the
+ clustered index record. */
+ ut_ad(dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP);
ut_a(clust_len >= BTR_EXTERN_FIELD_REF_SIZE);
+ ut_ad(prefix_len >= sec_len);
+ ut_ad(prefix_len > 0);
+ ut_a(prefix_len <= sizeof buf);
if (UNIV_UNLIKELY
(!memcmp(clust_field + clust_len - BTR_EXTERN_FIELD_REF_SIZE,
@@ -118,7 +126,7 @@ row_sel_sec_rec_is_for_blob(
return(FALSE);
}
- len = btr_copy_externally_stored_field_prefix(buf, max_prefix_len,
+ len = btr_copy_externally_stored_field_prefix(buf, prefix_len,
zip_size,
clust_field, clust_len);
@@ -132,7 +140,7 @@ row_sel_sec_rec_is_for_blob(
}
len = dtype_get_at_most_n_mbchars(prtype, mbminmaxlen,
- sec_len, len, (const char*) buf);
+ prefix_len, len, (const char*) buf);
return(!cmp_data_data(mtype, prtype, buf, len, sec_field, sec_len));
}
@@ -224,6 +232,7 @@ row_sel_sec_rec_is_for_clust_rec(
col->mbminmaxlen,
clust_field, clust_len,
sec_field, sec_len,
+ ifield->prefix_len,
clust_index->table)) {
goto inequal;
}
@@ -493,7 +502,7 @@ sel_col_prefetch_buf_alloc(
sel_buf = column->prefetch_buf + i;
sel_buf->data = NULL;
-
+ sel_buf->len = 0;
sel_buf->val_buf_size = 0;
}
}
@@ -518,6 +527,8 @@ sel_col_prefetch_buf_free(
mem_free(sel_buf->data);
}
}
+
+ mem_free(prefetch_buf);
}
/*********************************************************************//**
@@ -2541,6 +2552,8 @@ row_sel_field_store_in_mysql_format(
ut_ad(len != UNIV_SQL_NULL);
UNIV_MEM_ASSERT_RW(data, len);
+ UNIV_MEM_ASSERT_W(dest, templ->mysql_col_len);
+ UNIV_MEM_INVALID(dest, templ->mysql_col_len);
switch (templ->type) {
const byte* field_end;
@@ -2579,14 +2592,16 @@ row_sel_field_store_in_mysql_format(
dest = row_mysql_store_true_var_len(
dest, len, templ->mysql_length_bytes);
+ /* Copy the actual data. Leave the rest of the
+ buffer uninitialized. */
+ memcpy(dest, data, len);
+ break;
}
/* Copy the actual data */
ut_memcpy(dest, data, len);
- /* Pad with trailing spaces. We pad with spaces also the
- unused end of a >= 5.0.3 true VARCHAR column, just in case
- MySQL expects its contents to be deterministic. */
+ /* Pad with trailing spaces. */
pad = dest + len;
@@ -3113,6 +3128,39 @@ sel_restore_position_for_mysql(
}
/********************************************************************//**
+Copies a cached field for MySQL from the fetch cache. */
+static
+void
+row_sel_copy_cached_field_for_mysql(
+/*================================*/
+ byte* buf, /*!< in/out: row buffer */
+ const byte* cache, /*!< in: cached row */
+ const mysql_row_templ_t*templ) /*!< in: column template */
+{
+ ulint len;
+
+ buf += templ->mysql_col_offset;
+ cache += templ->mysql_col_offset;
+
+ UNIV_MEM_ASSERT_W(buf, templ->mysql_col_len);
+
+ if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR
+ && templ->type != DATA_INT) {
+ /* Check for != DATA_INT to make sure we do
+ not treat MySQL ENUM or SET as a true VARCHAR!
+ Find the actual length of the true VARCHAR field. */
+ row_mysql_read_true_varchar(
+ &len, cache, templ->mysql_length_bytes);
+ len += templ->mysql_length_bytes;
+ UNIV_MEM_INVALID(buf, templ->mysql_col_len);
+ } else {
+ len = templ->mysql_col_len;
+ }
+
+ ut_memcpy(buf, cache, len);
+}
+
+/********************************************************************//**
Pops a cached row for MySQL from the fetch cache. */
UNIV_INLINE
void
@@ -3124,26 +3172,22 @@ row_sel_pop_cached_row_for_mysql(
{
ulint i;
const mysql_row_templ_t*templ;
- byte* cached_rec;
+ const byte* cached_rec;
ut_ad(prebuilt->n_fetch_cached > 0);
ut_ad(prebuilt->mysql_prefix_len <= prebuilt->mysql_row_len);
+ UNIV_MEM_ASSERT_W(buf, prebuilt->mysql_row_len);
+
+ cached_rec = prebuilt->fetch_cache[prebuilt->fetch_cache_first];
+
if (UNIV_UNLIKELY(prebuilt->keep_other_fields_on_keyread)) {
/* Copy cache record field by field, don't touch fields that
are not covered by current key */
- cached_rec = prebuilt->fetch_cache[
- prebuilt->fetch_cache_first];
for (i = 0; i < prebuilt->n_template; i++) {
templ = prebuilt->mysql_template + i;
-#if 0 /* Some of the cached_rec may legitimately be uninitialized. */
- UNIV_MEM_ASSERT_RW(cached_rec
- + templ->mysql_col_offset,
- templ->mysql_col_len);
-#endif
- ut_memcpy(buf + templ->mysql_col_offset,
- cached_rec + templ->mysql_col_offset,
- templ->mysql_col_len);
+ row_sel_copy_cached_field_for_mysql(
+ buf, cached_rec, templ);
/* Copy NULL bit of the current field from cached_rec
to buf */
if (templ->mysql_null_bit_mask) {
@@ -3153,17 +3197,24 @@ row_sel_pop_cached_row_for_mysql(
& (byte)templ->mysql_null_bit_mask;
}
}
+ } else if (prebuilt->mysql_prefix_len > 63) {
+ /* The record is long. Copy it field by field, in case
+ there are some long VARCHAR column of which only a
+ small length is being used. */
+ UNIV_MEM_INVALID(buf, prebuilt->mysql_prefix_len);
+
+ /* First copy the NULL bits. */
+ ut_memcpy(buf, cached_rec, prebuilt->null_bitmap_len);
+ /* Then copy the requested fields. */
+
+ for (i = 0; i < prebuilt->n_template; i++) {
+ row_sel_copy_cached_field_for_mysql(
+ buf, cached_rec, prebuilt->mysql_template + i);
+ }
+ } else {
+ ut_memcpy(buf, cached_rec, prebuilt->mysql_prefix_len);
}
- else {
-#if 0 /* Some of the cached_rec may legitimately be uninitialized. */
- UNIV_MEM_ASSERT_RW(prebuilt->fetch_cache
- [prebuilt->fetch_cache_first],
- prebuilt->mysql_prefix_len);
-#endif
- ut_memcpy(buf,
- prebuilt->fetch_cache[prebuilt->fetch_cache_first],
- prebuilt->mysql_prefix_len);
- }
+
prebuilt->n_fetch_cached--;
prebuilt->fetch_cache_first++;
@@ -3401,6 +3452,13 @@ row_search_for_mysql(
return(DB_MISSING_HISTORY);
}
+ if (dict_index_is_corrupted(index)) {
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
+ return(DB_CORRUPTION);
+ }
+
if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
fprintf(stderr,
"InnoDB: Error: trying to free a corrupt\n"
diff --git a/storage/innobase/row/row0uins.c b/storage/innobase/row/row0uins.c
index d25afed3840..4fa97c9355d 100644
--- a/storage/innobase/row/row0uins.c
+++ b/storage/innobase/row/row0uins.c
@@ -328,6 +328,8 @@ row_undo_ins(
node->index = dict_table_get_next_index(
dict_table_get_first_index(node->table));
+ dict_table_skip_corrupt_index(node->index);
+
while (node->index != NULL) {
dtuple_t* entry;
ulint err;
@@ -355,7 +357,7 @@ row_undo_ins(
}
}
- node->index = dict_table_get_next_index(node->index);
+ dict_table_next_uncorrupted_index(node->index);
}
log_free_check();
diff --git a/storage/innobase/row/row0umod.c b/storage/innobase/row/row0umod.c
index 2188fdeff49..b86ce9eeabd 100644
--- a/storage/innobase/row/row0umod.c
+++ b/storage/innobase/row/row0umod.c
@@ -573,6 +573,14 @@ row_undo_mod_upd_del_sec(
heap = mem_heap_create(1024);
while (node->index != NULL) {
+
+ /* Skip all corrupted secondary index */
+ dict_table_skip_corrupt_index(node->index);
+
+ if (!node->index) {
+ break;
+ }
+
index = node->index;
entry = row_build_index_entry(node->row, node->ext,
@@ -626,6 +634,13 @@ row_undo_mod_del_mark_sec(
heap = mem_heap_create(1024);
while (node->index != NULL) {
+ /* Skip all corrupted secondary index */
+ dict_table_skip_corrupt_index(node->index);
+
+ if (!node->index) {
+ break;
+ }
+
index = node->index;
entry = row_build_index_entry(node->row, node->ext,
@@ -677,6 +692,13 @@ row_undo_mod_upd_exist_sec(
heap = mem_heap_create(1024);
while (node->index != NULL) {
+ /* Skip all corrupted secondary index */
+ dict_table_skip_corrupt_index(node->index);
+
+ if (!node->index) {
+ break;
+ }
+
index = node->index;
if (row_upd_changes_ord_field_binary(node->index, node->update,
@@ -859,6 +881,9 @@ row_undo_mod(
node->index = dict_table_get_next_index(
dict_table_get_first_index(node->table));
+ /* Skip all corrupted secondary index */
+ dict_table_skip_corrupt_index(node->index);
+
if (node->rec_type == TRX_UNDO_UPD_EXIST_REC) {
err = row_undo_mod_upd_exist_sec(node, thr);
diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c
index 053b3513f1d..0c6036fe218 100644
--- a/storage/innobase/row/row0upd.c
+++ b/storage/innobase/row/row0upd.c
@@ -2305,6 +2305,13 @@ row_upd(
while (node->index != NULL) {
+ /* Skip corrupted index */
+ dict_table_skip_corrupt_index(node->index);
+
+ if (!node->index) {
+ break;
+ }
+
log_free_check();
err = row_upd_sec_step(node, thr);