diff options
author | Monty <monty@mariadb.org> | 2018-06-17 14:19:51 +0300 |
---|---|---|
committer | Monty <monty@mariadb.org> | 2018-06-19 16:23:34 +0300 |
commit | ab194666564acab29a4bcb7ca763e0ae0e691d1f (patch) | |
tree | d40e6dfb9ac2b451cc0758e5523917385a19ae28 | |
parent | 831df10981b7851871e1f3b8f04079df0cf5da36 (diff) | |
download | mariadb-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.result | 53 | ||||
-rw-r--r-- | mysql-test/suite/vcol/t/index.test | 62 | ||||
-rw-r--r-- | sql/field.h | 4 | ||||
-rw-r--r-- | sql/table.cc | 48 | ||||
-rw-r--r-- | sql/table.h | 7 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 82 | ||||
-rw-r--r-- | storage/innobase/include/row0mysql.h | 39 | ||||
-rw-r--r-- | storage/innobase/row/row0ins.cc | 20 | ||||
-rw-r--r-- | storage/innobase/row/row0merge.cc | 27 | ||||
-rw-r--r-- | storage/innobase/row/row0sel.cc | 19 | ||||
-rw-r--r-- | storage/innobase/row/row0upd.cc | 23 | ||||
-rw-r--r-- | storage/innobase/row/row0vers.cc | 18 |
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 |