mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-29021 ALTER TABLE fails when a stored virtual column is dropped+added
We shouldn't rely on `fill_extra_persistent_columns`, as it only updates fields which have an index > cols->n_bits (replication bitmap width). Actually, it should never be used, as its approach is error-prone. Normal update_virtual_fields+update_default_fields should be done.
This commit is contained in:
committed by
Sergei Golubchik
parent
ea46fdcea4
commit
93fb92d3f9
@ -643,6 +643,67 @@ insert t1 (b) values ('k');
|
|||||||
insert t1 (b) values ('m');
|
insert t1 (b) values ('m');
|
||||||
set debug_sync= 'now signal goforit';
|
set debug_sync= 'now signal goforit';
|
||||||
connection con2;
|
connection con2;
|
||||||
|
connection default;
|
||||||
|
drop table t1;
|
||||||
|
set debug_sync= reset;
|
||||||
|
#
|
||||||
|
# MDEV-29021 ALTER TABLE fails when a stored virtual column is dropped and added
|
||||||
|
#
|
||||||
|
create table t1 (a char(9), b char(9) as (a) stored) engine=InnoDB;
|
||||||
|
insert into t1(a) values ('foobar');
|
||||||
|
set debug_sync= 'now wait_for downgraded';
|
||||||
|
connection con2;
|
||||||
|
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
|
||||||
|
alter ignore table t1 drop b, add b char(3) as (a) stored, algorithm=copy, lock=none;
|
||||||
|
connection default;
|
||||||
|
update t1 set a = 'foobarqux';
|
||||||
|
set debug_sync= 'now signal goforit';
|
||||||
|
connection con2;
|
||||||
|
Warnings:
|
||||||
|
Warning 1265 Data truncated for column 'b' at row 1
|
||||||
|
Warning 1265 Data truncated for column 'b' at row 2
|
||||||
|
connection default;
|
||||||
|
drop table t1;
|
||||||
|
set debug_sync= reset;
|
||||||
|
# (duplicate) MDEV-29007 Assertion `marked_for_write_or_computed()'
|
||||||
|
# failed upon online ADD COLUMN .. FIRST
|
||||||
|
create table t (a int);
|
||||||
|
insert into t values (1),(2);
|
||||||
|
set debug_sync= 'now wait_for downgraded';
|
||||||
|
connection con2;
|
||||||
|
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
|
||||||
|
alter table t add c int first, algorithm=copy, lock=none;
|
||||||
|
connection default;
|
||||||
|
insert into t values (3);
|
||||||
|
set debug_sync= 'now signal goforit';
|
||||||
|
connection con2;
|
||||||
|
connection default;
|
||||||
|
drop table t;
|
||||||
|
set debug_sync= reset;
|
||||||
|
# UNIQUE blob duplicates are not ignored.
|
||||||
|
create table t1 (b blob);
|
||||||
|
insert into t1 values ('foo'),('bar');
|
||||||
|
set debug_sync= 'now wait_for downgraded';
|
||||||
|
connection con2;
|
||||||
|
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
|
||||||
|
alter table t1 add unique(b), algorithm=copy, lock=none;
|
||||||
|
connection default;
|
||||||
|
insert into t1 values ('qux'),('foo');
|
||||||
|
set debug_sync= 'now signal goforit';
|
||||||
|
connection con2;
|
||||||
|
ERROR 23000: Duplicate entry 'foo' for key 'b'
|
||||||
|
select * from t1;
|
||||||
|
b
|
||||||
|
foo
|
||||||
|
bar
|
||||||
|
qux
|
||||||
|
foo
|
||||||
|
show create table t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`b` blob DEFAULT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
|
||||||
|
connection default;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
set debug_sync= reset;
|
set debug_sync= reset;
|
||||||
#
|
#
|
||||||
|
@ -796,7 +796,81 @@ set debug_sync= 'now signal goforit';
|
|||||||
|
|
||||||
--connection con2
|
--connection con2
|
||||||
--reap
|
--reap
|
||||||
|
--connection default
|
||||||
|
drop table t1;
|
||||||
|
set debug_sync= reset;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-29021 ALTER TABLE fails when a stored virtual column is dropped and added
|
||||||
|
--echo #
|
||||||
|
create table t1 (a char(9), b char(9) as (a) stored) engine=InnoDB;
|
||||||
|
insert into t1(a) values ('foobar');
|
||||||
|
|
||||||
|
--send set debug_sync= 'now wait_for downgraded'
|
||||||
|
|
||||||
|
--connection con2
|
||||||
|
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
|
||||||
|
--send alter ignore table t1 drop b, add b char(3) as (a) stored, algorithm=copy, lock=none
|
||||||
|
|
||||||
|
--connection default
|
||||||
|
--reap
|
||||||
|
update t1 set a = 'foobarqux';
|
||||||
|
set debug_sync= 'now signal goforit';
|
||||||
|
|
||||||
|
--connection con2
|
||||||
|
--reap
|
||||||
|
--connection default
|
||||||
|
drop table t1;
|
||||||
|
set debug_sync= reset;
|
||||||
|
|
||||||
|
--echo # (duplicate) MDEV-29007 Assertion `marked_for_write_or_computed()'
|
||||||
|
--echo # failed upon online ADD COLUMN .. FIRST
|
||||||
|
create table t (a int);
|
||||||
|
insert into t values (1),(2);
|
||||||
|
--send
|
||||||
|
set debug_sync= 'now wait_for downgraded';
|
||||||
|
|
||||||
|
--connection con2
|
||||||
|
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
|
||||||
|
--send
|
||||||
|
alter table t add c int first, algorithm=copy, lock=none;
|
||||||
|
|
||||||
|
--connection default
|
||||||
|
--reap
|
||||||
|
insert into t values (3);
|
||||||
|
set debug_sync= 'now signal goforit';
|
||||||
|
|
||||||
|
--connection con2
|
||||||
|
--reap
|
||||||
|
--connection default
|
||||||
|
drop table t;
|
||||||
|
set debug_sync= reset;
|
||||||
|
|
||||||
|
--echo # UNIQUE blob duplicates are not ignored.
|
||||||
|
|
||||||
|
create table t1 (b blob);
|
||||||
|
insert into t1 values ('foo'),('bar');
|
||||||
|
--send
|
||||||
|
set debug_sync= 'now wait_for downgraded';
|
||||||
|
|
||||||
|
--connection con2
|
||||||
|
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
|
||||||
|
--send
|
||||||
|
alter table t1 add unique(b), algorithm=copy, lock=none;
|
||||||
|
|
||||||
|
--connection default
|
||||||
|
--reap
|
||||||
|
insert into t1 values ('qux'),('foo');
|
||||||
|
set debug_sync= 'now signal goforit';
|
||||||
|
|
||||||
|
--connection con2
|
||||||
|
--error ER_DUP_ENTRY
|
||||||
|
--reap
|
||||||
|
select * from t1;
|
||||||
|
show create table t1;
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
--connection default
|
||||||
drop table t1;
|
drop table t1;
|
||||||
set debug_sync= reset;
|
set debug_sync= reset;
|
||||||
|
|
||||||
|
@ -32,8 +32,24 @@ a z1 z2
|
|||||||
4 5 6
|
4 5 6
|
||||||
5 6 7
|
5 6 7
|
||||||
6 7 8
|
6 7 8
|
||||||
#UPDATE query
|
alter table t1 add column z3 int default(a+2);
|
||||||
connection master;
|
connection master;
|
||||||
|
insert into t1 values(7);
|
||||||
|
insert into t1 values(8);
|
||||||
|
connection slave;
|
||||||
|
select * from t1 order by a;
|
||||||
|
a z1 z2 z3
|
||||||
|
1 2 3 3
|
||||||
|
2 3 4 4
|
||||||
|
3 4 5 5
|
||||||
|
4 5 6 6
|
||||||
|
5 6 7 7
|
||||||
|
6 7 8 8
|
||||||
|
7 8 9 9
|
||||||
|
8 9 10 10
|
||||||
|
connection master;
|
||||||
|
delete from t1 where a > 6;
|
||||||
|
#UPDATE query
|
||||||
update t1 set a = a+10;
|
update t1 set a = a+10;
|
||||||
select * from t1 order by a;
|
select * from t1 order by a;
|
||||||
a
|
a
|
||||||
@ -45,13 +61,13 @@ a
|
|||||||
16
|
16
|
||||||
connection slave;
|
connection slave;
|
||||||
select * from t1 order by a;
|
select * from t1 order by a;
|
||||||
a z1 z2
|
a z1 z2 z3
|
||||||
11 12 13
|
11 12 13 13
|
||||||
12 13 14
|
12 13 14 14
|
||||||
13 14 15
|
13 14 15 15
|
||||||
14 15 16
|
14 15 16 16
|
||||||
15 16 17
|
15 16 17 17
|
||||||
16 17 18
|
16 17 18 18
|
||||||
connection master;
|
connection master;
|
||||||
update t1 set a = a-10;
|
update t1 set a = a-10;
|
||||||
select * from t1 order by a;
|
select * from t1 order by a;
|
||||||
@ -64,13 +80,13 @@ a
|
|||||||
6
|
6
|
||||||
connection slave;
|
connection slave;
|
||||||
select * from t1 order by a;
|
select * from t1 order by a;
|
||||||
a z1 z2
|
a z1 z2 z3
|
||||||
1 2 3
|
1 2 3 3
|
||||||
2 3 4
|
2 3 4 4
|
||||||
3 4 5
|
3 4 5 5
|
||||||
4 5 6
|
4 5 6 6
|
||||||
5 6 7
|
5 6 7 7
|
||||||
6 7 8
|
6 7 8 8
|
||||||
#DELETE quert
|
#DELETE quert
|
||||||
connection master;
|
connection master;
|
||||||
delete from t1 where a > 2 and a < 4;
|
delete from t1 where a > 2 and a < 4;
|
||||||
@ -83,12 +99,12 @@ a
|
|||||||
6
|
6
|
||||||
connection slave;
|
connection slave;
|
||||||
select * from t1 order by a;
|
select * from t1 order by a;
|
||||||
a z1 z2
|
a z1 z2 z3
|
||||||
1 2 3
|
1 2 3 3
|
||||||
2 3 4
|
2 3 4 4
|
||||||
4 5 6
|
4 5 6 6
|
||||||
5 6 7
|
5 6 7 7
|
||||||
6 7 8
|
6 7 8 8
|
||||||
#REPLACE query
|
#REPLACE query
|
||||||
connection master;
|
connection master;
|
||||||
replace into t1 values(1);
|
replace into t1 values(1);
|
||||||
@ -96,13 +112,13 @@ replace into t1 values(3);
|
|||||||
replace into t1 values(1);
|
replace into t1 values(1);
|
||||||
connection slave;
|
connection slave;
|
||||||
select * from t1 order by a;
|
select * from t1 order by a;
|
||||||
a z1 z2
|
a z1 z2 z3
|
||||||
1 2 3
|
1 2 3 3
|
||||||
2 3 4
|
2 3 4 4
|
||||||
3 4 5
|
3 4 5 5
|
||||||
4 5 6
|
4 5 6 6
|
||||||
5 6 7
|
5 6 7 7
|
||||||
6 7 8
|
6 7 8 8
|
||||||
#SELECT query
|
#SELECT query
|
||||||
connection master;
|
connection master;
|
||||||
select * from t1 where a > 2 and a < 4;
|
select * from t1 where a > 2 and a < 4;
|
||||||
@ -110,8 +126,8 @@ a
|
|||||||
3
|
3
|
||||||
connection slave;
|
connection slave;
|
||||||
select * from t1 where a > 2 and a < 4;
|
select * from t1 where a > 2 and a < 4;
|
||||||
a z1 z2
|
a z1 z2 z3
|
||||||
3 4 5
|
3 4 5 5
|
||||||
#UPDATE with SELECT query
|
#UPDATE with SELECT query
|
||||||
connection master;
|
connection master;
|
||||||
update t1 set a = a + 10 where a > 2 and a < 4;
|
update t1 set a = a + 10 where a > 2 and a < 4;
|
||||||
@ -125,13 +141,13 @@ a
|
|||||||
13
|
13
|
||||||
connection slave;
|
connection slave;
|
||||||
select * from t1 order by a;
|
select * from t1 order by a;
|
||||||
a z1 z2
|
a z1 z2 z3
|
||||||
1 2 3
|
1 2 3 3
|
||||||
2 3 4
|
2 3 4 4
|
||||||
4 5 6
|
4 5 6 6
|
||||||
5 6 7
|
5 6 7 7
|
||||||
6 7 8
|
6 7 8 8
|
||||||
13 14 15
|
13 14 15 15
|
||||||
connection master;
|
connection master;
|
||||||
update t1 set a = a - 10 where a = 13;
|
update t1 set a = a - 10 where a = 13;
|
||||||
select * from t1 order by a;
|
select * from t1 order by a;
|
||||||
@ -144,13 +160,13 @@ a
|
|||||||
6
|
6
|
||||||
connection slave;
|
connection slave;
|
||||||
select * from t1 order by a;
|
select * from t1 order by a;
|
||||||
a z1 z2
|
a z1 z2 z3
|
||||||
1 2 3
|
1 2 3 3
|
||||||
2 3 4
|
2 3 4 4
|
||||||
3 4 5
|
3 4 5 5
|
||||||
4 5 6
|
4 5 6 6
|
||||||
5 6 7
|
5 6 7 7
|
||||||
6 7 8
|
6 7 8 8
|
||||||
#Break Unique Constraint
|
#Break Unique Constraint
|
||||||
alter table t1 add column z4 int as (a % 6) persistent unique;
|
alter table t1 add column z4 int as (a % 6) persistent unique;
|
||||||
connection master;
|
connection master;
|
||||||
@ -168,27 +184,27 @@ a
|
|||||||
connection slave;
|
connection slave;
|
||||||
include/wait_for_slave_sql_error.inc [errno=1062]
|
include/wait_for_slave_sql_error.inc [errno=1062]
|
||||||
select * from t1 order by a;
|
select * from t1 order by a;
|
||||||
a z1 z2 z4
|
a z1 z2 z3 z4
|
||||||
1 2 3 1
|
1 2 3 3 1
|
||||||
2 3 4 2
|
2 3 4 4 2
|
||||||
3 4 5 3
|
3 4 5 5 3
|
||||||
4 5 6 4
|
4 5 6 6 4
|
||||||
5 6 7 5
|
5 6 7 7 5
|
||||||
6 7 8 0
|
6 7 8 8 0
|
||||||
alter table t1 drop column z4;
|
alter table t1 drop column z4;
|
||||||
start slave;
|
start slave;
|
||||||
include/wait_for_slave_sql_to_start.inc
|
include/wait_for_slave_sql_to_start.inc
|
||||||
connection master;
|
connection master;
|
||||||
connection slave;
|
connection slave;
|
||||||
select * from t1 order by a;
|
select * from t1 order by a;
|
||||||
a z1 z2
|
a z1 z2 z3
|
||||||
1 2 3
|
1 2 3 3
|
||||||
2 3 4
|
2 3 4 4
|
||||||
3 4 5
|
3 4 5 5
|
||||||
4 5 6
|
4 5 6 6
|
||||||
5 6 7
|
5 6 7 7
|
||||||
6 7 8
|
6 7 8 8
|
||||||
7 8 9
|
7 8 9 9
|
||||||
connection master;
|
connection master;
|
||||||
select * from t1 order by a;
|
select * from t1 order by a;
|
||||||
a
|
a
|
||||||
|
@ -20,11 +20,19 @@ insert into t1 values(6);
|
|||||||
|
|
||||||
--sync_slave_with_master
|
--sync_slave_with_master
|
||||||
select * from t1 order by a;
|
select * from t1 order by a;
|
||||||
|
alter table t1 add column z3 int default(a+2);
|
||||||
|
--connection master
|
||||||
|
insert into t1 values(7);
|
||||||
|
insert into t1 values(8);
|
||||||
|
|
||||||
|
--sync_slave_with_master
|
||||||
|
select * from t1 order by a;
|
||||||
|
|
||||||
|
--connection master
|
||||||
|
delete from t1 where a > 6;
|
||||||
|
|
||||||
--echo #UPDATE query
|
--echo #UPDATE query
|
||||||
|
|
||||||
--connection master
|
|
||||||
update t1 set a = a+10;
|
update t1 set a = a+10;
|
||||||
select * from t1 order by a;
|
select * from t1 order by a;
|
||||||
|
|
||||||
|
@ -5097,6 +5097,14 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
|
|||||||
bitmap_set_bit(table->write_set, table->s->vers.end_fieldno);
|
bitmap_set_bit(table->write_set, table->s->vers.end_fieldno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mark extra replica columns for write */
|
||||||
|
for (Field **field_ptr= table->field; *field_ptr; ++field_ptr)
|
||||||
|
{
|
||||||
|
Field *field= *field_ptr;
|
||||||
|
if (field->field_index >= m_cols.n_bits && field->stored_in_db())
|
||||||
|
bitmap_set_bit(table->write_set, field->field_index);
|
||||||
|
}
|
||||||
|
|
||||||
this->slave_exec_mode= slave_exec_mode_options; // fix the mode
|
this->slave_exec_mode= slave_exec_mode_options; // fix the mode
|
||||||
|
|
||||||
// Do event specific preparations
|
// Do event specific preparations
|
||||||
|
@ -144,34 +144,6 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
|
||||||
/**
|
|
||||||
Fills @c table->record[0] with computed values of extra persistent column
|
|
||||||
which are present on slave but not on master.
|
|
||||||
|
|
||||||
@param table Table whose record[0] buffer is prepared.
|
|
||||||
@param master_cols No of columns on master
|
|
||||||
@returns 0 on success
|
|
||||||
*/
|
|
||||||
static int fill_extra_persistent_columns(TABLE *table, int master_cols)
|
|
||||||
{
|
|
||||||
int error= 0;
|
|
||||||
|
|
||||||
if (!table->vfield)
|
|
||||||
return 0;
|
|
||||||
for (Field **vfield_ptr= table->vfield; *vfield_ptr; ++vfield_ptr)
|
|
||||||
{
|
|
||||||
Field *vfield= *vfield_ptr;
|
|
||||||
if (vfield->field_index >= master_cols && (vfield->stored_in_db() ||
|
|
||||||
(vfield->flags & (PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG))))
|
|
||||||
{
|
|
||||||
bitmap_set_bit(table->write_set, vfield->field_index);
|
|
||||||
error= vfield->vcol_info->expr->save_in_field(vfield,0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Unpack a row into @c table->record[0].
|
Unpack a row into @c table->record[0].
|
||||||
|
|
||||||
@ -411,12 +383,25 @@ int unpack_row(rpl_group_info *rgi, TABLE *table, uint const colcnt,
|
|||||||
|
|
||||||
if (copy_fields)
|
if (copy_fields)
|
||||||
{
|
{
|
||||||
for (auto *copy=copy_fields; copy != copy_fields_end; copy++)
|
for (const auto *copy=copy_fields; copy != copy_fields_end; copy++)
|
||||||
{
|
{
|
||||||
copy->do_copy(copy);
|
copy->do_copy(copy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (table->default_field)
|
||||||
|
{
|
||||||
|
error= table->update_default_fields(table->in_use->lex->ignore);
|
||||||
|
if (unlikely(error))
|
||||||
|
DBUG_RETURN(error);
|
||||||
|
}
|
||||||
|
if (table->vfield)
|
||||||
|
{
|
||||||
|
error= table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_WRITE);
|
||||||
|
if (unlikely(error))
|
||||||
|
DBUG_RETURN(error);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
throw away master's extra fields
|
throw away master's extra fields
|
||||||
*/
|
*/
|
||||||
@ -442,12 +427,6 @@ int unpack_row(rpl_group_info *rgi, TABLE *table, uint const colcnt,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Add Extra slave persistent columns
|
|
||||||
*/
|
|
||||||
if (unlikely(error= fill_extra_persistent_columns(table, cols->n_bits)))
|
|
||||||
DBUG_RETURN(error);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We should now have read all the null bytes, otherwise something is
|
We should now have read all the null bytes, otherwise something is
|
||||||
really wrong.
|
really wrong.
|
||||||
|
Reference in New Issue
Block a user