mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Fix Bug #53592 in plugin code, "crash replacing duplicates into table
after fast alter table added unique key". Look up MySQL index number should go through index translation table. rb://347, approved by Marko
This commit is contained in:
26
mysql-test/suite/innodb_plugin/r/innodb_bug53592.result
Normal file
26
mysql-test/suite/innodb_plugin/r/innodb_bug53592.result
Normal file
@ -0,0 +1,26 @@
|
||||
set old_alter_table=0;
|
||||
create table bug53592(a int) engine=innodb row_format=compact;
|
||||
alter table bug53592 add column b text charset utf8;
|
||||
alter table bug53592 add column c blob not null;
|
||||
create index bug53592_b on bug53592(b(81));
|
||||
create unique index bug53592_c on bug53592(c(1));
|
||||
replace into bug53592 values (),();
|
||||
Warnings:
|
||||
Warning 1364 Field 'c' doesn't have a default value
|
||||
check table bug53592;
|
||||
Table Op Msg_type Msg_text
|
||||
test.bug53592 check status OK
|
||||
drop table bug53592;
|
||||
set old_alter_table=1;
|
||||
create table bug53592(a int) engine=innodb row_format=compact;
|
||||
alter table bug53592 add column b text charset utf8;
|
||||
alter table bug53592 add column c blob not null;
|
||||
create index bug53592_b on bug53592(b(81));
|
||||
create unique index bug53592_c on bug53592(c(1));
|
||||
replace into bug53592 values (),();
|
||||
Warnings:
|
||||
Warning 1364 Field 'c' doesn't have a default value
|
||||
check table bug53592;
|
||||
Table Op Msg_type Msg_text
|
||||
test.bug53592 check status OK
|
||||
drop table bug53592;
|
59
mysql-test/suite/innodb_plugin/t/innodb_bug53592.test
Normal file
59
mysql-test/suite/innodb_plugin/t/innodb_bug53592.test
Normal file
@ -0,0 +1,59 @@
|
||||
# Testcase for Bug #53592 - "crash replacing duplicates into
|
||||
# table after fast alter table added unique key". The fix is to make
|
||||
# sure index number lookup should go through "index translation table".
|
||||
|
||||
--source include/have_innodb.inc
|
||||
|
||||
# Use FIC for index creation
|
||||
set old_alter_table=0;
|
||||
|
||||
create table bug53592(a int) engine=innodb row_format=compact;
|
||||
|
||||
alter table bug53592 add column b text charset utf8;
|
||||
|
||||
alter table bug53592 add column c blob not null;
|
||||
|
||||
# Create a non-unique nonclustered index
|
||||
create index bug53592_b on bug53592(b(81));
|
||||
|
||||
# Create a unique index, this unique index should have smaller
|
||||
# index number than bug53592_b, since unique index ranks higher
|
||||
# than regular index does
|
||||
create unique index bug53592_c on bug53592(c(1));
|
||||
|
||||
# This will trigger a dup key error and will require fetching
|
||||
# the index number through a index structure for the error reporting.
|
||||
# To get the correct index number, the code should go through index
|
||||
# translation table. Otherwise, it will get the wrong index
|
||||
# number and later trigger a server crash.
|
||||
replace into bug53592 values (),();
|
||||
|
||||
check table bug53592;
|
||||
|
||||
drop table bug53592;
|
||||
|
||||
# Running the same set of test when "old_alter_table" is turned on
|
||||
set old_alter_table=1;
|
||||
|
||||
create table bug53592(a int) engine=innodb row_format=compact;
|
||||
|
||||
alter table bug53592 add column b text charset utf8;
|
||||
|
||||
alter table bug53592 add column c blob not null;
|
||||
|
||||
# Create a non-unique nonclustered index
|
||||
create index bug53592_b on bug53592(b(81));
|
||||
|
||||
# Create a unique index
|
||||
create unique index bug53592_c on bug53592(c(1));
|
||||
|
||||
# This will trigger a dup key error and will require fetching
|
||||
# the index number through a index structure for the error reporting.
|
||||
# To get the correct index number, the code should go through index
|
||||
# translation table. Otherwise, it will get the wrong index
|
||||
# number and later trigger a server crash.
|
||||
replace into bug53592 values (),();
|
||||
|
||||
check table bug53592;
|
||||
|
||||
drop table bug53592;
|
@ -6673,7 +6673,7 @@ ha_innobase::create(
|
||||
(int) form->s->primary_key :
|
||||
-1);
|
||||
|
||||
/* Our function row_get_mysql_key_number_for_index assumes
|
||||
/* Our function innobase_get_mysql_key_number_for_index assumes
|
||||
the primary key is always number 0, if it exists */
|
||||
|
||||
ut_a(primary_key_no == -1 || primary_key_no == 0);
|
||||
@ -7389,6 +7389,67 @@ ha_innobase::read_time(
|
||||
return(ranges + (double) rows / (double) total_rows * time_for_scan);
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Calculates the key number used inside MySQL for an Innobase index. We will
|
||||
first check the "index translation table" for a match of the index to get
|
||||
the index number. If there does not exist an "index translation table",
|
||||
or not able to find the index in the translation table, then we will fall back
|
||||
to the traditional way of looping through dict_index_t list to find a
|
||||
match. In this case, we have to take into account if we generated a
|
||||
default clustered index for the table
|
||||
@return the key number used inside MySQL */
|
||||
static
|
||||
unsigned int
|
||||
innobase_get_mysql_key_number_for_index(
|
||||
/*====================================*/
|
||||
INNOBASE_SHARE* share, /*!< in: share structure for index
|
||||
translation table. */
|
||||
const TABLE* table, /*!< in: table in MySQL data
|
||||
dictionary */
|
||||
dict_table_t* ib_table,/*!< in: table in Innodb data
|
||||
dictionary */
|
||||
const dict_index_t* index) /*!< in: index */
|
||||
{
|
||||
const dict_index_t* ind;
|
||||
unsigned int i;
|
||||
|
||||
ut_ad(index);
|
||||
ut_ad(ib_table);
|
||||
ut_ad(table);
|
||||
ut_ad(share);
|
||||
|
||||
/* If index translation table exists, we will first check
|
||||
the index through index translation table for a match. */
|
||||
if (share->idx_trans_tbl.index_mapping) {
|
||||
for (i = 0; i < share->idx_trans_tbl.index_count; i++) {
|
||||
if (share->idx_trans_tbl.index_mapping[i] == index) {
|
||||
return(i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print an error message if we cannot find the index
|
||||
** in the "index translation table". */
|
||||
sql_print_error("Cannot find index %s in InnoDB index "
|
||||
"translation table.", index->name);
|
||||
}
|
||||
|
||||
/* If we do not have an "index translation table", or not able
|
||||
to find the index in the translation table, we'll directly find
|
||||
matching index in the dict_index_t list */
|
||||
for (i = 0; i < table->s->keys; i++) {
|
||||
ind = dict_table_get_index_on_name(
|
||||
ib_table, table->key_info[i].name);
|
||||
|
||||
if (index == ind) {
|
||||
return(i);
|
||||
}
|
||||
}
|
||||
|
||||
sql_print_error("Cannot find matching index number for index %s "
|
||||
"in InnoDB index list.", index->name);
|
||||
|
||||
return(0);
|
||||
}
|
||||
/*********************************************************************//**
|
||||
Returns statistics information of the table to the MySQL interpreter,
|
||||
in various fields of the handle object. */
|
||||
@ -7658,8 +7719,8 @@ ha_innobase::info(
|
||||
err_index = trx_get_error_info(prebuilt->trx);
|
||||
|
||||
if (err_index) {
|
||||
errkey = (unsigned int)
|
||||
row_get_mysql_key_number_for_index(err_index);
|
||||
errkey = innobase_get_mysql_key_number_for_index(
|
||||
share, table, ib_table, err_index);
|
||||
} else {
|
||||
errkey = (unsigned int) prebuilt->trx->error_key_num;
|
||||
}
|
||||
|
@ -253,15 +253,6 @@ row_table_got_default_clust_index(
|
||||
/*==============================*/
|
||||
const dict_table_t* table); /*!< in: table */
|
||||
/*********************************************************************//**
|
||||
Calculates the key number used inside MySQL for an Innobase index. We have
|
||||
to take into account if we generated a default clustered index for the table
|
||||
@return the key number used inside MySQL */
|
||||
UNIV_INTERN
|
||||
ulint
|
||||
row_get_mysql_key_number_for_index(
|
||||
/*===============================*/
|
||||
const dict_index_t* index); /*!< in: index */
|
||||
/*********************************************************************//**
|
||||
Does an update or delete of a row for MySQL.
|
||||
@return error code or DB_SUCCESS */
|
||||
UNIV_INTERN
|
||||
|
@ -1645,37 +1645,6 @@ row_table_got_default_clust_index(
|
||||
return(dict_index_get_nth_col(clust_index, 0)->mtype == DATA_SYS);
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Calculates the key number used inside MySQL for an Innobase index. We have
|
||||
to take into account if we generated a default clustered index for the table
|
||||
@return the key number used inside MySQL */
|
||||
UNIV_INTERN
|
||||
ulint
|
||||
row_get_mysql_key_number_for_index(
|
||||
/*===============================*/
|
||||
const dict_index_t* index) /*!< in: index */
|
||||
{
|
||||
const dict_index_t* ind;
|
||||
ulint i;
|
||||
|
||||
ut_a(index);
|
||||
|
||||
i = 0;
|
||||
ind = dict_table_get_first_index(index->table);
|
||||
|
||||
while (index != ind) {
|
||||
ind = dict_table_get_next_index(ind);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (row_table_got_default_clust_index(index->table)) {
|
||||
ut_a(i > 0);
|
||||
i--;
|
||||
}
|
||||
|
||||
return(i);
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Locks the data dictionary in shared mode from modifications, for performing
|
||||
foreign key check, rollback, or other operation invisible to MySQL. */
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
set -eu
|
||||
|
||||
TARGETDIR=../storage/innobase
|
||||
TARGETDIR=../storage/innodb_plugin
|
||||
|
||||
# link the build scripts
|
||||
BUILDSCRIPTS="compile-innodb compile-innodb-debug"
|
||||
|
Reference in New Issue
Block a user