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
This commit is contained in:
parent
b74eb5a5fe
commit
802ce9672f
@ -865,6 +865,27 @@ WHERE T.NAME='test/t1';
|
||||
NAME
|
||||
a
|
||||
DROP TABLE t1;
|
||||
# and an MDEV-18041 regression related to indexes prefixes
|
||||
create table `test` (
|
||||
`test_old` varchar(255) NOT NULL,
|
||||
`other` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`test_old`,`other`),
|
||||
UNIQUE KEY uk (`test_old`(100), `other`)
|
||||
) ENGINE=InnoDB;
|
||||
select name, pos from information_schema.innodb_SYS_FIELDS where name in ('test_old', 'other', 'test_new');
|
||||
name pos
|
||||
test_old 0
|
||||
other 1
|
||||
test_old 0
|
||||
other 1
|
||||
alter table `test` CHANGE COLUMN `test_old` `test_new` varchar(255) NOT NULL;
|
||||
select name, pos from information_schema.innodb_SYS_FIELDS where name in ('test_old', 'other', 'test_new');
|
||||
name pos
|
||||
test_new 0
|
||||
other 1
|
||||
test_new 0
|
||||
other 1
|
||||
drop table `test`;
|
||||
#
|
||||
# BUG 20029625 - HANDLE_FATAL_SIGNAL (SIG=11) IN
|
||||
# DICT_MEM_TABLE_COL_RENAME_LOW
|
||||
|
@ -522,6 +522,19 @@ SELECT C.NAME FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS C INNER JOIN
|
||||
WHERE T.NAME='test/t1';
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo # and an MDEV-18041 regression related to indexes prefixes
|
||||
create table `test` (
|
||||
`test_old` varchar(255) NOT NULL,
|
||||
`other` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`test_old`,`other`),
|
||||
UNIQUE KEY uk (`test_old`(100), `other`)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
select name, pos from information_schema.innodb_SYS_FIELDS where name in ('test_old', 'other', 'test_new');
|
||||
alter table `test` CHANGE COLUMN `test_old` `test_new` varchar(255) NOT NULL;
|
||||
select name, pos from information_schema.innodb_SYS_FIELDS where name in ('test_old', 'other', 'test_new');
|
||||
drop table `test`;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # BUG 20029625 - HANDLE_FATAL_SIGNAL (SIG=11) IN
|
||||
|
@ -4533,36 +4533,40 @@ err_exit:
|
||||
index != NULL;
|
||||
index = dict_table_get_next_index(index)) {
|
||||
|
||||
bool has_prefixes = false;
|
||||
for (size_t i = 0; i < dict_index_get_n_fields(index); i++) {
|
||||
if (dict_index_get_nth_field(index, i)->prefix_len) {
|
||||
has_prefixes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (ulint i = 0; i < dict_index_get_n_fields(index); i++) {
|
||||
if (my_strcasecmp(
|
||||
system_charset_info,
|
||||
dict_index_get_nth_field(index, i)->name,
|
||||
from)) {
|
||||
const dict_field_t* field
|
||||
= dict_index_get_nth_field(index, i);
|
||||
if (my_strcasecmp(system_charset_info, field->name,
|
||||
from)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
info = pars_info_create();
|
||||
|
||||
int pos = i;
|
||||
if (has_prefixes) {
|
||||
pos = (pos << 16) + field->prefix_len;
|
||||
}
|
||||
|
||||
pars_info_add_ull_literal(info, "indexid", index->id);
|
||||
pars_info_add_int4_literal(info, "nth", i);
|
||||
pars_info_add_int4_literal(info, "nth", pos);
|
||||
pars_info_add_str_literal(info, "new", to);
|
||||
|
||||
error = que_eval_sql(
|
||||
info,
|
||||
"PROCEDURE RENAME_SYS_FIELDS_PROC () IS\n"
|
||||
"BEGIN\n"
|
||||
|
||||
"UPDATE SYS_FIELDS SET COL_NAME=:new\n"
|
||||
"WHERE INDEX_ID=:indexid\n"
|
||||
"AND POS=:nth;\n"
|
||||
|
||||
/* Try again, in case there is a prefix_len
|
||||
encoded in SYS_FIELDS.POS */
|
||||
|
||||
"UPDATE SYS_FIELDS SET COL_NAME=:new\n"
|
||||
"WHERE INDEX_ID=:indexid\n"
|
||||
"AND POS>=65536*:nth AND POS<65536*(:nth+1);\n"
|
||||
|
||||
"END;\n",
|
||||
FALSE, trx);
|
||||
|
||||
|
@ -4547,36 +4547,40 @@ err_exit:
|
||||
index != NULL;
|
||||
index = dict_table_get_next_index(index)) {
|
||||
|
||||
bool has_prefixes = false;
|
||||
for (size_t i = 0; i < dict_index_get_n_fields(index); i++) {
|
||||
if (dict_index_get_nth_field(index, i)->prefix_len) {
|
||||
has_prefixes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (ulint i = 0; i < dict_index_get_n_fields(index); i++) {
|
||||
if (my_strcasecmp(
|
||||
system_charset_info,
|
||||
dict_index_get_nth_field(index, i)->name,
|
||||
from)) {
|
||||
const dict_field_t* field
|
||||
= dict_index_get_nth_field(index, i);
|
||||
if (my_strcasecmp(system_charset_info, field->name,
|
||||
from)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
info = pars_info_create();
|
||||
|
||||
int pos = i;
|
||||
if (has_prefixes) {
|
||||
pos = (pos << 16) + field->prefix_len;
|
||||
}
|
||||
|
||||
pars_info_add_ull_literal(info, "indexid", index->id);
|
||||
pars_info_add_int4_literal(info, "nth", i);
|
||||
pars_info_add_int4_literal(info, "nth", pos);
|
||||
pars_info_add_str_literal(info, "new", to);
|
||||
|
||||
error = que_eval_sql(
|
||||
info,
|
||||
"PROCEDURE RENAME_SYS_FIELDS_PROC () IS\n"
|
||||
"BEGIN\n"
|
||||
|
||||
"UPDATE SYS_FIELDS SET COL_NAME=:new\n"
|
||||
"WHERE INDEX_ID=:indexid\n"
|
||||
"AND POS=:nth;\n"
|
||||
|
||||
/* Try again, in case there is a prefix_len
|
||||
encoded in SYS_FIELDS.POS */
|
||||
|
||||
"UPDATE SYS_FIELDS SET COL_NAME=:new\n"
|
||||
"WHERE INDEX_ID=:indexid\n"
|
||||
"AND POS>=65536*:nth AND POS<65536*(:nth+1);\n"
|
||||
|
||||
"END;\n",
|
||||
FALSE, trx);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user