summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicențiu Ciorbaru <vicentiu@mariadb.org>2017-09-19 00:44:27 +0300
committerVicențiu Ciorbaru <vicentiu@mariadb.org>2017-09-19 00:44:27 +0300
commitb4606367d7ba82652a346320d458c25c391847ea (patch)
treee84665dc0c7f666b39d5e41755a5bd83c9ec357e
parent04ae1207edec4cac80d7206377ae22a8447aa08f (diff)
downloadmariadb-git-b4606367d7ba82652a346320d458c25c391847ea.tar.gz
5.6.37-82.2
-rw-r--r--storage/xtradb/api/api0api.cc21
-rw-r--r--storage/xtradb/handler/ha_innodb.cc21
-rw-r--r--storage/xtradb/handler/ha_innodb.h6
-rw-r--r--storage/xtradb/include/row0mysql.h7
-rw-r--r--storage/xtradb/include/row0sel.h14
-rw-r--r--storage/xtradb/include/univ.i2
-rw-r--r--storage/xtradb/row/row0merge.cc6
-rw-r--r--storage/xtradb/row/row0sel.cc157
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);
}
}