Skip to content

Commit 802ce96

Browse files
kevgsdr-m
authored andcommitted
MDEV-18041 Database corruption after renaming a prefix-indexed column
This is a regression after MDEV-13671. The bug is related to key part prefix lengths wich are stored in SYS_FIELDS. Storage format is not obvious and was handled incorrectly which led to data dictionary corruption. SYS_FIELDS.POS actually contains prefix length too in case if any key part has prefix length. innobase_rename_column_try(): fixed prefixes handling Tests for prefixed indexes added too. Closes #1063
1 parent b74eb5a commit 802ce96

File tree

4 files changed

+70
-28
lines changed

4 files changed

+70
-28
lines changed

mysql-test/suite/innodb/r/innodb-alter.result

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,27 @@ WHERE T.NAME='test/t1';
865865
NAME
866866
a
867867
DROP TABLE t1;
868+
# and an MDEV-18041 regression related to indexes prefixes
869+
create table `test` (
870+
`test_old` varchar(255) NOT NULL,
871+
`other` varchar(255) NOT NULL,
872+
PRIMARY KEY (`test_old`,`other`),
873+
UNIQUE KEY uk (`test_old`(100), `other`)
874+
) ENGINE=InnoDB;
875+
select name, pos from information_schema.innodb_SYS_FIELDS where name in ('test_old', 'other', 'test_new');
876+
name pos
877+
test_old 0
878+
other 1
879+
test_old 0
880+
other 1
881+
alter table `test` CHANGE COLUMN `test_old` `test_new` varchar(255) NOT NULL;
882+
select name, pos from information_schema.innodb_SYS_FIELDS where name in ('test_old', 'other', 'test_new');
883+
name pos
884+
test_new 0
885+
other 1
886+
test_new 0
887+
other 1
888+
drop table `test`;
868889
#
869890
# BUG 20029625 - HANDLE_FATAL_SIGNAL (SIG=11) IN
870891
# DICT_MEM_TABLE_COL_RENAME_LOW

mysql-test/suite/innodb/t/innodb-alter.test

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,19 @@ SELECT C.NAME FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS C INNER JOIN
522522
WHERE T.NAME='test/t1';
523523
DROP TABLE t1;
524524

525+
--echo # and an MDEV-18041 regression related to indexes prefixes
526+
create table `test` (
527+
`test_old` varchar(255) NOT NULL,
528+
`other` varchar(255) NOT NULL,
529+
PRIMARY KEY (`test_old`,`other`),
530+
UNIQUE KEY uk (`test_old`(100), `other`)
531+
) ENGINE=InnoDB;
532+
533+
select name, pos from information_schema.innodb_SYS_FIELDS where name in ('test_old', 'other', 'test_new');
534+
alter table `test` CHANGE COLUMN `test_old` `test_new` varchar(255) NOT NULL;
535+
select name, pos from information_schema.innodb_SYS_FIELDS where name in ('test_old', 'other', 'test_new');
536+
drop table `test`;
537+
525538

526539
--echo #
527540
--echo # BUG 20029625 - HANDLE_FATAL_SIGNAL (SIG=11) IN

storage/innobase/handler/handler0alter.cc

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4533,36 +4533,40 @@ innobase_rename_column_try(
45334533
index != NULL;
45344534
index = dict_table_get_next_index(index)) {
45354535

4536+
bool has_prefixes = false;
4537+
for (size_t i = 0; i < dict_index_get_n_fields(index); i++) {
4538+
if (dict_index_get_nth_field(index, i)->prefix_len) {
4539+
has_prefixes = true;
4540+
break;
4541+
}
4542+
}
4543+
45364544
for (ulint i = 0; i < dict_index_get_n_fields(index); i++) {
4537-
if (my_strcasecmp(
4538-
system_charset_info,
4539-
dict_index_get_nth_field(index, i)->name,
4540-
from)) {
4545+
const dict_field_t* field
4546+
= dict_index_get_nth_field(index, i);
4547+
if (my_strcasecmp(system_charset_info, field->name,
4548+
from)) {
45414549
continue;
45424550
}
45434551

45444552
info = pars_info_create();
45454553

4554+
int pos = i;
4555+
if (has_prefixes) {
4556+
pos = (pos << 16) + field->prefix_len;
4557+
}
4558+
45464559
pars_info_add_ull_literal(info, "indexid", index->id);
4547-
pars_info_add_int4_literal(info, "nth", i);
4560+
pars_info_add_int4_literal(info, "nth", pos);
45484561
pars_info_add_str_literal(info, "new", to);
45494562

45504563
error = que_eval_sql(
45514564
info,
45524565
"PROCEDURE RENAME_SYS_FIELDS_PROC () IS\n"
45534566
"BEGIN\n"
4554-
45554567
"UPDATE SYS_FIELDS SET COL_NAME=:new\n"
45564568
"WHERE INDEX_ID=:indexid\n"
45574569
"AND POS=:nth;\n"
4558-
4559-
/* Try again, in case there is a prefix_len
4560-
encoded in SYS_FIELDS.POS */
4561-
4562-
"UPDATE SYS_FIELDS SET COL_NAME=:new\n"
4563-
"WHERE INDEX_ID=:indexid\n"
4564-
"AND POS>=65536*:nth AND POS<65536*(:nth+1);\n"
4565-
45664570
"END;\n",
45674571
FALSE, trx);
45684572

storage/xtradb/handler/handler0alter.cc

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4547,36 +4547,40 @@ innobase_rename_column_try(
45474547
index != NULL;
45484548
index = dict_table_get_next_index(index)) {
45494549

4550+
bool has_prefixes = false;
4551+
for (size_t i = 0; i < dict_index_get_n_fields(index); i++) {
4552+
if (dict_index_get_nth_field(index, i)->prefix_len) {
4553+
has_prefixes = true;
4554+
break;
4555+
}
4556+
}
4557+
45504558
for (ulint i = 0; i < dict_index_get_n_fields(index); i++) {
4551-
if (my_strcasecmp(
4552-
system_charset_info,
4553-
dict_index_get_nth_field(index, i)->name,
4554-
from)) {
4559+
const dict_field_t* field
4560+
= dict_index_get_nth_field(index, i);
4561+
if (my_strcasecmp(system_charset_info, field->name,
4562+
from)) {
45554563
continue;
45564564
}
45574565

45584566
info = pars_info_create();
45594567

4568+
int pos = i;
4569+
if (has_prefixes) {
4570+
pos = (pos << 16) + field->prefix_len;
4571+
}
4572+
45604573
pars_info_add_ull_literal(info, "indexid", index->id);
4561-
pars_info_add_int4_literal(info, "nth", i);
4574+
pars_info_add_int4_literal(info, "nth", pos);
45624575
pars_info_add_str_literal(info, "new", to);
45634576

45644577
error = que_eval_sql(
45654578
info,
45664579
"PROCEDURE RENAME_SYS_FIELDS_PROC () IS\n"
45674580
"BEGIN\n"
4568-
45694581
"UPDATE SYS_FIELDS SET COL_NAME=:new\n"
45704582
"WHERE INDEX_ID=:indexid\n"
45714583
"AND POS=:nth;\n"
4572-
4573-
/* Try again, in case there is a prefix_len
4574-
encoded in SYS_FIELDS.POS */
4575-
4576-
"UPDATE SYS_FIELDS SET COL_NAME=:new\n"
4577-
"WHERE INDEX_ID=:indexid\n"
4578-
"AND POS>=65536*:nth AND POS<65536*(:nth+1);\n"
4579-
45804584
"END;\n",
45814585
FALSE, trx);
45824586

0 commit comments

Comments
 (0)