summaryrefslogtreecommitdiff
path: root/storage/xtradb/row/row0sel.c
diff options
context:
space:
mode:
Diffstat (limited to 'storage/xtradb/row/row0sel.c')
-rw-r--r--storage/xtradb/row/row0sel.c434
1 files changed, 264 insertions, 170 deletions
diff --git a/storage/xtradb/row/row0sel.c b/storage/xtradb/row/row0sel.c
index 2839d935167..fe8f33b7b4d 100644
--- a/storage/xtradb/row/row0sel.c
+++ b/storage/xtradb/row/row0sel.c
@@ -88,10 +88,8 @@ row_sel_sec_rec_is_for_blob(
/*========================*/
ulint mtype, /*!< in: main type */
ulint prtype, /*!< in: precise type */
- ulint mbminlen, /*!< in: minimum length of a
- multi-byte character */
- ulint mbmaxlen, /*!< in: maximum length of a
- multi-byte character */
+ ulint mbminmaxlen, /*!< in: minimum and maximum length of
+ a multi-byte character */
const byte* clust_field, /*!< in: the locally stored part of
the clustered index column, including
the BLOB pointer; the clustered
@@ -101,12 +99,26 @@ row_sel_sec_rec_is_for_blob(
ulint clust_len, /*!< in: length of clust_field */
const byte* sec_field, /*!< in: column in secondary index */
ulint sec_len, /*!< in: length of sec_field */
- ulint zip_size) /*!< in: compressed page size, or 0 */
+ dict_table_t* table) /*!< in: table */
{
ulint len;
- byte buf[DICT_MAX_INDEX_COL_LEN];
+ byte buf[REC_VERSION_56_MAX_INDEX_COL_LEN];
+ ulint zip_size = dict_table_flags_to_zip_size(table->flags);
+ ulint max_prefix_len = DICT_MAX_FIELD_LEN_BY_FORMAT(table);
+
+ ut_a(clust_len >= BTR_EXTERN_FIELD_REF_SIZE);
+
+ if (UNIV_UNLIKELY
+ (!memcmp(clust_field + clust_len - BTR_EXTERN_FIELD_REF_SIZE,
+ field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE))) {
+ /* The externally stored field was not written yet.
+ This record should only be seen by
+ recv_recovery_rollback_active() or any
+ TRX_ISO_READ_UNCOMMITTED transactions. */
+ return(FALSE);
+ }
- len = btr_copy_externally_stored_field_prefix(buf, sizeof buf,
+ len = btr_copy_externally_stored_field_prefix(buf, max_prefix_len,
zip_size,
clust_field, clust_len);
@@ -119,7 +131,7 @@ row_sel_sec_rec_is_for_blob(
return(FALSE);
}
- len = dtype_get_at_most_n_mbchars(prtype, mbminlen, mbmaxlen,
+ len = dtype_get_at_most_n_mbchars(prtype, mbminmaxlen,
sec_len, len, (const char*) buf);
return(!cmp_data_data(mtype, prtype, buf, len, sec_field, sec_len));
@@ -202,18 +214,17 @@ row_sel_sec_rec_is_for_clust_rec(
}
len = dtype_get_at_most_n_mbchars(
- col->prtype, col->mbminlen, col->mbmaxlen,
+ col->prtype, col->mbminmaxlen,
ifield->prefix_len, len, (char*) clust_field);
if (rec_offs_nth_extern(clust_offs, clust_pos)
&& len < sec_len) {
if (!row_sel_sec_rec_is_for_blob(
col->mtype, col->prtype,
- col->mbminlen, col->mbmaxlen,
+ col->mbminmaxlen,
clust_field, clust_len,
sec_field, sec_len,
- dict_table_zip_size(
- clust_index->table))) {
+ clust_index->table)) {
goto inequal;
}
@@ -1200,7 +1211,7 @@ row_sel_try_search_shortcut(
ut_ad(plan->unique_search);
ut_ad(!plan->must_get_clust);
#ifdef UNIV_SYNC_DEBUG
- ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
+ ut_ad(rw_lock_own(btr_search_get_latch(index->id), RW_LOCK_SHARED));
#endif /* UNIV_SYNC_DEBUG */
row_sel_open_pcur(plan, TRUE, mtr);
@@ -1371,10 +1382,10 @@ table_loop:
&& !plan->must_get_clust
&& !plan->table->big_rows) {
if (!search_latch_locked) {
- rw_lock_s_lock(&btr_search_latch);
+ rw_lock_s_lock(btr_search_get_latch(index->id));
search_latch_locked = TRUE;
- } else if (rw_lock_get_writer(&btr_search_latch) == RW_LOCK_WAIT_EX) {
+ } else if (rw_lock_get_writer(btr_search_get_latch(index->id)) == RW_LOCK_WAIT_EX) {
/* There is an x-latch request waiting: release the
s-latch for a moment; as an s-latch here is often
@@ -1383,8 +1394,8 @@ table_loop:
from acquiring an s-latch for a long time, lowering
performance significantly in multiprocessors. */
- rw_lock_s_unlock(&btr_search_latch);
- rw_lock_s_lock(&btr_search_latch);
+ rw_lock_s_unlock(btr_search_get_latch(index->id));
+ rw_lock_s_lock(btr_search_get_latch(index->id));
}
found_flag = row_sel_try_search_shortcut(node, plan, &mtr);
@@ -1407,7 +1418,7 @@ table_loop:
}
if (search_latch_locked) {
- rw_lock_s_unlock(&btr_search_latch);
+ rw_lock_s_unlock(btr_search_get_latch(index->id));
search_latch_locked = FALSE;
}
@@ -1941,7 +1952,7 @@ stop_for_a_while:
mtr_commit(&mtr);
#ifdef UNIV_SYNC_DEBUG
- ut_ad(sync_thread_levels_empty_gen(TRUE));
+ ut_ad(sync_thread_levels_empty_except_dict());
#endif /* UNIV_SYNC_DEBUG */
err = DB_SUCCESS;
goto func_exit;
@@ -1961,7 +1972,7 @@ commit_mtr_for_a_while:
mtr_has_extra_clust_latch = FALSE;
#ifdef UNIV_SYNC_DEBUG
- ut_ad(sync_thread_levels_empty_gen(TRUE));
+ ut_ad(sync_thread_levels_empty_except_dict());
#endif /* UNIV_SYNC_DEBUG */
goto table_loop;
@@ -1978,12 +1989,12 @@ lock_wait_or_error:
mtr_commit(&mtr);
#ifdef UNIV_SYNC_DEBUG
- ut_ad(sync_thread_levels_empty_gen(TRUE));
+ ut_ad(sync_thread_levels_empty_except_dict());
#endif /* UNIV_SYNC_DEBUG */
func_exit:
if (search_latch_locked) {
- rw_lock_s_unlock(&btr_search_latch);
+ rw_lock_s_unlock(btr_search_get_latch(index->id));
}
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
@@ -2527,13 +2538,13 @@ row_sel_field_store_in_mysql_format(
ulint len) /*!< in: length of the data */
{
byte* ptr;
- byte* field_end;
- byte* pad_ptr;
ut_ad(len != UNIV_SQL_NULL);
UNIV_MEM_ASSERT_RW(data, len);
switch (templ->type) {
+ const byte* field_end;
+ byte* pad;
case DATA_INT:
/* Convert integer data from Innobase to a little-endian
format, sign bit restored to normal */
@@ -2577,38 +2588,32 @@ row_sel_field_store_in_mysql_format(
unused end of a >= 5.0.3 true VARCHAR column, just in case
MySQL expects its contents to be deterministic. */
- pad_ptr = dest + len;
+ pad = dest + len;
ut_ad(templ->mbminlen <= templ->mbmaxlen);
- /* We handle UCS2 charset strings differently. */
- if (templ->mbminlen == 2) {
- /* A space char is two bytes, 0x0020 in UCS2 */
+ /* We treat some Unicode charset strings specially. */
+ switch (templ->mbminlen) {
+ case 4:
+ /* InnoDB should never have stripped partial
+ UTF-32 characters. */
+ ut_a(!(len & 3));
+ break;
+ case 2:
+ /* A space char is two bytes,
+ 0x0020 in UCS2 and UTF-16 */
- if (len & 1) {
+ if (UNIV_UNLIKELY(len & 1)) {
/* A 0x20 has been stripped from the column.
Pad it back. */
- if (pad_ptr < field_end) {
- *pad_ptr = 0x20;
- pad_ptr++;
+ if (pad < field_end) {
+ *pad++ = 0x20;
}
}
-
- /* Pad the rest of the string with 0x0020 */
-
- while (pad_ptr < field_end) {
- *pad_ptr = 0x00;
- pad_ptr++;
- *pad_ptr = 0x20;
- pad_ptr++;
- }
- } else {
- ut_ad(templ->mbminlen == 1);
- /* space=0x20 */
-
- memset(pad_ptr, 0x20, field_end - pad_ptr);
}
+
+ row_mysql_pad_col(templ->mbminlen, pad, field_end - pad);
break;
case DATA_BLOB:
@@ -2633,9 +2638,9 @@ row_sel_field_store_in_mysql_format(
|| !(templ->mysql_col_len % templ->mbmaxlen));
ut_ad(len * templ->mbmaxlen >= templ->mysql_col_len);
- if (templ->mbminlen != templ->mbmaxlen) {
+ if (templ->mbminlen == 1 && templ->mbmaxlen != 1) {
/* Pad with spaces. This undoes the stripping
- done in row0mysql.ic, function
+ done in row0mysql.c, function
row_mysql_store_col_in_innobase_format(). */
memset(dest + len, 0x20, templ->mysql_col_len - len);
@@ -2675,45 +2680,41 @@ row_sel_store_mysql_rec(
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct */
const rec_t* rec, /*!< in: Innobase record in the index
which was described in prebuilt's
- template; must be protected by
- a page latch */
- const ulint* offsets, /* in: array returned by
- rec_get_offsets() */
+ template, or in the clustered index;
+ must be protected by a page latch */
+ ibool rec_clust, /*!< in: TRUE if rec is in the
+ clustered index instead of
+ prebuilt->index */
+ const ulint* offsets, /*!< in: array returned by
+ rec_get_offsets(rec) */
ulint start_field_no, /* in: start from this field */
ulint end_field_no) /* in: end at this field */
{
- mysql_row_templ_t* templ;
- mem_heap_t* extern_field_heap = NULL;
- mem_heap_t* heap;
- const byte* data;
- ulint len;
- ulint i;
+ mem_heap_t* extern_field_heap = NULL;
+ mem_heap_t* heap;
+ ulint i;
ut_ad(prebuilt->mysql_template);
ut_ad(prebuilt->default_rec);
ut_ad(rec_offs_validate(rec, NULL, offsets));
+ ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
if (UNIV_LIKELY_NULL(prebuilt->blob_heap)) {
mem_heap_free(prebuilt->blob_heap);
prebuilt->blob_heap = NULL;
}
-// psergey@askmonty.org: don't take the following:
-#if 0
- /* init null bytes with default values as they might be
-
- left uninitialized in some cases and these uninited bytes
- might be copied into mysql record buffer that leads to
- valgrind warnings */
- memcpy(mysql_rec, prebuilt->default_rec, prebuilt->null_bitmap_len);
-#endif
-
for (i = start_field_no; i < end_field_no /* prebuilt->n_template */ ; i++) {
- templ = prebuilt->mysql_template + i;
+ const mysql_row_templ_t*templ = prebuilt->mysql_template + i;
+ const byte* data;
+ ulint len;
+ ulint field_no;
- if (UNIV_UNLIKELY(rec_offs_nth_extern(offsets,
- templ->rec_field_no))) {
+ field_no = rec_clust
+ ? templ->clust_rec_field_no : templ->rec_field_no;
+
+ if (UNIV_UNLIKELY(rec_offs_nth_extern(offsets, field_no))) {
/* Copy an externally stored field to the temporary
heap */
@@ -2741,7 +2742,7 @@ row_sel_store_mysql_rec(
data = btr_rec_copy_externally_stored_field(
rec, offsets,
dict_table_zip_size(prebuilt->table),
- templ->rec_field_no, &len, heap);
+ field_no, &len, heap);
if (UNIV_UNLIKELY(!data)) {
/* The externally stored field
@@ -2762,8 +2763,7 @@ row_sel_store_mysql_rec(
} else {
/* Field is stored in the row. */
- data = rec_get_nth_field(rec, offsets,
- templ->rec_field_no, &len);
+ data = rec_get_nth_field(rec, offsets, field_no, &len);
if (UNIV_UNLIKELY(templ->type == DATA_BLOB)
&& len != UNIV_SQL_NULL) {
@@ -3125,7 +3125,7 @@ row_sel_pop_cached_row_for_mysql(
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct */
{
ulint i;
- mysql_row_templ_t* templ;
+ const mysql_row_templ_t*templ;
byte* cached_rec;
ut_ad(prebuilt->n_fetch_cached > 0);
ut_ad(prebuilt->mysql_prefix_len <= prebuilt->mysql_row_len);
@@ -3186,9 +3186,14 @@ ibool
row_sel_push_cache_row_for_mysql(
/*=============================*/
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct */
- const rec_t* rec, /*!< in: record to push; must
- be protected by a page latch */
- const ulint* offsets, /* in: rec_get_offsets() */
+ const rec_t* rec, /*!< in: record to push, in the index
+ which was described in prebuilt's
+ template, or in the clustered index;
+ must be protected by a page latch */
+ ibool rec_clust, /*!< in: TRUE if rec is in the
+ clustered index instead of
+ prebuilt->index */
+ const ulint* offsets, /*!< in: rec_get_offsets(rec) */
ulint start_field_no, /* in: start from this field */
byte* remainder_buf) /* in: if start_field_no !=0,
where to take prev fields */
@@ -3198,6 +3203,7 @@ row_sel_push_cache_row_for_mysql(
ut_ad(prebuilt->n_fetch_cached < MYSQL_FETCH_CACHE_SIZE);
ut_ad(rec_offs_validate(rec, NULL, offsets));
+ ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
ut_a(!prebuilt->templ_contains_blob);
if (prebuilt->fetch_cache[0] == NULL) {
@@ -3227,7 +3233,7 @@ row_sel_push_cache_row_for_mysql(
prebuilt->fetch_cache[
prebuilt->n_fetch_cached],
prebuilt,
- rec,
+ rec, rec_clust,
offsets,
start_field_no,
prebuilt->n_template))) {
@@ -3391,6 +3397,8 @@ row_search_for_mysql(
/* if the returned record was locked and we did a semi-consistent
read (fetch the newest committed version), then this is set to
TRUE */
+ ulint i;
+ ulint should_release;
#ifdef UNIV_SEARCH_DEBUG
ulint cnt = 0;
#endif /* UNIV_SEARCH_DEBUG */
@@ -3401,13 +3409,13 @@ row_search_for_mysql(
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
ibool some_fields_in_buffer;
- ibool problematic_use = FALSE;
+ ibool table_lock_waited = FALSE;
+ ibool problematic_use = FALSE;
ibool get_clust_rec = 0;
rec_offs_init(offsets_);
ut_ad(index && pcur && search_tuple);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
if (UNIV_UNLIKELY(prebuilt->table->ibd_file_missing)) {
ut_print_timestamp(stderr);
@@ -3424,11 +3432,17 @@ row_search_for_mysql(
"InnoDB: how you can resolve the problem.\n",
prebuilt->table->name);
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
return(DB_ERROR);
}
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
return(DB_MISSING_HISTORY);
}
@@ -3477,18 +3491,33 @@ row_search_for_mysql(
/* PHASE 0: Release a possible s-latch we are holding on the
adaptive hash index latch if there is someone waiting behind */
- if (UNIV_UNLIKELY(rw_lock_get_writer(&btr_search_latch) != RW_LOCK_NOT_LOCKED)
- && trx->has_search_latch) {
+ should_release = 0;
+ for (i = 0; i < btr_search_index_num; i++) {
+ /* we should check all latches (fix Bug#791030) */
+ if (rw_lock_get_writer(btr_search_latch_part[i])
+ != RW_LOCK_NOT_LOCKED) {
+ should_release |= ((ulint)1 << i);
+ }
+ }
+
+ if (should_release) {
/* There is an x-latch request on the adaptive hash index:
release the s-latch to reduce starvation and wait for
BTR_SEA_TIMEOUT rounds before trying to keep it again over
calls from MySQL */
- rw_lock_s_unlock(&btr_search_latch);
- trx->has_search_latch = FALSE;
+ for (i = 0; i < btr_search_index_num; i++) {
+ /* we should release all s-latches (fix Bug#791030) */
+ if (trx->has_search_latch & ((ulint)1 << i)) {
+ rw_lock_s_unlock(btr_search_latch_part[i]);
+ trx->has_search_latch &= (~((ulint)1 << i));
+ }
+ }
+ if (!trx->has_search_latch) {
trx->search_latch_timeout = BTR_SEA_TIMEOUT;
+ }
}
/* Reset the new record lock info if srv_locks_unsafe_for_binlog
@@ -3639,9 +3668,28 @@ row_search_for_mysql(
hash index semaphore! */
#ifndef UNIV_SEARCH_DEBUG
- if (!trx->has_search_latch) {
- rw_lock_s_lock(&btr_search_latch);
- trx->has_search_latch = TRUE;
+ if (!(trx->has_search_latch
+ & ((ulint)1 << (index->id % btr_search_index_num)))) {
+ if (trx->has_search_latch
+ < ((ulint)1 << (index->id % btr_search_index_num))) {
+ rw_lock_s_lock(btr_search_get_latch(index->id));
+ trx->has_search_latch |=
+ ((ulint)1 << (index->id % btr_search_index_num));
+ } else {
+ /* should re-lock to obay latch-order */
+ for (i = 0; i < btr_search_index_num; i++) {
+ if (trx->has_search_latch & ((ulint)1 << i)) {
+ rw_lock_s_unlock(btr_search_latch_part[i]);
+ }
+ }
+ trx->has_search_latch |=
+ ((ulint)1 << (index->id % btr_search_index_num));
+ for (i = 0; i < btr_search_index_num; i++) {
+ if (trx->has_search_latch & ((ulint)1 << i)) {
+ rw_lock_s_lock(btr_search_latch_part[i]);
+ }
+ }
+ }
}
#endif
switch (row_sel_try_search_shortcut_for_mysql(
@@ -3660,7 +3708,7 @@ row_search_for_mysql(
ut_ad(!rec_get_deleted_flag(rec, comp));
if (!row_sel_store_mysql_rec(buf, prebuilt,
- rec, offsets, 0,
+ rec, FALSE, offsets, 0,
prebuilt->n_template)) {
/* Only fresh inserts may contain
incomplete externally stored
@@ -3702,7 +3750,11 @@ release_search_latch_if_needed:
trx->search_latch_timeout--;
- rw_lock_s_unlock(&btr_search_latch);
+ for (i = 0; i < btr_search_index_num; i++) {
+ if (trx->has_search_latch & ((ulint)1 << i)) {
+ rw_lock_s_unlock(btr_search_latch_part[i]);
+ }
+ }
trx->has_search_latch = FALSE;
}
@@ -3726,7 +3778,12 @@ release_search_latch_if_needed:
/* PHASE 3: Open or restore index cursor position */
if (trx->has_search_latch) {
- rw_lock_s_unlock(&btr_search_latch);
+
+ for (i = 0; i < btr_search_index_num; i++) {
+ if (trx->has_search_latch & ((ulint)1 << i)) {
+ rw_lock_s_unlock(btr_search_latch_part[i]);
+ }
+ }
trx->has_search_latch = FALSE;
}
@@ -3767,6 +3824,67 @@ release_search_latch_if_needed:
clust_index = dict_table_get_first_index(index->table);
+ /* Do some start-of-statement preparations */
+
+ if (!prebuilt->mysql_has_locked) {
+ if (!(prebuilt->table->flags & (DICT_TF2_TEMPORARY << DICT_TF2_SHIFT))) {
+ fprintf(stderr, "InnoDB: Error: row_search_for_mysql() is called without ha_innobase::external_lock()\n");
+ if (trx->mysql_thd != NULL) {
+ innobase_mysql_print_thd(stderr, trx->mysql_thd, 600);
+ }
+ }
+ problematic_use = TRUE;
+ }
+retry_check:
+
+ if (!prebuilt->sql_stat_start) {
+ /* No need to set an intention lock or assign a read view */
+
+ if (trx->read_view == NULL
+ && prebuilt->select_lock_type == LOCK_NONE) {
+
+ fputs("InnoDB: Error: MySQL is trying to"
+ " perform a consistent read\n"
+ "InnoDB: but the read view is not assigned!\n",
+ stderr);
+ if (problematic_use) {
+ fprintf(stderr, "InnoDB: It may be caused by calling "
+ "without ha_innobase::external_lock()\n"
+ "InnoDB: For the first-aid, avoiding the crash. "
+ "But it should be fixed ASAP.\n");
+ if (prebuilt->table->flags & (DICT_TF2_TEMPORARY << DICT_TF2_SHIFT)
+ && trx->mysql_thd != NULL) {
+ innobase_mysql_print_thd(stderr, trx->mysql_thd, 600);
+ }
+ prebuilt->sql_stat_start = TRUE;
+ goto retry_check;
+ }
+ trx_print(stderr, trx, 600);
+ fputc('\n', stderr);
+ ut_error;
+ }
+ } else if (prebuilt->select_lock_type == LOCK_NONE) {
+ /* This is a consistent read */
+ /* Assign a read view for the query */
+
+ trx_assign_read_view(trx);
+ prebuilt->sql_stat_start = FALSE;
+ } else {
+wait_table_again:
+ err = lock_table(0, index->table,
+ prebuilt->select_lock_type == LOCK_S
+ ? LOCK_IS : LOCK_IX, thr);
+
+ if (err != DB_SUCCESS) {
+
+ table_lock_waited = TRUE;
+ goto lock_table_wait;
+ }
+ prebuilt->sql_stat_start = FALSE;
+ }
+
+ /* Open or restore index cursor position */
+
if (UNIV_LIKELY(direction != 0)) {
ibool need_to_process = sel_restore_position_for_mysql(
&same_user_rec, BTR_SEARCH_LEAF,
@@ -3842,59 +3960,6 @@ release_search_latch_if_needed:
}
}
- if (!prebuilt->mysql_has_locked) {
- fprintf(stderr, "InnoDB: Error: row_search_for_mysql() is called without ha_innobase::external_lock()\n");
- if (trx->mysql_thd != NULL) {
- innobase_mysql_print_thd(stderr, trx->mysql_thd, 600);
- }
- problematic_use = TRUE;
- }
-retry_check:
-
- if (!prebuilt->sql_stat_start) {
- /* No need to set an intention lock or assign a read view */
-
- if (trx->read_view == NULL
- && prebuilt->select_lock_type == LOCK_NONE) {
-
- fputs("InnoDB: Error: MySQL is trying to"
- " perform a consistent read\n"
- "InnoDB: but the read view is not assigned!\n",
- stderr);
- if (problematic_use) {
- fprintf(stderr, "InnoDB: It may be caused by calling "
- "without ha_innobase::external_lock()\n"
- "InnoDB: For the first-aid, avoiding the crash. "
- "But it should be fixed ASAP.\n");
- prebuilt->sql_stat_start = TRUE;
- goto retry_check;
- }
- trx_print(stderr, trx, 600);
- fputc('\n', stderr);
- ut_a(0);
- }
- } else if (prebuilt->select_lock_type == LOCK_NONE) {
- /* This is a consistent read */
- /* Assign a read view for the query */
-
- trx_assign_read_view(trx);
- prebuilt->sql_stat_start = FALSE;
- } else {
- ulint lock_mode;
- if (prebuilt->select_lock_type == LOCK_S) {
- lock_mode = LOCK_IS;
- } else {
- lock_mode = LOCK_IX;
- }
- err = lock_table(0, index->table, lock_mode, thr);
-
- if (err != DB_SUCCESS) {
-
- goto lock_wait_or_error;
- }
- prebuilt->sql_stat_start = FALSE;
- }
-
rec_loop:
/*-------------------------------------------------------------*/
/* PHASE 4: Look for matching records in a loop */
@@ -3984,7 +4049,13 @@ rec_loop:
if (UNIV_UNLIKELY(next_offs >= UNIV_PAGE_SIZE - PAGE_DIR)) {
wrong_offs:
- if (srv_force_recovery == 0 || moves_up == FALSE) {
+ if (srv_pass_corrupt_table && !trx_sys_sys_space(index->table->space)) {
+ index->table->is_corrupt = TRUE;
+ fil_space_set_corrupt(index->table->space);
+ }
+
+ if ((srv_force_recovery == 0 || moves_up == FALSE)
+ && srv_pass_corrupt_table <= 1) {
ut_print_timestamp(stderr);
buf_page_print(page_align(rec), 0);
fprintf(stderr,
@@ -4035,7 +4106,8 @@ wrong_offs:
offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
- if (UNIV_UNLIKELY(srv_force_recovery > 0)) {
+ if (UNIV_UNLIKELY(srv_force_recovery > 0)
+ || (srv_pass_corrupt_table == 2 && index->table->is_corrupt)) {
if (!rec_validate(rec, offsets)
|| !btr_index_rec_validate(rec, index, FALSE)) {
fprintf(stderr,
@@ -4317,7 +4389,6 @@ no_gap_lock:
is necessary, because we can only get the undo
information via the clustered index record. */
- ut_ad(index != clust_index);
ut_ad(!dict_index_is_clust(index));
if (!lock_sec_rec_cons_read_sees(
@@ -4372,10 +4443,18 @@ no_gap_lock:
idx_cond_check:
if (prebuilt->idx_cond_func) {
int res;
+ ibool ib_res;
ut_ad(prebuilt->template_type != ROW_MYSQL_DUMMY_TEMPLATE);
offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
- row_sel_store_mysql_rec(buf, prebuilt, rec,
+ ib_res= row_sel_store_mysql_rec(buf, prebuilt, rec, FALSE,
offsets, 0, prebuilt->n_index_fields);
+ /*
+ The above call will fail and return FALSE when requested to
+ store an "externally stored column" (afaiu, a blob). Index
+ Condition Pushdown is not supported for indexes with blob
+ columns, so we should never get this error.
+ */
+ ut_ad(ib_res);
res= prebuilt->idx_cond_func(prebuilt->idx_cond_func_arg);
if (res == 0)
goto next_rec;
@@ -4450,26 +4529,10 @@ idx_cond_check:
goto next_rec;
}
- if (prebuilt->need_to_access_clustered) {
-
- result_rec = clust_rec;
-
- ut_ad(rec_offs_validate(result_rec, clust_index,
- offsets));
- } else {
- /* We used 'offsets' for the clust rec, recalculate
- them for 'rec' */
- offsets = rec_get_offsets(rec, index, offsets,
- ULINT_UNDEFINED, &heap);
- result_rec = rec;
- }
-
- /* result_rec can legitimately be delete-marked
- now that it has been established that it points to a
- clustered index record that exists in the read view. */
+ result_rec = clust_rec;
+ ut_ad(rec_offs_validate(result_rec, clust_index, offsets));
} else {
result_rec = rec;
- ut_ad(!rec_get_deleted_flag(rec, comp));
}
/* We found a qualifying record 'result_rec'. At this point,
@@ -4478,6 +4541,7 @@ idx_cond_check:
ut_ad(rec_offs_validate(result_rec,
result_rec != rec ? clust_index : index,
offsets));
+ ut_ad(!rec_get_deleted_flag(result_rec, comp));
/* At this point, the clustered index record is protected
by a page latch that was acquired when pcur was positioned.
@@ -4504,6 +4568,7 @@ idx_cond_check:
&& prebuilt->idx_cond_func);
if (!row_sel_push_cache_row_for_mysql(prebuilt, result_rec,
+ result_rec != rec,
offsets,
some_fields_in_buffer?
prebuilt->n_index_fields : 0,
@@ -4524,15 +4589,32 @@ idx_cond_check:
goto next_rec;
} else {
- if (prebuilt->template_type == ROW_MYSQL_DUMMY_TEMPLATE) {
+ if (UNIV_UNLIKELY
+ (prebuilt->template_type == ROW_MYSQL_DUMMY_TEMPLATE)) {
+ /* CHECK TABLE: fetch the row */
+
+ if (result_rec != rec
+ && !prebuilt->need_to_access_clustered) {
+ /* We used 'offsets' for the clust
+ rec, recalculate them for 'rec' */
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED,
+ &heap);
+ result_rec = rec;
+ }
+
memcpy(buf + 4, result_rec
- rec_offs_extra_size(offsets),
rec_offs_size(offsets));
mach_write_to_4(buf,
rec_offs_extra_size(offsets) + 4);
} else {
+ /* Returning a row to MySQL */
+
if (!row_sel_store_mysql_rec(buf, prebuilt,
- result_rec, offsets,
+ result_rec,
+ result_rec != rec,
+ offsets,
prebuilt->idx_cond_func?
prebuilt->n_index_fields: 0,
prebuilt->n_template)) {
@@ -4658,6 +4740,7 @@ lock_wait_or_error:
btr_pcur_store_position(pcur, &mtr);
+lock_table_wait:
mtr_commit(&mtr);
mtr_has_extra_clust_latch = FALSE;
@@ -4675,6 +4758,14 @@ lock_wait_or_error:
thr->lock_state = QUE_THR_LOCK_NOLOCK;
mtr_start(&mtr);
+ /* Table lock waited, go try to obtain table lock
+ again */
+ if (table_lock_waited) {
+ table_lock_waited = FALSE;
+
+ goto wait_table_again;
+ }
+
sel_restore_position_for_mysql(&same_user_rec,
BTR_SEARCH_LEAF, pcur,
moves_up, &mtr);
@@ -4756,6 +4847,10 @@ func_exit:
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
}
}
+
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
return(err);
}
@@ -4793,8 +4888,7 @@ row_search_check_if_query_cache_permitted(
IX type locks actually would require ret = FALSE. */
if (UT_LIST_GET_LEN(table->locks) == 0
- && ut_dulint_cmp(trx->id,
- table->query_cache_inv_trx_id) >= 0) {
+ && trx->id >= table->query_cache_inv_trx_id) {
ret = TRUE;