Commit 2be4c836 authored by Nikita Malyavin's avatar Nikita Malyavin Committed by Sergei Golubchik

MDEV-29069 ER_KEY_NOT_FOUND on online autoinc addition + concurrent DELETE

We can't rely on keys formed with columns that were added during this
ALTER. These columns can be set with non-deterministic values, which can
end up with broken or incorrect search.

The same applies to the keys that contain reliable columns, but also have
bogus ones. Using them can narrow the search, but they're also ignored.

Also, added columns shouldn't be considered during the record match. To
determine them, table->has_value_set bitmap is used.

To fill has_value_set bitmap in the find_key call, extra unpack_row call
has been added.

For replication case, extra replica columns can be considered for this
case. We try to ignore them, too.
parent d1e09972
......@@ -979,5 +979,142 @@ xa commit 'xid' one phase;
drop table t;
set debug_sync= reset;
#
# MDEV-29069 ER_KEY_NOT_FOUND upon online autoinc addition and
# concurrent DELETE
#
set @old_dbug=@@debug_dbug;
set debug_dbug="+d,rpl_report_chosen_key";
create table t (a int);
insert into t values (10),(20),(30);
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
alter table t add pk int auto_increment primary key, algorithm=copy, lock=none;
connection con2;
set debug_sync= 'now wait_for downgraded';
delete from t where a = 20;
update t set a = a + 1 where a = 10;
set debug_sync= 'now signal goforit';
connection default;
Warnings:
Note 1105 Key chosen: -1
Note 1105 Key chosen: -1
select * from t;
a pk
11 1
30 3
#
# Add clumsy DEFAULT
#
create or replace table t (a int);
insert into t values (10),(20),(30);
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
alter table t add b int default(RAND() * 20), add key(b),
algorithm=copy, lock=none;
connection con2;
set debug_sync= 'now wait_for downgraded';
delete from t where a = 20;
update t set a = a + 1 where a = 10;
set debug_sync= 'now signal goforit';
connection default;
Warnings:
Note 1105 Key chosen: -1
Note 1105 Key chosen: -1
select a from t;
a
11
30
# CURRENT_TIMESTAMP
create or replace table t (a int);
insert into t values (10),(20),(30);
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
alter table t add b timestamp default CURRENT_TIMESTAMP, add key(b),
algorithm=copy, lock=none;
connection con2;
set debug_sync= 'now wait_for downgraded';
delete from t where a = 20;
update t set a = a + 1 where a = 10;
set debug_sync= 'now signal goforit';
connection default;
Warnings:
Note 1105 Key chosen: -1
Note 1105 Key chosen: -1
select a from t;
a
11
30
# CURRENT_TIMESTAMP, mixed key
create or replace table t (a int);
insert into t values (10),(20),(30);
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
alter table t add b timestamp default CURRENT_TIMESTAMP, add key(a, b),
algorithm=copy, lock=none;
connection con2;
set debug_sync= 'now wait_for downgraded';
delete from t where a = 20;
update t set a = a + 1 where a = 10;
set debug_sync= 'now signal goforit';
connection default;
Warnings:
Note 1105 Key chosen: -1
Note 1105 Key chosen: -1
select a from t;
a
11
30
# Mixed primary key
create or replace table t (a int);
insert into t values (10),(20),(30);
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
alter table t add b int default (a+1), add primary key(b, a),
algorithm=copy, lock=none;
connection con2;
set debug_sync= 'now wait_for downgraded';
delete from t where a = 20;
update t set a = a + 1 where a = 10;
set debug_sync= 'now signal goforit';
connection default;
Warnings:
Note 1105 Key chosen: -1
Note 1105 Key chosen: -1
select a from t;
a
11
30
#
# Normal row, could be used as a key
#
create or replace table t (a int);
insert into t values (10),(20),(30);
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
alter table t add b int as (a * 10) unique, algorithm=copy, lock=none;
connection con2;
set debug_sync= 'now wait_for downgraded';
delete from t where a = 20;
update t set a = a + 1 where a = 10;
set debug_sync= 'now signal goforit';
connection default;
Warnings:
Note 1105 Key chosen: -1
Note 1105 Key chosen: -1
#
# Add key for old row
#
create or replace table t (a int);
insert into t values (10),(20),(30);
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
alter table t add unique(a), algorithm=copy, lock=none;
connection con2;
set debug_sync= 'now wait_for downgraded';
delete from t where a = 20;
update t set a = a + 1 where a = 10;
set debug_sync= 'now signal goforit';
connection default;
Warnings:
Note 1105 Key chosen: 0
Note 1105 Key chosen: 0
drop table t;
set debug_sync= reset;
set debug_dbug= @old_debug;
connection default;
#
# End of 11.2 tests
#
......@@ -1152,6 +1152,144 @@ xa commit 'xid' one phase;
drop table t;
set debug_sync= reset;
--echo #
--echo # MDEV-29069 ER_KEY_NOT_FOUND upon online autoinc addition and
--echo # concurrent DELETE
--echo #
set @old_dbug=@@debug_dbug;
set debug_dbug="+d,rpl_report_chosen_key";
create table t (a int);
insert into t values (10),(20),(30);
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
--send
alter table t add pk int auto_increment primary key, algorithm=copy, lock=none;
--connection con2
set debug_sync= 'now wait_for downgraded';
delete from t where a = 20;
update t set a = a + 1 where a = 10;
set debug_sync= 'now signal goforit';
--connection default
--reap
select * from t;
--echo #
--echo # Add clumsy DEFAULT
--echo #
create or replace table t (a int);
insert into t values (10),(20),(30);
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
--send
alter table t add b int default(RAND() * 20), add key(b),
algorithm=copy, lock=none;
--connection con2
set debug_sync= 'now wait_for downgraded';
delete from t where a = 20;
update t set a = a + 1 where a = 10;
set debug_sync= 'now signal goforit';
--connection default
--reap
select a from t;
--echo # CURRENT_TIMESTAMP
create or replace table t (a int);
insert into t values (10),(20),(30);
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
--send
alter table t add b timestamp default CURRENT_TIMESTAMP, add key(b),
algorithm=copy, lock=none;
--connection con2
set debug_sync= 'now wait_for downgraded';
delete from t where a = 20;
update t set a = a + 1 where a = 10;
set debug_sync= 'now signal goforit';
--connection default
--reap
select a from t;
--echo # CURRENT_TIMESTAMP, mixed key
create or replace table t (a int);
insert into t values (10),(20),(30);
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
--send
alter table t add b timestamp default CURRENT_TIMESTAMP, add key(a, b),
algorithm=copy, lock=none;
--connection con2
set debug_sync= 'now wait_for downgraded';
delete from t where a = 20;
update t set a = a + 1 where a = 10;
set debug_sync= 'now signal goforit';
--connection default
--reap
select a from t;
--echo # Mixed primary key
create or replace table t (a int);
insert into t values (10),(20),(30);
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
--send
alter table t add b int default (a+1), add primary key(b, a),
algorithm=copy, lock=none;
--connection con2
set debug_sync= 'now wait_for downgraded';
delete from t where a = 20;
update t set a = a + 1 where a = 10;
set debug_sync= 'now signal goforit';
--connection default
--reap
select a from t;
--echo #
--echo # Normal row, could be used as a key
--echo #
create or replace table t (a int);
insert into t values (10),(20),(30);
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
--send
alter table t add b int as (a * 10) unique, algorithm=copy, lock=none;
--connection con2
set debug_sync= 'now wait_for downgraded';
delete from t where a = 20;
update t set a = a + 1 where a = 10;
set debug_sync= 'now signal goforit';
--connection default
--reap
--echo #
--echo # Add key for old row
--echo #
create or replace table t (a int);
insert into t values (10),(20),(30);
set debug_sync= 'alter_table_online_downgraded signal downgraded wait_for goforit';
--send
alter table t add unique(a), algorithm=copy, lock=none;
--connection con2
set debug_sync= 'now wait_for downgraded';
delete from t where a = 20;
update t set a = a + 1 where a = 10;
set debug_sync= 'now signal goforit';
--connection default
--reap
# Cleanup
drop table t;
set debug_sync= reset;
set debug_dbug= @old_debug;
--connection default
--echo #
--echo # End of 11.2 tests
--echo #
......@@ -4798,7 +4798,9 @@ class Rows_log_event : public Log_event
friend class Rows_log_event;
};
int find_key(); // Find a best key to use in find_row()
int find_key(const rpl_group_info *); // Find a best key to use in find_row()
bool is_key_usable(const KEY *key) const;
bool use_pk_position() const;
int find_row(rpl_group_info *);
int write_row(rpl_group_info *, const bool);
int update_sequence();
......@@ -4864,8 +4866,8 @@ class Rows_log_event : public Log_event
The member function will return 0 if all went OK, or a non-zero
error code otherwise.
*/
virtual
int do_before_row_operations(const Slave_reporting_capability *const log) = 0;
virtual
int do_before_row_operations(const rpl_group_info *) = 0;
/*
Primitive to clean up after a sequence of row executions.
......@@ -4954,7 +4956,7 @@ class Write_rows_log_event : public Rows_log_event
#endif
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_before_row_operations(const Slave_reporting_capability *const);
virtual int do_before_row_operations(const rpl_group_info *);
virtual int do_after_row_operations(const Slave_reporting_capability *const,int);
virtual int do_exec_row(rpl_group_info *);
#endif
......@@ -5044,7 +5046,7 @@ class Update_rows_log_event : public Rows_log_event
#endif
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_before_row_operations(const Slave_reporting_capability *const);
virtual int do_before_row_operations(const rpl_group_info *);
virtual int do_after_row_operations(const Slave_reporting_capability *const,int);
virtual int do_exec_row(rpl_group_info *);
#endif /* defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) */
......@@ -5131,7 +5133,7 @@ class Delete_rows_log_event : public Rows_log_event
#endif
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
virtual int do_before_row_operations(const Slave_reporting_capability *const);
virtual int do_before_row_operations(const rpl_group_info *const);
virtual int do_after_row_operations(const Slave_reporting_capability *const,int);
virtual int do_exec_row(rpl_group_info *);
#endif
......
This diff is collapsed.
......@@ -188,7 +188,7 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
@retval HA_ERR_CORRUPT_EVENT
Found error when trying to unpack fields.
*/
int unpack_row(rpl_group_info *rgi, TABLE *table, uint const colcnt,
int unpack_row(const rpl_group_info *rgi, TABLE *table, uint const colcnt,
uchar const *const row_data, MY_BITMAP const *cols,
uchar const **const current_row_end,
ulong *const master_reclength, uchar const *const row_end)
......
......@@ -29,7 +29,7 @@ size_t pack_row(TABLE* table, MY_BITMAP const* cols,
#endif
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
int unpack_row(rpl_group_info *rgi,
int unpack_row(const rpl_group_info *rgi,
TABLE *table, uint const colcnt,
uchar const *const row_data, MY_BITMAP const *cols,
uchar const **const curr_row_end, ulong *const master_reclength,
......
......@@ -2473,7 +2473,7 @@ rpl_group_info::mark_start_commit()
If no GTID is available, then NULL is returned.
*/
char *
rpl_group_info::gtid_info()
rpl_group_info::gtid_info() const
{
if (!gtid_sub_id || !current_gtid.seq_no)
return NULL;
......
......@@ -830,7 +830,7 @@ struct rpl_group_info
longlong row_stmt_start_timestamp;
bool long_find_row_note_printed;
/* Needs room for "Gtid D-S-N\x00". */
char gtid_info_buf[5+10+1+10+1+20+1];
mutable char gtid_info_buf[5+10+1+10+1+20+1];
/*
The timestamp, from the master, of the commit event.
......@@ -962,7 +962,7 @@ struct rpl_group_info
void slave_close_thread_tables(THD *);
void mark_start_commit_no_lock();
void mark_start_commit();
char *gtid_info();
char *gtid_info() const;
void unmark_start_commit();
longlong get_row_stmt_start_timestamp()
......
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