summaryrefslogtreecommitdiff
path: root/storage/innobase/btr/btr0btr.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/btr/btr0btr.cc')
-rw-r--r--storage/innobase/btr/btr0btr.cc287
1 files changed, 186 insertions, 101 deletions
diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc
index 429a973c05d..13c3b5a18cb 100644
--- a/storage/innobase/btr/btr0btr.cc
+++ b/storage/innobase/btr/btr0btr.cc
@@ -760,6 +760,9 @@ btr_page_get_father_block(
rec_t* rec
= page_rec_get_next(page_get_infimum_rec(buf_block_get_frame(
block)));
+ if (UNIV_UNLIKELY(!rec)) {
+ return nullptr;
+ }
btr_cur_position(index, rec, block, cursor);
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
= page_rec_get_next(page_get_infimum_rec(buf_block_get_frame(
block)));
+ if (UNIV_UNLIKELY(!rec)) {
+ return false;
+ }
btr_cur_position(index, rec, block, cursor);
heap = mem_heap_create(100);
@@ -1240,8 +1246,6 @@ btr_write_autoinc(dict_index_t* index, ib_uint64_t autoinc, bool reset)
static dberr_t btr_page_reorganize_low(page_cur_t *cursor, dict_index_t *index,
mtr_t *mtr)
{
- const mtr_log_t log_mode= mtr->set_log_mode(MTR_LOG_NO_REDO);
-
buf_block_t *const block= cursor->block;
ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX));
@@ -1252,15 +1256,20 @@ 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 ||
!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();
/* Copy the old page to temporary space */
memcpy_aligned<UNIV_PAGE_SIZE_MIN>(old->page.frame, block->page.frame,
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);
+ const mtr_log_t log_mode= mtr->set_log_mode(MTR_LOG_NO_REDO);
page_create(block, mtr, index->table->not_redundant());
if (index->is_spatial())
@@ -1272,10 +1281,13 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, dict_index_t *index,
/* Copy the records from the temporary space to the recreated page;
do not copy the lock bits yet */
- if (dberr_t err=
- page_copy_rec_list_end_no_locks(block, old,
- page_get_infimum_rec(old->page.frame),
- index, mtr))
+ dberr_t err=
+ page_copy_rec_list_end_no_locks(block, old,
+ page_get_infimum_rec(old->page.frame),
+ index, mtr);
+ mtr->set_log_mode(log_mode);
+
+ if (UNIV_UNLIKELY(err != DB_SUCCESS))
return err;
/* Copy the PAGE_MAX_TRX_ID or PAGE_ROOT_AUTO_INC. */
@@ -1315,12 +1327,10 @@ static dberr_t btr_page_reorganize_low(page_cur_t *cursor, dict_index_t *index,
}
/* Restore the cursor position. */
- if (pos)
- cursor->rec = page_rec_get_nth(block->page.frame, pos);
- else
+ if (!pos)
ut_ad(cursor->rec == page_get_infimum_rec(block->page.frame));
-
- mtr->set_log_mode(log_mode);
+ else if (!(cursor->rec= page_rec_get_nth(block->page.frame, pos)))
+ return DB_CORRUPTION;
if (block->page.id().page_no() != index->page ||
fil_page_get_type(old->page.frame) != FIL_PAGE_TYPE_INSTANT)
@@ -1543,13 +1553,16 @@ btr_page_reorganize(
return btr_page_reorganize_low(cursor, index, mtr);
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,
true);
if (err == DB_FAIL);
- else if (pos)
- cursor->rec= page_rec_get_nth(cursor->block->page.frame, pos);
- else
+ else if (!pos)
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;
}
@@ -1745,7 +1758,6 @@ btr_root_raise_and_insert(
dberr_t* err) /*!< out: error code */
{
dict_index_t* index;
- ulint new_page_no;
rec_t* rec;
dtuple_t* node_ptr;
ulint level;
@@ -1907,8 +1919,9 @@ btr_root_raise_and_insert(
*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));
- 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
child */
@@ -1961,9 +1974,20 @@ btr_root_raise_and_insert(
ibuf_reset_free_bits(new_block);
}
- if (tuple != NULL) {
+ if (tuple) {
+ ut_ad(dtuple_check_typed(tuple));
/* 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 {
/* Set cursor to first record on child node */
page_cur_set_before_first(new_block, page_cursor);
@@ -2042,7 +2066,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);
- if (page_rec_is_supremum(insert_point)) {
+ if (!insert_point || page_rec_is_supremum(insert_point)) {
insert_point = NULL;
} else {
insert_point = page_rec_get_next(insert_point);
@@ -2230,20 +2254,20 @@ btr_page_insert_fits(
end_rec) will end up on the other half page from tuple when it is
inserted. */
- if (split_rec == NULL) {
- rec = page_rec_get_next(page_get_infimum_rec(page));
+ if (!(end_rec = split_rec)) {
end_rec = page_rec_get_next(btr_cur_get_rec(cursor));
-
} else if (cmp_dtuple_rec(tuple, split_rec, cursor->index,
- *offsets) >= 0) {
-
- rec = page_rec_get_next(page_get_infimum_rec(page));
- end_rec = split_rec;
- } else {
+ *offsets) < 0) {
rec = split_rec;
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)
<= free_space) {
@@ -2275,7 +2299,9 @@ btr_page_insert_fits(
return(true);
}
- rec = page_rec_get_next_const(rec);
+ if (!(rec = page_rec_get_next_const(rec))) {
+ break;
+ }
}
return(false);
@@ -2512,8 +2538,10 @@ btr_page_tuple_smaller(
/* Read the first user record in the page. */
block = btr_cur_get_block(cursor);
page_cur_set_before_first(block, &pcur);
- page_cur_move_to_next(&pcur);
- first_rec = page_cur_get_rec(&pcur);
+ if (UNIV_UNLIKELY(!(first_rec = page_cur_move_to_next(&pcur)))) {
+ ut_ad("corrupted page" == 0);
+ return false;
+ }
*offsets = rec_get_offsets(first_rec, cursor->index, *offsets,
page_is_leaf(block->page.frame)
@@ -2555,6 +2583,7 @@ btr_insert_into_right_sibling(
MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK));
ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX));
ut_ad(heap);
+ ut_ad(dtuple_check_typed(tuple));
if (next_page_no == FIL_NULL || !page_rec_is_supremum(
page_rec_get_next(btr_cur_get_rec(cursor)))) {
@@ -2582,9 +2611,13 @@ btr_insert_into_right_sibling(
return nullptr;
}
- page_cur_search(
- next_block, cursor->index, tuple, PAGE_CUR_LE,
- &next_page_cursor);
+ ulint up_match = 0, low_match = 0;
+
+ 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);
@@ -2789,6 +2822,7 @@ btr_page_split_and_insert(
ulint n_uniq;
ut_ad(*err == DB_SUCCESS);
+ ut_ad(dtuple_check_typed(tuple));
if (cursor->index->is_spatial()) {
/* Split rtree page and update parent */
@@ -2856,9 +2890,16 @@ func_start:
page_get_infimum_rec(page));
} else {
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 */
const uint16_t page_level = btr_page_get_level(page);
new_block = btr_page_alloc(cursor->index, hint_page_no, direction,
@@ -2908,9 +2949,17 @@ func_start:
goto insert_empty;
}
} 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));
+insert_move_limit:
move_limit = page_rec_get_next(btr_cur_get_rec(cursor));
+ if (UNIV_UNLIKELY(!first_rec || !move_limit)) {
+ goto corrupted;
+ }
} else {
insert_empty:
ut_ad(!split_rec);
@@ -2921,7 +2970,7 @@ insert_empty:
first_rec = rec_convert_dtuple_to_rec(buf, cursor->index,
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 */
@@ -3088,7 +3137,14 @@ insert_empty:
/* 7. Reposition the cursor for insert and try insertion */
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,
offsets, heap, n_ext, mtr);
@@ -3442,8 +3498,8 @@ btr_compress(
mtr_t* mtr) /*!< in/out: mini-transaction */
{
dict_index_t* index;
- buf_block_t* merge_block;
- page_t* merge_page = NULL;
+ buf_block_t* merge_block = nullptr;
+ page_t* merge_page = nullptr;
page_zip_des_t* merge_page_zip;
ibool is_left;
buf_block_t* block;
@@ -3501,7 +3557,10 @@ btr_compress(
if (adjust) {
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) {
@@ -3650,7 +3709,12 @@ cannot_merge:
}
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 {
rec_t* orig_succ;
@@ -3868,16 +3932,20 @@ cannot_merge:
ut_ad(leftmost_child
|| btr_check_node_ptr(index, merge_block, mtr));
func_exit:
- MONITOR_INC(MONITOR_INDEX_MERGE_SUCCESSFUL);
-
if (adjust) {
ut_ad(nth_rec > 0);
- btr_cur_position(
- index,
- page_rec_get_nth(merge_block->page.frame,
- nth_rec),
- merge_block, cursor);
- }
+ if (rec_t* nth
+ = page_rec_get_nth(merge_block->page.frame,
+ nth_rec)) {
+ btr_cur_position(index, nth,
+ merge_block, cursor);
+ } else {
+ err = DB_CORRUPTION;
+ goto err_exit;
+ }
+ }
+
+ MONITOR_INC(MONITOR_INDEX_MERGE_SUCCESSFUL);
} else {
err_exit:
/* We play it safe and reset the free bits. */
@@ -3914,6 +3982,9 @@ btr_discard_only_page_on_level(
const trx_id_t max_trx_id = page_get_max_trx_id(block->page.frame);
const rec_t* r = page_rec_get_next(
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());
while (block->page.id().page_no() != dict_index_get_page(index)) {
@@ -4085,14 +4156,17 @@ btr_discard_page(
ut_d(parent_is_different = page_rec_is_supremum(
page_rec_get_next(btr_cur_get_rec(&parent_cursor))));
- if (!page_is_leaf(merge_block->page.frame)) {
- rec_t* node_ptr = page_rec_get_next(
- page_get_infimum_rec(merge_block->page.frame));
+ if (page_is_leaf(merge_block->page.frame)) {
+ } else if (rec_t* node_ptr =
+ page_rec_get_next(page_get_infimum_rec(
+ merge_block->page.frame))) {
ut_ad(page_rec_is_user_rec(node_ptr));
/* We have to mark the leftmost node pointer as the
predefined minimum record. */
btr_set_min_rec_mark<true>(node_ptr, *merge_block,
mtr);
+ } else {
+ return DB_CORRUPTION;
}
} else {
btr_discard_only_page_on_level(index, block, mtr);
@@ -4553,16 +4627,15 @@ next_field:
/************************************************************//**
Checks the size and number of fields in records based on the definition of
the index.
-@return TRUE if ok */
+@return true if ok */
static
-ibool
+bool
btr_index_page_validate(
/*====================*/
buf_block_t* block, /*!< in: index page */
dict_index_t* index) /*!< in: index */
{
page_cur_t cur;
- ibool ret = TRUE;
#ifndef DBUG_OFF
ulint nth = 1;
#endif /* !DBUG_OFF */
@@ -4579,17 +4652,13 @@ btr_index_page_validate(
page_cur_get_page(&cur), 0))
== 1););
- page_cur_move_to_next(&cur);
-
- for (;;) {
+ while (page_cur_move_to_next(&cur)) {
if (page_cur_is_after_last(&cur)) {
-
- break;
+ return true;
}
if (!btr_index_rec_validate(cur.rec, index, TRUE)) {
-
- return(FALSE);
+ break;
}
/* Verify that page_rec_get_nth_const() is correctly
@@ -4601,11 +4670,9 @@ btr_index_page_validate(
cur.rec)));
ut_a(nth++ == page_rec_get_n_recs_before(
cur.rec)););
-
- page_cur_move_to_next(&cur);
}
- return(ret);
+ return false;
}
/************************************************************//**
@@ -4723,14 +4790,16 @@ btr_validate_level(
ut_a(!page_zip || page_zip_validate(page_zip, page, index));
#endif /* UNIV_ZIP_DEBUG */
if (page_is_leaf(page)) {
+corrupted:
err = DB_CORRUPTION;
goto invalid_page;
}
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,
ULINT_UNDEFINED, &heap);
@@ -4854,12 +4923,16 @@ func_exit:
}
if (!(rec = page_rec_get_prev(page_get_supremum_rec(page)))) {
+broken_links:
btr_validate_report1(index, level, block);
fputs("InnoDB: broken record links\n", stderr);
goto invalid_page;
}
- right_rec = page_rec_get_next(page_get_infimum_rec(
- right_page));
+ if (!(right_rec =
+ page_rec_get_next(page_get_infimum_rec(right_page)))) {
+ goto broken_links;
+ }
+
offsets = rec_get_offsets(rec, index, offsets,
page_is_leaf(page)
? index->n_core_fields : 0,
@@ -4890,19 +4963,26 @@ func_exit:
fputs("InnoDB: record ", stderr);
rec = page_rec_get_next(
page_get_infimum_rec(right_page));
- rec_print(stderr, rec, index);
+ if (rec) {
+ rec_print(stderr, rec, index);
+ }
putc('\n', stderr);
- err = DB_CORRUPTION;
+ err = DB_CORRUPTION;
}
}
- if (level > 0 && left_page_no == FIL_NULL
- && !(REC_INFO_MIN_REC_FLAG & rec_get_info_bits(
- page_rec_get_next(page_get_infimum_rec(page)),
- page_is_comp(page)))) {
- btr_validate_report1(index, level, block);
- ib::error() << "Missing REC_INFO_MIN_REC_FLAG";
+ if (!level || left_page_no != FIL_NULL) {
+ } else if (const rec_t* first =
+ page_rec_get_next_const(page_get_infimum_rec(page))) {
+ if (!(REC_INFO_MIN_REC_FLAG
+ & rec_get_info_bits(first, page_is_comp(page)))) {
+ btr_validate_report1(index, level, block);
+ ib::error() << "Missing REC_INFO_MIN_REC_FLAG";
+ err = DB_CORRUPTION;
+ }
+ } else {
err = DB_CORRUPTION;
+ goto node_ptr_fails;
}
/* Similarly skip the father node check for spatial index for now,
@@ -4913,11 +4993,14 @@ func_exit:
We will add special validation mechanism for R-tree later (WL #7520) */
if (index->is_btree() && block->page.id().page_no() != index->page) {
/* 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(
- index, page_rec_get_next(page_get_infimum_rec(page)),
- block, &node_cur);
+ btr_cur_position(index, node_ptr, block, &node_cur);
offsets = btr_page_get_father_node_ptr_for_validate(
offsets, heap, &node_cur, &mtr);
@@ -4966,17 +5049,15 @@ func_exit:
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(
- index,
- page_rec_get_next(page_get_infimum_rec(page)),
+ index, first_rec,
0, heap, btr_page_get_level(page));
if (cmp_dtuple_rec(node_ptr_tuple, node_ptr, index,
offsets)) {
- const rec_t* first_rec = page_rec_get_next(
- page_get_infimum_rec(page));
-
btr_validate_report1(index, level, block);
ib::error() << "Node ptrs differ on levels > 0";
@@ -4986,14 +5067,17 @@ func_exit:
fputs("InnoDB: first rec ", stderr);
rec_print(stderr, first_rec, index);
putc('\n', stderr);
- err = DB_CORRUPTION;
+ err = DB_CORRUPTION;
goto node_ptr_fails;
}
+ } else {
+ err = DB_CORRUPTION;
+ goto node_ptr_fails;
}
if (left_page_no == FIL_NULL) {
if (page_has_prev(father_page)
- || node_ptr != page_rec_get_next(
+ || node_ptr != page_rec_get_next(
page_get_infimum_rec(father_page))) {
err = DB_CORRUPTION;
goto node_ptr_fails;
@@ -5007,11 +5091,8 @@ func_exit:
err = DB_CORRUPTION;
goto node_ptr_fails;
}
- } else {
- const rec_t* right_node_ptr;
-
- right_node_ptr = page_rec_get_next(node_ptr);
-
+ } else if (const rec_t* right_node_ptr
+ = page_rec_get_next(node_ptr)) {
if (!lockout && rightmost_child) {
/* To obey latch order of tree blocks,
@@ -5042,11 +5123,12 @@ func_exit:
}
btr_cur_position(
- index, page_rec_get_next(
- page_get_infimum_rec(
- buf_block_get_frame(
- right_block))),
+ index,
+ page_get_infimum_rec(right_block->page.frame),
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, heap, &right_node_cur, &mtr);
@@ -5056,6 +5138,7 @@ func_exit:
if (btr_cur_get_rec(&right_node_cur)
!= right_node_ptr) {
+node_pointer_corrupted:
err = DB_CORRUPTION;
fputs("InnoDB: node pointer to"
" the right page is wrong\n",
@@ -5093,6 +5176,8 @@ func_exit:
block);
}
}
+ } else {
+ err = DB_CORRUPTION;
}
}