MDEV-21098: Assertion failure in rec_get_offsets_func()

The function rec_get_offsets_func() used to hit ut_error
due to an invalid rec_get_status() value of a
ROW_FORMAT!=REDUNDANT record. This fix is twofold:
We will not only avoid a crash on corruption in this case,
but we will also make more effort to validate each record
every time we are iterating over index page records.

rec_get_offsets_func(): Do not crash on a corrupted record.

page_rec_get_nth(): Return nullptr on error.

page_dir_slot_get_rec_validate(): Like page_dir_slot_get_rec(),
but validate the pointer and return nullptr on error.

page_cur_search_with_match(), page_cur_search_with_match_bytes(),
page_dir_split_slot(), page_cur_move_to_next():
Indicate failure in a return value.

page_cur_search(): Replaced with page_cur_search_with_match().

rec_get_next_ptr_const(), rec_get_next_ptr(): Replaced with
page_rec_get_next_low().

TODO: rtr_page_split_initialize_nodes(), rtr_update_mbr_field(),
and possibly other SPATIAL INDEX functions fail to properly handle
errors.

Reviewed by: Thirunarayanan Balathandayuthapani
Tested by: Matthias Leich
Performance tested by: Axel Schwenke
This commit is contained in:
Marko Mäkelä 2022-08-01 11:25:50 +03:00
parent a6f7c8edc9
commit 63478e72de
29 changed files with 1269 additions and 1058 deletions

View File

