Commit 7eda5561 authored by Aleksey Midenkov's avatar Aleksey Midenkov

MDEV-23672 Assertion `v.v_indexes.empty()' failed in dict_table_t::instant_column

dict_v_idx_t node was shared between two dict_v_col_t objects because
of wrong object copy. Replace memory plain copy with copy constructor.

Tha patch also removes n_v_indexes property and improves "page full"
judgements for trx_undo_log_v_idx().
parent a6f95648
...@@ -413,4 +413,29 @@ DROP TABLE t; ...@@ -413,4 +413,29 @@ DROP TABLE t;
CREATE TABLE t (pk SERIAL, b TEXT CHARACTER SET utf8) ENGINE=InnoDB; CREATE TABLE t (pk SERIAL, b TEXT CHARACTER SET utf8) ENGINE=InnoDB;
ALTER TABLE t MODIFY b TEXT CHARACTER SET utf8mb4 FIRST; ALTER TABLE t MODIFY b TEXT CHARACTER SET utf8mb4 FIRST;
DROP TABLE t; DROP TABLE t;
#
# MDEV-23672 Assertion `v.v_indexes.empty()' failed in dict_table_t::instant_column
#
create table t1 (
col_int integer,
col_text text not null,
col_int_g integer generated always as (col_int) unique,
col_text_g text generated always as (substr(col_text,1,499)) )
engine innodb row_format = redundant;
insert into t1 values (0, 'a', default, default);
insert into t1 values (null, 'b', default, default);
alter table t1 modify column col_text text null, algorithm = instant;
insert into t1 values (1, null, default, default);
insert into t1 values (null, null, default, default);
update t1 set col_text= 'd';
select * from t1;
col_int col_text col_int_g col_text_g
0 d 0 d
NULL d NULL d
1 d 1 d
NULL d NULL d
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency;
...@@ -436,4 +436,23 @@ CREATE TABLE t (pk SERIAL, b TEXT CHARACTER SET utf8) ENGINE=InnoDB; ...@@ -436,4 +436,23 @@ CREATE TABLE t (pk SERIAL, b TEXT CHARACTER SET utf8) ENGINE=InnoDB;
ALTER TABLE t MODIFY b TEXT CHARACTER SET utf8mb4 FIRST; ALTER TABLE t MODIFY b TEXT CHARACTER SET utf8mb4 FIRST;
DROP TABLE t; DROP TABLE t;
--echo #
--echo # MDEV-23672 Assertion `v.v_indexes.empty()' failed in dict_table_t::instant_column
--echo #
create table t1 (
col_int integer,
col_text text not null,
col_int_g integer generated always as (col_int) unique,
col_text_g text generated always as (substr(col_text,1,499)) )
engine innodb row_format = redundant;
insert into t1 values (0, 'a', default, default);
insert into t1 values (null, 'b', default, default);
alter table t1 modify column col_text text null, algorithm = instant;
insert into t1 values (1, null, default, default);
insert into t1 values (null, null, default, default);
update t1 set col_text= 'd';
select * from t1;
check table t1;
drop table t1;
SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency; SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency;
...@@ -2146,7 +2146,6 @@ dict_index_add_col( ...@@ -2146,7 +2146,6 @@ dict_index_add_col(
if (col->is_virtual()) { if (col->is_virtual()) {
dict_v_col_t* v_col = reinterpret_cast<dict_v_col_t*>(col); dict_v_col_t* v_col = reinterpret_cast<dict_v_col_t*>(col);
/* Register the index with the virtual column index list */ /* Register the index with the virtual column index list */
v_col->n_v_indexes++;
v_col->v_indexes.push_front(dict_v_idx_t(index, index->n_def)); v_col->v_indexes.push_front(dict_v_idx_t(index, index->n_def));
col_name = dict_table_get_v_col_name_mysql( col_name = dict_table_get_v_col_name_mysql(
table, dict_col_get_no(col)); table, dict_col_get_no(col));
......
...@@ -425,7 +425,6 @@ dict_mem_table_add_v_col( ...@@ -425,7 +425,6 @@ dict_mem_table_add_v_col(
/* Initialize the index list for virtual columns */ /* Initialize the index list for virtual columns */
ut_ad(v_col->v_indexes.empty()); ut_ad(v_col->v_indexes.empty());
v_col->n_v_indexes = 0;
return(v_col); return(v_col);
} }
......
...@@ -589,8 +589,10 @@ inline bool dict_table_t::instant_column(const dict_table_t& table, ...@@ -589,8 +589,10 @@ inline bool dict_table_t::instant_column(const dict_table_t& table,
mem_heap_dup(heap, table.v_col_names, mem_heap_dup(heap, table.v_col_names,
ulint(end - table.v_col_names))); ulint(end - table.v_col_names)));
v_cols = static_cast<dict_v_col_t*>( v_cols = static_cast<dict_v_col_t*>(
mem_heap_dup(heap, table.v_cols, mem_heap_alloc(heap, table.n_v_cols * sizeof(*v_cols)));
table.n_v_cols * sizeof *v_cols)); for (ulint i = table.n_v_cols; i--; ) {
new (&v_cols[i]) dict_v_col_t(table.v_cols[i]);
}
} else { } else {
ut_ad(table.n_v_cols == 0); ut_ad(table.n_v_cols == 0);
v_col_names = NULL; v_col_names = NULL;
...@@ -603,8 +605,6 @@ inline bool dict_table_t::instant_column(const dict_table_t& table, ...@@ -603,8 +605,6 @@ inline bool dict_table_t::instant_column(const dict_table_t& table,
for (unsigned i = 0; i < n_v_def; i++) { for (unsigned i = 0; i < n_v_def; i++) {
dict_v_col_t& v = v_cols[i]; dict_v_col_t& v = v_cols[i];
DBUG_ASSERT(v.v_indexes.empty());
v.n_v_indexes = 0;
v.base_col = static_cast<dict_col_t**>( v.base_col = static_cast<dict_col_t**>(
mem_heap_dup(heap, v.base_col, mem_heap_dup(heap, v.base_col,
v.num_base * sizeof *v.base_col)); v.num_base * sizeof *v.base_col));
...@@ -714,7 +714,6 @@ inline bool dict_table_t::instant_column(const dict_table_t& table, ...@@ -714,7 +714,6 @@ inline bool dict_table_t::instant_column(const dict_table_t& table,
<dict_v_col_t*>(f.col); <dict_v_col_t*>(f.col);
v_col->v_indexes.push_front( v_col->v_indexes.push_front(
dict_v_idx_t(index, i)); dict_v_idx_t(index, i));
v_col->n_v_indexes++;
} }
} }
} }
...@@ -5031,7 +5030,6 @@ prepare_inplace_add_virtual( ...@@ -5031,7 +5030,6 @@ prepare_inplace_add_virtual(
ctx->add_vcol[j].v_pos = ctx->old_table->n_v_cols ctx->add_vcol[j].v_pos = ctx->old_table->n_v_cols
- ctx->num_to_drop_vcol + j; - ctx->num_to_drop_vcol + j;
ctx->add_vcol[j].n_v_indexes = 0;
/* MDEV-17468: Do this on ctx->instant_table later */ /* MDEV-17468: Do this on ctx->instant_table later */
innodb_base_col_setup(ctx->old_table, field, &ctx->add_vcol[j]); innodb_base_col_setup(ctx->old_table, field, &ctx->add_vcol[j]);
j++; j++;
......
...@@ -766,9 +766,6 @@ struct dict_v_col_t{ ...@@ -766,9 +766,6 @@ struct dict_v_col_t{
/** column pos in table */ /** column pos in table */
unsigned v_pos:10; unsigned v_pos:10;
/** number of indexes */
unsigned n_v_indexes:12;
/** Virtual index list, and column position in the index */ /** Virtual index list, and column position in the index */
std::forward_list<dict_v_idx_t, ut_allocator<dict_v_idx_t> > std::forward_list<dict_v_idx_t, ut_allocator<dict_v_idx_t> >
v_indexes; v_indexes;
...@@ -777,21 +774,17 @@ struct dict_v_col_t{ ...@@ -777,21 +774,17 @@ struct dict_v_col_t{
@param index index to be detached from */ @param index index to be detached from */
void detach(const dict_index_t &index) void detach(const dict_index_t &index)
{ {
if (!n_v_indexes) return; if (v_indexes.empty()) return;
auto i= v_indexes.before_begin(); auto i= v_indexes.before_begin();
ut_d(unsigned n= 0);
do { do {
auto prev = i++; auto prev = i++;
if (i == v_indexes.end()) if (i == v_indexes.end())
{ {
ut_ad(n == n_v_indexes);
return; return;
} }
ut_ad(++n <= n_v_indexes);
if (i->index == &index) if (i->index == &index)
{ {
v_indexes.erase_after(prev); v_indexes.erase_after(prev);
n_v_indexes--;
return; return;
} }
} }
......
...@@ -230,20 +230,35 @@ trx_undo_log_v_idx( ...@@ -230,20 +230,35 @@ trx_undo_log_v_idx(
{ {
ut_ad(pos < table->n_v_def); ut_ad(pos < table->n_v_def);
dict_v_col_t* vcol = dict_table_get_nth_v_col(table, pos); dict_v_col_t* vcol = dict_table_get_nth_v_col(table, pos);
ulint n_idx = vcol->n_v_indexes;
byte* old_ptr; byte* old_ptr;
ut_ad(n_idx > 0); ut_ad(!vcol->v_indexes.empty());
/* Size to reserve, max 5 bytes for each index id and position, plus /* Size to reserve, max 5 bytes for each index id and position, plus
5 bytes for num of indexes, 2 bytes for write total length. 5 bytes for num of indexes, 2 bytes for write total length.
1 byte for undo log record format version marker */ 1 byte for undo log record format version marker */
ulint size = n_idx * (5 + 5) + 5 + 2 + (first_v_col ? 1 : 0); ulint size = 5 + 2 + (first_v_col ? 1 : 0);
const ulint avail = trx_undo_left(undo_block, ptr);
if (trx_undo_left(undo_block, ptr) < size) { if (avail < size) {
return(NULL); return(NULL);
} }
size = 0;
ulint n_idx = 0;
for (const auto& v_index : vcol->v_indexes) {
n_idx++;
/* FIXME: index->id is 64 bits! */
size += mach_get_compressed_size(uint32_t(v_index.index->id));
size += mach_get_compressed_size(v_index.nth_field);
}
size += 2 + mach_get_compressed_size(n_idx);
if (avail < size) {
return(NULL);
}
if (first_v_col) { if (first_v_col) {
/* write the version marker */ /* write the version marker */
mach_write_to_1(ptr, VIRTUAL_COL_UNDO_FORMAT_1); mach_write_to_1(ptr, VIRTUAL_COL_UNDO_FORMAT_1);
...@@ -259,7 +274,8 @@ trx_undo_log_v_idx( ...@@ -259,7 +274,8 @@ trx_undo_log_v_idx(
for (const auto& v_index : vcol->v_indexes) { for (const auto& v_index : vcol->v_indexes) {
ptr += mach_write_compressed( ptr += mach_write_compressed(
ptr, static_cast<ulint>(v_index.index->id)); /* FIXME: index->id is 64 bits! */
ptr, uint32_t(v_index.index->id));
ptr += mach_write_compressed(ptr, v_index.nth_field); ptr += mach_write_compressed(ptr, v_index.nth_field);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment