summaryrefslogtreecommitdiff
path: root/storage/xtradb/row/row0sel.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/xtradb/row/row0sel.cc')
-rw-r--r--storage/xtradb/row/row0sel.cc157
1 files changed, 113 insertions, 44 deletions
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);
}
}