Open midenok opened 3 years ago
#0 check_definition (t1_keyinfo=0x7f8c8401ea48, t1_recinfo=0x7f8c8401e928, t1_keys=3, t1_recs=3, t2_keyinfo=0x7f8c84029e40, t2_recinfo=0x7f8c8402a050, t2_keys=3, t2_recs=3, strict=true, table_arg=0x7f8c84027878) at ../src/storage/myisam/ha_myisam.cc:570
#1 0x0000000001621670 in ha_myisam::open (this=0x7f8c84028040, name=0x7f8c8402f928 "./test/t1", mode=2, test_if_locked=50) at ../src/storage/myisam/ha_myisam.cc:829
#2 0x0000000000cb75b4 in handler::ha_open (this=0x7f8c84028040, table_arg=0x7f8c84027878, name=0x7f8c8402f928 "./test/t1", mode=2, test_if_locked=50, mem_root=0x0, partitions_to_open=0x0) at ../src/sql/handler.cc:2997
#3 0x0000000000a539e9 in open_table_from_share (thd=0x7f8c84000d48, share=0x7f8c8402f390, alias=0x7f8c84015e88, db_stat=33, prgflag=8, ha_open_flags=50, outparam=0x7f8c84027878, is_create_table=false, partitions_to_open=0x0) at ../src/sql/table.cc:4234
#4 0x000000000081d4fc in open_table (thd=0x7f8c84000d48, table_list=0x7f8c84015e40, ot_ctx=0x7f8c9aa10e68) at ../src/sql/sql_base.cc:2001
#5 0x0000000000822547 in open_and_process_table (thd=0x7f8c84000d48, tables=0x7f8c84015e40, counter=0x7f8c9aa10f6c, flags=0, prelocking_strategy=0x7f8c9aa10fe0, has_prelocking_list=false, ot_ctx=0x7f8c9aa10e68) at ../src/sql/sql_base.cc:3786
#6 0x0000000000820ff0 in open_tables (thd=0x7f8c84000d48, options=..., start=0x7f8c9aa10f80, counter=0x7f8c9aa10f6c, flags=0, prelocking_strategy=0x7f8c9aa10fe0) at ../src/sql/sql_base.cc:4269
#7 0x0000000000825755 in open_and_lock_tables (thd=0x7f8c84000d48, options=..., tables=0x7f8c84015e40, derived=true, flags=0, prelocking_strategy=0x7f8c9aa10fe0) at ../src/sql/sql_base.cc:5215
#8 0x00000000007cc73c in open_and_lock_tables (thd=0x7f8c84000d48, tables=0x7f8c84015e40, derived=true, flags=0) at ../src/sql/sql_base.h:507
#9 0x0000000000ad891b in open_only_one_table (thd=0x7f8c84000d48, table=0x7f8c84015e40, repair_table_use_frm=false, is_view_operator_func=true) at ../src/sql/sql_admin.cc:408
#10 0x0000000000ad3d4d in mysql_admin_table (thd=0x7f8c84000d48, tables=0x7f8c84015e40, check_opt=0x7f8c84006188, operator_name=0x17af157 "check", lock_type=TL_READ_NO_INSERT, org_open_for_modify=false, repair_table_use_frm=false, extra_open_options=32, prepare_func=0x0, operator_func=(int (handler::*)(handler * const, THD *, HA_CHECK_OPT *)) 0xcbfb90 <handler::ha_check(THD*, st_ha_check_opt*)>, view_operator_func=0xa425a0 <view_check(THD*, TABLE_LIST*, st_ha_check_opt*)>, is_cmd_replicated=false) at ../src/sql/sql_admin.cc:614
#11 0x0000000000ad7682 in Sql_cmd_check_table::execute (this=0x7f8c84016520, thd=0x7f8c84000d48) at ../src/sql/sql_admin.cc:1477
#12 0x00000000008f049d in mysql_execute_command (thd=0x7f8c84000d48) at ../src/sql/sql_parse.cc:6056
#13 0x00000000008e108c in mysql_parse (thd=0x7f8c84000d48, rawbuf=0x7f8c84015d90 "check table t1", length=14, parser_state=0x7f8c9aa144f0, is_com_multi=false, is_next_command=false) at ../src/sql/sql_parse.cc:8
94 for (i= 0; i < t1_keys; i++)
495 {
496 HA_KEYSEG *t1_keysegs= t1_keyinfo[i].seg;
497 HA_KEYSEG *t2_keysegs= t2_keyinfo[i].seg;
...
531 for (j= t1_keyinfo[i].keysegs; j--;)
532 {
...
552 if ((!mysql_40_compat &&
553 t1_keysegs[j].language != t2_keysegs[j].language) ||
554 t1_keysegs_j__type != t2_keysegs[j].type ||
555 t1_keysegs[j].null_bit != t2_keysegs[j].null_bit ||
556 t1_keysegs[j].length != t2_keysegs[j].length ||
557 t1_keysegs[j].start != t2_keysegs[j].start)
558 {
559 DBUG_PRINT("error", ("Key segment %d (key %d) has different "
560 "definition", j, i));
561 DBUG_PRINT("error", ("t1_type=%d, t1_language=%d, t1_null_bit=%d, "
562 "t1_length=%d",
563 t1_keysegs[j].type, t1_keysegs[j].language,
564 t1_keysegs[j].null_bit, t1_keysegs[j].length));
565 DBUG_PRINT("error", ("t2_type=%d, t2_language=%d, t2_null_bit=%d, "
566 "t2_length=%d",
567 t2_keysegs[j].type, t2_keysegs[j].language,
568 t2_keysegs[j].null_bit, t2_keysegs[j].length));
569
570 DBUG_RETURN(1);
571 }
(rr) p i
$37 = 1
(rr) p j
$38 = 0
(rr) p t1_keysegs[j].null_bit
$50 = 0 '\000'
(rr) p t2_keysegs[j].null_bit
$51 = 2 '\002'
(rr) p t1_keysegs[j].null_bit
$28 = 2 '\002'
(rr) p t2_keysegs[j].null_bit
$29 = 2 '\002'
(rr) p t1_keysegs[j].null_bit
$10 = 0 '\000'
(rr) p t2_keysegs[j].null_bit
$11 = 0 '\000'
Order of keys changed. Stale t2_keyinfo[i].seg
.
Aria does not reproduce this error message because maria_check_definition() is never used! But the problem may still exist.
t1_keyinfo
came from TABLE instance, t2_keyinfo
came from MYISAM_SHARE.
#0 check_definition (t1_keyinfo=0x7f8c8401ea48, t1_recinfo=0x7f8c8401e928, t1_keys=3, t1_recs=3, t2_keyinfo=0x7f8c84029e40, t2_recinfo=0x7f8c8402a050, t2_keys=3, t2_recs=3, strict=true, table_arg=0x7f8c84027878) at ../src/storage/myisam/ha_myisam.cc:570
#1 0x0000000001621670 in ha_myisam::open (this=0x7f8c84028040, name=0x7f8c8402f928 "./test/t1", mode=2, test_if_locked=50) at ../src/storage/myisam/ha_myisam.cc:829
It is OK that some members are uninitialized.
(rr) p t1_keyinfo[i]
$45 = {
share = 0xa5a5a5a5a5a5a5a5,
keysegs = 1,
flag = 1,
key_alg = 1 '\001',
block_length = 1024,
underflow_block_length = 42405,
keylength = 42405,
minlength = 42405,
maxlength = 42405,
block_size_index = 42405,
version = 2779096485,
ftkey_nr = 2779096485,
seg = 0x7f8c8401ebb8,
end = 0xa5a5a5a5a5a5a5a5,
parser = 0xa5a5a5a5a5a5a5a5,
bin_search = 0xa5a5a5a5a5a5a5a5,
get_key = 0xa5a5a5a5a5a5a5a5,
pack_key = 0xa5a5a5a5a5a5a5a5,
store_key = 0xa5a5a5a5a5a5a5a5,
ck_insert = 0xa5a5a5a5a5a5a5a5,
ck_delete = 0xa5a5a5a5a5a5a5a5
}
(rr) p t2_keyinfo[i]
$46 = {
share = 0x7f8c84029838,
keysegs = 1,
flag = 73,
key_alg = 1 '\001',
block_length = 1024,
underflow_block_length = 341,
keylength = 11,
minlength = 11,
maxlength = 11,
block_size_index = 0,
version = 0,
ftkey_nr = 0,
seg = 0x7f8c84029fd0,
end = 0x7f8c84029ff0,
parser = 0x1ff70c0 <ft_default_parser>,
bin_search = 0x1666c70 <_mi_seq_search>,
get_key = 0x16688b0 <_mi_get_pack_key>,
pack_key = 0x166aa20 <_mi_calc_var_key_length>,
store_key = 0x166bb50 <_mi_store_static_key>,
ck_insert = 0x166fce0 <_mi_ck_write>,
ck_delete = 0x1640040 <_mi_ck_delete>
}
(rr) p *t1_keyinfo[i].seg
$52 = {
charset = 0xa5a5a5a5a5a5a5a5,
start = 1,
null_pos = 0,
bit_pos = 0,
flag = 0,
length = 4,
language = 63,
type = 4 '\004',
null_bit = 0 '\000',
bit_start = 0 '\000',
bit_length = 0 '\000'
}
(rr) p *t2_keyinfo[i].seg
$53 = {
charset = 0x0,
start = 5,
null_pos = 0,
bit_pos = 0,
flag = 80,
length = 4,
language = 63,
type = 4 '\004',
null_bit = 2 '\002',
bit_start = 0 '\000',
bit_length = 0 '\000'
}
mysql_prepare_create_table() changes key order:
4439 /* Sort keys in optimized order */
4440 my_qsort((uchar*) *key_info_buffer, *key_count, sizeof(KEY),
4441 (qsort_cmp) sort_keys);
Disable this my_qsort() for inplace alter (or when inplace is possible).
This is impossible because init_from_binary_frm_image() requires PK to be always first, so sorting is a must!
Reproduces with Aria and MyISAM (MyISAM is reproduced with --repeat=30).
create table lineitem (
l_partkey int(11) default null,
l_suppkey int(11) default null,
l_receiptdate date default null,
l_shipmode char(10) default null,
key i_l_suppkey_partkey (l_partkey,l_suppkey),
unique a (l_shipmode),
unique p (l_receiptdate),
primary key (l_receiptdate,l_partkey)
) engine=aria default charset utf8mb4;
insert into lineitem values
(156,4,'1996-03-22','truck'),
(68,9,'1996-04-20','mail');
alter table lineitem rename index if exists x to xx;
--connect (con1,localhost,root,,test)
--send
select * from lineitem;
--connection default
--error 0,1030
select * from lineitem where l_receiptdate > '1998-07-01';
# cleanup
--connection con1
--error 0,1030
--reap
drop table lineitem;
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -4902,8 +4902,7 @@ handler::check_if_supported_inplace_alter(TABLE *altered_table,
ALTER_DROP_CHECK_CONSTRAINT |
ALTER_PARTITIONED |
ALTER_VIRTUAL_GCOL_EXPR |
- ALTER_RENAME |
- ALTER_RENAME_INDEX;
+ ALTER_RENAME;
/* Is there at least one operation that requires copy algorithm? */
if (ha_alter_info->handler_flags & ~inplace_offline_operations)
But this doesn't fix all the commands, because every of this may reproduce:
alter_table_operations inplace_offline_operations=
ALTER_COLUMN_TYPE_CHANGE_BY_ENGINE |
ALTER_COLUMN_NAME |
ALTER_RENAME_COLUMN |
ALTER_CHANGE_COLUMN_DEFAULT |
ALTER_COLUMN_DEFAULT |
ALTER_COLUMN_OPTION |
ALTER_CHANGE_CREATE_OPTION |
ALTER_DROP_CHECK_CONSTRAINT |
ALTER_PARTITIONED |
ALTER_VIRTUAL_GCOL_EXPR |
ALTER_RENAME;
Aria reproduced always. MyISAM is reproduced with --repeat=30.
create table t1 (
x int,
y char(10),
unique (y),
unique (x),
primary key (x)
) engine=aria;
insert into t1 values
(1, 'truck'),
(2, 'mail');
alter table t1 change y z char(10), algorithm=inplace;
--connect (con1,localhost,root,,test)
--send
select * from t1;
--connection default
--error 0,1030
select * from t1 where x > 3;
# cleanup
--connection con1
--error 0,1030
--reap
drop table t1;
my_qsort()
is indeterministic: it can change order of already sorted array.
int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
uint columns, MI_COLUMNDEF *recinfo,
uint uniques, MI_UNIQUEDEF *uniquedefs,
MI_CREATE_INFO *ci,uint flags)
{
...
DBUG_PRINT("info", ("write state info and base info"));
if (mi_state_info_write(file, &share.state, 2) ||
mi_base_info_write(file, &share.base))
goto err;
#ifndef DBUG_OFF
if ((uint) mysql_file_tell(file, MYF(0)) != base_pos + MI_BASE_INFO_SIZE)
{
uint pos=(uint) mysql_file_tell(file, MYF(0));
DBUG_PRINT("warning",("base_length: %d != used_length: %d",
base_pos+ MI_BASE_INFO_SIZE, pos));
}
#endif
/* Write key and keyseg definitions */
DBUG_PRINT("info", ("write key and keyseg definitions"));
for (i=0 ; i < share.base.keys - uniques; i++)
{
uint sp_segs=(keydefs[i].flag & HA_SPATIAL) ? 2*SPDIMS : 0;
if (mi_keydef_write(file, &keydefs[i]))
goto err;
for (j=0 ; j < keydefs[i].keysegs-sp_segs ; j++)
if (mi_keyseg_write(file, &keydefs[i].seg[j]))
goto err;
There is a bug in inpace alter for MyISAM/Aria tables (MDEV-25803). mysql_prepare_create_table()
does my_qsort(sort_keys)
on key info. This sorting is indeterministic: a table is created with one order and inplace alter may overwrite frm with another order. Since inplace alter does nothing about key info for MyISAM/Aria storage engines this results in discrepancy between frm and storage engine key definitions. What would you recommend for the fix now?
Notes:
mi_keydef_write()
/mi_keyseg_write()
are used only in mi_create()
. They should be used in ha_inplace_alter_table()
as well.
Aria corruption detection is unimplemented: maria_check_definition() is never used!
Might be useful in the code, not committed now:
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -9054,6 +9054,11 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
goto err;
}
+ if (key->type == Key::PRIMARY)
+ {
+ DBUG_ASSERT(alter_info->flags & ALTER_ADD_INDEX);
+ alter_info->flags|= ALTER_ADD_PK_INDEX;
+ }
}
}
Reproduce
Result
mtr --mysqld=--debug=d,error main.x
Notes
Does not reproduce with algorithm=copy or with other engines.
MySQL 8.0 fails as well, but it has earlier error check:
Though it seems it does not recover from that correctly as this is not covered by atomic DDL: