diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2020-01-18 16:56:16 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2020-01-18 16:56:16 +0200 |
commit | 6373ec3ec74515574f8a08535ed0d090b13d9122 (patch) | |
tree | d2a7393afdf99b7b609a9c911e16a121c862b403 /storage | |
parent | e709eb9bf712006d070767629518f827cd2f6bed (diff) | |
parent | d595a91bc6bfb9f9c38bf91738b2a563d80c62e0 (diff) | |
download | mariadb-git-6373ec3ec74515574f8a08535ed0d090b13d9122.tar.gz |
Merge 10.2 into 10.3
Diffstat (limited to 'storage')
23 files changed, 289 insertions, 340 deletions
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 7292f3ea8c8..c79ea1c5467 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -1,9 +1,9 @@ /***************************************************************************** -Copyright (c) 1994, 2018, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2015, 2019, MariaDB Corporation. +Copyright (c) 2015, 2020, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -804,46 +804,66 @@ btr_cur_will_modify_tree( const ulint n_recs = page_get_n_recs(page); if (lock_intention <= BTR_INTENTION_BOTH) { - ulint margin; + compile_time_assert(BTR_INTENTION_DELETE < BTR_INTENTION_BOTH); + compile_time_assert(BTR_INTENTION_BOTH < BTR_INTENTION_INSERT); - /* check delete will cause. (BTR_INTENTION_BOTH - or BTR_INTENTION_DELETE) */ - /* first, 2nd, 2nd-last and last records are 4 records */ - if (n_recs < 5) { - return(true); + if (!page_has_siblings(page)) { + return true; } - /* is first, 2nd or last record */ - if (page_rec_is_first(rec, page) - || (page_has_next(page) - && (page_rec_is_last(rec, page) - || page_rec_is_second_last(rec, page))) - || (page_has_prev(page) - && page_rec_is_second(rec, page))) { - return(true); - } + ulint margin = rec_size; if (lock_intention == BTR_INTENTION_BOTH) { + ulint level = btr_page_get_level(page); + + /* This value is the worst expectation for the node_ptr + records to be deleted from this page. It is used to + expect whether the cursor position can be the left_most + record in this page or not. */ + ulint max_nodes_deleted = 0; + + /* By modifying tree operations from the under of this + level, logically (2 ^ (level - 1)) opportunities to + deleting records in maximum even unreally rare case. */ + if (level > 7) { + /* TODO: adjust this practical limit. */ + max_nodes_deleted = 64; + } else if (level > 0) { + max_nodes_deleted = (ulint)1 << (level - 1); + } + /* check delete will cause. (BTR_INTENTION_BOTH + or BTR_INTENTION_DELETE) */ + if (n_recs <= max_nodes_deleted * 2 + || page_rec_is_first(rec, page)) { + /* The cursor record can be the left most record + in this page. */ + return true; + } + + if (page_has_prev(page) + && page_rec_distance_is_at_most( + page_get_infimum_rec(page), rec, + max_nodes_deleted)) { + return true; + } + + if (page_has_next(page) + && page_rec_distance_is_at_most( + rec, page_get_supremum_rec(page), + max_nodes_deleted)) { + return true; + } + /* Delete at leftmost record in a page causes delete & insert at its parent page. After that, the delete might cause btr_compress() and delete record at its - parent page. Thus we should consider max 2 deletes. */ - - margin = rec_size * 2; - } else { - ut_ad(lock_intention == BTR_INTENTION_DELETE); - - margin = rec_size; + parent page. Thus we should consider max deletes. */ + margin *= max_nodes_deleted; } - /* NOTE: call mach_read_from_4() directly to avoid assertion - failure. It is safe because we already have SX latch of the - index tree */ + + /* Safe because we already have SX latch of the index tree */ if (page_get_data_size(page) - < margin + BTR_CUR_PAGE_COMPRESS_LIMIT(index) - || (mach_read_from_4(page + FIL_PAGE_NEXT) - == FIL_NULL - && mach_read_from_4(page + FIL_PAGE_PREV) - == FIL_NULL)) { + < margin + BTR_CUR_PAGE_COMPRESS_LIMIT(index)) { return(true); } } @@ -2025,9 +2045,9 @@ need_opposite_intention: offsets2 = rec_get_offsets( first_rec, index, offsets2, false, ULINT_UNDEFINED, &heap); - cmp_rec_rec_with_match(node_ptr, first_rec, - offsets, offsets2, index, FALSE, - &matched_fields); + cmp_rec_rec(node_ptr, first_rec, + offsets, offsets2, index, false, + &matched_fields); if (matched_fields >= rec_offs_n_fields(offsets) - 1) { @@ -2043,10 +2063,10 @@ need_opposite_intention: offsets2 = rec_get_offsets( last_rec, index, offsets2, false, ULINT_UNDEFINED, &heap); - cmp_rec_rec_with_match( + cmp_rec_rec( node_ptr, last_rec, offsets, offsets2, index, - FALSE, &matched_fields); + false, &matched_fields); if (matched_fields >= rec_offs_n_fields(offsets) - 1) { detected_same_key_root = true; @@ -4242,7 +4262,6 @@ btr_cur_optimistic_update( dtuple_t* new_entry; roll_ptr_t roll_ptr; ulint i; - ulint n_ext; block = btr_cur_get_block(cursor); page = buf_block_get_frame(block); @@ -4319,10 +4338,8 @@ any_extern: + DTUPLE_EST_ALLOC(rec_offs_n_fields(*offsets))); } - new_entry = row_rec_to_index_entry(rec, index, *offsets, - &n_ext, *heap); - /* We checked above that there are no externally stored fields. */ - ut_a(!n_ext); + new_entry = row_rec_to_index_entry(rec, index, *offsets, *heap); + ut_ad(!dtuple_get_n_ext(new_entry)); /* The page containing the clustered index record corresponding to new_entry is latched in mtr. @@ -4586,7 +4603,6 @@ btr_cur_pessimistic_update( roll_ptr_t roll_ptr; ibool was_first; ulint n_reserved = 0; - ulint n_ext; ulint max_ins_size = 0; *offsets = NULL; @@ -4651,7 +4667,7 @@ btr_cur_pessimistic_update( ut_ad(rec_offs_validate(rec, index, *offsets)); dtuple_t* new_entry = row_rec_to_index_entry( - rec, index, *offsets, &n_ext, entry_heap); + rec, index, *offsets, entry_heap); /* The page containing the clustered index record corresponding to new_entry is latched in mtr. If the @@ -4671,7 +4687,6 @@ btr_cur_pessimistic_update( ut_ad(!page_is_comp(page) || !rec_get_node_ptr_flag(rec)); ut_ad(rec_offs_validate(rec, index, *offsets)); - n_ext += btr_push_update_extern_fields(new_entry, update, entry_heap); if ((flags & BTR_NO_UNDO_LOG_FLAG) && rec_offs_any_extern(*offsets)) { @@ -4692,6 +4707,8 @@ btr_cur_pessimistic_update( index, rec, page_zip, *offsets, update, true, mtr); } + ulint n_ext = dtuple_get_n_ext(new_entry); + if (page_zip_rec_needs_ext( rec_get_converted_size(index, new_entry, n_ext), page_is_comp(page), @@ -6722,10 +6739,10 @@ btr_estimate_number_of_different_key_vals( ULINT_UNDEFINED, &heap); - cmp_rec_rec_with_match(rec, next_rec, - offsets_rec, offsets_next_rec, - index, stats_null_not_equal, - &matched_fields); + cmp_rec_rec(rec, next_rec, + offsets_rec, offsets_next_rec, + index, stats_null_not_equal, + &matched_fields); for (j = matched_fields; j < n_cols; j++) { /* We add one if this index record has @@ -7006,84 +7023,6 @@ btr_cur_unmark_extern_fields( } /*******************************************************************//** -Flags the data tuple fields that are marked as extern storage in the -update vector. We use this function to remember which fields we must -mark as extern storage in a record inserted for an update. -@return number of flagged external columns */ -ulint -btr_push_update_extern_fields( -/*==========================*/ - dtuple_t* tuple, /*!< in/out: data tuple */ - const upd_t* update, /*!< in: update vector */ - mem_heap_t* heap) /*!< in: memory heap */ -{ - ulint n_pushed = 0; - ulint n; - const upd_field_t* uf; - - uf = update->fields; - n = upd_get_n_fields(update); - - for (; n--; uf++) { - if (dfield_is_ext(&uf->new_val)) { - dfield_t* field - = dtuple_get_nth_field(tuple, uf->field_no); - - if (!dfield_is_ext(field)) { - dfield_set_ext(field); - n_pushed++; - } - - switch (uf->orig_len) { - byte* data; - ulint len; - byte* buf; - case 0: - break; - case BTR_EXTERN_FIELD_REF_SIZE: - /* Restore the original locally stored - part of the column. In the undo log, - InnoDB writes a longer prefix of externally - stored columns, so that column prefixes - in secondary indexes can be reconstructed. */ - dfield_set_data(field, - (byte*) dfield_get_data(field) - + dfield_get_len(field) - - BTR_EXTERN_FIELD_REF_SIZE, - BTR_EXTERN_FIELD_REF_SIZE); - dfield_set_ext(field); - break; - default: - /* Reconstruct the original locally - stored part of the column. The data - will have to be copied. */ - ut_a(uf->orig_len > BTR_EXTERN_FIELD_REF_SIZE); - - data = (byte*) dfield_get_data(field); - len = dfield_get_len(field); - - buf = (byte*) mem_heap_alloc(heap, - uf->orig_len); - /* Copy the locally stored prefix. */ - memcpy(buf, data, - unsigned(uf->orig_len) - - BTR_EXTERN_FIELD_REF_SIZE); - /* Copy the BLOB pointer. */ - memcpy(buf + unsigned(uf->orig_len) - - BTR_EXTERN_FIELD_REF_SIZE, - data + len - BTR_EXTERN_FIELD_REF_SIZE, - BTR_EXTERN_FIELD_REF_SIZE); - - dfield_set_data(field, buf, uf->orig_len); - dfield_set_ext(field); - } - } - } - - return(n_pushed); -} - -/*******************************************************************//** Returns the length of a BLOB part stored on the header page. @return part length */ static diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index addf212f984..f60d574d3b9 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2009, 2019, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2019, MariaDB Corporation. +Copyright (c) 2015, 2020, MariaDB Corporation. 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 @@ -1169,13 +1169,9 @@ dict_stats_analyze_index_level( prev_rec, index, prev_rec_offsets, !level, n_uniq, &heap); - cmp_rec_rec_with_match(rec, - prev_rec, - rec_offsets, - prev_rec_offsets, - index, - FALSE, - &matched_fields); + cmp_rec_rec(prev_rec, rec, + prev_rec_offsets, rec_offsets, index, + false, &matched_fields); for (i = matched_fields; i < n_uniq; i++) { @@ -1395,9 +1391,8 @@ dict_stats_scan_page( /* check whether rec != next_rec when looking at the first n_prefix fields */ - cmp_rec_rec_with_match(rec, next_rec, - offsets_rec, offsets_next_rec, - index, FALSE, &matched_fields); + cmp_rec_rec(rec, next_rec, offsets_rec, offsets_next_rec, + index, false, &matched_fields); if (matched_fields < n_prefix) { /* rec != next_rec, => rec is non-boring */ diff --git a/storage/innobase/gis/gis0rtree.cc b/storage/innobase/gis/gis0rtree.cc index 7ba6f59c2d4..5a80d394d77 100644 --- a/storage/innobase/gis/gis0rtree.cc +++ b/storage/innobase/gis/gis0rtree.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2018, 2019, MariaDB Corporation. +Copyright (c) 2018, 2020, MariaDB Corporation. 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 @@ -1436,10 +1436,9 @@ rtr_page_copy_rec_list_end_no_locks( offsets2 = rec_get_offsets(cur_rec, index, offsets2, is_leaf, ULINT_UNDEFINED, &heap); - cmp = cmp_rec_rec_with_match(cur1_rec, cur_rec, - offsets1, offsets2, - index, FALSE, - &cur_matched_fields); + cmp = cmp_rec_rec(cur1_rec, cur_rec, + offsets1, offsets2, index, false, + &cur_matched_fields); if (cmp < 0) { page_cur_move_to_prev(&page_cur); break; @@ -1551,15 +1550,13 @@ rtr_page_copy_rec_list_start_no_locks( while (!page_rec_is_supremum(cur_rec)) { ulint cur_matched_fields = 0; - int cmp; offsets2 = rec_get_offsets(cur_rec, index, offsets2, is_leaf, ULINT_UNDEFINED, &heap); - cmp = cmp_rec_rec_with_match(cur1_rec, cur_rec, - offsets1, offsets2, - index, FALSE, - &cur_matched_fields); + int cmp = cmp_rec_rec(cur1_rec, cur_rec, + offsets1, offsets2, index, false, + &cur_matched_fields); if (cmp < 0) { page_cur_move_to_prev(&page_cur); cur_rec = page_cur_get_rec(&page_cur); diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index 2954f14b310..13a420fd912 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -1,7 +1,7 @@ /***************************************************************************** -Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2017, 2020, MariaDB Corporation. 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 @@ -784,18 +784,6 @@ btr_rec_copy_externally_stored_field( ulint* len, mem_heap_t* heap); -/*******************************************************************//** -Flags the data tuple fields that are marked as extern storage in the -update vector. We use this function to remember which fields we must -mark as extern storage in a record inserted for an update. -@return number of flagged external columns */ -ulint -btr_push_update_extern_fields( -/*==========================*/ - dtuple_t* tuple, /*!< in/out: data tuple */ - const upd_t* update, /*!< in: update vector */ - mem_heap_t* heap) /*!< in: memory heap */ - MY_ATTRIBUTE((nonnull)); /***********************************************************//** Sets a secondary index record's delete mark to the given value. This function is only used by the insert buffer merge mechanism. */ diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h index 56091c455e1..0876bc54aaf 100644 --- a/storage/innobase/include/page0page.h +++ b/storage/innobase/include/page0page.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2019, MariaDB Corporation. +Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2013, 2020, MariaDB Corporation. 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 @@ -858,6 +858,22 @@ page_rec_is_last( MY_ATTRIBUTE((warn_unused_result)); /************************************************************//** +true if distance between the records (measured in number of times we have to +move to the next record) is at most the specified value +@param[in] left_rec lefter record +@param[in] right_rec righter record +@param[in] val specified value to compare +@return true if the distance is smaller than the value */ +UNIV_INLINE +bool +page_rec_distance_is_at_most( +/*=========================*/ + const rec_t* left_rec, + const rec_t* right_rec, + ulint val) + MY_ATTRIBUTE((warn_unused_result)); + +/************************************************************//** true if the record is the second last user record on a page. @return true if the second last user record */ UNIV_INLINE diff --git a/storage/innobase/include/page0page.ic b/storage/innobase/include/page0page.ic index 69582cf4267..94887a0925a 100644 --- a/storage/innobase/include/page0page.ic +++ b/storage/innobase/include/page0page.ic @@ -1,7 +1,7 @@ /***************************************************************************** -Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, 2019, MariaDB Corporation. +Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2016, 2020, MariaDB Corporation. 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 @@ -359,6 +359,26 @@ page_rec_is_last( } /************************************************************//** +true if distance between the records (measured in number of times we have to +move to the next record) is at most the specified value */ +UNIV_INLINE +bool +page_rec_distance_is_at_most( +/*=========================*/ + const rec_t* left_rec, + const rec_t* right_rec, + ulint val) +{ + for (ulint i = 0; i <= val; i++) { + if (left_rec == right_rec) { + return (true); + } + left_rec = page_rec_get_next_const(left_rec); + } + return (false); +} + +/************************************************************//** true if the record is the second last user record on a page. @return true if the second last user record */ UNIV_INLINE diff --git a/storage/innobase/include/rem0cmp.h b/storage/innobase/include/rem0cmp.h index 0877c7b5b6a..af1b145b0d9 100644 --- a/storage/innobase/include/rem0cmp.h +++ b/storage/innobase/include/rem0cmp.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2017, 2020, MariaDB Corporation. 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 @@ -80,7 +80,7 @@ cmp_dfield_dfield( /** Compare a GIS data tuple to a physical record. @param[in] dtuple data tuple -@param[in] rec B-tree record +@param[in] rec R-tree record @param[in] offsets rec_get_offsets(rec) @param[in] mode compare mode @retval negative if dtuple is less than rec */ @@ -190,43 +190,23 @@ cmp_rec_rec_simple( duplicate key value if applicable, or NULL */ MY_ATTRIBUTE((nonnull(1,2,3,4), warn_unused_result)); -/** Compare two B-tree records. -@param[in] rec1 B-tree record -@param[in] rec2 B-tree record -@param[in] offsets1 rec_get_offsets(rec1, index) -@param[in] offsets2 rec_get_offsets(rec2, index) -@param[in] index B-tree index -@param[in] nulls_unequal true if this is for index cardinality -statistics estimation, and innodb_stats_method=nulls_unequal -or innodb_stats_method=nulls_ignored -@param[out] matched_fields number of completely matched fields -within the first field not completely matched -@return the comparison result -@retval 0 if rec1 is equal to rec2 -@retval negative if rec1 is less than rec2 -@retval positive if rec2 is greater than rec2 */ -int -cmp_rec_rec_with_match( - const rec_t* rec1, - const rec_t* rec2, - const offset_t* offsets1, - const offset_t* offsets2, - const dict_index_t* index, - bool nulls_unequal, - ulint* matched_fields); -/** Compare two B-tree records. +/** Compare two B-tree or R-tree records. Only the common first fields are compared, and externally stored field are treated as equal. -@param[in] rec1 B-tree record -@param[in] rec2 B-tree record +@param[in] rec1 record (possibly not on an index page) +@param[in] rec2 B-tree or R-tree record in an index page @param[in] offsets1 rec_get_offsets(rec1, index) @param[in] offsets2 rec_get_offsets(rec2, index) +@param[in] nulls_unequal true if this is for index cardinality + statistics estimation with + innodb_stats_method=nulls_unequal + or innodb_stats_method=nulls_ignored @param[out] matched_fields number of completely matched fields within the first field not completely matched -@return positive, 0, negative if rec1 is greater, equal, less, than rec2, -respectively */ -UNIV_INLINE +@retval 0 if rec1 is equal to rec2 +@retval negative if rec1 is less than rec2 +@retval positive if rec1 is greater than rec2 */ int cmp_rec_rec( const rec_t* rec1, @@ -234,7 +214,9 @@ cmp_rec_rec( const offset_t* offsets1, const offset_t* offsets2, const dict_index_t* index, - ulint* matched_fields = NULL); + bool nulls_unequal = false, + ulint* matched_fields = NULL) + MY_ATTRIBUTE((nonnull(1,2,3,4,5))); /** Compare two data fields. @param[in] dfield1 data field diff --git a/storage/innobase/include/rem0cmp.ic b/storage/innobase/include/rem0cmp.ic index 5ac3838f244..4230543615a 100644 --- a/storage/innobase/include/rem0cmp.ic +++ b/storage/innobase/include/rem0cmp.ic @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2020, MariaDB Corporation. 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 @@ -52,40 +53,6 @@ cmp_dfield_dfield( dfield_get_len(dfield2))); } -/** Compare two B-tree records. -Only the common first fields are compared, and externally stored field -are treated as equal. -@param[in] rec1 B-tree record -@param[in] rec2 B-tree record -@param[in] offsets1 rec_get_offsets(rec1, index) -@param[in] offsets2 rec_get_offsets(rec2, index) -@param[out] matched_fields number of completely matched fields - within the first field not completely matched -@return positive, 0, negative if rec1 is greater, equal, less, than rec2, -respectively */ -UNIV_INLINE -int -cmp_rec_rec( - const rec_t* rec1, - const rec_t* rec2, - const offset_t* offsets1, - const offset_t* offsets2, - const dict_index_t* index, - ulint* matched_fields) -{ - ulint match_f; - int ret; - - ret = cmp_rec_rec_with_match( - rec1, rec2, offsets1, offsets2, index, false, &match_f); - - if (matched_fields != NULL) { - *matched_fields = match_f; - } - - return(ret); -} - /** Compare two data fields. @param[in] dfield1 data field @param[in] dfield2 data field diff --git a/storage/innobase/include/rem0rec.ic b/storage/innobase/include/rem0rec.ic index 5deb53f5a84..44a471e4156 100644 --- a/storage/innobase/include/rem0rec.ic +++ b/storage/innobase/include/rem0rec.ic @@ -1,7 +1,7 @@ /***************************************************************************** -Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2017, 2020, MariaDB Corporation. 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 @@ -1410,6 +1410,7 @@ rec_get_converted_size( data_size = dtuple_get_data_size(dtuple, 0); + ut_ad(n_ext == dtuple_get_n_ext(dtuple)); extra_size = rec_get_converted_extra_size( data_size, dtuple_get_n_fields(dtuple), n_ext); diff --git a/storage/innobase/include/row0row.h b/storage/innobase/include/row0row.h index 656a18ff9f2..d4d979cdad5 100644 --- a/storage/innobase/include/row0row.h +++ b/storage/innobase/include/row0row.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, 2017, MariaDB Corporation. +Copyright (c) 2016, 2020, MariaDB Corporation. 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 @@ -207,8 +207,6 @@ row_rec_to_index_entry_low( const rec_t* rec, /*!< in: record in the index */ const dict_index_t* index, /*!< in: index */ const offset_t* offsets,/*!< in: rec_get_offsets(rec, index) */ - ulint* n_ext, /*!< out: number of externally - stored columns */ mem_heap_t* heap) /*!< in: memory heap from which the memory needed is allocated */ MY_ATTRIBUTE((warn_unused_result)); @@ -222,8 +220,6 @@ row_rec_to_index_entry( const rec_t* rec, /*!< in: record in the index */ const dict_index_t* index, /*!< in: index */ const offset_t* offsets,/*!< in/out: rec_get_offsets(rec) */ - ulint* n_ext, /*!< out: number of externally - stored columns */ mem_heap_t* heap) /*!< in: memory heap from which the memory needed is allocated */ MY_ATTRIBUTE((warn_unused_result)); diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index 19a03009ad5..ab30024116e 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2013, 2019, MariaDB Corporation. +Copyright (c) 2013, 2020, MariaDB Corporation. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 63e8627b9db..9a1276ef364 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -1,8 +1,8 @@ /*********************************************************************** -Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1995, 2019, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2009, Percona Inc. -Copyright (c) 2013, 2019, MariaDB Corporation. +Copyright (c) 2013, 2020, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Percona Inc.. Those modifications are @@ -1470,6 +1470,12 @@ os_file_get_parent_dir( return(NULL); } + if (last_slash - path < 0) { + /* Sanity check, it prevents gcc from trying to handle this case which + * results in warnings for some optimized builds */ + return (NULL); + } + /* Non-trivial directory component */ return(mem_strdupl(path, ulint(last_slash - path))); diff --git a/storage/innobase/rem/rem0cmp.cc b/storage/innobase/rem/rem0cmp.cc index 8992e82d370..b093a8b5952 100644 --- a/storage/innobase/rem/rem0cmp.cc +++ b/storage/innobase/rem/rem0cmp.cc @@ -1,6 +1,7 @@ /***************************************************************************** -Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2020, MariaDB Corporation. 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 @@ -534,7 +535,7 @@ cmp_data( /** Compare a GIS data tuple to a physical record. @param[in] dtuple data tuple -@param[in] rec B-tree record +@param[in] rec R-tree record @param[in] offsets rec_get_offsets(rec) @param[in] mode compare mode @retval negative if dtuple is less than rec */ @@ -1096,23 +1097,24 @@ cmp_rec_rec_simple( return(0); } -/** Compare two B-tree records. -@param[in] rec1 B-tree record -@param[in] rec2 B-tree record -@param[in] offsets1 rec_get_offsets(rec1, index) -@param[in] offsets2 rec_get_offsets(rec2, index) -@param[in] index B-tree index -@param[in] nulls_unequal true if this is for index cardinality -statistics estimation, and innodb_stats_method=nulls_unequal -or innodb_stats_method=nulls_ignored -@param[out] matched_fields number of completely matched fields -within the first field not completely matched -@return the comparison result +/** Compare two B-tree or R-tree records. +Only the common first fields are compared, and externally stored field +are treated as equal. +@param[in] rec1 record (possibly not on an index page) +@param[in] rec2 B-tree or R-tree record in an index page +@param[in] offsets1 rec_get_offsets(rec1, index) +@param[in] offsets2 rec_get_offsets(rec2, index) +@param[in] nulls_unequal true if this is for index cardinality + statistics estimation with + innodb_stats_method=nulls_unequal + or innodb_stats_method=nulls_ignored +@param[out] matched_fields number of completely matched fields + within the first field not completely matched @retval 0 if rec1 is equal to rec2 @retval negative if rec1 is less than rec2 -@retval positive if rec2 is greater than rec2 */ +@retval positive if rec1 is greater than rec2 */ int -cmp_rec_rec_with_match( +cmp_rec_rec( const rec_t* rec1, const rec_t* rec2, const offset_t* offsets1, @@ -1121,17 +1123,14 @@ cmp_rec_rec_with_match( bool nulls_unequal, ulint* matched_fields) { - ulint rec1_n_fields; /* the number of fields in rec */ ulint rec1_f_len; /* length of current field in rec */ const byte* rec1_b_ptr; /* pointer to the current byte in rec field */ - ulint rec2_n_fields; /* the number of fields in rec */ ulint rec2_f_len; /* length of current field in rec */ const byte* rec2_b_ptr; /* pointer to the current byte in rec field */ ulint cur_field = 0; /* current field number */ int ret = 0; /* return value */ - ulint comp; ut_ad(rec1 != NULL); ut_ad(rec2 != NULL); @@ -1139,10 +1138,12 @@ cmp_rec_rec_with_match( ut_ad(rec_offs_validate(rec1, index, offsets1)); ut_ad(rec_offs_validate(rec2, index, offsets2)); ut_ad(rec_offs_comp(offsets1) == rec_offs_comp(offsets2)); + ut_ad(fil_page_index_page_check(page_align(rec2))); + ut_ad(!!dict_index_is_spatial(index) + == (fil_page_get_type(page_align(rec2)) == FIL_PAGE_RTREE)); - comp = rec_offs_comp(offsets1); - rec1_n_fields = rec_offs_n_fields(offsets1); - rec2_n_fields = rec_offs_n_fields(offsets2); + ulint comp = rec_offs_comp(offsets1); + ulint n_fields; /* Test if rec is the predefined minimum record */ if (UNIV_UNLIKELY(rec_get_info_bits(rec1, comp) @@ -1158,37 +1159,41 @@ cmp_rec_rec_with_match( goto order_resolved; } - /* Match fields in a loop */ + /* For non-leaf spatial index records, the + dict_index_get_n_unique_in_tree() does include the child page + number, because spatial index node pointers only contain + the MBR (minimum bounding rectangle) and the child page number. - for (; cur_field < rec1_n_fields && cur_field < rec2_n_fields; - cur_field++) { + For B-tree node pointers, the key alone (secondary index + columns and PRIMARY KEY columns) must be unique, and there is + no need to compare the child page number. */ + n_fields = std::min(rec_offs_n_fields(offsets1), + rec_offs_n_fields(offsets2)); + n_fields = std::min(n_fields, dict_index_get_n_unique_in_tree(index)); + for (; cur_field < n_fields; cur_field++) { ulint mtype; ulint prtype; - /* If this is node-ptr records then avoid comparing node-ptr - field. Only key field needs to be compared. */ - if (cur_field == dict_index_get_n_unique_in_tree(index)) { - break; - } - - if (dict_index_is_ibuf(index)) { + if (UNIV_UNLIKELY(dict_index_is_ibuf(index))) { /* This is for the insert buffer B-tree. */ mtype = DATA_BINARY; prtype = 0; } else { - const dict_col_t* col; - - col = dict_index_get_nth_col(index, cur_field); - + const dict_col_t* col = dict_index_get_nth_col( + index, cur_field); mtype = col->mtype; prtype = col->prtype; - /* If the index is spatial index, we mark the - prtype of the first field as MBR field. */ - if (cur_field == 0 && dict_index_is_spatial(index)) { + if (UNIV_LIKELY(!dict_index_is_spatial(index))) { + } else if (cur_field == 0) { ut_ad(DATA_GEOMETRY_MTYPE(mtype)); prtype |= DATA_GIS_MBR; + } else if (!page_rec_is_leaf(rec2)) { + /* Compare the child page number. */ + ut_ad(cur_field == 1); + mtype = DATA_SYS_CHILD; + prtype = 0; } } @@ -1226,8 +1231,10 @@ cmp_rec_rec_with_match( to the common fields */ ut_ad(ret == 0); order_resolved: - *matched_fields = cur_field; - return(ret); + if (matched_fields) { + *matched_fields = cur_field; + } + return ret; } #ifdef UNIV_COMPILE_TEST_FUNCS diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc index e32b8d954bb..d439d7563d9 100644 --- a/storage/innobase/row/row0ftsort.cc +++ b/storage/innobase/row/row0ftsort.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2010, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2019, MariaDB Corporation. +Copyright (c) 2015, 2020, MariaDB Corporation. 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 @@ -1722,7 +1722,6 @@ row_fts_merge_insert( corresponding FTS index auxiliary tables */ for (;;) { dtuple_t* dtuple; - ulint n_ext; int min_rec = 0; if (fts_sort_pll_degree <= 2) { @@ -1765,7 +1764,7 @@ row_fts_merge_insert( } dtuple = row_rec_to_index_entry_low( - mrec[min_rec], index, offsets[min_rec], &n_ext, + mrec[min_rec], index, offsets[min_rec], tuple_heap); row_fts_insert_tuple( diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 2d8f9405007..268d196036a 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2019, MariaDB Corporation. +Copyright (c) 2015, 2020, MariaDB Corporation. 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 @@ -1526,13 +1526,70 @@ IndexPurge::next() UNIV_NOTHROW mtr_set_log_mode(&m_mtr, MTR_LOG_NO_REDO); btr_pcur_restore_position(BTR_MODIFY_LEAF, &m_pcur, &m_mtr); + /* The following is based on btr_pcur_move_to_next_user_rec(). */ + m_pcur.old_stored = false; + ut_ad(m_pcur.latch_mode == BTR_MODIFY_LEAF); + do { + if (btr_pcur_is_after_last_on_page(&m_pcur)) { + if (btr_pcur_is_after_last_in_tree(&m_pcur)) { + return DB_END_OF_INDEX; + } - if (!btr_pcur_move_to_next_user_rec(&m_pcur, &m_mtr)) { + buf_block_t* block = btr_pcur_get_block(&m_pcur); + uint32_t next_page = btr_page_get_next(block->frame); - return(DB_END_OF_INDEX); - } + /* MDEV-13542 FIXME: Make these checks part of + btr_pcur_move_to_next_page(), and introduce a + return status that will be checked in all callers! */ + switch (next_page) { + default: + if (next_page != block->page.id.page_no()) { + break; + } + /* MDEV-20931 FIXME: Check that + next_page is within the tablespace + bounds! Also check that it is not a + change buffer bitmap page. */ + /* fall through */ + case 0: + case 1: + case FIL_NULL: + return DB_CORRUPTION; + } - return(DB_SUCCESS); + dict_index_t* index = m_pcur.btr_cur.index; + buf_block_t* next_block = btr_block_get( + page_id_t(block->page.id.space(), next_page), + block->page.size, BTR_MODIFY_LEAF, index, + &m_mtr); + + if (UNIV_UNLIKELY(!next_block + || !fil_page_index_page_check( + next_block->frame) + || !!dict_index_is_spatial(index) + != (fil_page_get_type( + next_block->frame) + == FIL_PAGE_RTREE) + || page_is_comp(next_block->frame) + != page_is_comp(block->frame) + || btr_page_get_prev( + next_block->frame) + != block->page.id.page_no())) { + return DB_CORRUPTION; + } + + btr_leaf_page_release(block, BTR_MODIFY_LEAF, &m_mtr); + + page_cur_set_before_first(next_block, + &m_pcur.btr_cur.page_cur); + + ut_d(page_check_dir(next_block->frame)); + } else { + btr_pcur_move_to_next_on_page(&m_pcur); + } + } while (!btr_pcur_is_on_user_rec(&m_pcur)); + + return DB_SUCCESS; } /** diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index 6f522229c8d..f6d0657ad5a 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 2017, 2020, MariaDB Corporation. 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 @@ -3559,7 +3559,6 @@ row_log_apply_op( enum row_op op; ulint extra_size; ulint data_size; - ulint n_ext; dtuple_t* entry; trx_id_t trx_id; @@ -3637,10 +3636,10 @@ corrupted: } entry = row_rec_to_index_entry_low( - mrec - data_size, index, offsets, &n_ext, heap); + mrec - data_size, index, offsets, heap); /* Online index creation is only implemented for secondary indexes, which never contain off-page columns. */ - ut_ad(n_ext == 0); + ut_ad(dtuple_get_n_ext(entry) == 0); row_log_apply_op_low(index, dup, error, offsets_heap, has_index_lock, op, trx_id, entry); diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 44d4a5553b7..68166705a3b 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2005, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2014, 2019, MariaDB Corporation. +Copyright (c) 2014, 2020, MariaDB Corporation. 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 @@ -3535,7 +3535,6 @@ row_merge_insert_index_tuples( double curr_progress = 0; dict_index_t* old_index = NULL; const mrec_t* mrec = NULL; - ulint n_ext = 0; mtr_t mtr; @@ -3601,8 +3600,6 @@ row_merge_insert_index_tuples( row buffer to data tuple record */ row_merge_mtuple_to_dtuple( index, dtuple, &row_buf->tuples[n_rows]); - - n_ext = dtuple_get_n_ext(dtuple); n_rows++; /* BLOB pointers must be copied from dtuple */ mrec = NULL; @@ -3621,7 +3618,7 @@ row_merge_insert_index_tuples( } dtuple = row_rec_to_index_entry_low( - mrec, index, offsets, &n_ext, tuple_heap); + mrec, index, offsets, tuple_heap); } old_index = dict_table_get_first_index(old_table); @@ -3634,10 +3631,7 @@ row_merge_insert_index_tuples( } } - if (!n_ext) { - /* There are no externally stored columns. */ - } else { - ut_ad(dict_index_is_clust(index)); + if (dict_index_is_clust(index) && dtuple_get_n_ext(dtuple)) { /* Off-page columns can be fetched safely when concurrent modifications to the table are disabled. (Purge can process delete-marked diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index fcb57f47a7f..7eb3742b987 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -4681,7 +4681,6 @@ row_scan_index_for_mysql( ulint i; ulint cnt; mem_heap_t* heap = NULL; - ulint n_ext; offset_t offsets_[REC_OFFS_NORMAL_SIZE]; offset_t* offsets; rec_offs_init(offsets_); @@ -4823,7 +4822,7 @@ not_ok: mem_heap_empty(heap); prev_entry = row_rec_to_index_entry( - rec, index, offsets, &n_ext, heap); + rec, index, offsets, heap); if (UNIV_LIKELY_NULL(tmp_heap)) { mem_heap_free(tmp_heap); diff --git a/storage/innobase/row/row0row.cc b/storage/innobase/row/row0row.cc index cdcb568a508..c19aa42b48e 100644 --- a/storage/innobase/row/row0row.cc +++ b/storage/innobase/row/row0row.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2018, 2019, MariaDB Corporation. +Copyright (c) 2018, 2020, MariaDB Corporation. 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 @@ -685,7 +685,6 @@ row_rec_to_index_entry_impl( const rec_t* rec, const dict_index_t* index, const offset_t* offsets, - ulint* n_ext, mem_heap_t* heap) { dtuple_t* entry; @@ -703,8 +702,6 @@ row_rec_to_index_entry_impl( /* Because this function may be invoked by row0merge.cc on a record whose header is in different format, the check rec_offs_validate(rec, index, offsets) must be avoided here. */ - ut_ad(n_ext); - *n_ext = 0; rec_len = rec_offs_n_fields(offsets); @@ -731,7 +728,6 @@ row_rec_to_index_entry_impl( if (rec_offs_nth_extern(offsets, i)) { dfield_set_ext(dfield); - (*n_ext)++; } } @@ -743,18 +739,15 @@ row_rec_to_index_entry_impl( @param[in] rec index record @param[in] index index @param[in] offsets rec_get_offsets(rec, index) -@param[out] n_ext number of externally stored columns @param[in,out] heap memory heap for allocations */ dtuple_t* row_rec_to_index_entry_low( const rec_t* rec, const dict_index_t* index, const offset_t* offsets, - ulint* n_ext, mem_heap_t* heap) { - return row_rec_to_index_entry_impl<false>( - rec, index, offsets, n_ext, heap); + return row_rec_to_index_entry_impl<false>(rec, index, offsets, heap); } /*******************************************************************//** @@ -767,8 +760,6 @@ row_rec_to_index_entry( const rec_t* rec, /*!< in: record in the index */ const dict_index_t* index, /*!< in: index */ const offset_t* offsets,/*!< in: rec_get_offsets(rec) */ - ulint* n_ext, /*!< out: number of externally - stored columns */ mem_heap_t* heap) /*!< in: memory heap from which the memory needed is allocated */ { @@ -790,7 +781,7 @@ row_rec_to_index_entry( rec_offs_make_valid(copy_rec, index, true, const_cast<offset_t*>(offsets)); entry = row_rec_to_index_entry_impl<true>( - copy_rec, index, offsets, n_ext, heap); + copy_rec, index, offsets, heap); rec_offs_make_valid(rec, index, true, const_cast<offset_t*>(offsets)); diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index bb91cb2b672..11de19ba62c 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 2017, 2020, MariaDB Corporation. 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 @@ -186,6 +186,7 @@ static bool row_undo_mod_must_purge(undo_node_t* node, mtr_t* mtr) btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&node->pcur); ut_ad(btr_cur->index->is_primary()); + DEBUG_SYNC_C("rollback_purge_clust"); mtr->s_lock(&purge_sys.latch, __FILE__, __LINE__); @@ -319,6 +320,7 @@ row_undo_mod_clust( == node->new_trx_id); btr_pcur_commit_specify_mtr(pcur, &mtr); + DEBUG_SYNC_C("rollback_undo_pk"); if (err != DB_SUCCESS) { goto func_exit; diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index ba66c3db1de..aff8ae125b5 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2019, MariaDB Corporation. +Copyright (c) 2015, 2020, MariaDB Corporation. 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 @@ -223,7 +223,6 @@ row_upd_check_references_constraints( dtuple_t* entry; trx_t* trx; const rec_t* rec; - ulint n_ext; dberr_t err; ibool got_s_lock = FALSE; @@ -240,7 +239,7 @@ row_upd_check_references_constraints( heap = mem_heap_create(500); - entry = row_rec_to_index_entry(rec, index, offsets, &n_ext, heap); + entry = row_rec_to_index_entry(rec, index, offsets, heap); mtr_commit(mtr); @@ -341,7 +340,6 @@ wsrep_row_upd_check_foreign_constraints( dtuple_t* entry; trx_t* trx; const rec_t* rec; - ulint n_ext; dberr_t err; ibool got_s_lock = FALSE; ibool opened = FALSE; @@ -359,8 +357,7 @@ wsrep_row_upd_check_foreign_constraints( heap = mem_heap_create(500); - entry = row_rec_to_index_entry(rec, index, offsets, - &n_ext, heap); + entry = row_rec_to_index_entry(rec, index, offsets, heap); mtr_commit(mtr); @@ -2812,9 +2809,9 @@ check_fk: mtr_commit(mtr); - err = row_ins_clust_index_entry( - index, entry, thr, - node->upd_ext ? node->upd_ext->n_ext : 0); + err = row_ins_clust_index_entry(index, entry, thr, node->upd_ext + ? node->upd_ext->n_ext + : dtuple_get_n_ext(entry)); node->state = UPD_NODE_INSERT_CLUSTERED; mem_heap_free(heap); diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc index 9fe183ecb29..5935b0a11ca 100644 --- a/storage/innobase/row/row0vers.cc +++ b/storage/innobase/row/row0vers.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 2017, 2020, MariaDB Corporation. 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 @@ -153,15 +153,13 @@ row_vers_impl_x_locked_low( const ulint rec_del = rec_get_deleted_flag(rec, comp); if (dict_index_has_virtual(index)) { - ulint n_ext; ulint est_size = DTUPLE_EST_ALLOC(index->n_fields); /* Allocate the dtuple for virtual columns extracted from undo log with its own heap, so to avoid it being freed as we iterating in the version loop below. */ v_heap = mem_heap_create(est_size); - ientry = row_rec_to_index_entry( - rec, index, offsets, &n_ext, v_heap); + ientry = row_rec_to_index_entry(rec, index, offsets, v_heap); } /* We look up if some earlier version, which was modified by diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index 2a5866b3f44..ab17dd03a43 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -1,7 +1,7 @@ /***************************************************************************** -Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 1996, 2019, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2017, 2020, MariaDB Corporation. 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 @@ -2335,8 +2335,6 @@ trx_undo_prev_version_build( ut_a(ptr); if (row_upd_changes_field_size_or_external(index, offsets, update)) { - ulint n_ext; - /* We should confirm the existence of disowned external data, if the previous version record is delete marked. If the trx_id of the previous record is seen by purge view, we should treat @@ -2377,14 +2375,15 @@ trx_undo_prev_version_build( those fields that update updates to become externally stored fields. Store the info: */ - entry = row_rec_to_index_entry( - rec, index, offsets, &n_ext, heap); - n_ext += btr_push_update_extern_fields(entry, update, heap); + entry = row_rec_to_index_entry(rec, index, offsets, heap); /* The page containing the clustered index record corresponding to entry is latched in mtr. Thus the following call is safe. */ row_upd_index_replace_new_col_vals(entry, index, update, heap); + /* Get number of externally stored columns in updated record */ + const ulint n_ext = dtuple_get_n_ext(entry); + buf = static_cast<byte*>(mem_heap_alloc( heap, rec_get_converted_size(index, entry, n_ext))); |