diff options
Diffstat (limited to 'innobase/row/row0sel.c')
-rw-r--r-- | innobase/row/row0sel.c | 44 |
1 files changed, 37 insertions, 7 deletions
diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index a516699edf9..5f110d85e7d 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -31,6 +31,8 @@ Created 12/19/1997 Heikki Tuuri #include "pars0pars.h" #include "row0mysql.h" +byte row_sel_dummy_byte; + /* Maximum number of rows to prefetch; MySQL interface has another parameter */ #define SEL_MAX_N_PREFETCH 16 @@ -2070,13 +2072,11 @@ row_sel_store_mysql_rec( data = rec_get_nth_field(rec, templ->rec_field_no, &len); if (rec_get_nth_field_extern_bit(rec, templ->rec_field_no)) { + /* Copy an externally stored field to the temporary heap */ - if (prebuilt->trx->has_search_latch) { - rw_lock_s_unlock(&btr_search_latch); - prebuilt->trx->has_search_latch = FALSE; - } + ut_a(!prebuilt->trx->has_search_latch); extern_field_heap = mem_heap_create(UNIV_PAGE_SIZE); @@ -2090,6 +2090,8 @@ row_sel_store_mysql_rec( if (len != UNIV_SQL_NULL) { if (templ->type == DATA_BLOB) { + ut_a(prebuilt->templ_contains_blob); + /* Copy the BLOB data to the BLOB heap of prebuilt */ @@ -2115,6 +2117,21 @@ row_sel_store_mysql_rec( extern_field_heap = NULL; } } else { + /* MySQL sometimes seems to copy the 'data' + pointed to by a BLOB field even if the field + has been marked to contain the SQL NULL value. + This caused seg faults reported by two users. + Set the BLOB length to 0 and the data pointer + to a dummy allocated mem address to avoid + a seg fault. */ + + if (templ->type == DATA_BLOB) { + row_sel_field_store_in_mysql_format( + mysql_rec + templ->mysql_col_offset, + templ->mysql_col_len, &row_sel_dummy_byte, + 0, templ->type, templ->is_unsigned); + } + if (!templ->mysql_null_bit_mask) { fprintf(stderr, "InnoDB: Error: trying to return an SQL NULL field in a non-null\n" @@ -2368,6 +2385,7 @@ row_sel_push_cache_row_for_mysql( ulint i; ut_ad(prebuilt->n_fetch_cached < MYSQL_FETCH_CACHE_SIZE); + ut_a(!prebuilt->templ_contains_blob); if (prebuilt->fetch_cache[0] == NULL) { /* Allocate memory for the fetch cache */ @@ -2408,6 +2426,7 @@ row_sel_try_search_shortcut_for_mysql( rec_t* rec; ut_ad(index->type & DICT_CLUSTERED); + ut_ad(!prebuilt->templ_contains_blob); btr_pcur_open_with_no_init(index, search_tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, pcur, @@ -2590,8 +2609,16 @@ row_search_for_mysql( mtr_start(&mtr); - if (match_mode == ROW_SEL_EXACT && index->type & DICT_UNIQUE + /* Since we must release the search system latch when we retrieve an + externally stored field, we cannot use the adaptive hash index in a + search in the case the row may be long and there may be externally + stored fields */ + + if (match_mode == ROW_SEL_EXACT + && index->type & DICT_UNIQUE && index->type & DICT_CLUSTERED + && !prebuilt->templ_contains_blob + && (prebuilt->mysql_row_len < UNIV_PAGE_SIZE / 8) && dtuple_get_n_fields(search_tuple) == dict_index_get_n_unique(index)) { @@ -2944,15 +2971,18 @@ rec_loop: /* We found a qualifying row */ if (prebuilt->n_rows_fetched >= MYSQL_FETCH_CACHE_THRESHOLD - && !prebuilt->templ_contains_blob && prebuilt->select_lock_type == LOCK_NONE + && !prebuilt->templ_contains_blob && !prebuilt->clust_index_was_generated && prebuilt->template_type != ROW_MYSQL_DUMMY_TEMPLATE) { /* Inside an update, for example, we do not cache rows, since we may use the cursor position to do the actual - update, that is why we require ...lock_type == LOCK_NONE */ + update, that is why we require ...lock_type == LOCK_NONE. + Since we keep space in prebuilt only for the BLOBs of + a single row, we cannot cache rows in the case there + are BLOBs in the fields to be fetched. */ row_sel_push_cache_row_for_mysql(prebuilt, rec); |