Commit 16d43150 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-17721 Corrupted data dictionary after instant ADD COLUMN

dict_index_t::reconstruct_fields(): Correctly permute the fields
of the columns. The code was totally wrong in MDEV-15562.
It would only work when columns are added last or dropped,
but not when columns are permuted.
parent f8501224
......@@ -534,6 +534,14 @@ a c
3 42
4 42
DROP TABLE t1;
CREATE TABLE t1 (i INT) ENGINE=InnoDB ROW_FORMAT=REDUNDANT;
INSERT INTO t1 SET i=1;
ALTER TABLE t1 ADD COLUMN b BIT FIRST;
ALTER TABLE t1 ADD COLUMN v INT AS (i) VIRTUAL;
SELECT * FROM t1;
b i v
NULL 1 1
DROP TABLE t1;
CREATE TABLE t1
(id INT PRIMARY KEY, c2 INT UNIQUE,
c3 POINT NOT NULL DEFAULT ST_GeomFromText('POINT(3 4)'),
......@@ -1014,6 +1022,14 @@ a c
3 42
4 42
DROP TABLE t1;
CREATE TABLE t1 (i INT) ENGINE=InnoDB ROW_FORMAT=COMPACT;
INSERT INTO t1 SET i=1;
ALTER TABLE t1 ADD COLUMN b BIT FIRST;
ALTER TABLE t1 ADD COLUMN v INT AS (i) VIRTUAL;
SELECT * FROM t1;
b i v
NULL 1 1
DROP TABLE t1;
CREATE TABLE t1
(id INT PRIMARY KEY, c2 INT UNIQUE,
c3 POINT NOT NULL DEFAULT ST_GeomFromText('POINT(3 4)'),
......@@ -1494,10 +1510,18 @@ a c
3 42
4 42
DROP TABLE t1;
CREATE TABLE t1 (i INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
INSERT INTO t1 SET i=1;
ALTER TABLE t1 ADD COLUMN b BIT FIRST;
ALTER TABLE t1 ADD COLUMN v INT AS (i) VIRTUAL;
SELECT * FROM t1;
b i v
NULL 1 1
DROP TABLE t1;
disconnect analyze;
SELECT variable_value-@old_instant instants
FROM information_schema.global_status
WHERE variable_name = 'innodb_instant_alter_column';
instants
84
87
SET GLOBAL innodb_purge_rseg_truncate_frequency= @saved_frequency;
......@@ -130,11 +130,12 @@ update t1 set f3 = 19;
select * from t1;
f1 f3
1 19
alter table t1 drop column f1, add column f5 int default 10, algorithm=instant;
alter table t1 drop column f1, add column f5 tinyint default 10 first,
algorithm=instant;
insert into t1 values(4, 10);
select * from t1;
f3 f5
19 10
f5 f3
10 19
4 10
create table t2(f1 int, f2 int not null) engine=innodb;
insert into t2(f1, f2) values(1, 2);
......@@ -154,8 +155,8 @@ create table t3(f1 int, f2 int not null)engine=innodb;
insert into t3 values(1, 2);
alter table t3 drop column f2, add column f3 int default 1, add column f4 int default 4, algorithm=instant;
select * from t1;
f3 f5
19 10
f5 f3
10 19
4 10
alter table t1 add column f6 int default 9,drop column f5, algorithm = instant;
insert into t1 values(4, 9);
......@@ -163,7 +164,7 @@ alter table t1 force, algorithm=inplace;
select * from t1;
f3 f6
19 9
4 9
10 9
4 9
select * from t2;
f1 f4 f5 f6
......
......@@ -410,6 +410,13 @@ UPDATE t1 SET a=a+2;
SELECT * FROM t1;
DROP TABLE t1;
eval CREATE TABLE t1 (i INT) $engine;
INSERT INTO t1 SET i=1;
ALTER TABLE t1 ADD COLUMN b BIT FIRST;
ALTER TABLE t1 ADD COLUMN v INT AS (i) VIRTUAL;
SELECT * FROM t1;
DROP TABLE t1;
dec $format;
}
disconnect analyze;
......
......@@ -64,7 +64,8 @@ alter table t1 drop column f2, add column f3 int default 3, algorithm=instant;
select * from t1;
update t1 set f3 = 19;
select * from t1;
alter table t1 drop column f1, add column f5 int default 10, algorithm=instant;
alter table t1 drop column f1, add column f5 tinyint default 10 first,
algorithm=instant;
insert into t1 values(4, 10);
select * from t1;
......
......@@ -1217,17 +1217,23 @@ inline void dict_index_t::reconstruct_fields()
ulint n_core_null = 0;
const bool comp = dict_table_is_comp(table);
const auto* non_pk_col_map = table->instant->non_pk_col_map;
for (unsigned i = n_first, o = i, j = 0; i < n_fields; ) {
for (unsigned i = n_first, j = 0; i < n_fields; ) {
dict_field_t& f = tfields[i++];
auto c = *non_pk_col_map++;
if (c & 1U << 15) {
f.col = &table->instant->dropped[j++];
ut_ad(f.col->is_dropped());
DBUG_ASSERT(f.col->is_dropped());
f.fixed_len = dict_col_get_fixed_size(f.col, comp);
} else {
f = fields[o++];
f.col = dict_table_get_nth_col(table, c);
f.name = f.col->name(*table);
const auto old = std::find_if(
fields + n_first, fields + n_fields,
[c](const dict_field_t& o)
{ return o.col->ind == c; });
ut_ad(old >= &fields[n_first]);
ut_ad(old < &fields[n_fields]);
DBUG_ASSERT(!old->prefix_len);
DBUG_ASSERT(old->col == &table->cols[c]);
f = *old;
}
f.col->clear_instant();
......
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