diff options
author | Vicențiu Ciorbaru <vicentiu@mariadb.org> | 2017-09-19 00:44:27 +0300 |
---|---|---|
committer | Vicențiu Ciorbaru <vicentiu@mariadb.org> | 2017-09-19 00:44:27 +0300 |
commit | b4606367d7ba82652a346320d458c25c391847ea (patch) | |
tree | e84665dc0c7f666b39d5e41755a5bd83c9ec357e | |
parent | 04ae1207edec4cac80d7206377ae22a8447aa08f (diff) | |
download | mariadb-git-b4606367d7ba82652a346320d458c25c391847ea.tar.gz |
5.6.37-82.2
-rw-r--r-- | storage/xtradb/api/api0api.cc | 21 | ||||
-rw-r--r-- | storage/xtradb/handler/ha_innodb.cc | 21 | ||||
-rw-r--r-- | storage/xtradb/handler/ha_innodb.h | 6 | ||||
-rw-r--r-- | storage/xtradb/include/row0mysql.h | 7 | ||||
-rw-r--r-- | storage/xtradb/include/row0sel.h | 14 | ||||
-rw-r--r-- | storage/xtradb/include/univ.i | 2 | ||||
-rw-r--r-- | storage/xtradb/row/row0merge.cc | 6 | ||||
-rw-r--r-- | storage/xtradb/row/row0sel.cc | 157 |
8 files changed, 179 insertions, 55 deletions
diff --git a/storage/xtradb/api/api0api.cc b/storage/xtradb/api/api0api.cc index 07eecdc46d0..d01b221d71c 100644 --- a/storage/xtradb/api/api0api.cc +++ b/storage/xtradb/api/api0api.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2008, 2015, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2008, 2017, Oracle and/or its affiliates. All Rights Reserved. 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 @@ -1976,11 +1976,14 @@ ib_cursor_read_row( page_format = static_cast<ib_bool_t>( dict_table_is_comp(tuple->index->table)); + rec = btr_pcur_get_rec(pcur); - if (prebuilt->innodb_api_rec && - prebuilt->innodb_api_rec != rec) { - rec = prebuilt->innodb_api_rec; + if (!rec_get_deleted_flag(rec, page_format)) { + if (prebuilt->innodb_api && + prebuilt->innodb_api_rec != NULL) { + rec =prebuilt->innodb_api_rec; + } } if (!rec_get_deleted_flag(rec, page_format)) { @@ -2017,6 +2020,10 @@ ib_cursor_position( buf = static_cast<unsigned char*>(mem_alloc(UNIV_PAGE_SIZE)); + if (prebuilt->innodb_api) { + prebuilt->cursor_heap = cursor->heap; + } + /* We want to position at one of the ends, row_search_for_mysql() uses the search_tuple fields to work out what to do. */ dtuple_set_n_fields(prebuilt->search_tuple, 0); @@ -2071,6 +2078,9 @@ ib_cursor_next( row_prebuilt_t* prebuilt = cursor->prebuilt; byte buf[UNIV_PAGE_SIZE_MAX]; + if (prebuilt->innodb_api) { + prebuilt->cursor_heap = cursor->heap; + } /* We want to move to the next record */ dtuple_set_n_fields(prebuilt->search_tuple, 0); @@ -2123,6 +2133,9 @@ ib_cursor_moveto( buf = static_cast<unsigned char*>(mem_alloc(UNIV_PAGE_SIZE)); + if (prebuilt->innodb_api) { + prebuilt->cursor_heap = cursor->heap; + } err = static_cast<ib_err_t>(row_search_for_mysql( buf, ib_srch_mode, prebuilt, cursor->match_mode, 0)); diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index d1f6c3b499a..5926ef77794 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -9427,6 +9427,27 @@ ha_innobase::ft_init_ext( } /*****************************************************************//** +Copy a cached MySQL row. +If requested, also avoids overwriting non-read columns. +@param[out] buf Row in MySQL format. +@param[in] cached_row Which row to copy. +@param[in] rec_len Record length. */ +void +ha_innobase::copy_cached_row( + uchar* buf, + const uchar* cached_row, + uint rec_len) +{ + if (prebuilt->keep_other_fields_on_keyread) { + row_sel_copy_cached_fields_for_mysql(buf, cached_row, + prebuilt); + } else { + memcpy(buf, cached_row, rec_len); + } +} + + +/*****************************************************************//** Set up search tuple for a query through FTS_DOC_ID_INDEX on supplied Doc ID. This is used by MySQL to retrieve the documents once the search result (Doc IDs) is available */ diff --git a/storage/xtradb/handler/ha_innodb.h b/storage/xtradb/handler/ha_innodb.h index 99953a22121..f4ea77bff33 100644 --- a/storage/xtradb/handler/ha_innodb.h +++ b/storage/xtradb/handler/ha_innodb.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2000, 2017, Oracle and/or its affiliates. All Rights Reserved. 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 @@ -144,6 +144,10 @@ class ha_innobase: public handler int index_first(uchar * buf); int index_last(uchar * buf); + /* Copy a cached MySQL row. If requested, also avoids + overwriting non-read columns. */ + void copy_cached_row(uchar *to_rec, const uchar *from_rec, + uint rec_length); bool has_gap_locks() const { return true; } int rnd_init(bool scan); diff --git a/storage/xtradb/include/row0mysql.h b/storage/xtradb/include/row0mysql.h index eb604d05557..c12cb2f250c 100644 --- a/storage/xtradb/include/row0mysql.h +++ b/storage/xtradb/include/row0mysql.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2000, 2017, Oracle and/or its affiliates. All Rights Reserved. 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 @@ -808,6 +808,8 @@ struct row_prebuilt_t { mem_heap_t* heap; /*!< memory heap from which these auxiliary structures are allocated when needed */ + mem_heap_t* cursor_heap; /*!< memory heap from which + innodb_api_buf is allocated per session*/ ins_node_t* ins_node; /*!< Innobase SQL insert node used to perform inserts to the table */ @@ -960,6 +962,9 @@ struct row_prebuilt_t { unsigned innodb_api:1; /*!< whether this is a InnoDB API query */ const rec_t* innodb_api_rec; /*!< InnoDB API search result */ + void* innodb_api_buf; /*!< Buffer holding copy of the physical + Innodb API search record */ + ulint innodb_api_rec_size; /*!< Size of the Innodb API record */ byte* srch_key_val1; /*!< buffer used in converting search key values from MySQL format to InnoDB format.*/ diff --git a/storage/xtradb/include/row0sel.h b/storage/xtradb/include/row0sel.h index fd5bc755a22..afeb216c2a2 100644 --- a/storage/xtradb/include/row0sel.h +++ b/storage/xtradb/include/row0sel.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved. 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 @@ -205,6 +205,18 @@ struct sel_buf_t{ when data != NULL */ }; +/** Copy used fields from cached row. +Copy cache record field by field, don't touch fields that +are not covered by current key. +@param[out] buf Where to copy the MySQL row. +@param[in] cached_rec What to copy (in MySQL row format). +@param[in] prebuilt prebuilt struct. */ +void +row_sel_copy_cached_fields_for_mysql( + byte* buf, + const byte* cached_rec, + row_prebuilt_t* prebuilt); + /** Query plan */ struct plan_t{ dict_table_t* table; /*!< table struct in the dictionary diff --git a/storage/xtradb/include/univ.i b/storage/xtradb/include/univ.i index beaef2a2272..639faca0fe3 100644 --- a/storage/xtradb/include/univ.i +++ b/storage/xtradb/include/univ.i @@ -47,7 +47,7 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_BUGFIX MYSQL_VERSION_PATCH #ifndef PERCONA_INNODB_VERSION -#define PERCONA_INNODB_VERSION 82.1 +#define PERCONA_INNODB_VERSION 82.2 #endif /* Enable UNIV_LOG_ARCHIVE in XtraDB */ diff --git a/storage/xtradb/row/row0merge.cc b/storage/xtradb/row/row0merge.cc index 691b6b1e8de..346b1616fd0 100644 --- a/storage/xtradb/row/row0merge.cc +++ b/storage/xtradb/row/row0merge.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2005, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2005, 2017, Oracle and/or its affiliates. All Rights Reserved. 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 @@ -1469,6 +1469,8 @@ row_merge_read_clustered_index( row_ext_t* ext; page_cur_t* cur = btr_pcur_get_page_cur(&pcur); + mem_heap_empty(row_heap); + page_cur_move_to_next(cur); if (page_cur_is_after_last(cur)) { @@ -1898,8 +1900,6 @@ write_buffers: if (err != DB_SUCCESS) { goto func_exit; } - - mem_heap_empty(row_heap); } func_exit: diff --git a/storage/xtradb/row/row0sel.cc b/storage/xtradb/row/row0sel.cc index 9f66d12283a..5866021cffa 100644 --- a/storage/xtradb/row/row0sel.cc +++ b/storage/xtradb/row/row0sel.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -2561,53 +2561,56 @@ row_sel_store_row_id_to_prebuilt( #ifdef UNIV_DEBUG /** Convert a non-SQL-NULL field from Innobase format to MySQL format. */ # define row_sel_field_store_in_mysql_format( \ - dest,templ,idx,field,src,len,prebuilt) \ + dest,templ,idx,field,src,len,sec,prebuilt) \ row_sel_field_store_in_mysql_format_func \ - (dest,templ,idx,field,src,len, prebuilt) + (dest,templ,idx,field,src,len,sec,prebuilt) #else /* UNIV_DEBUG */ /** Convert a non-SQL-NULL field from Innobase format to MySQL format. */ # define row_sel_field_store_in_mysql_format( \ - dest,templ,idx,field,src,len,prebuilt) \ + dest,templ,idx,field,src,len,sec,prebuilt) \ row_sel_field_store_in_mysql_format_func \ - (dest,templ,src,len, prebuilt) + (dest,templ,src,len,sec,prebuilt) #endif /* UNIV_DEBUG */ -/**************************************************************//** -Stores a non-SQL-NULL field in the MySQL format. The counterpart of this -function is row_mysql_store_col_in_innobase_format() in row0mysql.cc. */ +/** Stores a non-SQL-NULL field in the MySQL format. The counterpart of this +function is row_mysql_store_col_in_innobase_format() in row0mysql.cc. +@param[in,out] dest buffer where to store; NOTE + that BLOBs are not in themselves stored + here: the caller must allocate and copy + the BLOB into buffer before, and pass + the pointer to the BLOB in 'data' +@param[in] templ MySQL column template. Its following fields + are referenced: type, is_unsigned, mysql_col_len, + mbminlen, mbmaxlen +@param[in] index InnoDB index +@param[in] field_no templ->rec_field_no or templ->clust_rec_field_no + or templ->icp_rec_field_no +@param[in] data data to store +@param[in] len length of the data +@param[in] sec_field secondary index field no if the secondary index + record but the prebuilt template is in + clustered index format and used only for end + range comparison. +@param[in[ prebuilt needed to access compress_heap */ static MY_ATTRIBUTE((nonnull)) void row_sel_field_store_in_mysql_format_func( -/*=====================================*/ - byte* dest, /*!< in/out: buffer where to store; NOTE - that BLOBs are not in themselves - stored here: the caller must allocate - and copy the BLOB into buffer before, - and pass the pointer to the BLOB in - 'data' */ + byte* dest, const mysql_row_templ_t* templ, - /*!< in: MySQL column template. - Its following fields are referenced: - type, is_unsigned, mysql_col_len, - mbminlen, mbmaxlen */ #ifdef UNIV_DEBUG const dict_index_t* index, - /*!< in: InnoDB index */ ulint field_no, - /*!< in: templ->rec_field_no or - templ->clust_rec_field_no or - templ->icp_rec_field_no */ #endif /* UNIV_DEBUG */ - const byte* data, /*!< in: data to store */ - ulint len, /*!< in: length of the data */ + const byte* data, + ulint len, + ulint sec_field, row_prebuilt_t* prebuilt) - /*!< in: use prebuilt->compress_heap - only here */ { byte* ptr; #ifdef UNIV_DEBUG const dict_field_t* field = dict_index_get_nth_field(index, field_no); + bool clust_templ_for_sec = (sec_field != ULINT_UNDEFINED); #endif /* UNIV_DEBUG */ ut_ad(len != UNIV_SQL_NULL); @@ -2734,7 +2737,8 @@ row_sel_field_store_in_mysql_format_func( containing UTF-8 ENUM columns due to Bug #9526. */ ut_ad(!templ->mbmaxlen || !(templ->mysql_col_len % templ->mbmaxlen)); - ut_ad(len * templ->mbmaxlen >= templ->mysql_col_len + ut_ad(clust_templ_for_sec + || len * templ->mbmaxlen >= templ->mysql_col_len || (field_no == templ->icp_rec_field_no && field->prefix_len > 0) || templ->rec_field_is_prefix); @@ -2763,21 +2767,26 @@ row_sel_field_store_in_mysql_format_func( case DATA_DECIMAL: /* Above are the valid column types for MySQL data. */ #endif /* UNIV_DEBUG */ + /* If sec_field value is present then mapping of + secondary index records to clustered index template + happens for end range comparison. So length can + vary according to secondary index record length. */ ut_ad(field->prefix_len ? field->prefix_len == len - : templ->mysql_col_len == len); + : (clust_templ_for_sec ? + 1 : (templ->mysql_col_len == len))); memcpy(dest, data, len); } } #ifdef UNIV_DEBUG /** Convert a field from Innobase format to MySQL format. */ -# define row_sel_store_mysql_field(m,p,r,i,o,f,t,c) \ - row_sel_store_mysql_field_func(m,p,r,i,o,f,t,c) +# define row_sel_store_mysql_field(m,p,r,i,o,f,t,s) \ + row_sel_store_mysql_field_func(m,p,r,i,o,f,t,s) #else /* UNIV_DEBUG */ /** Convert a field from Innobase format to MySQL format. */ -# define row_sel_store_mysql_field(m,p,r,i,o,f,t,c) \ - row_sel_store_mysql_field_func(m,p,r,o,f,t,c) +# define row_sel_store_mysql_field(m,p,r,i,o,f,t,s) \ + row_sel_store_mysql_field_func(m,p,r,o,f,t,s) #endif /* UNIV_DEBUG */ /** Convert a field in the Innobase format to a field in the MySQL format. @param[out] mysql_rec record in the MySQL format @@ -2792,7 +2801,7 @@ row_sel_field_store_in_mysql_format_func( or sec field no if clust_templ_for_sec is TRUE @param[in] templ row template -@param[in] clust_templ_for_sec TRUE if rec belongs to secondary index +@param[in] sec_field_no field_no if rec belongs to secondary index but prebuilt template is in clustered index format and used only for end range comparison. */ @@ -2808,10 +2817,12 @@ row_sel_store_mysql_field_func( const ulint* offsets, ulint field_no, const mysql_row_templ_t*templ, - bool clust_templ_for_sec) + ulint sec_field_no) { const byte* data; ulint len; + ulint clust_field_no; + bool clust_templ_for_sec = (sec_field_no != ULINT_UNDEFINED); ut_ad(prebuilt->default_rec); ut_ad(templ); @@ -2822,7 +2833,14 @@ row_sel_store_mysql_field_func( || field_no == templ->rec_field_no || field_no == templ->icp_rec_field_no); ut_ad(rec_offs_validate(rec, - clust_templ_for_sec == true ? prebuilt->index : index, offsets)); + clust_templ_for_sec ? prebuilt->index : index, offsets)); + + /* If sec_field_no is present then extract the data from record + using secondary field no. */ + if (clust_templ_for_sec) { + clust_field_no = field_no; + field_no = sec_field_no; + } if (UNIV_UNLIKELY(rec_offs_nth_extern(offsets, field_no))) { @@ -2874,7 +2892,8 @@ row_sel_store_mysql_field_func( row_sel_field_store_in_mysql_format( mysql_rec + templ->mysql_col_offset, - templ, index, field_no, data, len, prebuilt); + templ, index, field_no, data, len, + ULINT_UNDEFINED, prebuilt); if (heap != prebuilt->blob_heap) { mem_heap_free(heap); @@ -2922,9 +2941,15 @@ row_sel_store_mysql_field_func( mem_heap_dup(prebuilt->blob_heap, data, len)); } + /* Reassign the clustered index field no. */ + if (clust_templ_for_sec) { + field_no = clust_field_no; + } + row_sel_field_store_in_mysql_format( mysql_rec + templ->mysql_col_offset, - templ, index, field_no, data, len, prebuilt); + templ, index, field_no, data, len, sec_field_no, + prebuilt); } ut_ad(len != UNIV_SQL_NULL); @@ -2999,6 +3024,8 @@ row_sel_store_mysql_rec( = rec_clust ? templ->clust_rec_field_no : templ->rec_field_no; + ulint sec_field_no = ULINT_UNDEFINED; + /* We should never deliver column prefixes to MySQL, except for evaluating innobase_index_cond() and if the prefix index is longer than the actual row data. */ @@ -3017,13 +3044,13 @@ row_sel_store_mysql_rec( ut_ad(templ->rec_field_no == templ->clust_rec_field_no); - field_no = it - template_col.begin(); + sec_field_no = it - template_col.begin(); } if (!row_sel_store_mysql_field(mysql_rec, prebuilt, rec, index, offsets, field_no, templ, - clust_templ_for_sec)) { + sec_field_no)) { return(FALSE); } } @@ -3033,7 +3060,8 @@ row_sel_store_mysql_rec( NOTE, the record must be cluster index record. Secondary index might not have the Doc ID */ if (dict_table_has_fts_index(prebuilt->table) - && dict_index_is_clust(index)) { + && dict_index_is_clust(index) + && !clust_templ_for_sec) { prebuilt->fts_doc_id = fts_get_doc_id_from_rec( prebuilt->table, rec, NULL); @@ -3406,6 +3434,36 @@ row_sel_copy_cached_field_for_mysql( ut_memcpy(buf, cache, len); } +/** Copy used fields from cached row. +Copy cache record field by field, don't touch fields that +are not covered by current key. +@param[out] buf Where to copy the MySQL row. +@param[in] cached_rec What to copy (in MySQL row format). +@param[in] prebuilt prebuilt struct. */ +void +row_sel_copy_cached_fields_for_mysql( + byte* buf, + const byte* cached_rec, + row_prebuilt_t* prebuilt) +{ + const mysql_row_templ_t*templ; + ulint i; + for (i = 0; i < prebuilt->n_template; i++) { + templ = prebuilt->mysql_template + i; + + row_sel_copy_cached_field_for_mysql( + buf, cached_rec, templ); + /* Copy NULL bit of the current field from cached_rec + to buf */ + if (templ->mysql_null_bit_mask) { + buf[templ->mysql_null_byte_offset] + ^= (buf[templ->mysql_null_byte_offset] + ^ cached_rec[templ->mysql_null_byte_offset]) + & (byte) templ->mysql_null_bit_mask; + } + } +} + /********************************************************************//** Pops a cached row for MySQL from the fetch cache. */ UNIV_INLINE @@ -3665,7 +3723,7 @@ row_search_idx_cond_check( if (!row_sel_store_mysql_field(mysql_rec, prebuilt, rec, prebuilt->index, offsets, templ->icp_rec_field_no, - templ, false)) { + templ, ULINT_UNDEFINED)) { return(ICP_NO_MATCH); } } @@ -5230,8 +5288,19 @@ idx_cond_failed: btr_pcur_store_position(pcur, &mtr); - if (prebuilt->innodb_api) { - prebuilt->innodb_api_rec = result_rec; + if (prebuilt->innodb_api + && (btr_pcur_get_rec(pcur) != result_rec)) { + ulint rec_size = rec_offs_size(offsets); + if (!prebuilt->innodb_api_rec_size || + (prebuilt->innodb_api_rec_size < rec_size)) { + prebuilt->innodb_api_buf = + static_cast<byte*> + (mem_heap_alloc(prebuilt->cursor_heap,rec_size)); + prebuilt->innodb_api_rec_size = rec_size; + } + prebuilt->innodb_api_rec = + rec_copy( + prebuilt->innodb_api_buf, result_rec, offsets); } } |