summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty <monty@mariadb.org>2018-06-17 14:19:51 +0300
committerMonty <monty@mariadb.org>2018-06-19 16:23:34 +0300
commitab194666564acab29a4bcb7ca763e0ae0e691d1f (patch)
treed40e6dfb9ac2b451cc0758e5523917385a19ae28
parent831df10981b7851871e1f3b8f04079df0cf5da36 (diff)
downloadmariadb-git-ab194666564acab29a4bcb7ca763e0ae0e691d1f.tar.gz
MDEV-15114 ASAN heap-use-after-free in mem_heap_dup or dfield_data_is_binary_equal
The bug was that innobase_get_computed_value() trashed record[0] and data in Field_blob::value Fixed by using a record on the heap for innobase_get_computed_value() Reviewer: Marko Mäkelä
-rw-r--r--mysql-test/suite/vcol/r/index.result53
-rw-r--r--mysql-test/suite/vcol/t/index.test62
-rw-r--r--sql/field.h4
-rw-r--r--sql/table.cc48
-rw-r--r--sql/table.h7
-rw-r--r--storage/innobase/handler/ha_innodb.cc82
-rw-r--r--storage/innobase/include/row0mysql.h39
-rw-r--r--storage/innobase/row/row0ins.cc20
-rw-r--r--storage/innobase/row/row0merge.cc27
-rw-r--r--storage/innobase/row/row0sel.cc19
-rw-r--r--storage/innobase/row/row0upd.cc23
-rw-r--r--storage/innobase/row/row0vers.cc18
12 files changed, 376 insertions, 26 deletions
diff --git a/mysql-test/suite/vcol/r/index.result b/mysql-test/suite/vcol/r/index.result
index cd4ebc96024..8860a728bd1 100644
--- a/mysql-test/suite/vcol/r/index.result
+++ b/mysql-test/suite/vcol/r/index.result
@@ -1,3 +1,6 @@
+#
+# Test table with a key that consists of indirect virtual fields
+#
CREATE TABLE t1 (a int, b int as (a+1) virtual, c int as (b+1) virtual, index(c)) engine=myisam;
insert into t1 (a) values (1),(2),(3);
update t1 set a=5 where a=3;
@@ -36,3 +39,53 @@ a b c
2 3 4
5 6 7
drop table t1;
+#
+# MDEV-15114
+# ASAN heap-use-after-free in mem_heap_dup or
+# dfield_data_is_binary_equal
+#
+CREATE TABLE t1 (
+pk INT,
+extra tinyint,
+c TEXT,
+vc LONGTEXT AS (c) VIRTUAL,
+i INT,
+PRIMARY KEY(pk),
+UNIQUE(i),
+INDEX(vc(64))
+) ENGINE=InnoDB;
+INSERT INTO t1 (pk,extra, c, i) VALUES (1, 10, REPEAT('foo ',15000),0);
+REPLACE INTO t1 (pk,extra, c,i) SELECT pk,extra+10, c,i FROM t1;
+select pk, extra, left(c, 10), length(c), left(vc,10), length(vc), extra from t1;
+pk extra left(c, 10) length(c) left(vc,10) length(vc) extra
+1 20 foo foo fo 60000 foo foo fo 60000 20
+DROP TABLE t1;
+#
+# Update of deleted row with binary logging enabled
+#
+SET BINLOG_FORMAT=row;
+CREATE TABLE t1 (
+pk INT,
+c TEXT,
+vc LONGTEXT AS (c) VIRTUAL,
+i INT,
+PRIMARY KEY(pk),
+UNIQUE(i),
+INDEX(vc(64))
+) ENGINE=InnoDB;
+INSERT INTO t1 (pk,c,i) VALUES (1,REPEAT('foo ',15000),10);
+INSERT INTO t1 (pk,c,i) VALUES (2,REPEAT('bar ',15000),11);
+connect c1,localhost,root,,;
+connection c1;
+begin;
+DELETE from t1 WHERE pk=1;
+connection default;
+update t1 set pk=1 where pk=2;
+connection c1;
+commit;
+connection default;
+select pk, left(c, 10), length(c), i from t1;
+pk left(c, 10) length(c) i
+1 bar bar ba 60000 11
+drop table t1;
+disconnect c1;
diff --git a/mysql-test/suite/vcol/t/index.test b/mysql-test/suite/vcol/t/index.test
index 55d5b68f26b..72eed0a8a40 100644
--- a/mysql-test/suite/vcol/t/index.test
+++ b/mysql-test/suite/vcol/t/index.test
@@ -1,8 +1,9 @@
--source include/have_innodb.inc
+--source include/have_log_bin.inc
-#
-# Test creating table with a key that consists of indirect virtual fields
-#
+--echo #
+--echo # Test table with a key that consists of indirect virtual fields
+--echo #
CREATE TABLE t1 (a int, b int as (a+1) virtual, c int as (b+1) virtual, index(c)) engine=myisam;
insert into t1 (a) values (1),(2),(3);
@@ -23,3 +24,58 @@ select * from t1 where c=7;
check table t1;
select * from t1;
drop table t1;
+
+--echo #
+--echo # MDEV-15114
+--echo # ASAN heap-use-after-free in mem_heap_dup or
+--echo # dfield_data_is_binary_equal
+--echo #
+
+CREATE TABLE t1 (
+ pk INT,
+ extra tinyint,
+ c TEXT,
+ vc LONGTEXT AS (c) VIRTUAL,
+ i INT,
+ PRIMARY KEY(pk),
+ UNIQUE(i),
+ INDEX(vc(64))
+) ENGINE=InnoDB;
+
+INSERT INTO t1 (pk,extra, c, i) VALUES (1, 10, REPEAT('foo ',15000),0);
+REPLACE INTO t1 (pk,extra, c,i) SELECT pk,extra+10, c,i FROM t1;
+select pk, extra, left(c, 10), length(c), left(vc,10), length(vc), extra from t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Update of deleted row with binary logging enabled
+--echo #
+
+SET BINLOG_FORMAT=row;
+
+CREATE TABLE t1 (
+ pk INT,
+ c TEXT,
+ vc LONGTEXT AS (c) VIRTUAL,
+ i INT,
+ PRIMARY KEY(pk),
+ UNIQUE(i),
+ INDEX(vc(64))
+) ENGINE=InnoDB;
+
+INSERT INTO t1 (pk,c,i) VALUES (1,REPEAT('foo ',15000),10);
+INSERT INTO t1 (pk,c,i) VALUES (2,REPEAT('bar ',15000),11);
+
+--connect (c1,localhost,root,,)
+--connection c1
+begin;
+DELETE from t1 WHERE pk=1;
+--connection default
+--send update t1 set pk=1 where pk=2
+--connection c1
+commit;
+--connection default
+--reap
+select pk, left(c, 10), length(c), i from t1;
+drop table t1;
+disconnect c1;
diff --git a/sql/field.h b/sql/field.h
index e554f92031c..820cc5f3a7a 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -3433,6 +3433,10 @@ public:
uint32 max_display_length();
uint32 char_length() const;
uint is_equal(Create_field *new_field);
+
+ friend void TABLE::remember_blob_values(String *blob_storage);
+ friend void TABLE::restore_blob_values(String *blob_storage);
+
private:
int do_save_field_metadata(uchar *first_byte);
};
diff --git a/sql/table.cc b/sql/table.cc
index 198e77f1872..f7aee3eae7d 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -2434,6 +2434,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
reg_field->vcol_info= vcol_info;
share->virtual_fields++;
share->stored_fields--;
+ if (reg_field->flags & BLOB_FLAG)
+ share->virtual_not_stored_blob_fields++;
/* Correct stored_rec_length as non stored fields are last */
recpos= (uint) (reg_field->ptr - record);
if (share->stored_rec_length >= recpos)
@@ -6776,6 +6778,52 @@ void TABLE::move_fields(Field **ptr, const uchar *to, const uchar *from)
}
+/*
+ Store all allocated virtual fields blob values
+ Used by InnoDB when calculating virtual fields for it's own internal
+ records
+*/
+
+void TABLE::remember_blob_values(String *blob_storage)
+{
+ Field **vfield_ptr;
+ for (vfield_ptr= vfield; *vfield_ptr; vfield_ptr++)
+ {
+ if ((*vfield_ptr)->type() == MYSQL_TYPE_BLOB &&
+ !(*vfield_ptr)->vcol_info->stored_in_db)
+ {
+ Field_blob *blob= ((Field_blob*) *vfield_ptr);
+ memcpy((void*) blob_storage, (void*) &blob->value, sizeof(blob->value));
+ blob_storage++;
+ blob->value.release();
+ }
+ }
+}
+
+
+/*
+ Restore all allocated virtual fields blob values
+ Used by InnoDB when calculating virtual fields for it's own internal
+ records
+*/
+
+void TABLE::restore_blob_values(String *blob_storage)
+{
+ Field **vfield_ptr;
+ for (vfield_ptr= vfield; *vfield_ptr; vfield_ptr++)
+ {
+ if ((*vfield_ptr)->type() == MYSQL_TYPE_BLOB &&
+ !(*vfield_ptr)->vcol_info->stored_in_db)
+ {
+ Field_blob *blob= ((Field_blob*) *vfield_ptr);
+ blob->value.free();
+ memcpy((void*) &blob->value, (void*) blob_storage, sizeof(blob->value));
+ blob_storage++;
+ }
+ }
+}
+
+
/**
@brief
Allocate space for keys
diff --git a/sql/table.h b/sql/table.h
index 4c409342c27..c0cca1026ea 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -663,8 +663,11 @@ struct TABLE_SHARE
*/
uint null_bytes_for_compare;
uint fields; /* number of fields */
- uint stored_fields; /* number of stored fields, purely virtual not included */
+ /* number of stored fields, purely virtual not included */
+ uint stored_fields;
uint virtual_fields; /* number of purely virtual fields */
+ /* number of purely virtual not stored blobs */
+ uint virtual_not_stored_blob_fields;
uint null_fields; /* number of null fields */
uint blob_fields; /* number of blob fields */
uint varchar_fields; /* number of varchar fields */
@@ -1423,6 +1426,8 @@ public:
{ return (my_ptrdiff_t) (s->default_values - record[0]); }
void move_fields(Field **ptr, const uchar *to, const uchar *from);
+ void remember_blob_values(String *blob_storage);
+ void restore_blob_values(String *blob_storage);
uint actual_n_key_parts(KEY *keyinfo);
ulong actual_key_flags(KEY *keyinfo);
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 2c8ea81e286..7ac7495e221 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -21760,6 +21760,77 @@ innobase_get_field_from_update_vector(
return (NULL);
}
+
+/**
+ Allocate a heap and record for calculating virtual fields
+ Used mainly for virtual fields in indexes
+
+@param[in] thd MariaDB THD
+@param[in] index Index in use
+@param[out] heap Heap that holds temporary row
+@param[in,out] mysql_table MariaDB table
+@param[out] rec Pointer to allocated MariaDB record
+@param[out] storage Internal storage for blobs etc
+
+@return FALSE ok
+@return TRUE malloc failure
+*/
+
+bool innobase_allocate_row_for_vcol(
+ THD * thd,
+ dict_index_t* index,
+ mem_heap_t** heap,
+ TABLE** table,
+ byte** record,
+ VCOL_STORAGE** storage)
+{
+ TABLE *maria_table;
+ String *blob_value_storage;
+ if (!*table)
+ *table= innobase_find_mysql_table_for_vc(thd, index->table);
+ maria_table= *table;
+ if (!*heap && !(*heap= mem_heap_create(srv_page_size)))
+ {
+ *storage= 0;
+ return TRUE;
+ }
+ *record= static_cast<byte*>(mem_heap_alloc(*heap,
+ maria_table->s->reclength));
+ *storage= static_cast<VCOL_STORAGE*>
+ (mem_heap_alloc(*heap, sizeof(**storage)));
+ blob_value_storage= static_cast<String*>
+ (mem_heap_alloc(*heap,
+ maria_table->s->virtual_not_stored_blob_fields *
+ sizeof(String)));
+ if (!*record || !*storage || !blob_value_storage)
+ {
+ *storage= 0;
+ return TRUE;
+ }
+ (*storage)->maria_table= maria_table;
+ (*storage)->innobase_record= *record;
+ (*storage)->maria_record= maria_table->field[0]->record_ptr();
+ (*storage)->blob_value_storage= blob_value_storage;
+
+ maria_table->move_fields(maria_table->field, *record,
+ (*storage)->maria_record);
+ maria_table->remember_blob_values(blob_value_storage);
+
+ return FALSE;
+}
+
+
+/** Free memory allocated by innobase_allocate_row_for_vcol() */
+
+void innobase_free_row_for_vcol(VCOL_STORAGE *storage)
+{
+ TABLE *maria_table= storage->maria_table;
+ maria_table->move_fields(maria_table->field, storage->maria_record,
+ storage->innobase_record);
+ maria_table->restore_blob_values(storage->blob_value_storage);
+}
+
+
/** Get the computed value by supplying the base column values.
@param[in,out] row the data row
@param[in] col virtual column
@@ -21785,12 +21856,12 @@ innobase_get_computed_value(
const dict_field_t* ifield,
THD* thd,
TABLE* mysql_table,
+ byte* mysql_rec,
const dict_table_t* old_table,
upd_t* parent_update,
dict_foreign_t* foreign)
{
byte rec_buf2[REC_VERSION_56_MAX_INDEX_COL_LEN];
- byte* mysql_rec;
byte* buf;
dfield_t* field;
ulint len;
@@ -21803,6 +21874,7 @@ innobase_get_computed_value(
ut_ad(index->table->vc_templ);
ut_ad(thd != NULL);
+ ut_ad(mysql_table);
const mysql_row_templ_t*
vctempl = index->table->vc_templ->vtempl[
@@ -21820,14 +21892,6 @@ innobase_get_computed_value(
buf = rec_buf2;
}
- if (!mysql_table) {
- mysql_table = innobase_find_mysql_table_for_vc(thd, index->table);
- }
-
- ut_ad(mysql_table);
-
- mysql_rec = mysql_table->record[0];
-
for (ulint i = 0; i < col->num_base; i++) {
dict_col_t* base_col = col->base_col[i];
const dfield_t* row_field = NULL;
diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h
index 7a34c025dab..8a573a23652 100644
--- a/storage/innobase/include/row0mysql.h
+++ b/storage/innobase/include/row0mysql.h
@@ -846,6 +846,44 @@ struct SysIndexCallback {
virtual void operator()(mtr_t* mtr, btr_pcur_t* pcur) throw() = 0;
};
+
+/** Storage for calculating virtual columns */
+
+class String;
+struct VCOL_STORAGE
+{
+ TABLE *maria_table;
+ byte *innobase_record;
+ byte *maria_record;
+ String *blob_value_storage;
+};
+
+/**
+ Allocate a heap and record for calculating virtual fields
+ Used mainly for virtual fields in indexes
+
+@param[in] thd MariaDB THD
+@param[in] index Index in use
+@param[out] heap Heap that holds temporary row
+@param[in,out] mysql_table MariaDB table
+@param[out] rec Pointer to allocated MariaDB record
+@param[out] storage Internal storage for blobs etc
+
+@return FALSE ok
+@return TRUE malloc failure
+*/
+
+bool innobase_allocate_row_for_vcol(
+ THD * thd,
+ dict_index_t* index,
+ mem_heap_t** heap,
+ TABLE** table,
+ byte** record,
+ VCOL_STORAGE** storage);
+
+/** Free memory allocated by innobase_allocate_row_for_vcol() */
+void innobase_free_row_for_vcol(VCOL_STORAGE *storage);
+
/** Get the computed value by supplying the base column values.
@param[in,out] row the data row
@param[in] col virtual column
@@ -870,6 +908,7 @@ innobase_get_computed_value(
const dict_field_t* ifield,
THD* thd,
TABLE* mysql_table,
+ byte* mysql_rec,
const dict_table_t* old_table,
upd_t* parent_update,
dict_foreign_t* foreign);
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
index 1aa97bc34c5..57796939be1 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -944,6 +944,9 @@ row_ins_foreign_fill_virtual(
rec_get_offsets(rec, index, offsets_, true,
ULINT_UNDEFINED, &cascade->heap);
mem_heap_t* v_heap = NULL;
+ TABLE* mysql_table= NULL;
+ VCOL_STORAGE* vcol_storage= NULL;
+ byte* record;
upd_t* update = cascade->update;
ulint n_v_fld = index->table->n_v_def;
ulint n_diff;
@@ -963,6 +966,14 @@ row_ins_foreign_fill_virtual(
innobase_init_vc_templ(index->table);
}
+ if (innobase_allocate_row_for_vcol(thd, index, &v_heap,
+ &mysql_table,
+ &record, &vcol_storage))
+ {
+ *err = DB_OUT_OF_MEMORY;
+ goto func_exit;
+ }
+
for (ulint i = 0; i < n_v_fld; i++) {
dict_v_col_t* col = dict_table_get_nth_v_col(
@@ -976,8 +987,8 @@ row_ins_foreign_fill_virtual(
dfield_t* vfield = innobase_get_computed_value(
update->old_vrow, col, index,
- &v_heap, update->heap, NULL, thd, NULL,
- NULL, NULL, NULL);
+ &v_heap, update->heap, NULL, thd, mysql_table,
+ record, NULL, NULL, NULL);
if (vfield == NULL) {
*err = DB_COMPUTE_VALUE_FAILED;
@@ -1007,7 +1018,8 @@ row_ins_foreign_fill_virtual(
dfield_t* new_vfield = innobase_get_computed_value(
update->old_vrow, col, index,
&v_heap, update->heap, NULL, thd,
- NULL, NULL, node->update, foreign);
+ mysql_table, record, NULL,
+ node->update, foreign);
if (new_vfield == NULL) {
*err = DB_COMPUTE_VALUE_FAILED;
@@ -1025,6 +1037,8 @@ row_ins_foreign_fill_virtual(
func_exit:
if (v_heap) {
+ if (vcol_storage)
+ innobase_free_row_for_vcol(vcol_storage);
mem_heap_free(v_heap);
}
}
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index bed15941638..66f3b3936af 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -534,6 +534,8 @@ row_merge_buf_add(
ulint bucket = 0;
doc_id_t write_doc_id;
ulint n_row_added = 0;
+ VCOL_STORAGE* vcol_storage= 0;
+ byte* record;
DBUG_ENTER("row_merge_buf_add");
if (buf->n_tuples >= buf->max_tuples) {
@@ -606,14 +608,21 @@ row_merge_buf_add(
dict_index_t* clust_index
= dict_table_get_first_index(new_table);
+ if (!vcol_storage &&
+ innobase_allocate_row_for_vcol(trx->mysql_thd, clust_index, v_heap, &my_table, &record, &vcol_storage)) {
+ *err = DB_OUT_OF_MEMORY;
+ goto error;
+ }
+
row_field = innobase_get_computed_value(
row, v_col, clust_index,
v_heap, NULL, ifield, trx->mysql_thd,
- my_table, old_table, NULL, NULL);
+ my_table, record, old_table, NULL,
+ NULL);
if (row_field == NULL) {
*err = DB_COMPUTE_VALUE_FAILED;
- DBUG_RETURN(0);
+ goto error;
}
dfield_copy(field, row_field);
} else {
@@ -649,7 +658,7 @@ row_merge_buf_add(
ib::warn() << "FTS Doc ID is"
" zero. Record"
" skipped";
- DBUG_RETURN(0);
+ goto error;
}
}
@@ -797,7 +806,7 @@ row_merge_buf_add(
/* If this is FTS index, we already populated the sort buffer, return
here */
if (index->type & DICT_FTS) {
- DBUG_RETURN(n_row_added);
+ goto end;
}
#ifdef UNIV_DEBUG
@@ -831,7 +840,7 @@ row_merge_buf_add(
/* Reserve bytes for the end marker of row_merge_block_t. */
if (buf->total_size + data_size >= srv_sort_buf_size) {
- DBUG_RETURN(0);
+ goto error;
}
buf->total_size += data_size;
@@ -850,7 +859,15 @@ row_merge_buf_add(
mem_heap_empty(conv_heap);
}
+end:
+ if (vcol_storage)
+ innobase_free_row_for_vcol(vcol_storage);
DBUG_RETURN(n_row_added);
+
+error:
+ if (vcol_storage)
+ innobase_free_row_for_vcol(vcol_storage);
+ DBUG_RETURN(0);
}
/*************************************************************//**
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index 7383d3d9510..68a81615e88 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -179,6 +179,8 @@ row_sel_sec_rec_is_for_clust_rec(
ulint* clust_offs = clust_offsets_;
ulint* sec_offs = sec_offsets_;
ibool is_equal = TRUE;
+ VCOL_STORAGE* vcol_storage= 0;
+ byte* record;
rec_offs_init(clust_offsets_);
rec_offs_init(sec_offsets_);
@@ -226,6 +228,17 @@ row_sel_sec_rec_is_for_clust_rec(
dfield_t* vfield;
row_ext_t* ext;
+ if (!vcol_storage)
+ {
+ TABLE *mysql_table= thr->prebuilt->m_mysql_table;
+ innobase_allocate_row_for_vcol(thr_get_trx(thr)->mysql_thd,
+ clust_index,
+ &heap,
+ &mysql_table,
+ &record,
+ &vcol_storage);
+ }
+
v_col = reinterpret_cast<const dict_v_col_t*>(col);
row = row_build(ROW_COPY_POINTERS,
@@ -237,8 +250,8 @@ row_sel_sec_rec_is_for_clust_rec(
row, v_col, clust_index,
&heap, NULL, NULL,
thr_get_trx(thr)->mysql_thd,
- thr->prebuilt->m_mysql_table, NULL,
- NULL, NULL);
+ thr->prebuilt->m_mysql_table,
+ record, NULL, NULL, NULL);
clust_len = vfield->len;
clust_field = static_cast<byte*>(vfield->data);
@@ -326,6 +339,8 @@ inequal:
func_exit:
if (UNIV_LIKELY_NULL(heap)) {
+ if (UNIV_LIKELY_NULL(vcol_storage))
+ innobase_free_row_for_vcol(vcol_storage);
mem_heap_free(heap);
}
return(is_equal);
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index 18a6a26f3ce..171e06894ca 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -1023,6 +1023,7 @@ row_upd_build_sec_rec_difference_binary(
return(update);
}
+
/** Builds an update vector from those fields, excluding the roll ptr and
trx id fields, which in an index entry differ from a record that has
the equal ordering fields. NOTE: we compare the fields as binary strings!
@@ -1123,6 +1124,9 @@ row_upd_build_difference_binary(
if (n_v_fld > 0) {
row_ext_t* ext;
mem_heap_t* v_heap = NULL;
+ byte* record;
+ VCOL_STORAGE* vcol_storage;
+
THD* thd;
if (trx == NULL) {
@@ -1133,6 +1137,10 @@ row_upd_build_difference_binary(
ut_ad(!update->old_vrow);
+ innobase_allocate_row_for_vcol(thd, index, &v_heap,
+ &mysql_table,
+ &record, &vcol_storage);
+
for (i = 0; i < n_v_fld; i++) {
const dict_v_col_t* col
= dict_table_get_nth_v_col(index->table, i);
@@ -1151,7 +1159,7 @@ row_upd_build_difference_binary(
dfield_t* vfield = innobase_get_computed_value(
update->old_vrow, col, index,
- &v_heap, heap, NULL, thd, mysql_table,
+ &v_heap, heap, NULL, thd, mysql_table, record,
NULL, NULL, NULL);
if (!dfield_data_is_binary_equal(
@@ -1177,6 +1185,8 @@ row_upd_build_difference_binary(
}
if (v_heap) {
+ if (vcol_storage)
+ innobase_free_row_for_vcol(vcol_storage);
mem_heap_free(v_heap);
}
}
@@ -2116,6 +2126,12 @@ row_upd_store_v_row(
{
mem_heap_t* heap = NULL;
dict_index_t* index = dict_table_get_first_index(node->table);
+ byte* record= 0;
+ VCOL_STORAGE *vcol_storage= 0;
+
+ if (!update)
+ innobase_allocate_row_for_vcol(thd, index, &heap, &mysql_table,
+ &record, &vcol_storage);
for (ulint col_no = 0; col_no < dict_table_get_n_v_cols(node->table);
col_no++) {
@@ -2168,7 +2184,7 @@ row_upd_store_v_row(
innobase_get_computed_value(
node->row, col, index,
&heap, node->heap, NULL,
- thd, mysql_table, NULL,
+ thd, mysql_table, record, NULL,
NULL, NULL);
}
}
@@ -2176,8 +2192,11 @@ row_upd_store_v_row(
}
if (heap) {
+ if (vcol_storage)
+ innobase_free_row_for_vcol(vcol_storage);
mem_heap_free(heap);
}
+
}
/** Stores to the heap the row on which the node->pcur is positioned.
diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc
index 31cef0bad2d..aebcf70715f 100644
--- a/storage/innobase/row/row0vers.cc
+++ b/storage/innobase/row/row0vers.cc
@@ -446,6 +446,19 @@ row_vers_build_clust_v_col(
mem_heap_t* heap)
{
mem_heap_t* local_heap = NULL;
+ VCOL_STORAGE *vcol_storage= NULL;
+ THD* thd= current_thd;
+ TABLE* maria_table= 0;
+ byte* record= 0;
+
+ ut_ad(dict_index_has_virtual(index));
+
+ innobase_allocate_row_for_vcol(thd, index,
+ &local_heap,
+ &maria_table,
+ &record,
+ &vcol_storage);
+
for (ulint i = 0; i < dict_index_get_n_fields(index); i++) {
const dict_field_t* ind_field = dict_index_get_nth_field(
index, i);
@@ -458,15 +471,18 @@ row_vers_build_clust_v_col(
innobase_get_computed_value(
row, col, clust_index, &local_heap,
- heap, NULL, current_thd, NULL, NULL,
+ heap, NULL, thd, maria_table, record, NULL,
NULL, NULL);
}
}
if (local_heap) {
+ if (vcol_storage)
+ innobase_free_row_for_vcol(vcol_storage);
mem_heap_free(local_heap);
}
}
+
/** Build latest virtual column data from undo log
@param[in] in_purge whether this is the purge thread
@param[in] rec clustered index record