@ -760,6 +760,9 @@ btr_page_get_father_block(
rec_t* rec rec_t* rec
= page_rec_get_next(page_get_infimum_rec(buf_block_get_frame( = page_rec_get_next(page_get_infimum_rec(buf_block_get_frame(
block))); block)));
if (UNIV_UNLIKELY(!rec)) {
return nullptr;
}
btr_cur_position(index, rec, block, cursor); btr_cur_position(index, rec, block, cursor);
return(btr_page_get_father_node_ptr(offsets, heap, cursor, mtr)); return(btr_page_get_father_node_ptr(offsets, heap, cursor, mtr));
} }
@ -777,6 +780,9 @@ bool btr_page_get_father(dict_index_t* index, buf_block_t* block, mtr_t* mtr,
rec_t* rec rec_t* rec
= page_rec_get_next(page_get_infimum_rec(buf_block_get_frame( = page_rec_get_next(page_get_infimum_rec(buf_block_get_frame(
block))); block)));
if (UNIV_UNLIKELY(!rec)) {
return false;
}
btr_cur_position(index, rec, block, cursor); btr_cur_position(index, rec, block, cursor);
heap = mem_heap_create(100); heap = mem_heap_create(100);
@ -1252,16 +1258,19 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, dict_index_t *index,
ut_ad(index->is_dummy || block->page.id().page_no() != index->page || ut_ad(index->is_dummy || block->page.id().page_no() != index->page ||
!page_has_siblings(block->page.frame)); !page_has_siblings(block->page.frame));
/* Save the cursor position. */
const ulint pos= page_rec_get_n_recs_before(cursor->rec);
if (UNIV_UNLIKELY(pos == ULINT_UNDEFINED))
return DB_CORRUPTION;
btr_search_drop_page_hash_index(block);
buf_block_t *old= buf_block_alloc(); buf_block_t *old= buf_block_alloc();
/* Copy the old page to temporary space */ /* Copy the old page to temporary space */
memcpy_aligned<UNIV_PAGE_SIZE_MIN>(old->page.frame, block->page.frame, memcpy_aligned<UNIV_PAGE_SIZE_MIN>(old->page.frame, block->page.frame,
srv_page_size); srv_page_size);
btr_search_drop_page_hash_index(block);
/* Save the cursor position. */
const ulint pos= page_rec_get_n_recs_before(cursor->rec);
page_create(block, mtr, index->table->not_redundant()); page_create(block, mtr, index->table->not_redundant());
if (index->is_spatial()) if (index->is_spatial())
block->page.frame[FIL_PAGE_TYPE + 1]= byte(FIL_PAGE_RTREE); block->page.frame[FIL_PAGE_TYPE + 1]= byte(FIL_PAGE_RTREE);
@ -1315,10 +1324,10 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, dict_index_t *index,
} }
/* Restore the cursor position. */ /* Restore the cursor position. */
if (pos) if (!pos)
cursor->rec = page_rec_get_nth(block->page.frame, pos);
else
ut_ad(cursor->rec == page_get_infimum_rec(block->page.frame)); ut_ad(cursor->rec == page_get_infimum_rec(block->page.frame));
else if (!(cursor->rec= page_rec_get_nth(block->page.frame, pos)))
return DB_CORRUPTION;
mtr->set_log_mode(log_mode); mtr->set_log_mode(log_mode);
@ -1543,13 +1552,16 @@ btr_page_reorganize(
return btr_page_reorganize_low(cursor, index, mtr); return btr_page_reorganize_low(cursor, index, mtr);
ulint pos= page_rec_get_n_recs_before(cursor->rec); ulint pos= page_rec_get_n_recs_before(cursor->rec);
if (UNIV_UNLIKELY(pos == ULINT_UNDEFINED))
return DB_CORRUPTION;
dberr_t err= page_zip_reorganize(cursor->block, index, page_zip_level, mtr, dberr_t err= page_zip_reorganize(cursor->block, index, page_zip_level, mtr,
true); true);
if (err == DB_FAIL); if (err == DB_FAIL);
else if (pos) else if (!pos)
cursor->rec= page_rec_get_nth(cursor->block->page.frame, pos);
else
ut_ad(cursor->rec == page_get_infimum_rec(cursor->block->page.frame)); ut_ad(cursor->rec == page_get_infimum_rec(cursor->block->page.frame));
else if (!(cursor->rec= page_rec_get_nth(cursor->block->page.frame, pos)))
err= DB_CORRUPTION;
return err; return err;
} }
@ -1745,7 +1757,6 @@ btr_root_raise_and_insert(
dberr_t* err) /*!< out: error code */ dberr_t* err) /*!< out: error code */
{ {
dict_index_t* index; dict_index_t* index;
ulint new_page_no;
rec_t* rec; rec_t* rec;
dtuple_t* node_ptr; dtuple_t* node_ptr;
ulint level; ulint level;
@ -1907,8 +1918,9 @@ btr_root_raise_and_insert(
*heap = mem_heap_create(1000); *heap = mem_heap_create(1000);
} }
const uint32_t new_page_no = new_block->page.id().page_no();
rec = page_rec_get_next(page_get_infimum_rec(new_block->page.frame)); rec = page_rec_get_next(page_get_infimum_rec(new_block->page.frame));
new_page_no = new_block->page.id().page_no(); ut_ad(rec); /* We just created the page. */
/* Build the node pointer (= node key and page address) for the /* Build the node pointer (= node key and page address) for the
child */ child */
@ -1961,9 +1973,20 @@ btr_root_raise_and_insert(
ibuf_reset_free_bits(new_block); ibuf_reset_free_bits(new_block);
} }
if (tuple != NULL) { if (tuple) {
ut_ad(dtuple_check_typed(tuple));
/* Reposition the cursor to the child node */ /* Reposition the cursor to the child node */
page_cur_search(new_block, index, tuple, page_cursor); ulint low_match = 0, up_match = 0;
if (page_cur_search_with_match(new_block, index, tuple,
PAGE_CUR_LE,
&up_match, &low_match,
page_cursor, nullptr)) {
if (err) {
*err = DB_CORRUPTION;
}
return nullptr;
}
} else { } else {
/* Set cursor to first record on child node */ /* Set cursor to first record on child node */
page_cur_set_before_first(new_block, page_cursor); page_cur_set_before_first(new_block, page_cursor);
@ -2042,7 +2065,7 @@ btr_page_get_split_rec_to_right(const btr_cur_t* cursor, rec_t** split_rec)
insert_point = page_rec_get_next(insert_point); insert_point = page_rec_get_next(insert_point);
if (page_rec_is_supremum(insert_point)) { if (!insert_point || page_rec_is_supremum(insert_point)) {
insert_point = NULL; insert_point = NULL;
} else { } else {
insert_point = page_rec_get_next(insert_point); insert_point = page_rec_get_next(insert_point);
@ -2230,19 +2253,19 @@ btr_page_insert_fits(
end_rec) will end up on the other half page from tuple when it is end_rec) will end up on the other half page from tuple when it is
inserted. */ inserted. */
if (split_rec == NULL) { if (!(end_rec = split_rec)) {
rec = page_rec_get_next(page_get_infimum_rec(page));
end_rec = page_rec_get_next(btr_cur_get_rec(cursor)); end_rec = page_rec_get_next(btr_cur_get_rec(cursor));
} else if (cmp_dtuple_rec(tuple, split_rec, *offsets) < 0) {
} else if (cmp_dtuple_rec(tuple, split_rec, *offsets) >= 0) {
rec = page_rec_get_next(page_get_infimum_rec(page));
end_rec = split_rec;
} else {
rec = split_rec; rec = split_rec;
end_rec = page_get_supremum_rec(page); end_rec = page_get_supremum_rec(page);
goto got_rec;
} }
if (!(rec = page_rec_get_next(page_get_infimum_rec(page)))) {
return false;
}
got_rec:
if (total_data + page_dir_calc_reserved_space(total_n_recs) if (total_data + page_dir_calc_reserved_space(total_n_recs)
<= free_space) { <= free_space) {
@ -2274,7 +2297,9 @@ btr_page_insert_fits(
return(true); return(true);
} }
rec = page_rec_get_next_const(rec); if (!(rec = page_rec_get_next_const(rec))) {
break;
}
} }
return(false); return(false);
@ -2511,8 +2536,10 @@ btr_page_tuple_smaller(
/* Read the first user record in the page. */ /* Read the first user record in the page. */
block = btr_cur_get_block(cursor); block = btr_cur_get_block(cursor);
page_cur_set_before_first(block, &pcur); page_cur_set_before_first(block, &pcur);
page_cur_move_to_next(&pcur); if (UNIV_UNLIKELY(!(first_rec = page_cur_move_to_next(&pcur)))) {
first_rec = page_cur_get_rec(&pcur); ut_ad("corrupted page" == 0);
return false;
}
*offsets = rec_get_offsets(first_rec, cursor->index, *offsets, *offsets = rec_get_offsets(first_rec, cursor->index, *offsets,
page_is_leaf(block->page.frame) page_is_leaf(block->page.frame)
@ -2554,6 +2581,7 @@ btr_insert_into_right_sibling(
MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK)); MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK));
ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX)); ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX));
ut_ad(heap); ut_ad(heap);
ut_ad(dtuple_check_typed(tuple));
if (next_page_no == FIL_NULL || !page_rec_is_supremum( if (next_page_no == FIL_NULL || !page_rec_is_supremum(
page_rec_get_next(btr_cur_get_rec(cursor)))) { page_rec_get_next(btr_cur_get_rec(cursor)))) {
@ -2581,9 +2609,13 @@ btr_insert_into_right_sibling(
return nullptr; return nullptr;
} }
page_cur_search( ulint up_match = 0, low_match = 0;
next_block, cursor->index, tuple, PAGE_CUR_LE,
&next_page_cursor); if (page_cur_search_with_match(next_block, cursor->index, tuple,
PAGE_CUR_LE, &up_match, &low_match,
&next_page_cursor, nullptr)) {
return nullptr;
}
max_size = page_get_max_insert_size_after_reorganize(next_page, 1); max_size = page_get_max_insert_size_after_reorganize(next_page, 1);
@ -2788,6 +2820,7 @@ btr_page_split_and_insert(
ulint n_uniq; ulint n_uniq;
ut_ad(*err == DB_SUCCESS); ut_ad(*err == DB_SUCCESS);
ut_ad(dtuple_check_typed(tuple));
if (cursor->index->is_spatial()) { if (cursor->index->is_spatial()) {
/* Split rtree page and update parent */ /* Split rtree page and update parent */
@ -2855,9 +2888,16 @@ func_start:
page_get_infimum_rec(page)); page_get_infimum_rec(page));
} else { } else {
split_rec = NULL; split_rec = NULL;
goto got_split_rec;
}
if (UNIV_UNLIKELY(!split_rec)) {
*err = DB_CORRUPTION;
return nullptr;
} }
} }
got_split_rec:
/* 2. Allocate a new page to the index */ /* 2. Allocate a new page to the index */
const uint16_t page_level = btr_page_get_level(page); const uint16_t page_level = btr_page_get_level(page);
new_block = btr_page_alloc(cursor->index, hint_page_no, direction, new_block = btr_page_alloc(cursor->index, hint_page_no, direction,
@ -2906,9 +2946,17 @@ func_start:
goto insert_empty; goto insert_empty;
} }
} else if (insert_left) { } else if (insert_left) {
ut_a(n_iterations > 0); if (UNIV_UNLIKELY(!n_iterations)) {
corrupted:
*err = DB_CORRUPTION;
return nullptr;
}
first_rec = page_rec_get_next(page_get_infimum_rec(page)); first_rec = page_rec_get_next(page_get_infimum_rec(page));
insert_move_limit:
move_limit = page_rec_get_next(btr_cur_get_rec(cursor)); move_limit = page_rec_get_next(btr_cur_get_rec(cursor));
if (UNIV_UNLIKELY(!first_rec || !move_limit)) {
goto corrupted;
}
} else { } else {
insert_empty: insert_empty:
ut_ad(!split_rec); ut_ad(!split_rec);
@ -2919,7 +2967,7 @@ insert_empty:
first_rec = rec_convert_dtuple_to_rec(buf, cursor->index, first_rec = rec_convert_dtuple_to_rec(buf, cursor->index,
tuple, n_ext); tuple, n_ext);
move_limit = page_rec_get_next(btr_cur_get_rec(cursor)); goto insert_move_limit;
} }
/* 4. Do first the modifications in the tree structure */ /* 4. Do first the modifications in the tree structure */
@ -3086,7 +3134,14 @@ insert_empty:
/* 7. Reposition the cursor for insert and try insertion */ /* 7. Reposition the cursor for insert and try insertion */
page_cursor = btr_cur_get_page_cur(cursor); page_cursor = btr_cur_get_page_cur(cursor);
page_cur_search(insert_block, cursor->index, tuple, page_cursor); ulint up_match = 0, low_match = 0;
if (page_cur_search_with_match(insert_block, cursor->index, tuple,
PAGE_CUR_LE, &up_match, &low_match,
page_cursor, nullptr)) {
*err = DB_CORRUPTION;
return nullptr;
}
rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index, rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index,
offsets, heap, n_ext, mtr); offsets, heap, n_ext, mtr);
@ -3440,8 +3495,8 @@ btr_compress(
mtr_t* mtr) /*!< in/out: mini-transaction */ mtr_t* mtr) /*!< in/out: mini-transaction */
{ {
dict_index_t* index; dict_index_t* index;
buf_block_t* merge_block; buf_block_t* merge_block = nullptr;
page_t* merge_page = NULL; page_t* merge_page = nullptr;
page_zip_des_t* merge_page_zip; page_zip_des_t* merge_page_zip;
ibool is_left; ibool is_left;
buf_block_t* block; buf_block_t* block;
@ -3499,7 +3554,10 @@ btr_compress(
if (adjust) { if (adjust) {
nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor)); nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor));
ut_ad(nth_rec > 0); if (UNIV_UNLIKELY(!nth_rec || nth_rec == ULINT_UNDEFINED)) {
err = DB_CORRUPTION;
goto err_exit;
}
} }
if (left_page_no == FIL_NULL && right_page_no == FIL_NULL) { if (left_page_no == FIL_NULL && right_page_no == FIL_NULL) {
@ -3648,7 +3706,12 @@ cannot_merge:
} }
if (adjust) { if (adjust) {
nth_rec += page_rec_get_n_recs_before(orig_pred); ulint n = page_rec_get_n_recs_before(orig_pred);
if (UNIV_UNLIKELY(!n || n == ULINT_UNDEFINED)) {
err = DB_CORRUPTION;
goto err_exit;
}
nth_rec += n;
} }
} else { } else {
rec_t* orig_succ; rec_t* orig_succ;
@ -3866,16 +3929,20 @@ cannot_merge:
ut_ad(leftmost_child ut_ad(leftmost_child
|| btr_check_node_ptr(index, merge_block, mtr)); || btr_check_node_ptr(index, merge_block, mtr));
func_exit: func_exit:
MONITOR_INC(MONITOR_INDEX_MERGE_SUCCESSFUL);
if (adjust) { if (adjust) {
ut_ad(nth_rec > 0); ut_ad(nth_rec > 0);
btr_cur_position( if (rec_t* nth
index, = page_rec_get_nth(merge_block->page.frame,
page_rec_get_nth(merge_block->page.frame, nth_rec)) {
nth_rec), btr_cur_position(index, nth,
merge_block, cursor); merge_block, cursor);
} else {
err = DB_CORRUPTION;
goto err_exit;
} }
}
MONITOR_INC(MONITOR_INDEX_MERGE_SUCCESSFUL);
} else { } else {
err_exit: err_exit:
/* We play it safe and reset the free bits. */ /* We play it safe and reset the free bits. */
@ -3912,6 +3979,9 @@ btr_discard_only_page_on_level(
const trx_id_t max_trx_id = page_get_max_trx_id(block->page.frame); const trx_id_t max_trx_id = page_get_max_trx_id(block->page.frame);
const rec_t* r = page_rec_get_next( const rec_t* r = page_rec_get_next(
page_get_infimum_rec(block->page.frame)); page_get_infimum_rec(block->page.frame));
/* In the caller we checked that a valid key exists in the page,
because we were able to look up a parent page. */
ut_ad(r);
ut_ad(rec_is_metadata(r, *index) == index->is_instant()); ut_ad(rec_is_metadata(r, *index) == index->is_instant());
while (block->page.id().page_no() != dict_index_get_page(index)) { while (block->page.id().page_no() != dict_index_get_page(index)) {
@ -4083,14 +4153,17 @@ btr_discard_page(
ut_d(parent_is_different = page_rec_is_supremum( ut_d(parent_is_different = page_rec_is_supremum(
page_rec_get_next(btr_cur_get_rec(&parent_cursor)))); page_rec_get_next(btr_cur_get_rec(&parent_cursor))));
if (!page_is_leaf(merge_block->page.frame)) { if (page_is_leaf(merge_block->page.frame)) {
rec_t* node_ptr = page_rec_get_next( } else if (rec_t* node_ptr =
page_get_infimum_rec(merge_block->page.frame)); page_rec_get_next(page_get_infimum_rec(
merge_block->page.frame))) {
ut_ad(page_rec_is_user_rec(node_ptr)); ut_ad(page_rec_is_user_rec(node_ptr));
/* We have to mark the leftmost node pointer as the /* We have to mark the leftmost node pointer as the
predefined minimum record. */ predefined minimum record. */
btr_set_min_rec_mark<true>(node_ptr, *merge_block, btr_set_min_rec_mark<true>(node_ptr, *merge_block,
mtr); mtr);
} else {
return DB_CORRUPTION;
} }
} else { } else {
btr_discard_only_page_on_level(index, block, mtr); btr_discard_only_page_on_level(index, block, mtr);
@ -4550,16 +4623,15 @@ next_field:
/************************************************************//** /************************************************************//**
Checks the size and number of fields in records based on the definition of Checks the size and number of fields in records based on the definition of
the index. the index.
@return TRUE if ok */ @return true if ok */
static static
ibool bool
btr_index_page_validate( btr_index_page_validate(
/*====================*/ /*====================*/
buf_block_t* block, /*!< in: index page */ buf_block_t* block, /*!< in: index page */
dict_index_t* index) /*!< in: index */ dict_index_t* index) /*!< in: index */
{ {
page_cur_t cur; page_cur_t cur;
ibool ret = TRUE;
#ifndef DBUG_OFF #ifndef DBUG_OFF
ulint nth = 1; ulint nth = 1;
#endif /* !DBUG_OFF */ #endif /* !DBUG_OFF */
@ -4576,17 +4648,13 @@ btr_index_page_validate(
page_cur_get_page(&cur), 0)) page_cur_get_page(&cur), 0))
== 1);); == 1););
page_cur_move_to_next(&cur); while (page_cur_move_to_next(&cur)) {
for (;;) {
if (page_cur_is_after_last(&cur)) { if (page_cur_is_after_last(&cur)) {
return true;
break;
} }
if (!btr_index_rec_validate(cur.rec, index, TRUE)) { if (!btr_index_rec_validate(cur.rec, index, TRUE)) {
break;
return(FALSE);
} }
/* Verify that page_rec_get_nth_const() is correctly /* Verify that page_rec_get_nth_const() is correctly
@ -4598,11 +4666,9 @@ btr_index_page_validate(
cur.rec))); cur.rec)));
ut_a(nth++ == page_rec_get_n_recs_before( ut_a(nth++ == page_rec_get_n_recs_before(
cur.rec));); cur.rec)););
page_cur_move_to_next(&cur);
} }
return(ret); return false;
} }
/************************************************************//** /************************************************************//**
@ -4720,14 +4786,16 @@ btr_validate_level(
ut_a(!page_zip || page_zip_validate(page_zip, page, index)); ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */ #endif /* UNIV_ZIP_DEBUG */
if (page_is_leaf(page)) { if (page_is_leaf(page)) {
corrupted:
err = DB_CORRUPTION; err = DB_CORRUPTION;
goto invalid_page; goto invalid_page;
} }
page_cur_set_before_first(block, &cursor); page_cur_set_before_first(block, &cursor);
page_cur_move_to_next(&cursor); if (!(node_ptr = page_cur_move_to_next(&cursor))) {
goto corrupted;
}
node_ptr = page_cur_get_rec(&cursor);
offsets = rec_get_offsets(node_ptr, index, offsets, 0, offsets = rec_get_offsets(node_ptr, index, offsets, 0,
ULINT_UNDEFINED, &heap); ULINT_UNDEFINED, &heap);
@ -4851,12 +4919,16 @@ func_exit:
} }
if (!(rec = page_rec_get_prev(page_get_supremum_rec(page)))) { if (!(rec = page_rec_get_prev(page_get_supremum_rec(page)))) {
broken_links:
btr_validate_report1(index, level, block); btr_validate_report1(index, level, block);
fputs("InnoDB: broken record links\n", stderr); fputs("InnoDB: broken record links\n", stderr);
goto invalid_page; goto invalid_page;
} }
right_rec = page_rec_get_next(page_get_infimum_rec( if (!(right_rec =
right_page)); page_rec_get_next(page_get_infimum_rec(right_page)))) {
goto broken_links;
}
offsets = rec_get_offsets(rec, index, offsets, offsets = rec_get_offsets(rec, index, offsets,
page_is_leaf(page) page_is_leaf(page)
? index->n_core_fields : 0, ? index->n_core_fields : 0,
@ -4869,7 +4941,7 @@ func_exit:
/* For spatial index, we cannot guarantee the key ordering /* For spatial index, we cannot guarantee the key ordering
across pages, so skip the record compare verification for across pages, so skip the record compare verification for
now. Will enhanced in special R-Tree index validation scheme */ now. Will enhanced in special R-Tree index validation scheme */
if (!dict_index_is_spatial(index) if (!index->is_spatial()
&& cmp_rec_rec(rec, right_rec, && cmp_rec_rec(rec, right_rec,
offsets, offsets2, index) >= 0) { offsets, offsets2, index) >= 0) {
@ -4887,20 +4959,27 @@ func_exit:
fputs("InnoDB: record ", stderr); fputs("InnoDB: record ", stderr);
rec = page_rec_get_next( rec = page_rec_get_next(
page_get_infimum_rec(right_page)); page_get_infimum_rec(right_page));
if (rec) {
rec_print(stderr, rec, index); rec_print(stderr, rec, index);
}
putc('\n', stderr); putc('\n', stderr);
err = DB_CORRUPTION; err = DB_CORRUPTION;
} }
} }
if (level > 0 && left_page_no == FIL_NULL if (!level || left_page_no != FIL_NULL) {
&& !(REC_INFO_MIN_REC_FLAG & rec_get_info_bits( } else if (const rec_t* first =
page_rec_get_next(page_get_infimum_rec(page)), page_rec_get_next_const(page_get_infimum_rec(page))) {
page_is_comp(page)))) { if (!(REC_INFO_MIN_REC_FLAG
& rec_get_info_bits(first, page_is_comp(page)))) {
btr_validate_report1(index, level, block); btr_validate_report1(index, level, block);
ib::error() << "Missing REC_INFO_MIN_REC_FLAG"; ib::error() << "Missing REC_INFO_MIN_REC_FLAG";
err = DB_CORRUPTION; err = DB_CORRUPTION;
} }
} else {
err = DB_CORRUPTION;
goto node_ptr_fails;
}
/* Similarly skip the father node check for spatial index for now, /* Similarly skip the father node check for spatial index for now,
for a couple of reasons: for a couple of reasons:
@ -4908,15 +4987,17 @@ func_exit:
in parent level and linked pages in the child level. in parent level and linked pages in the child level.
2) Search parent from root is very costly for R-tree. 2) Search parent from root is very costly for R-tree.
We will add special validation mechanism for R-tree later (WL #7520) */ We will add special validation mechanism for R-tree later (WL #7520) */
if (!dict_index_is_spatial(index) if (!index->is_spatial()
&& block->page.id().page_no() != dict_index_get_page(index)) { && block->page.id().page_no() != index->page) {
/* Check father node pointers */ /* Check father node pointers */
rec_t* node_ptr; rec_t* node_ptr
= page_rec_get_next(page_get_infimum_rec(page));
if (!node_ptr) {
err = DB_CORRUPTION;
goto node_ptr_fails;
}
btr_cur_position( btr_cur_position(index, node_ptr, block, &node_cur);
index, page_rec_get_next(page_get_infimum_rec(page)),
block, &node_cur);
offsets = btr_page_get_father_node_ptr_for_validate( offsets = btr_page_get_father_node_ptr_for_validate(
offsets, heap, &node_cur, &mtr); offsets, heap, &node_cur, &mtr);
@ -4965,17 +5046,15 @@ func_exit:
goto node_ptr_fails; goto node_ptr_fails;
} }
if (!page_is_leaf(page)) { if (page_is_leaf(page)) {
} else if (const rec_t* first_rec =
page_rec_get_next(page_get_infimum_rec(page))) {
node_ptr_tuple = dict_index_build_node_ptr( node_ptr_tuple = dict_index_build_node_ptr(
index, index, first_rec,
page_rec_get_next(page_get_infimum_rec(page)),
0, heap, btr_page_get_level(page)); 0, heap, btr_page_get_level(page));
if (cmp_dtuple_rec(node_ptr_tuple, node_ptr, if (cmp_dtuple_rec(node_ptr_tuple, node_ptr,
offsets)) { offsets)) {
const rec_t* first_rec = page_rec_get_next(
page_get_infimum_rec(page));
btr_validate_report1(index, level, block); btr_validate_report1(index, level, block);
ib::error() << "Node ptrs differ on levels > 0"; ib::error() << "Node ptrs differ on levels > 0";
@ -4988,6 +5067,9 @@ func_exit:
err = DB_CORRUPTION; err = DB_CORRUPTION;
goto node_ptr_fails; goto node_ptr_fails;
} }
} else {
err = DB_CORRUPTION;
goto node_ptr_fails;
} }
if (left_page_no == FIL_NULL) { if (left_page_no == FIL_NULL) {
@ -5006,11 +5088,8 @@ func_exit:
err = DB_CORRUPTION; err = DB_CORRUPTION;
goto node_ptr_fails; goto node_ptr_fails;
} }
} else { } else if (const rec_t* right_node_ptr
const rec_t* right_node_ptr; = page_rec_get_next(node_ptr)) {
right_node_ptr = page_rec_get_next(node_ptr);
if (!lockout && rightmost_child) { if (!lockout && rightmost_child) {
/* To obey latch order of tree blocks, /* To obey latch order of tree blocks,
@ -5041,11 +5120,12 @@ func_exit:
} }
btr_cur_position( btr_cur_position(
index, page_rec_get_next( index,
page_get_infimum_rec( page_get_infimum_rec(right_block->page.frame),
buf_block_get_frame(
right_block))),
right_block, &right_node_cur); right_block, &right_node_cur);
if (!page_cur_move_to_next(&right_node_cur.page_cur)) {
goto node_pointer_corrupted;
}
offsets = btr_page_get_father_node_ptr_for_validate( offsets = btr_page_get_father_node_ptr_for_validate(
offsets, heap, &right_node_cur, &mtr); offsets, heap, &right_node_cur, &mtr);
@ -5055,6 +5135,7 @@ func_exit:
if (btr_cur_get_rec(&right_node_cur) if (btr_cur_get_rec(&right_node_cur)
!= right_node_ptr) { != right_node_ptr) {
node_pointer_corrupted:
err = DB_CORRUPTION; err = DB_CORRUPTION;
fputs("InnoDB: node pointer to" fputs("InnoDB: node pointer to"
" the right page is wrong\n", " the right page is wrong\n",
@ -5092,6 +5173,8 @@ func_exit:
block); block);
} }
} }
} else {
err = DB_CORRUPTION;
} }
} }

View File

@ -1199,6 +1199,9 @@ err_exit:
first_rec = page_rec_get_next( first_rec = page_rec_get_next(
page_get_infimum_rec(last_block->page.frame)); page_get_infimum_rec(last_block->page.frame));
/* Because this index tree is being created by this thread,
we assume that it cannot be corrupted. */
ut_ad(first_rec);
ut_ad(page_rec_is_user_rec(first_rec)); ut_ad(page_rec_is_user_rec(first_rec));
/* Copy last page to root page. */ /* Copy last page to root page. */

View File

@ -403,15 +403,13 @@ unreadable:
ut_ad(page_cur_is_before_first(&cur.page_cur)); ut_ad(page_cur_is_before_first(&cur.page_cur));
ut_ad(page_is_leaf(cur.page_cur.block->page.frame)); ut_ad(page_is_leaf(cur.page_cur.block->page.frame));
page_cur_move_to_next(&cur.page_cur); const rec_t* rec = page_cur_move_to_next(&cur.page_cur);
const rec_t* rec = cur.page_cur.rec;
const ulint comp = dict_table_is_comp(index->table); const ulint comp = dict_table_is_comp(index->table);
const ulint info_bits = rec_get_info_bits(rec, comp); const ulint info_bits = rec ? rec_get_info_bits(rec, comp) : 0;
if (page_rec_is_supremum(rec) if (page_rec_is_supremum(rec)
|| !(info_bits & REC_INFO_MIN_REC_FLAG)) { || !(info_bits & REC_INFO_MIN_REC_FLAG)) {
if (!index->is_instant()) { if (rec && !index->is_instant()) {
/* The FIL_PAGE_TYPE_INSTANT and PAGE_INSTANT may be /* The FIL_PAGE_TYPE_INSTANT and PAGE_INSTANT may be
assigned even if instant ADD COLUMN was not assigned even if instant ADD COLUMN was not
committed. Changes to these page header fields are not committed. Changes to these page header fields are not
@ -884,6 +882,21 @@ btr_cur_latch_for_root_leaf(
return(RW_NO_LATCH); /* avoid compiler warnings */ return(RW_NO_LATCH); /* avoid compiler warnings */
} }
/** @return whether the distance between two records is at most the
specified value */
static bool
page_rec_distance_is_at_most(const rec_t *left, const rec_t *right, ulint val)
{
do
{
if (left == right)
return true;
left= page_rec_get_next_const(left);
}
while (left && val--);
return false;
}
/** Detects whether the modifying record might need a modifying tree structure. /** Detects whether the modifying record might need a modifying tree structure.
@param[in] index index @param[in] index index
@param[in] page page @param[in] page page
@ -1914,22 +1927,28 @@ retry_page_get:
#ifdef BTR_CUR_HASH_ADAPT #ifdef BTR_CUR_HASH_ADAPT
} else if (height == 0 && btr_search_enabled } else if (height == 0 && btr_search_enabled
&& !(tuple->info_bits & REC_INFO_MIN_REC_FLAG) && !(tuple->info_bits & REC_INFO_MIN_REC_FLAG)
&& !dict_index_is_spatial(index)) { && index->is_btree()) {
/* The adaptive hash index is only used when searching /* The adaptive hash index is only used when searching
for leaf pages (height==0), but not in r-trees. for leaf pages (height==0), but not in r-trees.
We only need the byte prefix comparison for the purpose We only need the byte prefix comparison for the purpose
of updating the adaptive hash index. */ of updating the adaptive hash index. */
page_cur_search_with_match_bytes( if (page_cur_search_with_match_bytes(
block, index, tuple, page_mode, &up_match, &up_bytes, block, index, tuple, page_mode, &up_match, &up_bytes,
&low_match, &low_bytes, page_cursor); &low_match, &low_bytes, page_cursor)) {
err = DB_CORRUPTION;
goto func_exit;
}
#endif /* BTR_CUR_HASH_ADAPT */ #endif /* BTR_CUR_HASH_ADAPT */
} else { } else {
/* Search for complete index fields. */ /* Search for complete index fields. */
up_bytes = low_bytes = 0; up_bytes = low_bytes = 0;
page_cur_search_with_match( if (page_cur_search_with_match(
block, index, tuple, page_mode, &up_match, block, index, tuple, page_mode, &up_match,
&low_match, page_cursor, &low_match, page_cursor,
need_path ? cursor->rtr_info : NULL); need_path ? cursor->rtr_info : nullptr)) {
err = DB_CORRUPTION;
goto func_exit;
}
} }
/* If this is the desired level, leave the loop */ /* If this is the desired level, leave the loop */
@ -2097,6 +2116,11 @@ need_opposite_intention:
ut_ad(upper_rw_latch == RW_X_LATCH); ut_ad(upper_rw_latch == RW_X_LATCH);
if (UNIV_UNLIKELY(!first_rec)) {
corrupted:
err = DB_CORRUPTION;
goto func_exit;
}
if (node_ptr == first_rec if (node_ptr == first_rec
|| page_rec_is_last(node_ptr, page)) { || page_rec_is_last(node_ptr, page)) {
detected_same_key_root = true; detected_same_key_root = true;
@ -2131,8 +2155,7 @@ need_opposite_intention:
detected_same_key_root = true; detected_same_key_root = true;
} }
} else { } else {
err = DB_CORRUPTION; goto corrupted;
goto func_exit;
} }
} }
} }
@ -2241,11 +2264,14 @@ need_opposite_intention:
? cursor->rtr_info : NULL; ? cursor->rtr_info : NULL;
for (ulint i = 0; i < n_blocks; i++) { for (ulint i = 0; i < n_blocks; i++) {
page_cur_search_with_match( if (page_cur_search_with_match(
tree_blocks[i], index, tuple, tree_blocks[i], index, tuple,
page_mode, &up_match, page_mode, &up_match,
&low_match, page_cursor, &low_match, page_cursor,
rtr_info); rtr_info)) {
err = DB_CORRUPTION;
goto func_exit;
}
} }
goto search_loop; goto search_loop;
@ -2678,14 +2704,12 @@ btr_cur_open_at_index_side(
ut_ad(height > 0); ut_ad(height > 0);
if (from_left) { if (from_left
page_cur_move_to_next(page_cursor); ? !page_cur_move_to_next(page_cursor)
} else { : !page_cur_move_to_prev(page_cursor)) {
if (!page_cur_move_to_prev(page_cursor)) {
err = DB_CORRUPTION; err = DB_CORRUPTION;
goto exit_loop; goto exit_loop;
} }
}
height--; height--;
@ -3117,7 +3141,7 @@ btr_cur_insert_if_possible(
/*************************************************************//** /*************************************************************//**
For an insert, checks the locks and does the undo logging if desired. For an insert, checks the locks and does the undo logging if desired.
@return DB_SUCCESS, DB_WAIT_LOCK, DB_FAIL, or error number */ @return DB_SUCCESS, DB_LOCK_WAIT, DB_FAIL, or error number */
UNIV_INLINE MY_ATTRIBUTE((warn_unused_result, nonnull(2,3,5,6))) UNIV_INLINE MY_ATTRIBUTE((warn_unused_result, nonnull(2,3,5,6)))
dberr_t dberr_t
btr_cur_ins_lock_and_undo( btr_cur_ins_lock_and_undo(
@ -3268,7 +3292,7 @@ It is assumed that mtr holds an x-latch on the page. The operation does
not succeed if there is too little space on the page. If there is just not succeed if there is too little space on the page. If there is just
one record on the page, the insert will always succeed; this is to one record on the page, the insert will always succeed; this is to
prevent trying to split a page with just one record. prevent trying to split a page with just one record.
@return DB_SUCCESS, DB_WAIT_LOCK, DB_FAIL, or error number */ @return DB_SUCCESS, DB_LOCK_WAIT, DB_FAIL, or error number */
dberr_t dberr_t
btr_cur_optimistic_insert( btr_cur_optimistic_insert(
/*======================*/ /*======================*/
@ -3736,7 +3760,7 @@ func_exit:
/*************************************************************//** /*************************************************************//**
For an update, checks the locks and does the undo logging. For an update, checks the locks and does the undo logging.
@return DB_SUCCESS, DB_WAIT_LOCK, or error number */ @return DB_SUCCESS, DB_LOCK_WAIT, or error number */
UNIV_INLINE MY_ATTRIBUTE((warn_unused_result)) UNIV_INLINE MY_ATTRIBUTE((warn_unused_result))
dberr_t dberr_t
btr_cur_upd_lock_and_undo( btr_cur_upd_lock_and_undo(
@ -4682,8 +4706,7 @@ any_extern:
rec = btr_cur_insert_if_possible(cursor, new_entry, offsets, heap, rec = btr_cur_insert_if_possible(cursor, new_entry, offsets, heap,
0/*n_ext*/, mtr); 0/*n_ext*/, mtr);
if (UNIV_UNLIKELY(!rec)) { if (UNIV_UNLIKELY(!rec)) {
err = DB_CORRUPTION; goto corrupted;
goto func_exit;
} }
if (UNIV_UNLIKELY(update->is_metadata())) { if (UNIV_UNLIKELY(update->is_metadata())) {
@ -4701,8 +4724,11 @@ any_extern:
block->page.id()); block->page.id());
} }
page_cur_move_to_next(page_cursor);
ut_ad(err == DB_SUCCESS); ut_ad(err == DB_SUCCESS);
if (!page_cur_move_to_next(page_cursor)) {
corrupted:
err = DB_CORRUPTION;
}
func_exit: func_exit:
if (!(flags & BTR_KEEP_IBUF_BITMAP) if (!(flags & BTR_KEEP_IBUF_BITMAP)
@ -5454,6 +5480,10 @@ btr_cur_optimistic_delete(
dict_index_t* index = cursor->index; dict_index_t* index = cursor->index;
const rec_t* first_rec = page_rec_get_next_const( const rec_t* first_rec = page_rec_get_next_const(
page_get_infimum_rec(block->page.frame)); page_get_infimum_rec(block->page.frame));
if (UNIV_UNLIKELY(!first_rec)) {
err = DB_CORRUPTION;
goto func_exit;
}
ut_ad(!index->is_instant() ut_ad(!index->is_instant()
|| rec_is_metadata(first_rec, *index)); || rec_is_metadata(first_rec, *index));
const bool is_metadata = rec_is_metadata(rec, *index); const bool is_metadata = rec_is_metadata(rec, *index);
@ -5683,6 +5713,10 @@ btr_cur_pessimistic_delete(
const rec_t* first_rec = page_rec_get_next_const( const rec_t* first_rec = page_rec_get_next_const(
page_get_infimum_rec(page)); page_get_infimum_rec(page));
if (UNIV_UNLIKELY(!first_rec)) {
*err = DB_CORRUPTION;
goto err_exit;
}
ut_ad(!index->is_instant() ut_ad(!index->is_instant()
|| rec_is_metadata(first_rec, *index)); || rec_is_metadata(first_rec, *index));
if (is_metadata || !index->is_instant() if (is_metadata || !index->is_instant()
@ -5729,7 +5763,11 @@ discard_page:
goto return_after_reservations; goto return_after_reservations;
} }
next_rec = page_rec_get_next(rec); if (UNIV_UNLIKELY(!(next_rec = page_rec_get_next(rec)))) {
ut_ad(!ret);
*err = DB_CORRUPTION;
goto err_exit;
}
if (!page_has_prev(page)) { if (!page_has_prev(page)) {
/* If we delete the leftmost node pointer on a /* If we delete the leftmost node pointer on a
@ -5996,9 +6034,10 @@ public:
if (dtuple_get_n_fields(&m_tuple) > 0) if (dtuple_get_n_fields(&m_tuple) > 0)
{ {
m_up_bytes= m_low_bytes= 0; m_up_bytes= m_low_bytes= 0;
page_cur_search_with_match(m_block, index(), &m_tuple, m_page_mode, if (page_cur_search_with_match(m_block, index(), &m_tuple, m_page_mode,
&m_up_match, &m_low_match, &m_page_cur, &m_up_match, &m_low_match, &m_page_cur,
nullptr); nullptr))
return false;
m_nth_rec= page_rec_get_n_recs_before(page_cur_get_rec(&m_page_cur)); m_nth_rec= page_rec_get_n_recs_before(page_cur_get_rec(&m_page_cur));
} }
else if (left) else if (left)
@ -6006,7 +6045,8 @@ public:
page_cur_set_before_first(m_block, &m_page_cur); page_cur_set_before_first(m_block, &m_page_cur);
if (level) if (level)
{ {
page_cur_move_to_next(&m_page_cur); if (!page_cur_move_to_next(&m_page_cur))
return false;
m_nth_rec= 1; m_nth_rec= 1;
} }
else else

View File

@ -259,9 +259,10 @@ btr_defragment_calc_n_recs_for_size(
const ulint n_core = page_is_leaf(page) ? index->n_core_fields : 0; const ulint n_core = page_is_leaf(page) ? index->n_core_fields : 0;
page_cur_set_before_first(block, &cur); page_cur_set_before_first(block, &cur);
page_cur_move_to_next(&cur); while (rec_t* cur_rec = page_cur_move_to_next(&cur)) {
while (page_cur_get_rec(&cur) != page_get_supremum_rec(page)) { if (page_rec_is_supremum(cur_rec)) {
rec_t* cur_rec = page_cur_get_rec(&cur); break;
}
offsets = rec_get_offsets(cur_rec, index, offsets, n_core, offsets = rec_get_offsets(cur_rec, index, offsets, n_core,
ULINT_UNDEFINED, &heap); ULINT_UNDEFINED, &heap);
ulint rec_size = rec_offs_size(offsets); ulint rec_size = rec_offs_size(offsets);
@ -271,7 +272,6 @@ btr_defragment_calc_n_recs_for_size(
break; break;
} }
n_recs ++; n_recs ++;
page_cur_move_to_next(&cur);
} }
*n_recs_size = size; *n_recs_size = size;
if (UNIV_LIKELY_NULL(heap)) { if (UNIV_LIKELY_NULL(heap)) {
@ -356,8 +356,9 @@ btr_defragment_merge_pages(
target_n_recs = n_recs_to_move; target_n_recs = n_recs_to_move;
dberr_t err; dberr_t err;
while (n_recs_to_move > 0) { while (n_recs_to_move > 0) {
rec = page_rec_get_nth(from_page, if (!(rec = page_rec_get_nth(from_page, n_recs_to_move + 1))) {
n_recs_to_move + 1); return nullptr;
}
orig_pred = page_copy_rec_list_start( orig_pred = page_copy_rec_list_start(
to_block, from_block, rec, index, mtr, &err); to_block, from_block, rec, index, mtr, &err);
if (orig_pred) if (orig_pred)
@ -439,6 +440,9 @@ btr_defragment_merge_pages(
} }
rec = page_rec_get_next( rec = page_rec_get_next(
page_get_infimum_rec(from_page)); page_get_infimum_rec(from_page));
if (!rec) {
return nullptr;
}
node_ptr = dict_index_build_node_ptr( node_ptr = dict_index_build_node_ptr(
index, rec, page_get_page_no(from_page), index, rec, page_get_page_no(from_page),
heap, level); heap, level);

View File

@ -176,10 +176,16 @@ before_first:
} else if (page_rec_is_infimum_low(offs)) { } else if (page_rec_is_infimum_low(offs)) {
rec = page_rec_get_next(rec); rec = page_rec_get_next(rec);
if (UNIV_UNLIKELY(!rec)) {
ut_ad("corrupted page" == 0);
goto before_first;
}
if (rec_is_metadata(rec, *index)) { if (rec_is_metadata(rec, *index)) {
ut_ad(!page_has_prev(block->page.frame)); ut_ad(!page_has_prev(block->page.frame));
rec = page_rec_get_next(rec); rec = page_rec_get_next(rec);
if (page_rec_is_supremum(rec)) { ut_ad(rec);
if (!rec || page_rec_is_supremum(rec)) {
goto before_first; goto before_first;
} }
} }

View File

@ -788,8 +788,20 @@ btr_search_check_guess(
rec = btr_cur_get_rec(cursor); rec = btr_cur_get_rec(cursor);
ut_ad(page_rec_is_user_rec(rec)); if (UNIV_UNLIKELY(!page_rec_is_user_rec(rec)
ut_ad(page_rec_is_leaf(rec)); || !page_rec_is_leaf(rec))) {
ut_ad("corrupted index" == 0);
return false;
} else if (cursor->index->table->not_redundant()) {
switch (rec_get_status(rec)) {
case REC_STATUS_INSTANT:
case REC_STATUS_ORDINARY:
break;
default:
ut_ad("corrupted index" == 0);
return false;
}
}
match = 0; match = 0;
@ -847,6 +859,17 @@ btr_search_check_guess(
goto exit_func; goto exit_func;
} }
if (cursor->index->table->not_redundant()) {
switch (rec_get_status(prev_rec)) {
case REC_STATUS_INSTANT:
case REC_STATUS_ORDINARY:
break;
default:
ut_ad("corrupted index" == 0);
goto exit_func;
}
}
offsets = rec_get_offsets(prev_rec, cursor->index, offsets, offsets = rec_get_offsets(prev_rec, cursor->index, offsets,
cursor->index->n_core_fields, cursor->index->n_core_fields,
n_unique, &heap); n_unique, &heap);
@ -862,15 +885,31 @@ btr_search_check_guess(
const rec_t* next_rec = page_rec_get_next(rec); const rec_t* next_rec = page_rec_get_next(rec);
if (UNIV_UNLIKELY(!next_rec)) {
ut_ad("corrupted index" == 0);
goto exit_func;
}
if (page_rec_is_supremum(next_rec)) { if (page_rec_is_supremum(next_rec)) {
if (!page_has_next(page_align(next_rec))) { if (!page_has_next(page_align(next_rec))) {
cursor->up_match = 0; cursor->up_match = 0;
success = TRUE; success = true;
} }
goto exit_func; goto exit_func;
} }
if (cursor->index->table->not_redundant()) {
switch (rec_get_status(next_rec)) {
case REC_STATUS_INSTANT:
case REC_STATUS_ORDINARY:
break;
default:
ut_ad("corrupted index" == 0);
goto exit_func;
}
}
offsets = rec_get_offsets(next_rec, cursor->index, offsets, offsets = rec_get_offsets(next_rec, cursor->index, offsets,
cursor->index->n_core_fields, cursor->index->n_core_fields,
n_unique, &heap); n_unique, &heap);
@ -1245,14 +1284,7 @@ void btr_search_drop_page_hash_index(buf_block_t* block)
{ {
ulint n_fields; ulint n_fields;
ulint n_bytes; ulint n_bytes;
const page_t* page;
const rec_t* rec; const rec_t* rec;
ulint fold;
ulint prev_fold;
ulint n_cached;
ulint n_recs;
ulint* folds;
ulint i;
mem_heap_t* heap; mem_heap_t* heap;
rec_offs* offsets; rec_offs* offsets;
@ -1323,33 +1355,50 @@ retry:
ut_a(n_fields > 0 || n_bytes > 0); ut_a(n_fields > 0 || n_bytes > 0);
page = block->page.frame; const page_t* const page = block->page.frame;
n_recs = page_get_n_recs(page); ulint n_recs = page_get_n_recs(page);
if (!n_recs) {
ut_ad("corrupted adaptive hash index" == 0);
return;
}
/* Calculate and cache fold values into an array for fast deletion /* Calculate and cache fold values into an array for fast deletion
from the hash index */ from the hash index */
folds = (ulint*) ut_malloc_nokey(n_recs * sizeof(ulint));
n_cached = 0;
rec = page_get_infimum_rec(page); rec = page_get_infimum_rec(page);
rec = page_rec_get_next_low(rec, page_is_comp(page)); rec = page_rec_get_next_low(rec, page_is_comp(page));
if (rec_is_metadata(rec, *index)) {
ulint* folds;
ulint n_cached = 0;
ulint prev_fold = 0;
if (rec && rec_is_metadata(rec, *index)) {
rec = page_rec_get_next_low(rec, page_is_comp(page)); rec = page_rec_get_next_low(rec, page_is_comp(page));
if (!--n_recs) {
/* The page only contains the hidden metadata record
for instant ALTER TABLE that the adaptive hash index
never points to. */
folds = nullptr;
goto all_deleted;
}
} }
prev_fold = 0; folds = (ulint*) ut_malloc_nokey(n_recs * sizeof(ulint));
heap = nullptr;
offsets = nullptr;
heap = NULL; while (rec) {
offsets = NULL; if (n_cached >= n_recs) {
ut_ad(page_rec_is_supremum(rec));
while (!page_rec_is_supremum(rec)) { break;
}
ut_ad(page_rec_is_user_rec(rec));
offsets = rec_get_offsets( offsets = rec_get_offsets(
rec, index, offsets, index->n_core_fields, rec, index, offsets, index->n_core_fields,
btr_search_get_n_fields(n_fields, n_bytes), btr_search_get_n_fields(n_fields, n_bytes),
&heap); &heap);
fold = rec_fold(rec, offsets, n_fields, n_bytes, index_id); const ulint fold = rec_fold(rec, offsets, n_fields, n_bytes,
index_id);
if (fold == prev_fold && prev_fold != 0) { if (fold == prev_fold && prev_fold != 0) {
@ -1358,11 +1407,13 @@ retry:
/* Remove all hash nodes pointing to this page from the /* Remove all hash nodes pointing to this page from the
hash chain */ hash chain */
folds[n_cached++] = fold;
folds[n_cached] = fold;
n_cached++;
next_rec: next_rec:
rec = page_rec_get_next_low(rec, page_rec_is_comp(rec)); rec = page_rec_get_next_low(rec, page_rec_is_comp(rec));
if (!rec || page_rec_is_supremum(rec)) {
break;
}
prev_fold = fold; prev_fold = fold;
} }
@ -1370,6 +1421,7 @@ next_rec:
mem_heap_free(heap); mem_heap_free(heap);
} }
all_deleted:
if (!is_freed) { if (!is_freed) {
part->latch.wr_lock(SRW_LOCK_CALL); part->latch.wr_lock(SRW_LOCK_CALL);
@ -1394,7 +1446,7 @@ next_rec:
goto retry; goto retry;
} }
for (i = 0; i < n_cached; i++) { for (ulint i = 0; i < n_cached; i++) {
ha_remove_all_nodes_to_page(&part->table, part->heap, ha_remove_all_nodes_to_page(&part->table, part->heap,
folds[i], page); folds[i], page);
} }
@ -1408,7 +1460,7 @@ next_rec:
} }
} }
block->index = NULL; block->index = nullptr;
MONITOR_INC(MONITOR_ADAPTIVE_HASH_PAGE_REMOVED); MONITOR_INC(MONITOR_ADAPTIVE_HASH_PAGE_REMOVED);
MONITOR_INC_VALUE(MONITOR_ADAPTIVE_HASH_ROW_REMOVED, n_cached); MONITOR_INC_VALUE(MONITOR_ADAPTIVE_HASH_ROW_REMOVED, n_cached);
@ -1472,7 +1524,6 @@ btr_search_build_page_hash_index(
bool left_side) bool left_side)
{ {
const rec_t* rec; const rec_t* rec;
const rec_t* next_rec;
ulint fold; ulint fold;
ulint next_fold; ulint next_fold;
ulint n_cached; ulint n_cached;
@ -1538,10 +1589,11 @@ btr_search_build_page_hash_index(
} }
rec = page_rec_get_next_const(page_get_infimum_rec(page)); rec = page_rec_get_next_const(page_get_infimum_rec(page));
if (!rec) return;
if (rec_is_metadata(rec, *index)) { if (rec_is_metadata(rec, *index)) {
rec = page_rec_get_next_const(rec); rec = page_rec_get_next_const(rec);
if (!--n_recs) return; if (!rec || !--n_recs) return;
} }
/* Calculate and cache fold values and corresponding records into /* Calculate and cache fold values and corresponding records into
@ -1571,9 +1623,7 @@ btr_search_build_page_hash_index(
n_cached++; n_cached++;
} }
for (;;) { while (const rec_t* next_rec = page_rec_get_next_const(rec)) {
next_rec = page_rec_get_next_const(rec);
if (page_rec_is_supremum(next_rec)) { if (page_rec_is_supremum(next_rec)) {
if (!left_side) { if (!left_side) {
@ -1906,13 +1956,16 @@ void btr_search_update_hash_node_on_insert(btr_cur_t *cursor,
&& (cursor->n_fields == block->curr_n_fields) && (cursor->n_fields == block->curr_n_fields)
&& (cursor->n_bytes == block->curr_n_bytes) && (cursor->n_bytes == block->curr_n_bytes)
&& !block->curr_left_side) { && !block->curr_left_side) {
if (const rec_t *new_rec = page_rec_get_next_const(rec)) {
if (ha_search_and_update_if_found( if (ha_search_and_update_if_found(
&btr_search_sys.get_part(*cursor->index)->table, &btr_search_sys.get_part(*cursor->index)
cursor->fold, rec, block, ->table,
page_rec_get_next(rec))) { cursor->fold, rec, block, new_rec)) {
MONITOR_INC(MONITOR_ADAPTIVE_HASH_ROW_UPDATED); MONITOR_INC(MONITOR_ADAPTIVE_HASH_ROW_UPDATED);
} }
} else {
ut_ad("corrupted page" == 0);
}
func_exit: func_exit:
assert_block_ahi_valid(block); assert_block_ahi_valid(block);
@ -1976,6 +2029,7 @@ void btr_search_update_hash_on_insert(btr_cur_t *cursor,
if (index != cursor->index) { if (index != cursor->index) {
ut_ad(index->id == cursor->index->id); ut_ad(index->id == cursor->index->id);
drop:
btr_search_drop_page_hash_index(block); btr_search_drop_page_hash_index(block);
return; return;
} }
@ -1988,7 +2042,9 @@ void btr_search_update_hash_on_insert(btr_cur_t *cursor,
const bool left_side = block->curr_left_side; const bool left_side = block->curr_left_side;
ins_rec = page_rec_get_next_const(rec); ins_rec = page_rec_get_next_const(rec);
if (UNIV_UNLIKELY(!ins_rec)) goto drop;
next_rec = page_rec_get_next_const(ins_rec); next_rec = page_rec_get_next_const(ins_rec);
if (UNIV_UNLIKELY(!next_rec)) goto drop;
offsets = rec_get_offsets(ins_rec, index, offsets, offsets = rec_get_offsets(ins_rec, index, offsets,
index->n_core_fields, index->n_core_fields,

View File

@ -1239,7 +1239,7 @@ btr_estimate_number_of_different_key_vals(dict_index_t* index,
const ulint n_core = page_is_leaf(page) const ulint n_core = page_is_leaf(page)
? index->n_core_fields : 0; ? index->n_core_fields : 0;
if (!page_rec_is_supremum(rec)) { if (rec && !page_rec_is_supremum(rec)) {
not_empty_flag = 1; not_empty_flag = 1;
offsets_rec = rec_get_offsets(rec, index, offsets_rec, offsets_rec = rec_get_offsets(rec, index, offsets_rec,
n_core, n_core,
@ -1254,7 +1254,7 @@ btr_estimate_number_of_different_key_vals(dict_index_t* index,
while (!page_rec_is_supremum(rec)) { while (!page_rec_is_supremum(rec)) {
ulint matched_fields; ulint matched_fields;
rec_t* next_rec = page_rec_get_next(rec); rec_t* next_rec = page_rec_get_next(rec);
if (page_rec_is_supremum(next_rec)) { if (!next_rec || page_rec_is_supremum(next_rec)) {
total_external_size += total_external_size +=
btr_rec_get_externally_stored_len( btr_rec_get_externally_stored_len(
rec, offsets_rec); rec, offsets_rec);
@ -1630,12 +1630,11 @@ dict_stats_analyze_index_level(
if (btr_pcur_open_at_index_side( if (btr_pcur_open_at_index_side(
true, index, BTR_SEARCH_TREE_ALREADY_S_LATCHED, true, index, BTR_SEARCH_TREE_ALREADY_S_LATCHED,
&pcur, true, level, mtr) != DB_SUCCESS) { &pcur, true, level, mtr) != DB_SUCCESS
|| !btr_pcur_move_to_next_on_page(&pcur)) {
goto func_exit; goto func_exit;
} }
btr_pcur_move_to_next_on_page(&pcur);
page = btr_pcur_get_page(&pcur); page = btr_pcur_get_page(&pcur);
/* The page must not be empty, except when /* The page must not be empty, except when
@ -1877,6 +1876,36 @@ func_exit:
mem_heap_free(heap); mem_heap_free(heap);
} }
/************************************************************//**
Gets the pointer to the next non delete-marked record on the page.
If all subsequent records are delete-marked, then this function
will return the supremum record.
@return pointer to next non delete-marked record or pointer to supremum */
static
const rec_t*
page_rec_get_next_non_del_marked(
/*=============================*/
const rec_t* rec) /*!< in: pointer to record */
{
const page_t *const page= page_align(rec);
if (page_is_comp(page))
{
for (rec= page_rec_get_next_low(rec, TRUE);
rec && rec_get_deleted_flag(rec, TRUE);
rec= page_rec_get_next_low(rec, TRUE));
return rec ? rec : page + PAGE_NEW_SUPREMUM;
}
else
{
for (rec= page_rec_get_next_low(rec, FALSE);
rec && rec_get_deleted_flag(rec, FALSE);
rec= page_rec_get_next_low(rec, FALSE));
return rec ? rec : page + PAGE_OLD_SUPREMUM;
}
}
/** Scan a page, reading records from left to right and counting the number /** Scan a page, reading records from left to right and counting the number
of distinct records (looking only at the first n_prefix of distinct records (looking only at the first n_prefix
columns) and the number of external pages pointed by records from this page. columns) and the number of external pages pointed by records from this page.
@ -1934,7 +1963,7 @@ dict_stats_scan_page(
rec = get_next(page_get_infimum_rec(page)); rec = get_next(page_get_infimum_rec(page));
if (page_rec_is_supremum(rec)) { if (!rec || page_rec_is_supremum(rec)) {
/* the page is empty or contains only delete-marked records */ /* the page is empty or contains only delete-marked records */
*n_diff = 0; *n_diff = 0;
*out_rec = NULL; *out_rec = NULL;
@ -1953,7 +1982,7 @@ dict_stats_scan_page(
*n_diff = 1; *n_diff = 1;
while (!page_rec_is_supremum(next_rec)) { while (next_rec && !page_rec_is_supremum(next_rec)) {
ulint matched_fields; ulint matched_fields;
@ -2242,12 +2271,11 @@ dict_stats_analyze_index_for_n_prefix(
if (btr_pcur_open_at_index_side(true, index, if (btr_pcur_open_at_index_side(true, index,
BTR_SEARCH_TREE_ALREADY_S_LATCHED, BTR_SEARCH_TREE_ALREADY_S_LATCHED,
&pcur, true, n_diff_data->level, mtr) &pcur, true, n_diff_data->level, mtr)
!= DB_SUCCESS) { != DB_SUCCESS
|| !btr_pcur_move_to_next_on_page(&pcur)) {
return; return;
} }
btr_pcur_move_to_next_on_page(&pcur);
page = btr_pcur_get_page(&pcur); page = btr_pcur_get_page(&pcur);
const rec_t* first_rec = btr_pcur_get_rec(&pcur); const rec_t* first_rec = btr_pcur_get_rec(&pcur);

View File

@ -405,21 +405,24 @@ update_mbr:
} }
/* Insert the new rec. */ /* Insert the new rec. */
page_cur_search_with_match(block, index, node_ptr, if (page_cur_search_with_match(block, index, node_ptr,
PAGE_CUR_LE , &up_match, &low_match, PAGE_CUR_LE,
btr_cur_get_page_cur(cursor), NULL); &up_match, &low_match,
btr_cur_get_page_cur(cursor),
NULL)) {
goto err_exit;
}
err = btr_cur_optimistic_insert(flags, cursor, &insert_offsets, err = btr_cur_optimistic_insert(flags, cursor, &insert_offsets,
&heap, node_ptr, &insert_rec, &heap, node_ptr, &insert_rec,
&dummy_big_rec, 0, NULL, mtr); &dummy_big_rec, 0, NULL, mtr);
if (!ins_suc && err == DB_SUCCESS) {
ins_suc = true;
}
/* If optimistic insert fail, try reorganize the page /* If optimistic insert fail, try reorganize the page
and insert again. */ and insert again. */
if (err != DB_SUCCESS && ins_suc) { if (err == DB_SUCCESS) {
ins_suc = true;
} else if (ins_suc) {
ut_ad(err == DB_FAIL);
err = btr_page_reorganize(btr_cur_get_page_cur(cursor), err = btr_page_reorganize(btr_cur_get_page_cur(cursor),
index, mtr); index, mtr);
if (err == DB_SUCCESS) { if (err == DB_SUCCESS) {
@ -431,6 +434,7 @@ update_mbr:
/* Will do pessimistic insert */ /* Will do pessimistic insert */
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
ut_ad(err == DB_FAIL);
ins_suc = false; ins_suc = false;
} }
} }
@ -462,10 +466,14 @@ update_mbr:
cur2_pno = btr_node_ptr_get_child_page_no(cur2_rec, offsets2); cur2_pno = btr_node_ptr_get_child_page_no(cur2_rec, offsets2);
if ((del_page_no != cur2_pno) if ((del_page_no != cur2_pno)
|| (cur2_rec == insert_rec)) { || (cur2_rec == insert_rec)) {
cur2_rec = page_rec_get_next( cur2_rec = page_get_infimum_rec(page);
page_get_infimum_rec(page));
while ((cur2_rec
= page_rec_get_next(cur2_rec))) {
if (page_rec_is_supremum(cur2_rec)) {
break;
}
while (!page_rec_is_supremum(cur2_rec)) {
offsets2 = rec_get_offsets(cur2_rec, index, offsets2 = rec_get_offsets(cur2_rec, index,
NULL, NULL,
n_core, n_core,
@ -480,10 +488,7 @@ update_mbr:
break; break;
} }
} }
cur2_rec = page_rec_get_next(cur2_rec);
} }
ut_ad(!page_rec_is_supremum(cur2_rec));
} }
rec_info = rec_get_info_bits(cur2_rec, rec_info = rec_get_info_bits(cur2_rec,
@ -529,7 +534,7 @@ update_mbr:
|| (REC_INFO_MIN_REC_FLAG & rec_get_info_bits( || (REC_INFO_MIN_REC_FLAG & rec_get_info_bits(
page_rec_get_next(page_get_infimum_rec(page)), page_rec_get_next(page_get_infimum_rec(page)),
page_is_comp(page)))); page_is_comp(page))));
err_exit:
mem_heap_free(heap); mem_heap_free(heap);
} }
@ -556,11 +561,10 @@ rtr_adjust_upper_level(
rec_offs* offsets; rec_offs* offsets;
mem_heap_t* heap; mem_heap_t* heap;
ulint level; ulint level;
dtuple_t* node_ptr_upper; dtuple_t* node_ptr_upper = nullptr;
page_cur_t* page_cursor; page_cur_t* page_cursor;
lock_prdt_t prdt; lock_prdt_t prdt;
lock_prdt_t new_prdt; lock_prdt_t new_prdt;
dberr_t err;
big_rec_t* dummy_big_rec; big_rec_t* dummy_big_rec;
rec_t* rec; rec_t* rec;
@ -597,29 +601,32 @@ rtr_adjust_upper_level(
} }
} }
dberr_t err;
if (const rec_t* first = page_rec_get_next_const(
page_get_infimum_rec(new_block->page.frame))) {
/* Insert the node for the new page. */ /* Insert the node for the new page. */
node_ptr_upper = rtr_index_build_node_ptr( node_ptr_upper = rtr_index_build_node_ptr(
index, new_mbr, index, new_mbr, first, new_page_no, heap);
page_rec_get_next(page_get_infimum_rec(new_block->page.frame)), ulint up_match = 0, low_match = 0;
new_page_no, heap); err = page_cur_search_with_match(btr_cur_get_block(&cursor),
index, node_ptr_upper,
ulint up_match = 0; PAGE_CUR_LE,
ulint low_match = 0; &up_match, &low_match,
btr_cur_get_page_cur(&cursor),
buf_block_t* father_block = btr_cur_get_block(&cursor); NULL)
? DB_CORRUPTION
page_cur_search_with_match( : btr_cur_optimistic_insert(flags
father_block, index, node_ptr_upper,
PAGE_CUR_LE , &up_match, &low_match,
btr_cur_get_page_cur(&cursor), NULL);
err = btr_cur_optimistic_insert(
flags
| BTR_NO_LOCKING_FLAG | BTR_NO_LOCKING_FLAG
| BTR_KEEP_SYS_FLAG | BTR_KEEP_SYS_FLAG
| BTR_NO_UNDO_LOG_FLAG, | BTR_NO_UNDO_LOG_FLAG,
&cursor, &offsets, &heap, &cursor, &offsets, &heap,
node_ptr_upper, &rec, &dummy_big_rec, 0, NULL, mtr); node_ptr_upper, &rec,
&dummy_big_rec, 0, NULL,
mtr);
} else {
err = DB_CORRUPTION;
}
if (err == DB_FAIL) { if (err == DB_FAIL) {
cursor.rtr_info = sea_cur->rtr_info; cursor.rtr_info = sea_cur->rtr_info;
@ -638,11 +645,10 @@ rtr_adjust_upper_level(
node_ptr_upper, &rec, node_ptr_upper, &rec,
&dummy_big_rec, 0, NULL, mtr); &dummy_big_rec, 0, NULL, mtr);
cursor.rtr_info = NULL; cursor.rtr_info = NULL;
ut_a(err == DB_SUCCESS);
mem_heap_free(new_heap); mem_heap_free(new_heap);
} }
if (err == DB_SUCCESS) {
prdt.data = static_cast<void*>(mbr); prdt.data = static_cast<void*>(mbr);
prdt.op = 0; prdt.op = 0;
new_prdt.data = static_cast<void*>(new_mbr); new_prdt.data = static_cast<void*>(new_mbr);
@ -650,11 +656,16 @@ rtr_adjust_upper_level(
lock_prdt_update_parent(block, new_block, &prdt, &new_prdt, lock_prdt_update_parent(block, new_block, &prdt, &new_prdt,
page_cursor->block->page.id()); page_cursor->block->page.id());
}
mem_heap_free(heap); mem_heap_free(heap);
ut_ad(block->zip_size() == index->table->space->zip_size()); ut_ad(block->zip_size() == index->table->space->zip_size());
if (err != DB_SUCCESS) {
return err;
}
const uint32_t next_page_no = btr_page_get_next(block->page.frame); const uint32_t next_page_no = btr_page_get_next(block->page.frame);
if (next_page_no == FIL_NULL) { if (next_page_no == FIL_NULL) {
@ -765,13 +776,15 @@ rtr_split_page_move_rec_list(
&new_page_cursor, &new_page_cursor,
index, cur_split_node->key, offsets, mtr); index, cur_split_node->key, offsets, mtr);
ut_a(rec); if (UNIV_UNLIKELY
(!rec
|| !page_cur_move_to_next(&new_page_cursor))) {
return DB_CORRUPTION;
}
lock_rec_restore_from_page_infimum( lock_rec_restore_from_page_infimum(
*new_block, rec, block->page.id()); *new_block, rec, block->page.id());
page_cur_move_to_next(&new_page_cursor);
rec_move[moved].new_rec = rec; rec_move[moved].new_rec = rec;
rec_move[moved].old_rec = cur_split_node->key; rec_move[moved].old_rec = cur_split_node->key;
rec_move[moved].moved = false; rec_move[moved].moved = false;
@ -913,6 +926,11 @@ func_start:
if (!page_has_prev(page) && !page_is_leaf(page)) { if (!page_has_prev(page) && !page_is_leaf(page)) {
first_rec = page_rec_get_next( first_rec = page_rec_get_next(
page_get_infimum_rec(buf_block_get_frame(block))); page_get_infimum_rec(buf_block_get_frame(block)));
if (UNIV_UNLIKELY(!first_rec)) {
corrupted:
*err = DB_CORRUPTION;
return nullptr;
}
} }
/* Initial split nodes array. */ /* Initial split nodes array. */
@ -1098,9 +1116,13 @@ func_start:
/* Reposition the cursor for insert and try insertion */ /* Reposition the cursor for insert and try insertion */
page_cursor = btr_cur_get_page_cur(cursor); page_cursor = btr_cur_get_page_cur(cursor);
ulint up_match = 0, low_match = 0;
page_cur_search(insert_block, cursor->index, tuple, if (page_cur_search_with_match(insert_block, cursor->index, tuple,
PAGE_CUR_LE, page_cursor); PAGE_CUR_LE, &up_match, &low_match,
page_cursor, nullptr)) {
goto corrupted;
}
/* It's possible that the new record is too big to be inserted into /* It's possible that the new record is too big to be inserted into
the page, and it'll need the second round split in this case. the page, and it'll need the second round split in this case.
@ -1180,6 +1202,9 @@ after_insert:
rec_t* i_rec = page_rec_get_next(page_get_infimum_rec( rec_t* i_rec = page_rec_get_next(page_get_infimum_rec(
buf_block_get_frame(block))); buf_block_get_frame(block)));
if (UNIV_UNLIKELY(!i_rec)) {
goto corrupted;
}
btr_cur_position(cursor->index, i_rec, block, cursor); btr_cur_position(cursor->index, i_rec, block, cursor);
goto func_start; goto func_start;
@ -1299,8 +1324,8 @@ rtr_page_copy_rec_list_end_no_locks(
page_cur_position(rec, block, &cur1); page_cur_position(rec, block, &cur1);
if (page_cur_is_before_first(&cur1)) { if (page_cur_is_before_first(&cur1) && !page_cur_move_to_next(&cur1)) {
page_cur_move_to_next(&cur1); return DB_CORRUPTION;
} }
ut_a(page_is_comp(new_page) == page_rec_is_comp(rec)); ut_a(page_is_comp(new_page) == page_rec_is_comp(rec));
@ -1309,6 +1334,9 @@ rtr_page_copy_rec_list_end_no_locks(
cur_rec = page_rec_get_next( cur_rec = page_rec_get_next(
page_get_infimum_rec(buf_block_get_frame(new_block))); page_get_infimum_rec(buf_block_get_frame(new_block)));
if (UNIV_UNLIKELY(!cur_rec)) {
return DB_CORRUPTION;
}
page_cur_position(cur_rec, new_block, &page_cur); page_cur_position(cur_rec, new_block, &page_cur);
/* Copy records from the original page to the new page */ /* Copy records from the original page to the new page */
@ -1318,6 +1346,9 @@ rtr_page_copy_rec_list_end_no_locks(
if (page_rec_is_infimum(cur_rec)) { if (page_rec_is_infimum(cur_rec)) {
cur_rec = page_rec_get_next(cur_rec); cur_rec = page_rec_get_next(cur_rec);
if (UNIV_UNLIKELY(!cur_rec)) {
return DB_CORRUPTION;
}
} }
offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core, offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core,
@ -1336,8 +1367,7 @@ rtr_page_copy_rec_list_end_no_locks(
goto move_to_prev; goto move_to_prev;
} else if (cmp > 0) { } else if (cmp > 0) {
/* Skip small recs. */ /* Skip small recs. */
page_cur_move_to_next(&page_cur); cur_rec = page_cur_move_to_next(&page_cur);
cur_rec = page_cur_get_rec(&page_cur);
} else if (n_core) { } else if (n_core) {
if (rec_get_deleted_flag(cur1_rec, if (rec_get_deleted_flag(cur1_rec,
dict_table_is_comp(index->table))) { dict_table_is_comp(index->table))) {
@ -1380,7 +1410,9 @@ move_to_prev:
rec_move[moved].moved = false; rec_move[moved].moved = false;
moved++; moved++;
next: next:
page_cur_move_to_next(&cur1); if (UNIV_UNLIKELY(!page_cur_move_to_next(&cur1))) {
return DB_CORRUPTION;
}
} }
*num_moved = moved; *num_moved = moved;
@ -1419,10 +1451,15 @@ rtr_page_copy_rec_list_start_no_locks(
rec_offs_init(offsets_2); rec_offs_init(offsets_2);
page_cur_set_before_first(block, &cur1); page_cur_set_before_first(block, &cur1);
page_cur_move_to_next(&cur1); if (UNIV_UNLIKELY(!page_cur_move_to_next(&cur1))) {
return DB_CORRUPTION;
}
cur_rec = page_rec_get_next( cur_rec = page_rec_get_next(
page_get_infimum_rec(buf_block_get_frame(new_block))); page_get_infimum_rec(buf_block_get_frame(new_block)));
if (UNIV_UNLIKELY(!cur_rec)) {
return DB_CORRUPTION;
}
page_cur_position(cur_rec, new_block, &page_cur); page_cur_position(cur_rec, new_block, &page_cur);
while (page_cur_get_rec(&cur1) != rec) { while (page_cur_get_rec(&cur1) != rec) {
@ -1431,6 +1468,9 @@ rtr_page_copy_rec_list_start_no_locks(
if (page_rec_is_infimum(cur_rec)) { if (page_rec_is_infimum(cur_rec)) {
cur_rec = page_rec_get_next(cur_rec); cur_rec = page_rec_get_next(cur_rec);
if (UNIV_UNLIKELY(!cur_rec)) {
return DB_CORRUPTION;
}
} }
offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core, offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core,
@ -1449,8 +1489,7 @@ rtr_page_copy_rec_list_start_no_locks(
goto move_to_prev; goto move_to_prev;
} else if (cmp > 0) { } else if (cmp > 0) {
/* Skip small recs. */ /* Skip small recs. */
page_cur_move_to_next(&page_cur); cur_rec = page_cur_move_to_next(&page_cur);
cur_rec = page_cur_get_rec(&page_cur);
} else if (n_core) { } else if (n_core) {
if (rec_get_deleted_flag( if (rec_get_deleted_flag(
cur1_rec, cur1_rec,
@ -1472,13 +1511,14 @@ rtr_page_copy_rec_list_start_no_locks(
if (page_rec_is_supremum(cur_rec)) { if (page_rec_is_supremum(cur_rec)) {
move_to_prev: move_to_prev:
cur_rec = page_cur_move_to_prev(&page_cur); cur_rec = page_cur_move_to_prev(&page_cur);
if (UNIV_UNLIKELY(!cur_rec)) {
return DB_CORRUPTION;
}
} else { } else {
cur_rec = page_cur_get_rec(&page_cur); cur_rec = page_cur_get_rec(&page_cur);
} }
if (UNIV_UNLIKELY(!cur_rec)) {
return DB_CORRUPTION;
}
offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core, offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core,
ULINT_UNDEFINED, &heap); ULINT_UNDEFINED, &heap);
@ -1493,7 +1533,9 @@ move_to_prev:
rec_move[moved].moved = false; rec_move[moved].moved = false;
moved++; moved++;
next: next:
page_cur_move_to_next(&cur1); if (UNIV_UNLIKELY(!page_cur_move_to_next(&cur1))) {
return DB_CORRUPTION;
}
} }
*num_moved = moved; *num_moved = moved;
@ -1604,10 +1646,9 @@ rtr_check_same_block(
{ {
ulint page_no = childb->page.id().page_no(); ulint page_no = childb->page.id().page_no();
rec_offs* offsets; rec_offs* offsets;
rec_t* rec = page_rec_get_next(page_get_infimum_rec( rec_t* rec = page_get_infimum_rec(parentb->page.frame);
buf_block_get_frame(parentb)));
while (!page_rec_is_supremum(rec)) { while ((rec = page_rec_get_next(rec)) && !page_rec_is_supremum(rec)) {
offsets = rec_get_offsets( offsets = rec_get_offsets(
rec, index, NULL, 0, ULINT_UNDEFINED, &heap); rec, index, NULL, 0, ULINT_UNDEFINED, &heap);
@ -1615,8 +1656,6 @@ rtr_check_same_block(
btr_cur_position(index, rec, parentb, cursor); btr_cur_position(index, rec, parentb, cursor);
return(true); return(true);
} }
rec = page_rec_get_next(rec);
} }
return(false); return(false);
@ -1826,9 +1865,9 @@ err_exit:
/* Scan records in root page and calculate area. */ /* Scan records in root page and calculate area. */
double area = 0; double area = 0;
for (const rec_t* rec = page_rec_get_next( for (const rec_t* rec = page_rec_get_next_const(
page_get_infimum_rec(block->page.frame)); page_get_infimum_rec(block->page.frame));
!page_rec_is_supremum(rec); rec && !page_rec_is_supremum(rec);
rec = page_rec_get_next_const(rec)) { rec = page_rec_get_next_const(rec)) {
rtr_mbr_t mbr; rtr_mbr_t mbr;
double rec_area; double rec_area;

View File

@ -301,18 +301,17 @@ rtr_pcur_getnext_from_path(
page_cursor->rec = NULL; page_cursor->rec = NULL;
if (mode == PAGE_CUR_RTREE_LOCATE) { if (mode == PAGE_CUR_RTREE_LOCATE) {
if (level == target_level && level == 0) { if (target_level == 0 && level == 0) {
ulint low_match; ulint low_match = 0, up_match = 0;
found = false; found = false;
low_match = page_cur_search( if (!page_cur_search_with_match(
block, index, tuple, block, index, tuple, PAGE_CUR_LE,
PAGE_CUR_LE, &up_match, &low_match,
btr_cur_get_page_cur(btr_cur)); btr_cur_get_page_cur(btr_cur), nullptr)
&& low_match
if (low_match == dtuple_get_n_fields_cmp( == dtuple_get_n_fields_cmp(tuple)) {
tuple)) {
rec_t* rec = btr_cur_get_rec(btr_cur); rec_t* rec = btr_cur_get_rec(btr_cur);
if (!rec_get_deleted_flag(rec, if (!rec_get_deleted_flag(rec,
@ -803,6 +802,9 @@ rtr_page_get_father_block(
{ {
rec_t* rec = page_rec_get_next( rec_t* rec = page_rec_get_next(
page_get_infimum_rec(buf_block_get_frame(block))); page_get_infimum_rec(buf_block_get_frame(block)));
if (!rec) {
return nullptr;
}
btr_cur_position(index, rec, block, cursor); btr_cur_position(index, rec, block, cursor);
return(rtr_page_get_father_node_ptr(offsets, heap, sea_cur, return(rtr_page_get_father_node_ptr(offsets, heap, sea_cur,
@ -1238,11 +1240,14 @@ rtr_cur_restore_position(
ut_ad(r_cursor == node->cursor); ut_ad(r_cursor == node->cursor);
search_again: search_again:
ulint up_match = 0, low_match = 0;
block = buf_page_get_gen( block = buf_page_get_gen(
page_id_t(index->table->space_id, page_no), page_id_t(index->table->space_id, page_no),
zip_size, RW_X_LATCH, NULL, BUF_GET, mtr); zip_size, RW_X_LATCH, NULL, BUF_GET, mtr);
if (!block) { if (!block) {
corrupted:
ret = false; ret = false;
goto func_exit; goto func_exit;
} }
@ -1251,8 +1256,13 @@ search_again:
page = buf_block_get_frame(block); page = buf_block_get_frame(block);
page_ssn = page_get_ssn_id(page); page_ssn = page_get_ssn_id(page);
if (page_cur_search(block, index, tuple, PAGE_CUR_LE, page_cursor) if (page_cur_search_with_match(block, index, tuple, PAGE_CUR_LE,
== r_cursor->old_n_fields) { &up_match, &low_match, page_cursor,
nullptr)) {
goto corrupted;
}
if (low_match == r_cursor->old_n_fields) {
const rec_t* rec; const rec_t* rec;
const rec_offs* offsets1; const rec_offs* offsets1;
const rec_offs* offsets2; const rec_offs* offsets2;
@ -1609,13 +1619,20 @@ rtr_cur_search_with_match(
mode = PAGE_CUR_WITHIN; mode = PAGE_CUR_WITHIN;
} }
rec = page_dir_slot_get_rec(page_dir_get_nth_slot(page, 0)); rec = page_dir_slot_get_rec_validate(page_dir_get_nth_slot(page, 0));
if (UNIV_UNLIKELY(!rec)) {
return false;
}
last_rec = rec; last_rec = rec;
best_rec = rec; best_rec = rec;
if (page_rec_is_infimum(rec)) { if (page_rec_is_infimum(rec)) {
rec = page_rec_get_next_const(rec); rec = page_rec_get_next_const(rec);
if (UNIV_UNLIKELY(!rec)) {
return false;
}
} }
/* Check insert tuple size is larger than first rec, and try to /* Check insert tuple size is larger than first rec, and try to
@ -1813,7 +1830,7 @@ rtr_cur_search_with_match(
} }
/* All records on page are searched */ /* All records on page are searched */
if (page_rec_is_supremum(rec)) { if (rec && page_rec_is_supremum(rec)) {
if (!n_core) { if (!n_core) {
if (!found) { if (!found) {
/* No match case, if it is for insertion, /* No match case, if it is for insertion,

View File

@ -2132,11 +2132,14 @@ non_empty:
return false; return false;
} }
rec= page_rec_get_next(btr_pcur_get_rec(&pcur)); rec= page_rec_get_next(btr_pcur_get_rec(&pcur));
if (UNIV_UNLIKELY(!rec))
goto non_empty;
if (rec_is_metadata(rec, *clust_index)) if (rec_is_metadata(rec, *clust_index))
btr_pcur_get_page_cur(&pcur)->rec= rec; btr_pcur_get_page_cur(&pcur)->rec= rec;
scan_leaf: scan_leaf:
cur= btr_pcur_get_page_cur(&pcur); cur= btr_pcur_get_page_cur(&pcur);
page_cur_move_to_next(cur); if (UNIV_UNLIKELY(!page_cur_move_to_next(cur)))
goto non_empty;
next_page: next_page:
if (next_page) if (next_page)
{ {
@ -2154,7 +2157,8 @@ next_page:
goto non_empty; goto non_empty;
btr_leaf_page_release(page_cur_get_block(cur), BTR_SEARCH_LEAF, &mtr); btr_leaf_page_release(page_cur_get_block(cur), BTR_SEARCH_LEAF, &mtr);
page_cur_set_before_first(block, cur); page_cur_set_before_first(block, cur);
page_cur_move_to_next(cur); if (UNIV_UNLIKELY(!page_cur_move_to_next(cur)))
goto non_empty;
} }
rec= page_cur_get_rec(cur); rec= page_cur_get_rec(cur);
@ -6029,13 +6033,17 @@ func_exit:
return false; return false;
} }
ut_ad(btr_pcur_is_before_first_on_page(&pcur)); ut_ad(btr_pcur_is_before_first_on_page(&pcur));
btr_pcur_move_to_next_on_page(&pcur);
buf_block_t* block = btr_pcur_get_block(&pcur); buf_block_t* block = btr_pcur_get_block(&pcur);
ut_ad(page_is_leaf(block->page.frame)); ut_ad(page_is_leaf(block->page.frame));
ut_ad(!page_has_prev(block->page.frame)); ut_ad(!page_has_prev(block->page.frame));
ut_ad(!buf_block_get_page_zip(block)); ut_ad(!buf_block_get_page_zip(block));
const rec_t* rec = btr_pcur_get_rec(&pcur); const rec_t* rec = btr_pcur_move_to_next_on_page(&pcur);
if (UNIV_UNLIKELY(!rec)) {
err = DB_CORRUPTION;
goto func_exit;
}
que_thr_t* thr = pars_complete_graph_for_exec( que_thr_t* thr = pars_complete_graph_for_exec(
NULL, trx, ctx->heap, NULL); NULL, trx, ctx->heap, NULL);
const bool is_root = block->page.id().page_no() == index->page; const bool is_root = block->page.id().page_no() == index->page;

View File

@ -2047,7 +2047,7 @@ corruption:
if (page_rec_is_infimum(rec)) { if (page_rec_is_infimum(rec)) {
rec = page_rec_get_next_const(rec); rec = page_rec_get_next_const(rec);
if (page_rec_is_supremum(rec)) { if (!rec || page_rec_is_supremum(rec)) {
return 0; return 0;
} }
} }
@ -2101,7 +2101,7 @@ corruption:
sum_volumes = 0; sum_volumes = 0;
volume_for_page = 0; volume_for_page = 0;
while (*n_stored < limit) { while (*n_stored < limit && rec) {
if (page_rec_is_supremum(rec)) { if (page_rec_is_supremum(rec)) {
/* When no more records available, mark this with /* When no more records available, mark this with
another 'impossible' pair of space id, page no */ another 'impossible' pair of space id, page no */
@ -2908,6 +2908,9 @@ count_later:
for (; !page_rec_is_supremum(rec); for (; !page_rec_is_supremum(rec);
rec = page_rec_get_next_const(rec)) { rec = page_rec_get_next_const(rec)) {
if (UNIV_UNLIKELY(!rec)) {
return srv_page_size;
}
if (page_no != ibuf_rec_get_page_no(mtr, rec) if (page_no != ibuf_rec_get_page_no(mtr, rec)
|| space != ibuf_rec_get_space(mtr, rec)) { || space != ibuf_rec_get_space(mtr, rec)) {
@ -2948,16 +2951,14 @@ count_later:
rec = page_get_infimum_rec(next_page); rec = page_get_infimum_rec(next_page);
rec = page_rec_get_next_const(rec); rec = page_rec_get_next_const(rec);
for (;; rec = page_rec_get_next_const(rec)) { for (; ; rec = page_rec_get_next_const(rec)) {
ut_ad(page_align(rec) == next_page); if (!rec || page_rec_is_supremum(rec)) {
if (page_rec_is_supremum(rec)) {
/* We give up */ /* We give up */
return(srv_page_size); return(srv_page_size);
} }
ut_ad(page_align(rec) == next_page);
if (page_no != ibuf_rec_get_page_no(mtr, rec) if (page_no != ibuf_rec_get_page_no(mtr, rec)
|| space != ibuf_rec_get_space(mtr, rec)) { || space != ibuf_rec_get_space(mtr, rec)) {
@ -3697,7 +3698,6 @@ ibuf_insert_to_index_page(
mtr_t* mtr) /*!< in: mtr */ mtr_t* mtr) /*!< in: mtr */
{ {
page_cur_t page_cur; page_cur_t page_cur;
ulint low_match;
page_t* page = buf_block_get_frame(block); page_t* page = buf_block_get_frame(block);
rec_t* rec; rec_t* rec;
rec_offs* offsets; rec_offs* offsets;
@ -3726,7 +3726,7 @@ ibuf_insert_to_index_page(
rec = page_rec_get_next(page_get_infimum_rec(page)); rec = page_rec_get_next(page_get_infimum_rec(page));
if (page_rec_is_supremum(rec)) { if (!rec || page_rec_is_supremum(rec)) {
return DB_CORRUPTION; return DB_CORRUPTION;
} }
@ -3734,8 +3734,15 @@ ibuf_insert_to_index_page(
return DB_CORRUPTION; return DB_CORRUPTION;
} }
ulint up_match = 0, low_match = 0;
if (page_cur_search_with_match(block, index, entry, PAGE_CUR_LE,
&up_match, &low_match, &page_cur,
nullptr)) {
return DB_CORRUPTION;
}
dberr_t err = DB_SUCCESS; dberr_t err = DB_SUCCESS;
low_match = page_cur_search(block, index, entry, &page_cur);
heap = mem_heap_create( heap = mem_heap_create(
sizeof(upd_t) sizeof(upd_t)
@ -3847,14 +3854,15 @@ ibuf_set_del_mark(
mtr_t* mtr) /*!< in: mtr */ mtr_t* mtr) /*!< in: mtr */
{ {
page_cur_t page_cur; page_cur_t page_cur;
ulint low_match; ulint up_match = 0, low_match = 0;
ut_ad(ibuf_inside(mtr)); ut_ad(ibuf_inside(mtr));
ut_ad(dtuple_check_typed(entry)); ut_ad(dtuple_check_typed(entry));
low_match = page_cur_search(block, index, entry, &page_cur); if (!page_cur_search_with_match(block, index, entry, PAGE_CUR_LE,
&up_match, &low_match, &page_cur,
if (low_match == dtuple_get_n_fields(entry)) { nullptr)
&& low_match == dtuple_get_n_fields(entry)) {
rec_t* rec = page_cur_get_rec(&page_cur); rec_t* rec = page_cur_get_rec(&page_cur);
/* Delete mark the old index record. According to a /* Delete mark the old index record. According to a
@ -3903,16 +3911,17 @@ ibuf_delete(
before latching any further pages */ before latching any further pages */
{ {
page_cur_t page_cur; page_cur_t page_cur;
ulint low_match; ulint up_match = 0, low_match = 0;
ut_ad(ibuf_inside(mtr)); ut_ad(ibuf_inside(mtr));
ut_ad(dtuple_check_typed(entry)); ut_ad(dtuple_check_typed(entry));
ut_ad(!index->is_spatial()); ut_ad(!index->is_spatial());
ut_ad(!index->is_clust()); ut_ad(!index->is_clust());
low_match = page_cur_search(block, index, entry, &page_cur); if (!page_cur_search_with_match(block, index, entry, PAGE_CUR_LE,
&up_match, &low_match, &page_cur,
if (low_match == dtuple_get_n_fields(entry)) { nullptr)
&& low_match == dtuple_get_n_fields(entry)) {
page_zip_des_t* page_zip= buf_block_get_page_zip(block); page_zip_des_t* page_zip= buf_block_get_page_zip(block);
page_t* page = buf_block_get_frame(block); page_t* page = buf_block_get_frame(block);
rec_t* rec = page_cur_get_rec(&page_cur); rec_t* rec = page_cur_get_rec(&page_cur);
@ -3976,8 +3985,6 @@ ibuf_delete(
if (UNIV_LIKELY_NULL(heap)) { if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap); mem_heap_free(heap);
} }
} else {
/* The record must have been purged already. */
} }
} }
@ -4016,9 +4023,6 @@ ibuf_restore_pos(
rec_print_old(stderr, btr_pcur_get_rec(pcur)); rec_print_old(stderr, btr_pcur_get_rec(pcur));
rec_print_old(stderr, pcur->old_rec); rec_print_old(stderr, pcur->old_rec);
dtuple_print(stderr, search_tuple); dtuple_print(stderr, search_tuple);
rec_print_old(stderr,
page_rec_get_next(btr_pcur_get_rec(pcur)));
} }
ibuf_btr_pcur_commit_specify_mtr(pcur, mtr); ibuf_btr_pcur_commit_specify_mtr(pcur, mtr);

View File

@ -222,7 +222,7 @@ It is assumed that mtr holds an x-latch on the page. The operation does
not succeed if there is too little space on the page. If there is just not succeed if there is too little space on the page. If there is just
one record on the page, the insert will always succeed; this is to one record on the page, the insert will always succeed; this is to
prevent trying to split a page with just one record. prevent trying to split a page with just one record.
@return DB_SUCCESS, DB_WAIT_LOCK, DB_FAIL, or error number */ @return DB_SUCCESS, DB_LOCK_WAIT, DB_FAIL, or error number */
dberr_t dberr_t
btr_cur_optimistic_insert( btr_cur_optimistic_insert(
/*======================*/ /*======================*/

View File

@ -324,10 +324,11 @@ static inline bool btr_pcur_is_before_first_in_tree(btr_pcur_t* cursor);
Checks if the persistent cursor is after the last user record in Checks if the persistent cursor is after the last user record in
the index tree. */ the index tree. */
static inline bool btr_pcur_is_after_last_in_tree(btr_pcur_t* cursor); static inline bool btr_pcur_is_after_last_in_tree(btr_pcur_t* cursor);
MY_ATTRIBUTE((nonnull, warn_unused_result))
/*********************************************************//** /*********************************************************//**
Moves the persistent cursor to the next record on the same page. */ Moves the persistent cursor to the next record on the same page. */
UNIV_INLINE UNIV_INLINE
void rec_t*
btr_pcur_move_to_next_on_page( btr_pcur_move_to_next_on_page(
/*==========================*/ /*==========================*/
btr_pcur_t* cursor);/*!< in/out: persistent cursor */ btr_pcur_t* cursor);/*!< in/out: persistent cursor */
@ -513,8 +514,7 @@ btr_pcur_open_on_user_rec(
return DB_SUCCESS; return DB_SUCCESS;
if (dberr_t err= btr_pcur_move_to_next_page(cursor, mtr)) if (dberr_t err= btr_pcur_move_to_next_page(cursor, mtr))
return err; return err;
btr_pcur_move_to_next_on_page(cursor); return btr_pcur_move_to_next_on_page(cursor) ? DB_SUCCESS : DB_CORRUPTION;
return DB_SUCCESS;
} }
#include "btr0pcur.inl" #include "btr0pcur.inl"

View File

@ -155,7 +155,7 @@ static inline bool btr_pcur_is_after_last_in_tree(btr_pcur_t* cursor)
/*********************************************************//** /*********************************************************//**
Moves the persistent cursor to the next record on the same page. */ Moves the persistent cursor to the next record on the same page. */
UNIV_INLINE UNIV_INLINE
void rec_t*
btr_pcur_move_to_next_on_page( btr_pcur_move_to_next_on_page(
/*==========================*/ /*==========================*/
btr_pcur_t* cursor) /*!< in/out: persistent cursor */ btr_pcur_t* cursor) /*!< in/out: persistent cursor */
@ -163,9 +163,8 @@ btr_pcur_move_to_next_on_page(
ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES); ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
page_cur_move_to_next(btr_pcur_get_page_cur(cursor));
cursor->old_stored = false; cursor->old_stored = false;
return page_cur_move_to_next(btr_pcur_get_page_cur(cursor));
} }
/*********************************************************//** /*********************************************************//**
@ -204,8 +203,8 @@ loop:
|| btr_pcur_move_to_next_page(cursor, mtr) != DB_SUCCESS) { || btr_pcur_move_to_next_page(cursor, mtr) != DB_SUCCESS) {
return(FALSE); return(FALSE);
} }
} else { } else if (UNIV_UNLIKELY(!btr_pcur_move_to_next_on_page(cursor))) {
btr_pcur_move_to_next_on_page(cursor); return false;
} }
if (btr_pcur_is_on_user_rec(cursor)) { if (btr_pcur_is_on_user_rec(cursor)) {
@ -231,17 +230,13 @@ btr_pcur_move_to_next(
ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES); ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
cursor->old_stored = false; cursor->old_stored= false;
if (btr_pcur_is_after_last_on_page(cursor)) { if (btr_pcur_is_after_last_on_page(cursor))
if (btr_pcur_is_after_last_in_tree(cursor) return !btr_pcur_is_after_last_in_tree(cursor) &&
|| btr_pcur_move_to_next_page(cursor, mtr) != DB_SUCCESS) { btr_pcur_move_to_next_page(cursor, mtr) == DB_SUCCESS;
return(FALSE); else
} return !!btr_pcur_move_to_next_on_page(cursor);
} else {
btr_pcur_move_to_next_on_page(cursor);
}
return(TRUE);
} }
/**************************************************************//** /**************************************************************//**

View File

@ -57,6 +57,9 @@ rtr_page_cal_mbr(
page = buf_block_get_frame(block); page = buf_block_get_frame(block);
rec = page_rec_get_next(page_get_infimum_rec(page)); rec = page_rec_get_next(page_get_infimum_rec(page));
if (UNIV_UNLIKELY(!rec)) {
return;
}
offsets = rec_get_offsets(rec, index, offsets, page_is_leaf(page) offsets = rec_get_offsets(rec, index, offsets, page_is_leaf(page)
? index->n_fields : 0, ? index->n_fields : 0,
ULINT_UNDEFINED, &heap); ULINT_UNDEFINED, &heap);

View File

@ -110,21 +110,6 @@ page_cur_position(
const buf_block_t* block, /*!< in: buffer block containing const buf_block_t* block, /*!< in: buffer block containing
the record */ the record */
page_cur_t* cur); /*!< out: page cursor */ page_cur_t* cur); /*!< out: page cursor */
/**********************************************************//**
Moves the cursor to the next record on page. */
UNIV_INLINE
void
page_cur_move_to_next(
/*==================*/
page_cur_t* cur); /*!< in/out: cursor; must not be after last */
MY_ATTRIBUTE((nonnull, warn_unused_result))
/**********************************************************//**
Moves the cursor to the previous record on page. */
UNIV_INLINE
rec_t*
page_cur_move_to_prev(
/*==================*/
page_cur_t* cur); /*!< in/out: cursor; not before first */
/***********************************************************//** /***********************************************************//**
Inserts a record next to page cursor. Returns pointer to inserted record if Inserts a record next to page cursor. Returns pointer to inserted record if
@ -166,20 +151,20 @@ page_cur_insert_rec_low(
/***********************************************************//** /***********************************************************//**
Inserts a record next to page cursor on a compressed and uncompressed Inserts a record next to page cursor on a compressed and uncompressed
page. Returns pointer to inserted record if succeed, i.e., page.
enough space available, NULL otherwise.
The cursor stays at the same position.
IMPORTANT: The caller will have to update IBUF_BITMAP_FREE IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
if this is a compressed leaf page in a secondary index. if this is a compressed leaf page in a secondary index.
This has to be done either within the same mini-transaction, This has to be done either within the same mini-transaction,
or by invoking ibuf_reset_free_bits() before mtr_commit(). or by invoking ibuf_reset_free_bits() before mtr_commit().
@return pointer to record if succeed, NULL otherwise */ @return pointer to inserted record
@return nullptr on failure */
rec_t* rec_t*
page_cur_insert_rec_zip( page_cur_insert_rec_zip(
/*====================*/ /*====================*/
page_cur_t* cursor, /*!< in/out: page cursor */ page_cur_t* cursor, /*!< in/out: page cursor,
logical position unchanged */
dict_index_t* index, /*!< in: record descriptor */ dict_index_t* index, /*!< in: record descriptor */
const rec_t* rec, /*!< in: pointer to a physical record */ const rec_t* rec, /*!< in: pointer to a physical record */
rec_offs* offsets,/*!< in/out: rec_get_offsets(rec, index) */ rec_offs* offsets,/*!< in/out: rec_get_offsets(rec, index) */
@ -248,39 +233,10 @@ page_cur_delete_rec() for a ROW_FORMAT=COMPACT or DYNAMIC page.
bool page_apply_delete_dynamic(const buf_block_t &block, ulint prev, bool page_apply_delete_dynamic(const buf_block_t &block, ulint prev,
size_t hdr_size, size_t data_size); size_t hdr_size, size_t data_size);
/** Search the right position for a page cursor. MY_ATTRIBUTE((warn_unused_result))
@param[in] block buffer block
@param[in] index index tree
@param[in] tuple data tuple
@param[in] mode PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G, or PAGE_CUR_GE
@param[out] cursor page cursor
@return number of matched fields on the left */
UNIV_INLINE
ulint
page_cur_search(
const buf_block_t* block,
const dict_index_t* index,
const dtuple_t* tuple,
page_cur_mode_t mode,
page_cur_t* cursor);
/** Search the right position for a page cursor.
@param[in] block buffer block
@param[in] index index tree
@param[in] tuple data tuple
@param[out] cursor page cursor
@return number of matched fields on the left */
UNIV_INLINE
ulint
page_cur_search(
const buf_block_t* block,
const dict_index_t* index,
const dtuple_t* tuple,
page_cur_t* cursor);
/****************************************************************//** /****************************************************************//**
Searches the right position for a page cursor. */ Searches the right position for a page cursor. */
void bool
page_cur_search_with_match( page_cur_search_with_match(
/*=======================*/ /*=======================*/
const buf_block_t* block, /*!< in: buffer block */ const buf_block_t* block, /*!< in: buffer block */
@ -298,6 +254,7 @@ page_cur_search_with_match(
page_cur_t* cursor, /*!< out: page cursor */ page_cur_t* cursor, /*!< out: page cursor */
rtr_info_t* rtr_info);/*!< in/out: rtree search stack */ rtr_info_t* rtr_info);/*!< in/out: rtree search stack */
#ifdef BTR_CUR_HASH_ADAPT #ifdef BTR_CUR_HASH_ADAPT
MY_ATTRIBUTE((warn_unused_result))
/** Search the right position for a page cursor. /** Search the right position for a page cursor.
@param[in] block buffer block @param[in] block buffer block
@param[in] index index tree @param[in] index index tree
@ -312,7 +269,7 @@ lower limit record
@param[in,out] ilow_matched_bytes already matched bytes in the @param[in,out] ilow_matched_bytes already matched bytes in the
first partially matched field in the lower limit record first partially matched field in the lower limit record
@param[out] cursor page cursor */ @param[out] cursor page cursor */
void bool
page_cur_search_with_match_bytes( page_cur_search_with_match_bytes(
const buf_block_t* block, const buf_block_t* block,
const dict_index_t* index, const dict_index_t* index,
@ -342,6 +299,19 @@ struct page_cur_t{
buf_block_t* block; /*!< pointer to the block containing rec */ buf_block_t* block; /*!< pointer to the block containing rec */
}; };
MY_ATTRIBUTE((nonnull, warn_unused_result))
inline rec_t *page_cur_move_to_next(page_cur_t *cur)
{
return cur->rec= page_rec_get_next(cur->rec);
}
MY_ATTRIBUTE((nonnull, warn_unused_result))
inline rec_t *page_cur_move_to_prev(page_cur_t *cur)
{
return cur->rec= page_rec_get_prev(cur->rec);
}
#include "page0cur.inl" #include "page0cur.inl"
#endif #endif

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, 2021, MariaDB Corporation. Copyright (c) 2015, 2022, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
@ -149,75 +149,6 @@ page_cur_position(
cur->block = (buf_block_t*) block; cur->block = (buf_block_t*) block;
} }
/**********************************************************//**
Moves the cursor to the next record on page. */
UNIV_INLINE
void
page_cur_move_to_next(
/*==================*/
page_cur_t* cur) /*!< in/out: cursor; must not be after last */
{
ut_ad(!page_cur_is_after_last(cur));
cur->rec = page_rec_get_next(cur->rec);
}
/**********************************************************//**
Moves the cursor to the previous record on page. */
UNIV_INLINE
rec_t*
page_cur_move_to_prev(
/*==================*/
page_cur_t* cur) /*!< in/out: page cursor, not before first */
{
ut_ad(!page_cur_is_before_first(cur));
return cur->rec = page_rec_get_prev(cur->rec);
}
/** Search the right position for a page cursor.
@param[in] block buffer block
@param[in] index index tree
@param[in] tuple data tuple
@param[in] mode PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G, or PAGE_CUR_GE
@param[out] cursor page cursor
@return number of matched fields on the left */
UNIV_INLINE
ulint
page_cur_search(
const buf_block_t* block,
const dict_index_t* index,
const dtuple_t* tuple,
page_cur_mode_t mode,
page_cur_t* cursor)
{
ulint low_match = 0;
ulint up_match = 0;
ut_ad(dtuple_check_typed(tuple));
page_cur_search_with_match(block, index, tuple, mode,
&up_match, &low_match, cursor, NULL);
return(low_match);
}
/** Search the right position for a page cursor.
@param[in] block buffer block
@param[in] index index tree
@param[in] tuple data tuple
@param[out] cursor page cursor
@return number of matched fields on the left */
UNIV_INLINE
ulint
page_cur_search(
const buf_block_t* block,
const dict_index_t* index,
const dtuple_t* tuple,
page_cur_t* cursor)
{
return(page_cur_search(block, index, tuple, PAGE_CUR_LE, cursor));
}
/***********************************************************//** /***********************************************************//**
Inserts a record next to page cursor. Returns pointer to inserted record if Inserts a record next to page cursor. Returns pointer to inserted record if
succeed, i.e., enough space available, NULL otherwise. The cursor stays at succeed, i.e., enough space available, NULL otherwise. The cursor stays at

View File

@ -534,7 +534,8 @@ inline void page_header_reset_last_insert(buf_block_t *block, mtr_t *mtr)
/************************************************************//** /************************************************************//**
Returns the nth record of the record list. Returns the nth record of the record list.
This is the inverse function of page_rec_get_n_recs_before(). This is the inverse function of page_rec_get_n_recs_before().
@return nth record */ @return nth record
@retval nullptr on corrupted page */
const rec_t* const rec_t*
page_rec_get_nth_const( page_rec_get_nth_const(
/*===================*/ /*===================*/
@ -544,14 +545,12 @@ page_rec_get_nth_const(
/************************************************************//** /************************************************************//**
Returns the nth record of the record list. Returns the nth record of the record list.
This is the inverse function of page_rec_get_n_recs_before(). This is the inverse function of page_rec_get_n_recs_before().
@return nth record */ @return nth record
UNIV_INLINE @retval nullptr on corrupted page */
rec_t* inline rec_t *page_rec_get_nth(page_t* page, ulint nth)
page_rec_get_nth( {
/*=============*/ return const_cast<rec_t*>(page_rec_get_nth_const(page, nth));
page_t* page, /*< in: page */ }
ulint nth) /*!< in: nth record */
MY_ATTRIBUTE((nonnull, warn_unused_result));
/************************************************************//** /************************************************************//**
Returns the middle record of the records on the page. If there is an Returns the middle record of the records on the page. If there is an
@ -592,15 +591,11 @@ page_get_n_recs(
/*============*/ /*============*/
const page_t* page); /*!< in: index page */ const page_t* page); /*!< in: index page */
/***************************************************************//** /** Return the number of preceding records in an index page.
Returns the number of records before the given record in chain. @param rec index record
The number includes infimum and supremum records. @return number of preceding records, including the infimum pseudo-record
This is the inverse function of page_rec_get_nth(). @retval ULINT_UNDEFINED on corrupted page */
@return number of records */ ulint page_rec_get_n_recs_before(const rec_t *rec);
ulint
page_rec_get_n_recs_before(
/*=======================*/
const rec_t* rec); /*!< in: the physical record */
/*************************************************************//** /*************************************************************//**
Gets the number of records in the heap. Gets the number of records in the heap.
@return number of user records */ @return number of user records */
@ -649,6 +644,23 @@ inline const rec_t *page_dir_slot_get_rec(const page_dir_slot_t *slot)
{ {
return page_dir_slot_get_rec(const_cast<rec_t*>(slot)); return page_dir_slot_get_rec(const_cast<rec_t*>(slot));
} }
inline rec_t *page_dir_slot_get_rec_validate(page_dir_slot_t *slot)
{
const size_t s= mach_read_from_2(my_assume_aligned<2>(slot));
page_t *page= page_align(slot);
return UNIV_LIKELY(s >= PAGE_NEW_INFIMUM &&
s <= page_header_get_field(page, PAGE_HEAP_TOP))
? page + s
: nullptr;
}
inline const rec_t *page_dir_slot_get_rec_validate(const page_dir_slot_t *slot)
{
return page_dir_slot_get_rec_validate(const_cast<rec_t*>(slot));
}
/***************************************************************//** /***************************************************************//**
Gets the number of records owned by a directory slot. Gets the number of records owned by a directory slot.
@return number of records */ @return number of records */
@ -753,20 +765,9 @@ page_rec_get_next_const(
/*====================*/ /*====================*/
const rec_t* rec); /*!< in: pointer to record */ const rec_t* rec); /*!< in: pointer to record */
/************************************************************//** /************************************************************//**
Gets the pointer to the next non delete-marked record on the page.
If all subsequent records are delete-marked, then this function
will return the supremum record.
@return pointer to next non delete-marked record or pointer to supremum */
UNIV_INLINE
const rec_t*
page_rec_get_next_non_del_marked(
/*=============================*/
const rec_t* rec); /*!< in: pointer to record */
/************************************************************//**
Gets the pointer to the previous record. Gets the pointer to the previous record.
@return pointer to previous record @return pointer to previous record
@retval nullptr on error */ @retval nullptr on error */
UNIV_INLINE
const rec_t* const rec_t*
page_rec_get_prev_const( page_rec_get_prev_const(
/*====================*/ /*====================*/
@ -815,22 +816,6 @@ page_rec_is_last(
const page_t* page) /*!< in: page */ const page_t* page) /*!< in: page */
MY_ATTRIBUTE((warn_unused_result)); 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. true if the record is the second last user record on a page.
@return true if the second last user record */ @return true if the second last user record */
@ -1129,9 +1114,7 @@ page_find_rec_with_heap_no(
@param[in] page index tree leaf page @param[in] page index tree leaf page
@return the last record, not delete-marked @return the last record, not delete-marked
@retval infimum record if all records are delete-marked */ @retval infimum record if all records are delete-marked */
const rec_t* const rec_t *page_find_rec_max_not_deleted(const page_t *page);
page_find_rec_max_not_deleted(
const page_t* page);
#endif /* !UNIV_INNOCHECKSUM */ #endif /* !UNIV_INNOCHECKSUM */

View File

@ -203,9 +203,9 @@ page_rec_is_second(
const page_t* page) /*!< in: page */ const page_t* page) /*!< in: page */
{ {
ut_ad(page_get_n_recs(page) > 1); ut_ad(page_get_n_recs(page) > 1);
if (const rec_t *first= page_rec_get_next_const(page_get_infimum_rec(page)))
return(page_rec_get_next_const( return page_rec_get_next_const(first) == rec;
page_rec_get_next_const(page_get_infimum_rec(page))) == rec); return false;
} }
/************************************************************//** /************************************************************//**
@ -223,26 +223,6 @@ page_rec_is_last(
return(page_rec_get_next_const(rec) == page_get_supremum_rec(page)); return(page_rec_get_next_const(rec) == page_get_supremum_rec(page));
} }
/************************************************************//**
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. true if the record is the second last user record on a page.
@return true if the second last user record */ @return true if the second last user record */
@ -256,22 +236,9 @@ page_rec_is_second_last(
ut_ad(page_get_n_recs(page) > 1); ut_ad(page_get_n_recs(page) > 1);
ut_ad(!page_rec_is_last(rec, page)); ut_ad(!page_rec_is_last(rec, page));
return(page_rec_get_next_const( if (const rec_t *next= page_rec_get_next_const(rec))
page_rec_get_next_const(rec)) == page_get_supremum_rec(page)); return page_rec_is_supremum(page_rec_get_next_const(next));
} return false;
/************************************************************//**
Returns the nth record of the record list.
This is the inverse function of page_rec_get_n_recs_before().
@return nth record */
UNIV_INLINE
rec_t*
page_rec_get_nth(
/*=============*/
page_t* page, /*!< in: page */
ulint nth) /*!< in: nth record */
{
return((rec_t*) page_rec_get_nth_const(page, nth));
} }
/************************************************************//** /************************************************************//**
@ -421,36 +388,19 @@ page_rec_get_next_low(
const rec_t* rec, /*!< in: pointer to record */ const rec_t* rec, /*!< in: pointer to record */
ulint comp) /*!< in: nonzero=compact page layout */ ulint comp) /*!< in: nonzero=compact page layout */
{ {
ulint offs; const page_t *page= page_align(rec);
const page_t* page;
ut_ad(page_rec_check(rec)); ut_ad(page_rec_check(rec));
ulint offs= rec_get_next_offs(rec, comp);
page = page_align(rec); if (!offs)
return nullptr;
offs = rec_get_next_offs(rec, comp); if (UNIV_UNLIKELY(offs < (comp ? PAGE_NEW_SUPREMUM : PAGE_OLD_SUPREMUM)))
return nullptr;
if (offs >= srv_page_size) { if (UNIV_UNLIKELY(offs > page_header_get_field(page, PAGE_HEAP_TOP)))
fprintf(stderr, return nullptr;
"InnoDB: Next record offset is nonsensical %lu" ut_ad(page_rec_is_infimum(rec) ||
" in record at offset %lu\n" (!page_is_leaf(page) && !page_has_prev(page)) ||
"InnoDB: rec address %p, space id %lu, page %lu\n", !(rec_get_info_bits(page + offs, comp) & REC_INFO_MIN_REC_FLAG));
(ulong) offs, (ulong) page_offset(rec), return page + offs;
(void*) rec,
(ulong) page_get_space_id(page),
(ulong) page_get_page_no(page));
ut_error;
} else if (offs == 0) {
return(NULL);
}
ut_ad(page_rec_is_infimum(rec)
|| (!page_is_leaf(page) && !page_has_prev(page))
|| !(rec_get_info_bits(page + offs, comp)
& REC_INFO_MIN_REC_FLAG));
return(page + offs);
} }
/************************************************************//** /************************************************************//**
@ -476,78 +426,6 @@ page_rec_get_next_const(
{ {
return(page_rec_get_next_low(rec, page_rec_is_comp(rec))); return(page_rec_get_next_low(rec, page_rec_is_comp(rec)));
} }
/************************************************************//**
Gets the pointer to the next non delete-marked record on the page.
If all subsequent records are delete-marked, then this function
will return the supremum record.
@return pointer to next non delete-marked record or pointer to supremum */
UNIV_INLINE
const rec_t*
page_rec_get_next_non_del_marked(
/*=============================*/
const rec_t* rec) /*!< in: pointer to record */
{
const rec_t* r;
ulint page_is_compact = page_rec_is_comp(rec);
for (r = page_rec_get_next_const(rec);
!page_rec_is_supremum(r)
&& rec_get_deleted_flag(r, page_is_compact);
r = page_rec_get_next_const(r)) {
/* noop */
}
return(r);
}
/************************************************************//**
Gets the pointer to the previous record.
@return pointer to previous record
@retval nullptr on error */
UNIV_INLINE
const rec_t*
page_rec_get_prev_const(
/*====================*/
const rec_t* rec) /*!< in: pointer to record, must not be page
infimum */
{
const page_dir_slot_t* slot;
ulint slot_no;
const rec_t* rec2;
const rec_t* prev_rec = NULL;
const page_t* page;
ut_ad(page_rec_check(rec));
page = page_align(rec);
ut_ad(!page_rec_is_infimum(rec));
slot_no = page_dir_find_owner_slot(rec);
if (UNIV_UNLIKELY(!slot_no || slot_no == ULINT_UNDEFINED)) {
return nullptr;
}
slot = page_dir_get_nth_slot(page, slot_no - 1);
rec2 = page_dir_slot_get_rec(slot);
if (page_is_comp(page)) {
while (rec2 && rec != rec2) {
prev_rec = rec2;
rec2 = page_rec_get_next_low(rec2, TRUE);
}
} else {
while (rec2 && rec != rec2) {
prev_rec = rec2;
rec2 = page_rec_get_next_low(rec2, FALSE);
}
}
return(prev_rec);
}
#endif /* UNIV_INNOCHECKSUM */ #endif /* UNIV_INNOCHECKSUM */
/************************************************************//** /************************************************************//**

View File

@ -141,28 +141,7 @@ constexpr rec_offs REC_OFFS_EXTERNAL= REC_OFFS_COMPACT >> 1;
/** Default value flag in offsets returned by rec_get_offsets() */ /** Default value flag in offsets returned by rec_get_offsets() */
constexpr rec_offs REC_OFFS_DEFAULT= REC_OFFS_COMPACT >> 2; constexpr rec_offs REC_OFFS_DEFAULT= REC_OFFS_COMPACT >> 2;
constexpr rec_offs REC_OFFS_MASK= REC_OFFS_DEFAULT - 1; constexpr rec_offs REC_OFFS_MASK= REC_OFFS_DEFAULT - 1;
/******************************************************//**
The following function is used to get the pointer of the next chained record
on the same page.
@return pointer to the next chained record, or NULL if none */
UNIV_INLINE
const rec_t*
rec_get_next_ptr_const(
/*===================*/
const rec_t* rec, /*!< in: physical record */
ulint comp) /*!< in: nonzero=compact page format */
MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
The following function is used to get the pointer of the next chained record
on the same page.
@return pointer to the next chained record, or NULL if none */
UNIV_INLINE
rec_t*
rec_get_next_ptr(
/*=============*/
rec_t* rec, /*!< in: physical record */
ulint comp) /*!< in: nonzero=compact page format */
MY_ATTRIBUTE((warn_unused_result));
/******************************************************//** /******************************************************//**
The following function is used to get the offset of the The following function is used to get the offset of the
next chained record on the same page. next chained record on the same page.

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2020, MariaDB Corporation. Copyright (c) 2017, 2022, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under 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 the terms of the GNU General Public License as published by the Free Software
@ -203,76 +203,6 @@ rec_set_bit_field_2(
| (val << shift)); | (val << shift));
} }
/******************************************************//**
The following function is used to get the pointer of the next chained record
on the same page.
@return pointer to the next chained record, or NULL if none */
UNIV_INLINE
const rec_t*
rec_get_next_ptr_const(
/*===================*/
const rec_t* rec, /*!< in: physical record */
ulint comp) /*!< in: nonzero=compact page format */
{
ulint field_value;
compile_time_assert(REC_NEXT_MASK == 0xFFFFUL);
compile_time_assert(REC_NEXT_SHIFT == 0);
field_value = mach_read_from_2(rec - REC_NEXT);
if (field_value == 0) {
return(NULL);
}
if (comp) {
#if UNIV_PAGE_SIZE_MAX <= 32768
/* Note that for 64 KiB pages, field_value can 'wrap around'
and the debug assertion is not valid */
/* In the following assertion, field_value is interpreted
as signed 16-bit integer in 2's complement arithmetics.
If all platforms defined int16_t in the standard headers,
the expression could be written simpler as
(int16_t) field_value + ut_align_offset(...) < srv_page_size
*/
ut_ad((field_value >= 32768
? field_value - 65536
: field_value)
+ ut_align_offset(rec, srv_page_size)
< srv_page_size);
#endif
/* There must be at least REC_N_NEW_EXTRA_BYTES + 1
between each record. */
ut_ad((field_value > REC_N_NEW_EXTRA_BYTES
&& field_value < 32768)
|| field_value < (uint16) -REC_N_NEW_EXTRA_BYTES);
return((byte*) ut_align_down(rec, srv_page_size)
+ ut_align_offset(rec + field_value, srv_page_size));
} else {
ut_ad(field_value < srv_page_size);
return((byte*) ut_align_down(rec, srv_page_size)
+ field_value);
}
}
/******************************************************//**
The following function is used to get the pointer of the next chained record
on the same page.
@return pointer to the next chained record, or NULL if none */
UNIV_INLINE
rec_t*
rec_get_next_ptr(
/*=============*/
rec_t* rec, /*!< in: physical record */
ulint comp) /*!< in: nonzero=compact page format */
{
return(const_cast<rec_t*>(rec_get_next_ptr_const(rec, comp)));
}
/******************************************************//** /******************************************************//**
The following function is used to get the offset of the next chained record The following function is used to get the offset of the next chained record
on the same page. on the same page.

View File

@ -2378,8 +2378,10 @@ lock_move_reorganize_page(
lock_trx->mutex_unlock(); lock_trx->mutex_unlock();
if (new_heap_no == PAGE_HEAP_NO_SUPREMUM) if (!rec1 || !rec2)
{ {
ut_ad(!rec1 == !rec2);
ut_ad(new_heap_no == PAGE_HEAP_NO_SUPREMUM);
ut_ad(old_heap_no == PAGE_HEAP_NO_SUPREMUM); ut_ad(old_heap_no == PAGE_HEAP_NO_SUPREMUM);
break; break;
} }
@ -2450,6 +2452,12 @@ lock_move_rec_list_end(
FALSE); FALSE);
} }
if (UNIV_UNLIKELY(!rec1 || !rec2))
{
ut_ad("corrupted page" == 0);
return;
}
/* Copy lock requests on user records to new page and /* Copy lock requests on user records to new page and
reset the lock bits on the old */ reset the lock bits on the old */
for (;;) for (;;)
@ -2463,28 +2471,37 @@ lock_move_rec_list_end(
if (comp) if (comp)
{ {
rec1_heap_no= rec_get_heap_no_new(rec1); rec1_heap_no= rec_get_heap_no_new(rec1);
if (rec1_heap_no == PAGE_HEAP_NO_SUPREMUM) if (!(rec1= page_rec_get_next_low(rec1, TRUE)))
{
ut_ad(rec1_heap_no == PAGE_HEAP_NO_SUPREMUM);
break; break;
}
rec2_heap_no= rec_get_heap_no_new(rec2); rec2_heap_no= rec_get_heap_no_new(rec2);
rec1= page_rec_get_next_low(rec1, TRUE);
rec2= page_rec_get_next_low(rec2, TRUE); rec2= page_rec_get_next_low(rec2, TRUE);
} }
else else
{ {
ut_d(const rec_t *old1= rec1);
rec1_heap_no= rec_get_heap_no_old(rec1); rec1_heap_no= rec_get_heap_no_old(rec1);
if (!(rec1= page_rec_get_next_low(rec1, FALSE)))
if (rec1_heap_no == PAGE_HEAP_NO_SUPREMUM) {
ut_ad(rec1_heap_no == PAGE_HEAP_NO_SUPREMUM);
break; break;
}
ut_ad(rec_get_data_size_old(old1) == rec_get_data_size_old(rec2));
ut_ad(!memcmp(old1, rec2, rec_get_data_size_old(old1)));
rec2_heap_no= rec_get_heap_no_old(rec2); rec2_heap_no= rec_get_heap_no_old(rec2);
ut_ad(rec_get_data_size_old(rec1) == rec_get_data_size_old(rec2));
ut_ad(!memcmp(rec1, rec2, rec_get_data_size_old(rec1)));
rec1= page_rec_get_next_low(rec1, FALSE);
rec2= page_rec_get_next_low(rec2, FALSE); rec2= page_rec_get_next_low(rec2, FALSE);
} }
if (UNIV_UNLIKELY(!rec2))
{
ut_ad("corrupted page" == 0);
return;
}
trx_t *lock_trx= lock->trx; trx_t *lock_trx= lock->trx;
lock_trx->mutex_lock(); lock_trx->mutex_lock();
@ -2577,6 +2594,12 @@ lock_move_rec_list_start(
while (rec1 != rec) while (rec1 != rec)
{ {
if (UNIV_UNLIKELY(!rec1 || !rec2))
{
ut_ad("corrupted page" == 0);
return;
}
ut_ad(page_rec_is_metadata(rec1) == page_rec_is_metadata(rec2)); ut_ad(page_rec_is_metadata(rec1) == page_rec_is_metadata(rec2));
ut_d(const rec_t* const prev= rec1); ut_d(const rec_t* const prev= rec1);
@ -2880,11 +2903,15 @@ void lock_update_merge_left(const buf_block_t& left, const rec_t *orig_pred,
ut_ad(left.page.frame == page_align(orig_pred)); ut_ad(left.page.frame == page_align(orig_pred));
const page_id_t l{left.page.id()}; const page_id_t l{left.page.id()};
const rec_t *left_next_rec= page_rec_get_next_const(orig_pred);
if (UNIV_UNLIKELY(!left_next_rec))
{
ut_ad("corrupted page" == 0);
return;
}
/* This would likely be too large for a memory transaction. */ /* This would likely be too large for a memory transaction. */
LockMultiGuard g{lock_sys.rec_hash, l, right}; LockMultiGuard g{lock_sys.rec_hash, l, right};
const rec_t *left_next_rec= page_rec_get_next_const(orig_pred);
if (!page_rec_is_supremum(left_next_rec)) if (!page_rec_is_supremum(left_next_rec))
{ {
/* Inherit the locks on the supremum of the left page to the /* Inherit the locks on the supremum of the left page to the
@ -3031,12 +3058,18 @@ lock_update_insert(
if (page_rec_is_comp(rec)) { if (page_rec_is_comp(rec)) {
receiver_heap_no = rec_get_heap_no_new(rec); receiver_heap_no = rec_get_heap_no_new(rec);
donator_heap_no = rec_get_heap_no_new( rec = page_rec_get_next_low(rec, TRUE);
page_rec_get_next_low(rec, TRUE)); if (UNIV_UNLIKELY(!rec)) {
return;
}
donator_heap_no = rec_get_heap_no_new(rec);
} else { } else {
receiver_heap_no = rec_get_heap_no_old(rec); receiver_heap_no = rec_get_heap_no_old(rec);
donator_heap_no = rec_get_heap_no_old( rec = page_rec_get_next_low(rec, FALSE);
page_rec_get_next_low(rec, FALSE)); if (UNIV_UNLIKELY(!rec)) {
return;
}
donator_heap_no = rec_get_heap_no_old(rec);
} }
lock_rec_inherit_to_gap_if_gap_lock( lock_rec_inherit_to_gap_if_gap_lock(
@ -4952,13 +4985,15 @@ lock_rec_insert_check_and_lock(
ut_ad(page_is_leaf(block->page.frame)); ut_ad(page_is_leaf(block->page.frame));
ut_ad(!index->table->is_temporary()); ut_ad(!index->table->is_temporary());
const rec_t *next_rec= page_rec_get_next_const(rec);
if (UNIV_UNLIKELY(!next_rec || rec_is_metadata(next_rec, *index)))
return DB_CORRUPTION;
dberr_t err= DB_SUCCESS; dberr_t err= DB_SUCCESS;
bool inherit_in= *inherit; bool inherit_in= *inherit;
trx_t *trx= thr_get_trx(thr); trx_t *trx= thr_get_trx(thr);
const rec_t *next_rec= page_rec_get_next_const(rec);
ulint heap_no= page_rec_get_heap_no(next_rec); ulint heap_no= page_rec_get_heap_no(next_rec);
const page_id_t id{block->page.id()}; const page_id_t id{block->page.id()};
ut_ad(!rec_is_metadata(next_rec, *index));
{ {
LockGuard g{lock_sys.rec_hash, id}; LockGuard g{lock_sys.rec_hash, id};
@ -6333,11 +6368,16 @@ void lock_update_split_and_merge(
const page_id_t l{left_block->page.id()}; const page_id_t l{left_block->page.id()};
const page_id_t r{right_block->page.id()}; const page_id_t r{right_block->page.id()};
const rec_t *left_next_rec= page_rec_get_next_const(orig_pred);
if (UNIV_UNLIKELY(!left_next_rec))
{
ut_ad("corrupted page" == 0);
return;
}
ut_ad(!page_rec_is_metadata(left_next_rec));
/* This would likely be too large for a memory transaction. */ /* This would likely be too large for a memory transaction. */
LockMultiGuard g{lock_sys.rec_hash, l, r}; LockMultiGuard g{lock_sys.rec_hash, l, r};
const rec_t *left_next_rec= page_rec_get_next_const(orig_pred);
ut_ad(!page_rec_is_metadata(left_next_rec));
/* Inherit the locks on the supremum of the left page to the /* Inherit the locks on the supremum of the left page to the
first record which was moved from the right page */ first record which was moved from the right page */

View File

@ -88,7 +88,10 @@ page_cur_try_search_shortcut(
goto exit_func; goto exit_func;
} }
next_rec = page_rec_get_next_const(rec); if (!(next_rec = page_rec_get_next_const(rec))) {
goto exit_func;
}
if (!page_rec_is_supremum(next_rec)) { if (!page_rec_is_supremum(next_rec)) {
offsets = rec_get_offsets(next_rec, index, offsets, offsets = rec_get_offsets(next_rec, index, offsets,
index->n_core_fields, index->n_core_fields,
@ -179,7 +182,10 @@ page_cur_try_search_shortcut_bytes(
goto exit_func; goto exit_func;
} }
next_rec = page_rec_get_next_const(rec); if (!(next_rec = page_rec_get_next_const(rec))) {
goto exit_func;
}
if (!page_rec_is_supremum(next_rec)) { if (!page_rec_is_supremum(next_rec)) {
offsets = rec_get_offsets(next_rec, index, offsets, offsets = rec_get_offsets(next_rec, index, offsets,
index->n_core_fields, index->n_core_fields,
@ -267,7 +273,7 @@ page_cur_rec_field_extends(
/****************************************************************//** /****************************************************************//**
Searches the right position for a page cursor. */ Searches the right position for a page cursor. */
void bool
page_cur_search_with_match( page_cur_search_with_match(
/*=======================*/ /*=======================*/
const buf_block_t* block, /*!< in: buffer block */ const buf_block_t* block, /*!< in: buffer block */
@ -289,7 +295,6 @@ page_cur_search_with_match(
ulint low; ulint low;
ulint mid; ulint mid;
const page_t* page; const page_t* page;
const page_dir_slot_t* slot;
const rec_t* up_rec; const rec_t* up_rec;
const rec_t* low_rec; const rec_t* low_rec;
const rec_t* mid_rec; const rec_t* mid_rec;
@ -335,7 +340,7 @@ page_cur_search_with_match(
&& page_cur_try_search_shortcut( && page_cur_try_search_shortcut(
block, index, tuple, block, index, tuple,
iup_matched_fields, ilow_matched_fields, cursor)) { iup_matched_fields, ilow_matched_fields, cursor)) {
return; return false;
} }
# ifdef PAGE_CUR_DBG # ifdef PAGE_CUR_DBG
if (mode == PAGE_CUR_DBG) { if (mode == PAGE_CUR_DBG) {
@ -352,10 +357,9 @@ page_cur_search_with_match(
if (mode == PAGE_CUR_RTREE_INSERT && n_core) { if (mode == PAGE_CUR_RTREE_INSERT && n_core) {
mode = PAGE_CUR_LE; mode = PAGE_CUR_LE;
} else { } else {
rtr_cur_search_with_match( return rtr_cur_search_with_match(
block, (dict_index_t*)index, tuple, mode, block, (dict_index_t*)index, tuple, mode,
cursor, rtr_info); cursor, rtr_info);
return;
} }
} }
@ -386,9 +390,11 @@ page_cur_search_with_match(
while (up - low > 1) { while (up - low > 1) {
mid = (low + up) / 2; mid = (low + up) / 2;
slot = page_dir_get_nth_slot(page, mid); const page_dir_slot_t* slot = page_dir_get_nth_slot(page, mid);
mid_rec = page_dir_slot_get_rec(slot); if (UNIV_UNLIKELY(!(mid_rec
= page_dir_slot_get_rec_validate(slot)))) {
goto corrupted;
}
cur_matched_fields = std::min(low_matched_fields, cur_matched_fields = std::min(low_matched_fields,
up_matched_fields); up_matched_fields);
@ -431,18 +437,30 @@ up_slot_match:
} }
} }
slot = page_dir_get_nth_slot(page, low); low_rec = page_dir_slot_get_rec_validate(
low_rec = page_dir_slot_get_rec(slot); page_dir_get_nth_slot(page, low));
slot = page_dir_get_nth_slot(page, up); up_rec = page_dir_slot_get_rec_validate(
up_rec = page_dir_slot_get_rec(slot); page_dir_get_nth_slot(page, up));
if (UNIV_UNLIKELY(!low_rec || !up_rec)) {
corrupted:
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return true;
}
/* Perform linear search until the upper and lower records come to /* Perform linear search until the upper and lower records come to
distance 1 of each other. */ distance 1 of each other. */
while (page_rec_get_next_const(low_rec) != up_rec) { for (;;) {
if (const rec_t* next = page_rec_get_next_const(low_rec)) {
mid_rec = page_rec_get_next_const(low_rec); if (next == up_rec) {
break;
}
mid_rec = next;
} else {
goto corrupted;
}
cur_matched_fields = std::min(low_matched_fields, cur_matched_fields = std::min(low_matched_fields,
up_matched_fields); up_matched_fields);
@ -512,6 +530,8 @@ up_rec_match:
if (UNIV_LIKELY_NULL(heap)) { if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap); mem_heap_free(heap);
} }
return false;
} }
#ifdef BTR_CUR_HASH_ADAPT #ifdef BTR_CUR_HASH_ADAPT
@ -529,7 +549,7 @@ lower limit record
@param[in,out] ilow_matched_bytes already matched bytes in the @param[in,out] ilow_matched_bytes already matched bytes in the
first partially matched field in the lower limit record first partially matched field in the lower limit record
@param[out] cursor page cursor */ @param[out] cursor page cursor */
void bool
page_cur_search_with_match_bytes( page_cur_search_with_match_bytes(
const buf_block_t* block, const buf_block_t* block,
const dict_index_t* index, const dict_index_t* index,
@ -543,9 +563,7 @@ page_cur_search_with_match_bytes(
{ {
ulint up; ulint up;
ulint low; ulint low;
ulint mid;
const page_t* page; const page_t* page;
const page_dir_slot_t* slot;
const rec_t* up_rec; const rec_t* up_rec;
const rec_t* low_rec; const rec_t* low_rec;
const rec_t* mid_rec; const rec_t* mid_rec;
@ -594,7 +612,7 @@ page_cur_search_with_match_bytes(
iup_matched_fields, iup_matched_bytes, iup_matched_fields, iup_matched_bytes,
ilow_matched_fields, ilow_matched_bytes, ilow_matched_fields, ilow_matched_bytes,
cursor)) { cursor)) {
return; return false;
} }
# ifdef PAGE_CUR_DBG # ifdef PAGE_CUR_DBG
if (mode == PAGE_CUR_DBG) { if (mode == PAGE_CUR_DBG) {
@ -632,9 +650,12 @@ page_cur_search_with_match_bytes(
const ulint n_core = page_is_leaf(page) ? index->n_core_fields : 0; const ulint n_core = page_is_leaf(page) ? index->n_core_fields : 0;
while (up - low > 1) { while (up - low > 1) {
mid = (low + up) / 2; const ulint mid = (low + up) / 2;
slot = page_dir_get_nth_slot(page, mid); mid_rec = page_dir_slot_get_rec_validate(
mid_rec = page_dir_slot_get_rec(slot); page_dir_get_nth_slot(page, mid));
if (UNIV_UNLIKELY(!mid_rec)) {
goto corrupted;
}
ut_pair_min(&cur_matched_fields, &cur_matched_bytes, ut_pair_min(&cur_matched_fields, &cur_matched_bytes,
low_matched_fields, low_matched_bytes, low_matched_fields, low_matched_bytes,
@ -681,18 +702,30 @@ up_slot_match:
} }
} }
slot = page_dir_get_nth_slot(page, low); low_rec = page_dir_slot_get_rec_validate(
low_rec = page_dir_slot_get_rec(slot); page_dir_get_nth_slot(page, low));
slot = page_dir_get_nth_slot(page, up); up_rec = page_dir_slot_get_rec_validate(
up_rec = page_dir_slot_get_rec(slot); page_dir_get_nth_slot(page, up));
if (UNIV_UNLIKELY(!low_rec || !up_rec)) {
corrupted:
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return true;
}
/* Perform linear search until the upper and lower records come to /* Perform linear search until the upper and lower records come to
distance 1 of each other. */ distance 1 of each other. */
while (page_rec_get_next_const(low_rec) != up_rec) { for (;;) {
if (const rec_t* next = page_rec_get_next_const(low_rec)) {
mid_rec = page_rec_get_next_const(low_rec); if (next == up_rec) {
break;
}
mid_rec = next;
} else {
goto corrupted;
}
ut_pair_min(&cur_matched_fields, &cur_matched_bytes, ut_pair_min(&cur_matched_fields, &cur_matched_bytes,
low_matched_fields, low_matched_bytes, low_matched_fields, low_matched_bytes,
up_matched_fields, up_matched_bytes); up_matched_fields, up_matched_bytes);
@ -761,6 +794,7 @@ up_rec_match:
if (UNIV_LIKELY_NULL(heap)) { if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap); mem_heap_free(heap);
} }
return false;
} }
#endif /* BTR_CUR_HASH_ADAPT */ #endif /* BTR_CUR_HASH_ADAPT */
@ -773,17 +807,12 @@ page_cur_open_on_rnd_user_rec(
buf_block_t* block, /*!< in: page */ buf_block_t* block, /*!< in: page */
page_cur_t* cursor) /*!< out: page cursor */ page_cur_t* cursor) /*!< out: page cursor */
{ {
const ulint n_recs = page_get_n_recs(block->page.frame); cursor->block= block;
if (const ulint n_recs= page_get_n_recs(block->page.frame))
page_cur_set_before_first(block, cursor); if ((cursor->rec= page_rec_get_nth(block->page.frame,
ut_rnd_interval(n_recs) + 1)))
if (UNIV_UNLIKELY(n_recs == 0)) {
return; return;
} cursor->rec= page_get_infimum_rec(block->page.frame);
cursor->rec = page_rec_get_nth(block->page.frame,
ut_rnd_interval(n_recs) + 1);
} }
/** /**
@ -802,7 +831,7 @@ static void page_rec_set_n_owned(rec_t *rec, ulint n_owned, bool comp)
Split a directory slot which owns too many records. Split a directory slot which owns too many records.
@param[in,out] block index page @param[in,out] block index page
@param[in,out] slot the slot that needs to be split */ @param[in,out] slot the slot that needs to be split */
static void page_dir_split_slot(const buf_block_t &block, static bool page_dir_split_slot(const buf_block_t &block,
page_dir_slot_t *slot) page_dir_slot_t *slot)
{ {
ut_ad(slot <= &block.page.frame[srv_page_size - PAGE_EMPTY_DIR_START]); ut_ad(slot <= &block.page.frame[srv_page_size - PAGE_EMPTY_DIR_START]);
@ -815,10 +844,17 @@ static void page_dir_split_slot(const buf_block_t &block,
PAGE_DIR_SLOT_MIN_N_OWNED, "compatibility"); PAGE_DIR_SLOT_MIN_N_OWNED, "compatibility");
/* Find a record approximately in the middle. */ /* Find a record approximately in the middle. */
const rec_t *rec= page_dir_slot_get_rec(slot + PAGE_DIR_SLOT_SIZE); const rec_t *rec= page_dir_slot_get_rec_validate(slot + PAGE_DIR_SLOT_SIZE);
for (ulint i= n_owned / 2; i--; ) for (ulint i= n_owned / 2; i--; )
{
if (UNIV_UNLIKELY(!rec))
return true;
rec= page_rec_get_next_const(rec); rec= page_rec_get_next_const(rec);
}
if (UNIV_UNLIKELY(!rec))
return true;
/* Add a directory slot immediately below this one. */ /* Add a directory slot immediately below this one. */
constexpr uint16_t n_slots_f= PAGE_N_DIR_SLOTS + PAGE_HEADER; constexpr uint16_t n_slots_f= PAGE_N_DIR_SLOTS + PAGE_HEADER;
@ -828,7 +864,10 @@ static void page_dir_split_slot(const buf_block_t &block,
page_dir_slot_t *last_slot= static_cast<page_dir_slot_t*> page_dir_slot_t *last_slot= static_cast<page_dir_slot_t*>
(block.page.frame + srv_page_size - (PAGE_DIR + PAGE_DIR_SLOT_SIZE) - (block.page.frame + srv_page_size - (PAGE_DIR + PAGE_DIR_SLOT_SIZE) -
n_slots * PAGE_DIR_SLOT_SIZE); n_slots * PAGE_DIR_SLOT_SIZE);
ut_ad(slot >= last_slot);
if (UNIV_UNLIKELY(slot < last_slot))
return true;
memmove_aligned<2>(last_slot, last_slot + PAGE_DIR_SLOT_SIZE, memmove_aligned<2>(last_slot, last_slot + PAGE_DIR_SLOT_SIZE,
slot - last_slot); slot - last_slot);
@ -841,6 +880,7 @@ static void page_dir_split_slot(const buf_block_t &block,
page_rec_set_n_owned(page_dir_slot_get_rec(slot), half_owned, comp); page_rec_set_n_owned(page_dir_slot_get_rec(slot), half_owned, comp);
page_rec_set_n_owned(page_dir_slot_get_rec(slot - PAGE_DIR_SLOT_SIZE), page_rec_set_n_owned(page_dir_slot_get_rec(slot - PAGE_DIR_SLOT_SIZE),
n_owned - half_owned, comp); n_owned - half_owned, comp);
return false;
} }
/** /**
@ -866,6 +906,10 @@ static void page_zip_dir_split_slot(buf_block_t *block, ulint s, mtr_t* mtr)
const rec_t *rec= page_dir_slot_get_rec(slot + PAGE_DIR_SLOT_SIZE); const rec_t *rec= page_dir_slot_get_rec(slot + PAGE_DIR_SLOT_SIZE);
/* We do not try to prevent crash on corruption here.
For ROW_FORMAT=COMPRESSED pages, the next-record links should
be validated in page_zip_decompress(). Corruption should only
be possible here if the buffer pool was corrupted later. */
for (ulint i= n_owned / 2; i--; ) for (ulint i= n_owned / 2; i--; )
rec= page_rec_get_next_const(rec); rec= page_rec_get_next_const(rec);
@ -951,8 +995,12 @@ static void page_zip_dir_balance_slot(buf_block_t *block, ulint s, mtr_t *mtr)
/* Transfer one record to the underfilled slot */ /* Transfer one record to the underfilled slot */
page_rec_set_n_owned<true>(block, slot_rec, 0, true, mtr); page_rec_set_n_owned<true>(block, slot_rec, 0, true, mtr);
rec_t* new_rec = rec_get_next_ptr(slot_rec, TRUE); const rec_t* new_rec = page_rec_get_next_low(slot_rec, TRUE);
page_rec_set_n_owned<true>(block, new_rec, /* We do not try to prevent crash on corruption here.
For ROW_FORMAT=COMPRESSED pages, the next-record links should
be validated in page_zip_decompress(). Corruption should only
be possible here if the buffer pool was corrupted later. */
page_rec_set_n_owned<true>(block, const_cast<rec_t*>(new_rec),
PAGE_DIR_SLOT_MIN_N_OWNED, PAGE_DIR_SLOT_MIN_N_OWNED,
true, mtr); true, mtr);
mach_write_to_2(slot, page_offset(new_rec)); mach_write_to_2(slot, page_offset(new_rec));
@ -1013,18 +1061,27 @@ static void page_dir_balance_slot(const buf_block_t &block, ulint s)
} }
/* Transfer one record to the underfilled slot */ /* Transfer one record to the underfilled slot */
rec_t* new_rec; const rec_t* new_rec;
if (comp) { if (comp) {
if (UNIV_UNLIKELY(!(new_rec =
page_rec_get_next_low(slot_rec, true)))) {
ut_ad("corrupted page" == 0);
return;
}
page_rec_set_n_owned(slot_rec, 0, true); page_rec_set_n_owned(slot_rec, 0, true);
new_rec = rec_get_next_ptr(slot_rec, TRUE); page_rec_set_n_owned(const_cast<rec_t*>(new_rec),
page_rec_set_n_owned(new_rec, PAGE_DIR_SLOT_MIN_N_OWNED, true); PAGE_DIR_SLOT_MIN_N_OWNED, true);
page_rec_set_n_owned(up_rec, up_n_owned - 1, true); page_rec_set_n_owned(up_rec, up_n_owned - 1, true);
} else { } else {
if (UNIV_UNLIKELY(!(new_rec =
page_rec_get_next_low(slot_rec, false)))) {
ut_ad("corrupted page" == 0);
return;
}
page_rec_set_n_owned(slot_rec, 0, false); page_rec_set_n_owned(slot_rec, 0, false);
new_rec = rec_get_next_ptr(slot_rec, FALSE); page_rec_set_n_owned(const_cast<rec_t*>(new_rec),
page_rec_set_n_owned(new_rec, PAGE_DIR_SLOT_MIN_N_OWNED, PAGE_DIR_SLOT_MIN_N_OWNED, false);
false);
page_rec_set_n_owned(up_rec, up_n_owned - 1, false); page_rec_set_n_owned(up_rec, up_n_owned - 1, false);
} }
@ -1281,6 +1338,20 @@ inline void mtr_t::page_insert(const buf_block_t &block, bool reuse,
m_last_offset= FIL_PAGE_TYPE; m_last_offset= FIL_PAGE_TYPE;
} }
/** Report page directory corruption.
@param block index page
@param index index tree
*/
ATTRIBUTE_COLD
static void page_cur_directory_corrupted(const buf_block_t &block,
const dict_index_t &index)
{
ib::error() << "Directory of " << block.page.id()
<< " of index " << index.name
<< " in table " << index.table->name
<< " is corrupted";
}
/***********************************************************//** /***********************************************************//**
Inserts a record next to page cursor on an uncompressed page. Inserts a record next to page cursor on an uncompressed page.
@return pointer to record @return pointer to record
@ -1623,9 +1694,14 @@ copied:
{ {
const ulint owner= page_dir_find_owner_slot(next_rec); const ulint owner= page_dir_find_owner_slot(next_rec);
if (UNIV_UNLIKELY(owner == ULINT_UNDEFINED)) if (UNIV_UNLIKELY(owner == ULINT_UNDEFINED))
{
page_cur_directory_corrupted(*block, *index);
return nullptr;
}
if (page_dir_split_slot(*block, page_dir_get_nth_slot(block->page.frame,
owner)))
return nullptr; return nullptr;
page_dir_split_slot(*block,
page_dir_get_nth_slot(block->page.frame, owner));
} }
rec_offs_make_valid(insert_buf + extra_size, index, rec_offs_make_valid(insert_buf + extra_size, index,
@ -1693,20 +1769,20 @@ static inline void page_zip_dir_add_slot(buf_block_t *block,
/***********************************************************//** /***********************************************************//**
Inserts a record next to page cursor on a compressed and uncompressed Inserts a record next to page cursor on a compressed and uncompressed
page. Returns pointer to inserted record if succeed, i.e., page.
enough space available, NULL otherwise.
The cursor stays at the same position.
IMPORTANT: The caller will have to update IBUF_BITMAP_FREE IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
if this is a compressed leaf page in a secondary index. if this is a compressed leaf page in a secondary index.
This has to be done either within the same mini-transaction, This has to be done either within the same mini-transaction,
or by invoking ibuf_reset_free_bits() before mtr_commit(). or by invoking ibuf_reset_free_bits() before mtr_commit().
@return pointer to record if succeed, NULL otherwise */ @return pointer to inserted record
@return nullptr on failure */
rec_t* rec_t*
page_cur_insert_rec_zip( page_cur_insert_rec_zip(
/*====================*/ /*====================*/
page_cur_t* cursor, /*!< in/out: page cursor */ page_cur_t* cursor, /*!< in/out: page cursor,
logical position unchanged */
dict_index_t* index, /*!< in: record descriptor */ dict_index_t* index, /*!< in: record descriptor */
const rec_t* rec, /*!< in: pointer to a physical record */ const rec_t* rec, /*!< in: pointer to a physical record */
rec_offs* offsets,/*!< in/out: rec_get_offsets(rec, index) */ rec_offs* offsets,/*!< in/out: rec_get_offsets(rec, index) */
@ -1786,6 +1862,9 @@ page_cur_insert_rec_zip(
{ {
ulint pos= page_rec_get_n_recs_before(cursor->rec); ulint pos= page_rec_get_n_recs_before(cursor->rec);
if (UNIV_UNLIKELY(pos == ULINT_UNDEFINED))
return nullptr;
switch (page_zip_reorganize(cursor->block, index, level, mtr, true)) { switch (page_zip_reorganize(cursor->block, index, level, mtr, true)) {
case DB_FAIL: case DB_FAIL:
ut_ad(cursor->rec == cursor_rec); ut_ad(cursor->rec == cursor_rec);
@ -1796,10 +1875,13 @@ page_cur_insert_rec_zip(
return nullptr; return nullptr;
} }
if (pos) if (!pos)
cursor->rec= page_rec_get_nth(page, pos); ut_ad(cursor->rec == page + PAGE_NEW_INFIMUM);
else else if (!(cursor->rec= page_rec_get_nth(page, pos)))
ut_ad(cursor->rec == page_get_infimum_rec(page)); {
cursor->rec= page + PAGE_NEW_SUPREMUM;
return nullptr;
}
ut_ad(!page_header_get_ptr(page, PAGE_FREE)); ut_ad(!page_header_get_ptr(page, PAGE_FREE));
@ -1816,16 +1898,21 @@ page_cur_insert_rec_zip(
if (insert_rec) if (insert_rec)
{ {
ulint pos= page_rec_get_n_recs_before(insert_rec); ulint pos= page_rec_get_n_recs_before(insert_rec);
ut_ad(pos > 0); if (UNIV_UNLIKELY(!pos || pos == ULINT_UNDEFINED))
return nullptr;
/* We are writing entire page images to the log. Reduce the redo /* We are writing entire page images to the log. Reduce the redo
log volume by reorganizing the page at the same time. */ log volume by reorganizing the page at the same time. */
switch (page_zip_reorganize(cursor->block, index, level, mtr)) { switch (page_zip_reorganize(cursor->block, index, level, mtr)) {
case DB_SUCCESS: case DB_SUCCESS:
/* The page was reorganized: Seek to pos. */ /* The page was reorganized: Seek to pos. */
cursor->rec= pos > 1 if (pos <= 1)
? page_rec_get_nth(page, pos - 1) cursor->rec= page + PAGE_NEW_INFIMUM;
: page + PAGE_NEW_INFIMUM; else if (!(cursor->rec= page_rec_get_nth(page, pos - 1)))
{
cursor->rec= page + PAGE_NEW_INFIMUM;
return nullptr;
}
insert_rec= page + rec_get_next_offs(cursor->rec, 1); insert_rec= page + rec_get_next_offs(cursor->rec, 1);
rec_offs_make_valid(insert_rec, index, page_is_leaf(page), offsets); rec_offs_make_valid(insert_rec, index, page_is_leaf(page), offsets);
break; break;
@ -1891,19 +1978,25 @@ too_small:
byte *const free_rec_ptr= page + free_rec; byte *const free_rec_ptr= page + free_rec;
heap_no= rec_get_heap_no_new(free_rec_ptr); heap_no= rec_get_heap_no_new(free_rec_ptr);
int16_t next_rec= mach_read_from_2(free_rec_ptr - REC_NEXT); int16_t next_free= mach_read_from_2(free_rec_ptr - REC_NEXT);
/* With innodb_page_size=64k, int16_t would be unsafe to use here, /* With innodb_page_size=64k, int16_t would be unsafe to use here,
but that cannot be used with ROW_FORMAT=COMPRESSED. */ but that cannot be used with ROW_FORMAT=COMPRESSED. */
static_assert(UNIV_ZIP_SIZE_SHIFT_MAX == 14, "compatibility"); static_assert(UNIV_ZIP_SIZE_SHIFT_MAX == 14, "compatibility");
if (next_rec) if (next_free)
{ {
next_rec= static_cast<int16_t>(next_rec + free_rec); next_free= static_cast<int16_t>(next_free + free_rec);
ut_ad(int{PAGE_NEW_SUPREMUM_END + REC_N_NEW_EXTRA_BYTES} <= next_rec); if (UNIV_UNLIKELY(int{PAGE_NEW_SUPREMUM_END + REC_N_NEW_EXTRA_BYTES} >
ut_ad(static_cast<uint16_t>(next_rec) < srv_page_size); next_free ||
uint16_t(next_free) >= srv_page_size))
{
if (UNIV_LIKELY_NULL(heap))
mem_heap_free(heap);
return nullptr;
}
} }
byte *hdr= my_assume_aligned<4>(&page_zip->data[page_free_f]); byte *hdr= my_assume_aligned<4>(&page_zip->data[page_free_f]);
mach_write_to_2(hdr, static_cast<uint16_t>(next_rec)); mach_write_to_2(hdr, static_cast<uint16_t>(next_free));
const byte *const garbage= my_assume_aligned<2>(page_free + 2); const byte *const garbage= my_assume_aligned<2>(page_free + 2);
ut_ad(mach_read_from_2(garbage) >= rec_size); ut_ad(mach_read_from_2(garbage) >= rec_size);
mach_write_to_2(my_assume_aligned<2>(hdr + 2), mach_write_to_2(my_assume_aligned<2>(hdr + 2),
@ -1959,18 +2052,20 @@ use_heap:
page_zip_dir_add_slot(cursor->block, index, mtr); page_zip_dir_add_slot(cursor->block, index, mtr);
} }
/* next record after current before the insertion */
const rec_t *next_rec = page_rec_get_next_low(cursor->rec, TRUE);
if (UNIV_UNLIKELY(!next_rec ||
rec_get_status(next_rec) == REC_STATUS_INFIMUM ||
rec_get_status(cursor->rec) > REC_STATUS_INFIMUM))
return nullptr;
/* 3. Create the record */ /* 3. Create the record */
byte *insert_rec= rec_copy(insert_buf, rec, offsets); byte *insert_rec= rec_copy(insert_buf, rec, offsets);
rec_offs_make_valid(insert_rec, index, page_is_leaf(page), offsets); rec_offs_make_valid(insert_rec, index, page_is_leaf(page), offsets);
/* 4. Insert the record in the linked list of records */ /* 4. Insert the record in the linked list of records */
ut_ad(cursor->rec != insert_rec); ut_ad(cursor->rec != insert_rec);
/* next record after current before the insertion */
const rec_t* next_rec = page_rec_get_next_low(cursor->rec, TRUE);
ut_ad(rec_get_status(cursor->rec) <= REC_STATUS_INFIMUM);
ut_ad(rec_get_status(insert_rec) < REC_STATUS_INFIMUM); ut_ad(rec_get_status(insert_rec) < REC_STATUS_INFIMUM);
ut_ad(rec_get_status(next_rec) != REC_STATUS_INFIMUM);
mach_write_to_2(insert_rec - REC_NEXT, static_cast<uint16_t> mach_write_to_2(insert_rec - REC_NEXT, static_cast<uint16_t>
(next_rec - insert_rec)); (next_rec - insert_rec));
@ -2037,8 +2132,9 @@ inc_dir:
/* 7. It remains to update the owner record. */ /* 7. It remains to update the owner record. */
ulint n_owned; ulint n_owned;
while (!(n_owned = rec_get_n_owned_new(next_rec))) while (!(n_owned= rec_get_n_owned_new(next_rec)))
next_rec= page_rec_get_next_low(next_rec, true); if (!(next_rec= page_rec_get_next_low(next_rec, true)))
return nullptr;
rec_set_bit_field_1(const_cast<rec_t*>(next_rec), n_owned + 1, rec_set_bit_field_1(const_cast<rec_t*>(next_rec), n_owned + 1,
REC_NEW_N_OWNED, REC_N_OWNED_MASK, REC_N_OWNED_SHIFT); REC_NEW_N_OWNED, REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);
@ -2052,7 +2148,10 @@ inc_dir:
{ {
const ulint owner= page_dir_find_owner_slot(next_rec); const ulint owner= page_dir_find_owner_slot(next_rec);
if (UNIV_UNLIKELY(owner == ULINT_UNDEFINED)) if (UNIV_UNLIKELY(owner == ULINT_UNDEFINED))
{
page_cur_directory_corrupted(*cursor->block, *index);
return nullptr; return nullptr;
}
page_zip_dir_split_slot(cursor->block, owner, mtr); page_zip_dir_split_slot(cursor->block, owner, mtr);
} }
@ -2185,8 +2284,8 @@ page_cur_delete_rec(
However, this could also be a call in However, this could also be a call in
btr_cur_pessimistic_update() to delete the only btr_cur_pessimistic_update() to delete the only
record in the page and to insert another one. */ record in the page and to insert another one. */
page_cur_move_to_next(cursor); ut_ad(page_rec_is_supremum(page_rec_get_next(cursor->rec)));
ut_ad(page_cur_is_after_last(cursor)); page_cur_set_after_last(block, cursor);
page_create_empty(page_cur_get_block(cursor), page_create_empty(page_cur_get_block(cursor),
const_cast<dict_index_t*>(index), mtr); const_cast<dict_index_t*>(index), mtr);
return; return;
@ -2197,6 +2296,7 @@ page_cur_delete_rec(
if (UNIV_UNLIKELY(!cur_slot_no || cur_slot_no == ULINT_UNDEFINED)) { if (UNIV_UNLIKELY(!cur_slot_no || cur_slot_no == ULINT_UNDEFINED)) {
/* Avoid crashing due to a corrupted page. */ /* Avoid crashing due to a corrupted page. */
page_cur_directory_corrupted(*block, *index);
return; return;
} }
@ -2220,11 +2320,16 @@ page_cur_delete_rec(
while (current_rec != rec) { while (current_rec != rec) {
prev_rec = rec; prev_rec = rec;
rec = page_rec_get_next(rec); if (!(rec = page_rec_get_next(rec))) {
/* Avoid crashing due to a corrupted page. */
return;
}
} }
page_cur_move_to_next(cursor); if (!(next_rec = page_cur_move_to_next(cursor))) {
next_rec = cursor->rec; /* Avoid crashing due to a corrupted page. */
return;
}
/* Remove the record from the linked list of records */ /* Remove the record from the linked list of records */
/* If the deleted record is pointed to by a dir slot, update the /* If the deleted record is pointed to by a dir slot, update the
@ -2546,7 +2651,7 @@ inc_dir:
mach_write_to_2(page_n_recs, mach_read_from_2(page_n_recs) + 1); mach_write_to_2(page_n_recs, mach_read_from_2(page_n_recs) + 1);
if (UNIV_UNLIKELY(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED)) if (UNIV_UNLIKELY(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED))
page_dir_split_slot(block, owner_slot); return page_dir_split_slot(block, owner_slot);
ut_ad(page_simple_validate_old(page)); ut_ad(page_simple_validate_old(page));
return false; return false;
} }
@ -2771,7 +2876,7 @@ inc_dir:
mach_write_to_2(page_n_recs, mach_read_from_2(page_n_recs) + 1); mach_write_to_2(page_n_recs, mach_read_from_2(page_n_recs) + 1);
if (UNIV_UNLIKELY(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED)) if (UNIV_UNLIKELY(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED))
page_dir_split_slot(block, owner_slot); return page_dir_split_slot(block, owner_slot);
ut_ad(page_simple_validate_new(page)); ut_ad(page_simple_validate_new(page));
return false; return false;
} }

View File

@ -99,43 +99,25 @@ page_dir_find_owner_slot(
if (page_is_comp(page)) { if (page_is_comp(page)) {
while (rec_get_n_owned_new(r) == 0) { while (rec_get_n_owned_new(r) == 0) {
r = rec_get_next_ptr_const(r, TRUE); r = page_rec_get_next_low(r, true);
ut_ad(r >= page + PAGE_NEW_SUPREMUM); if (UNIV_UNLIKELY(r < page + PAGE_NEW_SUPREMUM
ut_ad(r < page + (srv_page_size - PAGE_DIR)); || r >= slot)) {
return ULINT_UNDEFINED;
}
} }
} else { } else {
while (rec_get_n_owned_old(r) == 0) { while (rec_get_n_owned_old(r) == 0) {
r = rec_get_next_ptr_const(r, FALSE); r = page_rec_get_next_low(r, false);
ut_ad(r >= page + PAGE_OLD_SUPREMUM); if (UNIV_UNLIKELY(r < page + PAGE_OLD_SUPREMUM
ut_ad(r < page + (srv_page_size - PAGE_DIR)); || r >= slot)) {
return ULINT_UNDEFINED;
}
} }
} }
uint16 rec_offs_bytes = mach_encode_2(ulint(r - page)); while (UNIV_LIKELY(*(uint16*) slot
!= mach_encode_2(ulint(r - page)))) {
while (UNIV_LIKELY(*(uint16*) slot != rec_offs_bytes)) {
if (UNIV_UNLIKELY(slot == first_slot)) { if (UNIV_UNLIKELY(slot == first_slot)) {
ib::error() << "Probable data corruption on page "
<< page_get_page_no(page)
<< ". Original record on that page;";
if (page_is_comp(page)) {
fputs("(compact record)", stderr);
} else {
rec_print_old(stderr, rec);
}
ib::error() << "Cannot find the dir slot for this"
" record on that page;";
if (page_is_comp(page)) {
fputs("(compact record)", stderr);
} else {
rec_print_old(stderr, page
+ mach_decode_2(rec_offs_bytes));
}
return ULINT_UNDEFINED; return ULINT_UNDEFINED;
} }
@ -478,9 +460,8 @@ page_copy_rec_list_end_no_locks(
page_cur_position(rec, block, &cur1); page_cur_position(rec, block, &cur1);
if (page_cur_is_before_first(&cur1)) { if (page_cur_is_before_first(&cur1) && !page_cur_move_to_next(&cur1)) {
return DB_CORRUPTION;
page_cur_move_to_next(&cur1);
} }
if (UNIV_UNLIKELY(page_is_comp(new_page) != page_rec_is_comp(rec) if (UNIV_UNLIKELY(page_is_comp(new_page) != page_rec_is_comp(rec)
@ -504,12 +485,10 @@ page_copy_rec_list_end_no_locks(
ULINT_UNDEFINED, &heap); ULINT_UNDEFINED, &heap);
ins_rec = page_cur_insert_rec_low(&cur2, index, ins_rec = page_cur_insert_rec_low(&cur2, index,
cur1.rec, offsets, mtr); cur1.rec, offsets, mtr);
if (UNIV_UNLIKELY(!ins_rec)) { if (UNIV_UNLIKELY(!ins_rec || !page_cur_move_to_next(&cur1))) {
err = DB_CORRUPTION; err = DB_CORRUPTION;
break; break;
} }
page_cur_move_to_next(&cur1);
ut_ad(!(rec_get_info_bits(cur1.rec, page_is_comp(new_page)) ut_ad(!(rec_get_info_bits(cur1.rec, page_is_comp(new_page))
& REC_INFO_MIN_REC_FLAG)); & REC_INFO_MIN_REC_FLAG));
cur2.rec = ins_rec; cur2.rec = ins_rec;
@ -550,10 +529,13 @@ page_copy_rec_list_end(
rec_t* ret = page_rec_get_next( rec_t* ret = page_rec_get_next(
page_get_infimum_rec(new_page)); page_get_infimum_rec(new_page));
ulint num_moved = 0; ulint num_moved = 0;
rtr_rec_move_t* rec_move = NULL;
mem_heap_t* heap = NULL;
ut_ad(page_align(rec) == page); ut_ad(page_align(rec) == page);
if (UNIV_UNLIKELY(!ret)) {
*err = DB_CORRUPTION;
return nullptr;
}
#ifdef UNIV_ZIP_DEBUG #ifdef UNIV_ZIP_DEBUG
if (new_page_zip) { if (new_page_zip) {
page_zip_des_t* page_zip = buf_block_get_page_zip(block); page_zip_des_t* page_zip = buf_block_get_page_zip(block);
@ -579,15 +561,15 @@ page_copy_rec_list_end(
alignas(2) byte h[PAGE_N_DIRECTION + 2 - PAGE_LAST_INSERT]; alignas(2) byte h[PAGE_N_DIRECTION + 2 - PAGE_LAST_INSERT];
memcpy_aligned<2>(h, PAGE_HEADER + PAGE_LAST_INSERT + new_page, memcpy_aligned<2>(h, PAGE_HEADER + PAGE_LAST_INSERT + new_page,
sizeof h); sizeof h);
mem_heap_t* heap = nullptr;
rtr_rec_move_t* rec_move = nullptr;
if (index->is_spatial()) { if (index->is_spatial()) {
ulint max_to_move = page_get_n_recs( ulint max_to_move = page_get_n_recs(
buf_block_get_frame(block)); buf_block_get_frame(block));
heap = mem_heap_create(256); heap = mem_heap_create(256);
rec_move= static_cast<rtr_rec_move_t*>(
rec_move = static_cast<rtr_rec_move_t*>(
mem_heap_alloc(heap, max_to_move * sizeof *rec_move)); mem_heap_alloc(heap, max_to_move * sizeof *rec_move));
/* For spatial index, we need to insert recs one by one /* For spatial index, we need to insert recs one by one
to keep recs ordered. */ to keep recs ordered. */
*err = rtr_page_copy_rec_list_end_no_locks(new_block, *err = rtr_page_copy_rec_list_end_no_locks(new_block,
@ -600,6 +582,10 @@ page_copy_rec_list_end(
*err = page_copy_rec_list_end_no_locks(new_block, block, rec, *err = page_copy_rec_list_end_no_locks(new_block, block, rec,
index, mtr); index, mtr);
if (UNIV_UNLIKELY(*err != DB_SUCCESS)) { if (UNIV_UNLIKELY(*err != DB_SUCCESS)) {
err_exit:
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return nullptr; return nullptr;
} }
if (was_empty) { if (was_empty) {
@ -640,7 +626,11 @@ page_copy_rec_list_end(
have at least one predecessor (the predefined have at least one predecessor (the predefined
infimum record, or a freshly copied record infimum record, or a freshly copied record
that is smaller than "ret"). */ that is smaller than "ret"). */
ut_a(ret_pos > 0); if (UNIV_UNLIKELY(!ret_pos
|| ret_pos == ULINT_UNDEFINED)) {
*err = DB_CORRUPTION;
goto err_exit;
}
*err = page_zip_reorganize(new_block, index, *err = page_zip_reorganize(new_block, index,
page_zip_level, mtr); page_zip_level, mtr);
@ -653,14 +643,12 @@ page_copy_rec_list_end(
ut_ad(page_validate(new_page, index)); ut_ad(page_validate(new_page, index));
/* fall through */ /* fall through */
default: default:
if (heap) { goto err_exit;
mem_heap_free(heap);
}
return nullptr;
case DB_SUCCESS: case DB_SUCCESS:
/* The page was reorganized: /* The page was reorganized:
Seek to ret_pos. */ Seek to ret_pos. */
ret = page_rec_get_nth(new_page, ret_pos); ret = page_rec_get_nth(new_page, ret_pos);
ut_ad(ret);
} }
} }
} }
@ -668,13 +656,13 @@ page_copy_rec_list_end(
/* Update the lock table and possible hash index */ /* Update the lock table and possible hash index */
if (!index->has_locking()) { if (!index->has_locking()) {
} else if (rec_move && dict_index_is_spatial(index)) { } else if (UNIV_LIKELY_NULL(rec_move)) {
lock_rtr_move_rec_list(new_block, block, rec_move, num_moved); lock_rtr_move_rec_list(new_block, block, rec_move, num_moved);
} else { } else {
lock_move_rec_list_end(new_block, block, rec); lock_move_rec_list_end(new_block, block, rec);
} }
if (heap) { if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap); mem_heap_free(heap);
} }
@ -721,8 +709,9 @@ page_copy_rec_list_start(
rec_offs_init(offsets_); rec_offs_init(offsets_);
if (UNIV_UNLIKELY(!ret)) { if (UNIV_UNLIKELY(!ret)) {
corrupted:
*err = DB_CORRUPTION; *err = DB_CORRUPTION;
return ret; return nullptr;
} }
/* Here, "ret" may be pointing to a user record or the /* Here, "ret" may be pointing to a user record or the
@ -733,15 +722,17 @@ page_copy_rec_list_start(
return(ret); return(ret);
} }
page_cur_set_before_first(block, &cur1);
if (UNIV_UNLIKELY(!page_cur_move_to_next(&cur1))) {
goto corrupted;
}
mtr_log_t log_mode = MTR_LOG_NONE; mtr_log_t log_mode = MTR_LOG_NONE;
if (new_page_zip) { if (new_page_zip) {
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE); log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
} }
page_cur_set_before_first(block, &cur1);
page_cur_move_to_next(&cur1);
page_cur_position(ret, new_block, &cur2); page_cur_position(ret, new_block, &cur2);
const ulint n_core = page_rec_is_leaf(rec) ? index->n_core_fields : 0; const ulint n_core = page_rec_is_leaf(rec) ? index->n_core_fields : 0;
@ -775,12 +766,12 @@ page_copy_rec_list_start(
cur2.rec = page_cur_insert_rec_low(&cur2, index, cur2.rec = page_cur_insert_rec_low(&cur2, index,
cur1.rec, offsets, cur1.rec, offsets,
mtr); mtr);
if (UNIV_UNLIKELY(!cur2.rec)) { if (UNIV_UNLIKELY(!cur2.rec
|| !page_cur_move_to_next(&cur1))) {
*err = DB_CORRUPTION; *err = DB_CORRUPTION;
return nullptr; return nullptr;
} }
page_cur_move_to_next(&cur1);
ut_ad(!(rec_get_info_bits(cur1.rec, ut_ad(!(rec_get_info_bits(cur1.rec,
page_is_comp(new_page)) page_is_comp(new_page))
& REC_INFO_MIN_REC_FLAG)); & REC_INFO_MIN_REC_FLAG));
@ -821,11 +812,17 @@ zip_reorganize:
the predefined infimum record, then it would the predefined infimum record, then it would
still be the infimum, and we would have still be the infimum, and we would have
ret_pos == 0. */ ret_pos == 0. */
if (UNIV_UNLIKELY(!ret_pos
|| ret_pos == ULINT_UNDEFINED)) {
*err = DB_CORRUPTION;
return nullptr;
}
*err = page_zip_reorganize(new_block, index, *err = page_zip_reorganize(new_block, index,
page_zip_level, mtr); page_zip_level, mtr);
switch (*err) { switch (*err) {
case DB_SUCCESS: case DB_SUCCESS:
ret = page_rec_get_nth(new_page, ret_pos); ret = page_rec_get_nth(new_page, ret_pos);
ut_ad(ret);
break; break;
case DB_FAIL: case DB_FAIL:
if (UNIV_UNLIKELY if (UNIV_UNLIKELY
@ -936,7 +933,7 @@ page_delete_rec_list_end(
page_cur_position(rec, block, &cur); page_cur_position(rec, block, &cur);
offsets= rec_get_offsets(rec, index, offsets, n_core, offsets= rec_get_offsets(rec, index, offsets, n_core,
ULINT_UNDEFINED, &heap); ULINT_UNDEFINED, &heap);
rec= rec_get_next_ptr(rec, TRUE); rec= const_cast<rec_t*>(page_rec_get_next_low(rec, true));
#ifdef UNIV_ZIP_DEBUG #ifdef UNIV_ZIP_DEBUG
ut_a(page_zip_validate(&block->page.zip, page, index)); ut_a(page_zip_validate(&block->page.zip, page, index));
#endif /* UNIV_ZIP_DEBUG */ #endif /* UNIV_ZIP_DEBUG */
@ -981,12 +978,15 @@ page_delete_rec_list_end(
if (scrub) if (scrub)
mtr->memset(block, page_offset(rec2), rec_offs_data_size(offsets), 0); mtr->memset(block, page_offset(rec2), rec_offs_data_size(offsets), 0);
rec2 = page_rec_get_next(rec2); rec2= page_rec_get_next(rec2);
} }
while (!page_rec_is_supremum(rec2)); while (rec2 && !page_rec_is_supremum(rec2));
if (UNIV_LIKELY_NULL(heap)) if (UNIV_LIKELY_NULL(heap))
mem_heap_free(heap); mem_heap_free(heap);
if (UNIV_UNLIKELY(!rec))
return DB_CORRUPTION;
} }
ut_ad(size < srv_page_size); ut_ad(size < srv_page_size);
@ -1000,13 +1000,15 @@ page_delete_rec_list_end(
while (!(n_owned= rec_get_n_owned_new(owner_rec))) while (!(n_owned= rec_get_n_owned_new(owner_rec)))
{ {
count++; count++;
owner_rec= rec_get_next_ptr_const(owner_rec, TRUE); if (!(owner_rec= page_rec_get_next_low(owner_rec, true)))
return DB_CORRUPTION;
} }
else else
while (!(n_owned= rec_get_n_owned_old(owner_rec))) while (!(n_owned= rec_get_n_owned_old(owner_rec)))
{ {
count++; count++;
owner_rec= rec_get_next_ptr_const(owner_rec, FALSE); if (!(owner_rec= page_rec_get_next_low(owner_rec, false)))
return DB_CORRUPTION;
} }
ut_ad(n_owned > count); ut_ad(n_owned > count);
@ -1133,7 +1135,10 @@ page_delete_rec_list_start(
} }
page_cur_set_before_first(block, &cur1); page_cur_set_before_first(block, &cur1);
page_cur_move_to_next(&cur1); if (UNIV_UNLIKELY(!page_cur_move_to_next(&cur1))) {
ut_ad("corrupted page" == 0);
return;
}
const ulint n_core = page_rec_is_leaf(rec) const ulint n_core = page_rec_is_leaf(rec)
? index->n_core_fields : 0; ? index->n_core_fields : 0;
@ -1153,7 +1158,8 @@ page_delete_rec_list_start(
/************************************************************//** /************************************************************//**
Returns the nth record of the record list. Returns the nth record of the record list.
This is the inverse function of page_rec_get_n_recs_before(). This is the inverse function of page_rec_get_n_recs_before().
@return nth record */ @return nth record
@retval nullptr on corrupted page */
const rec_t* const rec_t*
page_rec_get_nth_const( page_rec_get_nth_const(
/*===================*/ /*===================*/
@ -1172,7 +1178,6 @@ page_rec_get_nth_const(
ut_ad(nth < srv_page_size / (REC_N_NEW_EXTRA_BYTES + 1)); ut_ad(nth < srv_page_size / (REC_N_NEW_EXTRA_BYTES + 1));
for (i = 0;; i++) { for (i = 0;; i++) {
slot = page_dir_get_nth_slot(page, i); slot = page_dir_get_nth_slot(page, i);
n_owned = page_dir_slot_get_n_owned(slot); n_owned = page_dir_slot_get_n_owned(slot);
@ -1183,87 +1188,154 @@ page_rec_get_nth_const(
} }
} }
ut_ad(i > 0); if (UNIV_UNLIKELY(!i)) {
slot = page_dir_get_nth_slot(page, i - 1); return nullptr;
rec = page_dir_slot_get_rec(slot); }
rec = page_dir_slot_get_rec(slot + 2);
if (page_is_comp(page)) { if (page_is_comp(page)) {
do { do {
rec = page_rec_get_next_low(rec, TRUE); rec = page_rec_get_next_low(rec, TRUE);
ut_ad(rec); } while (rec && nth--);
} while (nth--);
} else { } else {
do { do {
rec = page_rec_get_next_low(rec, FALSE); rec = page_rec_get_next_low(rec, FALSE);
ut_ad(rec); } while (rec && nth--);
} while (nth--);
} }
return(rec); return(rec);
} }
/***************************************************************//**
Returns the number of records before the given record in chain. /************************************************************//**
The number includes infimum and supremum records. Gets the pointer to the previous record.
@return number of records */ @return pointer to previous record
ulint @retval nullptr on error */
page_rec_get_n_recs_before( const rec_t*
/*=======================*/ page_rec_get_prev_const(
const rec_t* rec) /*!< in: the physical record */ /*====================*/
const rec_t* rec) /*!< in: pointer to record, must not be page
infimum */
{ {
const page_dir_slot_t* slot; const rec_t* rec2;
const rec_t* slot_rec; const rec_t* prev_rec = NULL;
const page_t* page;
ulint i;
lint n = 0;
ut_ad(page_rec_check(rec)); ut_ad(page_rec_check(rec));
page = page_align(rec); const page_t* const page = page_align(rec);
if (page_is_comp(page)) {
while (rec_get_n_owned_new(rec) == 0) {
rec = rec_get_next_ptr_const(rec, TRUE); ut_ad(!page_rec_is_infimum(rec));
n--;
ulint slot_no = page_dir_find_owner_slot(rec);
if (UNIV_UNLIKELY(!slot_no || slot_no == ULINT_UNDEFINED)) {
return nullptr;
} }
for (i = 0; ; i++) { const page_dir_slot_t* slot = page_dir_get_nth_slot(page, slot_no - 1);
slot = page_dir_get_nth_slot(page, i);
slot_rec = page_dir_slot_get_rec(slot);
n += lint(rec_get_n_owned_new(slot_rec)); if (UNIV_UNLIKELY(!(rec2 = page_dir_slot_get_rec_validate(slot)))) {
return nullptr;
if (rec == slot_rec) { }
if (page_is_comp(page)) {
while (rec2 && rec != rec2) {
prev_rec = rec2;
ulint offs = rec_get_next_offs(rec2, TRUE);
if (offs < PAGE_NEW_INFIMUM
|| offs > page_header_get_field(page,
PAGE_HEAP_TOP)) {
return nullptr;
}
rec2 = page + offs;
}
switch (rec_get_status(prev_rec)) {
case REC_STATUS_INSTANT:
case REC_STATUS_ORDINARY:
if (!page_is_leaf(page)) {
return nullptr;
}
break;
case REC_STATUS_INFIMUM:
break;
case REC_STATUS_NODE_PTR:
if (!page_is_leaf(page)) {
break; break;
} }
/* fall through */
default:
return nullptr;
} }
} else { } else {
while (rec_get_n_owned_old(rec) == 0) { while (rec2 && rec != rec2) {
prev_rec = rec2;
rec = rec_get_next_ptr_const(rec, FALSE); ulint offs = rec_get_next_offs(rec2, FALSE);
n--; if (offs < PAGE_OLD_INFIMUM
|| offs > page_header_get_field(page,
PAGE_HEAP_TOP)) {
return nullptr;
}
rec2 = page + offs;
}
} }
for (i = 0; ; i++) { return(prev_rec);
slot = page_dir_get_nth_slot(page, i); }
slot_rec = page_dir_slot_get_rec(slot);
n += lint(rec_get_n_owned_old(slot_rec)); /** Return the number of preceding records in an index page.
@param rec index record
@return number of preceding records, including the infimum pseudo-record
@retval ULINT_UNDEFINED on corrupted page */
ulint page_rec_get_n_recs_before(const rec_t *rec)
{
const page_t *const page= page_align(rec);
const page_dir_slot_t *slot = page_dir_get_nth_slot(page, 0);
const page_dir_slot_t *const end_slot= slot - 2 * page_dir_get_n_slots(page);
if (rec == slot_rec) { lint n= 0;
ut_ad(page_rec_check(rec));
if (page_is_comp(page))
{
for (; rec_get_n_owned_new(rec) == 0; n--)
if (UNIV_UNLIKELY(!(rec= page_rec_get_next_low(rec, true))))
return ULINT_UNDEFINED;
do
{
const rec_t *slot_rec= page_dir_slot_get_rec_validate(slot);
if (UNIV_UNLIKELY(!slot_rec))
break; break;
n+= lint(rec_get_n_owned_new(slot_rec));
if (rec == slot_rec)
goto found;
} }
while ((slot-= 2) > end_slot);
} }
else
{
for (; rec_get_n_owned_old(rec) == 0; n--)
if (UNIV_UNLIKELY(!(rec= page_rec_get_next_low(rec, false))))
return ULINT_UNDEFINED;
do
{
const rec_t *slot_rec= page_dir_slot_get_rec_validate(slot);
if (UNIV_UNLIKELY(!slot_rec))
break;
n+= lint(rec_get_n_owned_old(slot_rec));
if (rec == slot_rec)
goto found;
}
while ((slot-= 2) > end_slot);
} }
n--; return ULINT_UNDEFINED;
found:
ut_ad(n >= 0); return --n < 0 ? ULINT_UNDEFINED : ulint(n);
ut_ad((ulong) n < srv_page_size / (REC_N_NEW_EXTRA_BYTES + 1));
return((ulint) n);
} }
/************************************************************//** /************************************************************//**
@ -1783,15 +1855,14 @@ page_simple_validate_new(
slot_no = 0; slot_no = 0;
slot = page_dir_get_nth_slot(page, slot_no); slot = page_dir_get_nth_slot(page, slot_no);
rec = page_get_infimum_rec(page); rec = page + PAGE_NEW_INFIMUM;
for (;;) { for (;;) {
if (UNIV_UNLIKELY(rec > rec_heap_top)) { if (UNIV_UNLIKELY(rec < page + PAGE_NEW_INFIMUM
|| rec > rec_heap_top)) {
ib::error() << "Record " << page_offset(rec) ib::error() << "Record " << page_offset(rec)
<< " is above rec heap top " << " is out of bounds: "
<< page_offset(rec_heap_top); << page_offset(rec_heap_top);
goto func_exit; goto func_exit;
} }
@ -2247,14 +2318,21 @@ wrong_page_type:
} }
next_rec: next_rec:
if (page_rec_is_supremum(rec)) { old_rec = rec;
rec = page_rec_get_next_const(rec);
if (UNIV_UNLIKELY(!rec != page_rec_is_supremum(old_rec))) {
ib::error() << "supremum is not last record: " << offs;
ret = FALSE;
}
if (!rec) {
rec = old_rec; /* supremum */
break; break;
} }
count++; count++;
own_count++; own_count++;
old_rec = rec;
rec = page_rec_get_next_const(rec);
if (page_rec_is_infimum(old_rec) if (page_rec_is_infimum(old_rec)
&& page_rec_is_user_rec(rec)) { && page_rec_is_user_rec(rec)) {
@ -2409,37 +2487,36 @@ page_find_rec_with_heap_no(
@param[in] page index tree leaf page @param[in] page index tree leaf page
@return the last record, not delete-marked @return the last record, not delete-marked
@retval infimum record if all records are delete-marked */ @retval infimum record if all records are delete-marked */
const rec_t* const rec_t *page_find_rec_max_not_deleted(const page_t *page)
page_find_rec_max_not_deleted(
const page_t* page)
{ {
const rec_t* rec = page_get_infimum_rec(page);
const rec_t* prev_rec = NULL; // remove warning
/* Because the page infimum is never delete-marked
and never the metadata pseudo-record (MIN_REC_FLAG)),
prev_rec will always be assigned to it first. */
ut_ad(!rec_get_info_bits(rec, page_rec_is_comp(rec)));
ut_ad(page_is_leaf(page)); ut_ad(page_is_leaf(page));
if (page_is_comp(page)) { if (page_is_comp(page))
do { {
if (!(rec[-REC_NEW_INFO_BITS] const rec_t *rec= page + PAGE_NEW_INFIMUM;
& (REC_INFO_DELETED_FLAG const rec_t *prev_rec= rec;
| REC_INFO_MIN_REC_FLAG))) { do
prev_rec = rec; {
} if (!(rec[-REC_NEW_INFO_BITS] &
rec = page_rec_get_next_low(rec, true); (REC_INFO_DELETED_FLAG | REC_INFO_MIN_REC_FLAG)))
prev_rec= rec;
if (!(rec= page_rec_get_next_low(rec, true)))
return page + PAGE_NEW_INFIMUM;
} while (rec != page + PAGE_NEW_SUPREMUM); } while (rec != page + PAGE_NEW_SUPREMUM);
} else { return prev_rec;
do {
if (!(rec[-REC_OLD_INFO_BITS]
& (REC_INFO_DELETED_FLAG
| REC_INFO_MIN_REC_FLAG))) {
prev_rec = rec;
} }
rec = page_rec_get_next_low(rec, false); else
{
const rec_t *rec= page + PAGE_OLD_INFIMUM;
const rec_t *prev_rec= rec;
do
{
if (!(rec[-REC_OLD_INFO_BITS] &
(REC_INFO_DELETED_FLAG | REC_INFO_MIN_REC_FLAG)))
prev_rec= rec;
if (!(rec= page_rec_get_next_low(rec, false)))
return page + PAGE_OLD_INFIMUM;
} while (rec != page + PAGE_OLD_SUPREMUM); } while (rec != page + PAGE_OLD_SUPREMUM);
return prev_rec;
} }
return(prev_rec);
} }

View File

@ -864,6 +864,9 @@ rec_get_offsets_func(
ut_ad(!n_core); ut_ad(!n_core);
n = dict_index_get_n_unique_in_tree_nonleaf(index) + 1; n = dict_index_get_n_unique_in_tree_nonleaf(index) + 1;
break; break;
default:
ut_ad("corrupted record header" == 0);
/* fall through */
case REC_STATUS_INFIMUM: case REC_STATUS_INFIMUM:
case REC_STATUS_SUPREMUM: case REC_STATUS_SUPREMUM:
/* infimum or supremum record */ /* infimum or supremum record */
@ -874,9 +877,6 @@ rec_get_offsets_func(
: PAGE_HEAP_NO_SUPREMUM)); : PAGE_HEAP_NO_SUPREMUM));
n = 1; n = 1;
break; break;
default:
ut_error;
return(NULL);
} }
} else { } else {
n = rec_get_n_fields_old(rec); n = rec_get_n_fields_old(rec);

View File

@ -257,19 +257,17 @@ public:
} }
/** Position the cursor on the first user record. */ /** Position the cursor on the first user record. */
void open(buf_block_t* block) UNIV_NOTHROW rec_t* open(buf_block_t* block) noexcept
MY_ATTRIBUTE((warn_unused_result))
{ {
page_cur_set_before_first(block, &m_cur); page_cur_set_before_first(block, &m_cur);
return next();
if (!end()) {
next();
}
} }
/** Move to the next record. */ /** Move to the next record. */
void next() UNIV_NOTHROW rec_t* next() noexcept MY_ATTRIBUTE((warn_unused_result))
{ {
page_cur_move_to_next(&m_cur); return page_cur_move_to_next(&m_cur);
} }
/** /**
@ -1532,6 +1530,8 @@ inline bool IndexPurge::open() noexcept
return false; return false;
rec_t *rec= page_rec_get_next(btr_pcur_get_rec(&m_pcur)); rec_t *rec= page_rec_get_next(btr_pcur_get_rec(&m_pcur));
if (!rec)
return false;
if (rec_is_metadata(rec, *m_index)) if (rec_is_metadata(rec, *m_index))
/* Skip the metadata pseudo-record. */ /* Skip the metadata pseudo-record. */
btr_pcur_get_page_cur(&m_pcur)->rec= rec; btr_pcur_get_page_cur(&m_pcur)->rec= rec;
@ -1543,7 +1543,9 @@ Position the cursor on the next record.
@return DB_SUCCESS or error code */ @return DB_SUCCESS or error code */
dberr_t IndexPurge::next() noexcept dberr_t IndexPurge::next() noexcept
{ {
btr_pcur_move_to_next_on_page(&m_pcur); if (UNIV_UNLIKELY(!btr_pcur_move_to_next_on_page(&m_pcur))) {
return DB_CORRUPTION;
}
/* When switching pages, commit the mini-transaction /* When switching pages, commit the mini-transaction
in order to release the latch on the old page. */ in order to release the latch on the old page. */
@ -1581,8 +1583,8 @@ dberr_t IndexPurge::next() noexcept
&m_mtr)) { &m_mtr)) {
return err; return err;
} }
} else { } else if (!btr_pcur_move_to_next_on_page(&m_pcur)) {
btr_pcur_move_to_next_on_page(&m_pcur); return DB_CORRUPTION;
} }
} while (!btr_pcur_is_on_user_rec(&m_pcur)); } while (!btr_pcur_is_on_user_rec(&m_pcur));
@ -1799,7 +1801,9 @@ PageConverter::update_records(
/* This will also position the cursor on the first user record. */ /* This will also position the cursor on the first user record. */
m_rec_iter.open(block); if (!m_rec_iter.open(block)) {
return DB_CORRUPTION;
}
while (!m_rec_iter.end()) { while (!m_rec_iter.end()) {
rec_t* rec = m_rec_iter.current(); rec_t* rec = m_rec_iter.current();
@ -1830,17 +1834,19 @@ PageConverter::update_records(
optimistic delete. */ optimistic delete. */
if (deleted) { if (deleted) {
++m_index->m_stats.m_n_deleted;
/* A successful purge will move the cursor to the /* A successful purge will move the cursor to the
next record. */ next record. */
if (!purge()) { if (purge()) {
m_rec_iter.next(); continue;
} }
++m_index->m_stats.m_n_deleted;
} else { } else {
++m_index->m_stats.m_n_rows; ++m_index->m_stats.m_n_rows;
m_rec_iter.next(); }
if (!m_rec_iter.next()) {
return DB_CORRUPTION;
} }
} }
@ -3181,6 +3187,8 @@ static dberr_t handle_instant_metadata(dict_table_t *table,
while (btr_page_get_level(page.get()) != 0) while (btr_page_get_level(page.get()) != 0)
{ {
const rec_t *rec= page_rec_get_next(page_get_infimum_rec(page.get())); const rec_t *rec= page_rec_get_next(page_get_infimum_rec(page.get()));
if (!rec)
return DB_CORRUPTION;
/* Relax the assertion in rec_init_offsets(). */ /* Relax the assertion in rec_init_offsets(). */
ut_ad(!index->in_instant_init); ut_ad(!index->in_instant_init);
@ -3205,18 +3213,22 @@ static dberr_t handle_instant_metadata(dict_table_t *table,
return err; return err;
} }
const auto *rec= page_rec_get_next(page_get_infimum_rec(page.get())); const auto *rec= page_rec_get_next_const(page_get_infimum_rec(page.get()));
const auto comp= dict_table_is_comp(index->table); const auto comp= dict_table_is_comp(index->table);
const auto info_bits= rec_get_info_bits(rec, comp);
if (page_rec_is_supremum(rec) || !(info_bits & REC_INFO_MIN_REC_FLAG)) if (!rec || page_rec_is_supremum(rec))
{ {
corrupted_metadata:
ib::error() << "Table " << index->table->name ib::error() << "Table " << index->table->name
<< " is missing instant ALTER metadata"; << " is missing instant ALTER metadata";
index->table->corrupted= true; index->table->corrupted= true;
return DB_CORRUPTION; return DB_CORRUPTION;
} }
const auto info_bits= rec_get_info_bits(rec, comp);
if (!(info_bits & REC_INFO_MIN_REC_FLAG))
goto corrupted_metadata;
if ((info_bits & ~REC_INFO_DELETED_FLAG) != REC_INFO_MIN_REC_FLAG || if ((info_bits & ~REC_INFO_DELETED_FLAG) != REC_INFO_MIN_REC_FLAG ||
(comp && rec_get_status(rec) != REC_STATUS_INSTANT)) (comp && rec_get_status(rec) != REC_STATUS_INSTANT))
{ {

View File

@ -2229,7 +2229,9 @@ row_ins_duplicate_error_in_clust_online(
} }
} }
rec = page_rec_get_next_const(btr_cur_get_rec(cursor)); if (!(rec = page_rec_get_next_const(btr_cur_get_rec(cursor)))) {
return DB_CORRUPTION;
}
if (cursor->up_match >= n_uniq && !page_rec_is_supremum(rec)) { if (cursor->up_match >= n_uniq && !page_rec_is_supremum(rec)) {
*offsets = rec_get_offsets(rec, cursor->index, *offsets, *offsets = rec_get_offsets(rec, cursor->index, *offsets,
@ -2349,11 +2351,13 @@ duplicate:
} }
} }
err = DB_SUCCESS;
if (cursor->up_match >= n_unique) { if (cursor->up_match >= n_unique) {
rec = page_rec_get_next(btr_cur_get_rec(cursor)); rec = page_rec_get_next(btr_cur_get_rec(cursor));
if (!page_rec_is_supremum(rec)) { if (rec && !page_rec_is_supremum(rec)) {
offsets = rec_get_offsets(rec, cursor->index, offsets, offsets = rec_get_offsets(rec, cursor->index, offsets,
cursor->index->n_core_fields, cursor->index->n_core_fields,
ULINT_UNDEFINED, &heap); ULINT_UNDEFINED, &heap);
@ -2378,24 +2382,23 @@ duplicate:
} }
switch (err) { switch (err) {
case DB_SUCCESS_LOCKED_REC:
case DB_SUCCESS:
break;
default: default:
goto func_exit; break;
} case DB_SUCCESS_LOCKED_REC:
err = DB_SUCCESS;
/* fall through */
case DB_SUCCESS:
if (row_ins_dupl_error_with_rec( if (row_ins_dupl_error_with_rec(
rec, entry, cursor->index, offsets)) { rec, entry, cursor->index,
offsets)) {
goto duplicate; goto duplicate;
} }
} }
}
/* This should never happen */ /* This should never happen */
ut_error; err = DB_CORRUPTION;
} }
err = DB_SUCCESS;
func_exit: func_exit:
if (UNIV_LIKELY_NULL(heap)) { if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap); mem_heap_free(heap);

View File

@ -1971,10 +1971,14 @@ corrupted_metadata:
mem_heap_empty(row_heap); mem_heap_empty(row_heap);
page_cur_move_to_next(cur);
stage->n_pk_recs_inc(); stage->n_pk_recs_inc();
if (!page_cur_move_to_next(cur)) {
corrupted_rec:
err = DB_CORRUPTION;
goto err_exit;
}
if (page_cur_is_after_last(cur)) { if (page_cur_is_after_last(cur)) {
stage->inc(); stage->inc();
@ -2080,9 +2084,10 @@ end_of_index:
btr_leaf_page_release(page_cur_get_block(cur), btr_leaf_page_release(page_cur_get_block(cur),
BTR_SEARCH_LEAF, &mtr); BTR_SEARCH_LEAF, &mtr);
page_cur_set_before_first(block, cur); page_cur_set_before_first(block, cur);
page_cur_move_to_next(cur); if (!page_cur_move_to_next(cur)
|| page_cur_is_after_last(cur)) {
ut_ad(!page_cur_is_after_last(cur)); goto corrupted_rec;
}
} }
} }

View File

@ -1804,7 +1804,11 @@ rec_loop:
search result set, resulting in the phantom problem. */ search result set, resulting in the phantom problem. */
if (!node->read_view) { if (!node->read_view) {
rec_t* next_rec = page_rec_get_next(rec); const rec_t* next_rec = page_rec_get_next_const(rec);
if (UNIV_UNLIKELY(!next_rec)) {
err = DB_CORRUPTION;
goto lock_wait_or_error;
}
unsigned lock_type; unsigned lock_type;
offsets = rec_get_offsets(next_rec, index, offsets, offsets = rec_get_offsets(next_rec, index, offsets,
@ -3425,11 +3429,13 @@ Row_sel_get_clust_rec_for_mysql::operator()(
rec, sec_index, true, rec, sec_index, true,
sec_index->n_fields, heap); sec_index->n_fields, heap);
page_cur_t page_cursor; page_cur_t page_cursor;
ulint up_match = 0, low_match = 0;
ulint low_match = page_cur_search( ut_ad(!page_cur_search_with_match(block, sec_index,
block, sec_index, tuple, tuple, PAGE_CUR_LE,
PAGE_CUR_LE, &page_cursor); &up_match,
&low_match,
&page_cursor,
nullptr));
ut_ad(low_match < dtuple_get_n_fields_cmp(tuple)); ut_ad(low_match < dtuple_get_n_fields_cmp(tuple));
mem_heap_free(heap); mem_heap_free(heap);
clust_rec = NULL; clust_rec = NULL;
@ -4770,6 +4776,7 @@ wait_table_again:
pcur, 0, &mtr); pcur, 0, &mtr);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
page_corrupted:
rec = NULL; rec = NULL;
goto page_read_error; goto page_read_error;
} }
@ -4787,6 +4794,10 @@ wait_table_again:
/* Try to place a gap lock on the next index record /* Try to place a gap lock on the next index record
to prevent phantoms in ORDER BY ... DESC queries */ to prevent phantoms in ORDER BY ... DESC queries */
const rec_t* next_rec = page_rec_get_next_const(rec); const rec_t* next_rec = page_rec_get_next_const(rec);
if (UNIV_UNLIKELY(!next_rec)) {
err = DB_CORRUPTION;
goto page_corrupted;
}
offsets = rec_get_offsets(next_rec, index, offsets, offsets = rec_get_offsets(next_rec, index, offsets,
index->n_core_fields, index->n_core_fields,
@ -5792,8 +5803,8 @@ next_rec_after_check:
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
goto lock_wait_or_error; goto lock_wait_or_error;
} }
} else { } else if (!btr_pcur_move_to_next_on_page(pcur)) {
btr_pcur_move_to_next_on_page(pcur); goto corrupted;
} }
goto rec_loop; goto rec_loop;
@ -5803,6 +5814,7 @@ next_rec_after_check:
goto rec_loop; goto rec_loop;
} }
if (UNIV_UNLIKELY(!btr_pcur_get_rec(pcur))) { if (UNIV_UNLIKELY(!btr_pcur_get_rec(pcur))) {
corrupted:
err = DB_CORRUPTION; err = DB_CORRUPTION;
goto normal_return; goto normal_return;
} }