diff options
Diffstat (limited to 'storage/xtradb/row')
-rw-r--r-- | storage/xtradb/row/row0ins.c | 36 | ||||
-rw-r--r-- | storage/xtradb/row/row0merge.c | 6 | ||||
-rw-r--r-- | storage/xtradb/row/row0mysql.c | 105 | ||||
-rw-r--r-- | storage/xtradb/row/row0purge.c | 33 | ||||
-rw-r--r-- | storage/xtradb/row/row0row.c | 55 | ||||
-rw-r--r-- | storage/xtradb/row/row0sel.c | 116 | ||||
-rw-r--r-- | storage/xtradb/row/row0uins.c | 4 | ||||
-rw-r--r-- | storage/xtradb/row/row0umod.c | 25 | ||||
-rw-r--r-- | storage/xtradb/row/row0upd.c | 23 |
9 files changed, 304 insertions, 99 deletions
diff --git a/storage/xtradb/row/row0ins.c b/storage/xtradb/row/row0ins.c index b4e66a16b5f..da035421ab9 100644 --- a/storage/xtradb/row/row0ins.c +++ b/storage/xtradb/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); } } @@ -1499,6 +1502,11 @@ exit_func: if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } + + if (trx->fake_changes) { + err = DB_SUCCESS; + } + return(err); } @@ -2004,7 +2012,7 @@ row_ins_index_entry_low( } btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, - search_mode, + thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : search_mode, &cursor, 0, __FILE__, __LINE__, &mtr); if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) { @@ -2053,7 +2061,6 @@ row_ins_index_entry_low( mtr_start(&mtr); if (err != DB_SUCCESS) { - goto function_exit; } @@ -2065,7 +2072,7 @@ row_ins_index_entry_low( btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, - mode | BTR_INSERT, + thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : (mode | BTR_INSERT), &cursor, 0, __FILE__, __LINE__, &mtr); } @@ -2119,6 +2126,22 @@ function_exit: if (UNIV_LIKELY_NULL(big_rec)) { rec_t* rec; ulint* offsets; + + if (thr_get_trx(thr)->fake_changes) { + /* skip store extern */ + if (modify) { + dtuple_big_rec_free(big_rec); + } else { + dtuple_convert_back_big_rec(index, entry, big_rec); + } + + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + + return(err); + } + mtr_start(&mtr); btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, @@ -2403,6 +2426,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/xtradb/row/row0merge.c b/storage/xtradb/row/row0merge.c index 7d4716cb623..30cfa7c23af 100644 --- a/storage/xtradb/row/row0merge.c +++ b/storage/xtradb/row/row0merge.c @@ -56,6 +56,7 @@ Completed by Sunny Bains and Marko Makela #include "log0log.h" #include "ut0sort.h" #include "handler0alter.h" +#include "ha_prototypes.h" /* Ignore posix_fadvise() on those platforms where it does not exist */ #if defined __WIN__ @@ -2563,8 +2564,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/xtradb/row/row0mysql.c b/storage/xtradb/row/row0mysql.c index 836189e0eb8..ac424ded6cb 100644 --- a/storage/xtradb/row/row0mysql.c +++ b/storage/xtradb/row/row0mysql.c @@ -578,6 +578,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: @@ -1246,6 +1247,7 @@ run_again: prebuilt->table->stat_n_rows--; } + if (!(trx->fake_changes)) row_update_statistics_if_needed(prebuilt->table); trx->op_info = ""; @@ -1505,6 +1507,7 @@ run_again: that changes indexed columns, UPDATEs that change only non-indexed columns would not affect statistics. */ if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { + if (!(trx->fake_changes)) row_update_statistics_if_needed(prebuilt->table); } @@ -1722,6 +1725,7 @@ run_again: srv_n_rows_updated++; } + if (!(trx->fake_changes)) row_update_statistics_if_needed(table); return(err); @@ -2027,41 +2031,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]); } @@ -2069,6 +2045,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; } } @@ -2611,10 +2588,29 @@ row_discard_tablespace_for_mysql( err = DB_ERROR; } else { + dict_index_t* index; + /* Set the flag which tells that now it is legal to IMPORT a tablespace for this table */ table->tablespace_discarded = TRUE; table->ibd_file_missing = TRUE; + + /* check adaptive hash entries */ + index = dict_table_get_first_index(table); + while (index) { + ulint ref_count = btr_search_info_get_ref_count(index->search_info, index->id); + if (ref_count) { + fprintf(stderr, "InnoDB: Warning:" + " hash index ref_count (%lu) is not zero" + " after fil_discard_tablespace().\n" + "index: \"%s\"" + " table: \"%s\"\n", + ref_count, + index->name, + table->name); + } + index = dict_table_get_next_index(index); + } } } @@ -2963,6 +2959,19 @@ row_truncate_table_for_mysql( table->space = space; index = dict_table_get_first_index(table); do { + ulint ref_count = btr_search_info_get_ref_count(index->search_info, index->id); + /* check adaptive hash entries */ + if (ref_count) { + fprintf(stderr, "InnoDB: Warning:" + " hash index ref_count (%lu) is not zero" + " after fil_discard_tablespace().\n" + "index: \"%s\"" + " table: \"%s\"\n", + ref_count, + index->name, + table->name); + } + index->space = space; index = dict_table_get_next_index(index); } while (index); @@ -3212,7 +3221,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; @@ -3359,6 +3369,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" @@ -3381,13 +3404,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" @@ -3397,12 +3416,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" @@ -3415,6 +3433,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/xtradb/row/row0purge.c b/storage/xtradb/row/row0purge.c index 83e7c9e4857..efcfdc3bac5 100644 --- a/storage/xtradb/row/row0purge.c +++ b/storage/xtradb/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/xtradb/row/row0row.c b/storage/xtradb/row/row0row.c index 2882af00f30..0462f280858 100644 --- a/storage/xtradb/row/row0row.c +++ b/storage/xtradb/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/xtradb/row/row0sel.c b/storage/xtradb/row/row0sel.c index ef5e30ea16d..c7308ccb765 100644 --- a/storage/xtradb/row/row0sel.c +++ b/storage/xtradb/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 @@ -101,14 +101,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, @@ -120,7 +128,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); @@ -134,7 +142,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)); } @@ -226,6 +234,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; } @@ -495,7 +504,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; } } @@ -520,6 +529,8 @@ sel_col_prefetch_buf_free( mem_free(sel_buf->data); } } + + mem_free(prefetch_buf); } /*********************************************************************//** @@ -2543,6 +2554,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; @@ -2581,14 +2594,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; @@ -3148,6 +3163,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 @@ -3159,26 +3207,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) { @@ -3192,17 +3236,24 @@ row_sel_pop_cached_row_for_mysql( 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++; @@ -3510,6 +3561,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/xtradb/row/row0uins.c b/storage/xtradb/row/row0uins.c index d25afed3840..4fa97c9355d 100644 --- a/storage/xtradb/row/row0uins.c +++ b/storage/xtradb/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/xtradb/row/row0umod.c b/storage/xtradb/row/row0umod.c index 2188fdeff49..b86ce9eeabd 100644 --- a/storage/xtradb/row/row0umod.c +++ b/storage/xtradb/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/xtradb/row/row0upd.c b/storage/xtradb/row/row0upd.c index 2c7f3056329..5e8099691c5 100644 --- a/storage/xtradb/row/row0upd.c +++ b/storage/xtradb/row/row0upd.c @@ -1603,7 +1603,8 @@ row_upd_sec_index_entry( mode |= BTR_DELETE_MARK; } - search_result = row_search_index_entry(index, entry, mode, + search_result = row_search_index_entry(index, entry, + trx->fake_changes ? BTR_SEARCH_LEAF : mode, &pcur, &mtr); btr_cur = btr_pcur_get_btr_cur(&pcur); @@ -1850,9 +1851,11 @@ row_upd_clust_rec_by_insert( the previous invocation of this function. Mark the off-page columns in the entry inherited. */ + if (!(trx->fake_changes)) { change_ownership = row_upd_clust_rec_by_insert_inherit( NULL, NULL, entry, node->update); ut_a(change_ownership); + } /* fall through */ case UPD_NODE_INSERT_CLUSTERED: /* A lock wait occurred in row_ins_index_entry() in @@ -1882,7 +1885,7 @@ err_exit: delete-marked old record, mark them disowned by the old record and owned by the new entry. */ - if (rec_offs_any_extern(offsets)) { + if (rec_offs_any_extern(offsets) && !(trx->fake_changes)) { change_ownership = row_upd_clust_rec_by_insert_inherit( rec, offsets, entry, node->update); @@ -2012,7 +2015,8 @@ row_upd_clust_rec( the same transaction do not modify the record in the meantime. Therefore we can assert that the restoration of the cursor succeeds. */ - ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr)); + ut_a(btr_pcur_restore_position(thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : BTR_MODIFY_TREE, + pcur, mtr)); ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur), dict_table_is_comp(index->table))); @@ -2022,7 +2026,8 @@ row_upd_clust_rec( node->cmpl_info, thr, mtr); mtr_commit(mtr); - if (err == DB_SUCCESS && big_rec) { + /* skip store extern for fake_changes */ + if (err == DB_SUCCESS && big_rec && !(thr_get_trx(thr)->fake_changes)) { ulint offsets_[REC_OFFS_NORMAL_SIZE]; rec_t* rec; rec_offs_init(offsets_); @@ -2146,7 +2151,8 @@ row_upd_clust_step( ut_a(pcur->rel_pos == BTR_PCUR_ON); - success = btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr); + success = btr_pcur_restore_position(thr_get_trx(thr)->fake_changes ? BTR_SEARCH_LEAF : BTR_MODIFY_LEAF, + pcur, mtr); if (!success) { err = DB_RECORD_NOT_FOUND; @@ -2323,6 +2329,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); |