mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +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 :
|
(int) form->s->primary_key :
|
||||||
-1);
|
-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 */
|
the primary key is always number 0, if it exists */
|
||||||
|
|
||||||
ut_a(primary_key_no == -1 || primary_key_no == 0);
|
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);
|
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,
|
Returns statistics information of the table to the MySQL interpreter,
|
||||||
in various fields of the handle object. */
|
in various fields of the handle object. */
|
||||||
@ -7658,8 +7719,8 @@ ha_innobase::info(
|
|||||||
err_index = trx_get_error_info(prebuilt->trx);
|
err_index = trx_get_error_info(prebuilt->trx);
|
||||||
|
|
||||||
if (err_index) {
|
if (err_index) {
|
||||||
errkey = (unsigned int)
|
errkey = innobase_get_mysql_key_number_for_index(
|
||||||
row_get_mysql_key_number_for_index(err_index);
|
share, table, ib_table, err_index);
|
||||||
} else {
|
} else {
|
||||||
errkey = (unsigned int) prebuilt->trx->error_key_num;
|
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 */
|
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.
|
Does an update or delete of a row for MySQL.
|
||||||
@return error code or DB_SUCCESS */
|
@return error code or DB_SUCCESS */
|
||||||
UNIV_INTERN
|
UNIV_INTERN
|
||||||
|
@ -1645,37 +1645,6 @@ row_table_got_default_clust_index(
|
|||||||
return(dict_index_get_nth_col(clust_index, 0)->mtype == DATA_SYS);
|
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
|
Locks the data dictionary in shared mode from modifications, for performing
|
||||||
foreign key check, rollback, or other operation invisible to MySQL. */
|
foreign key check, rollback, or other operation invisible to MySQL. */
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
TARGETDIR=../storage/innobase
|
TARGETDIR=../storage/innodb_plugin
|
||||||
|
|
||||||
# link the build scripts
|
# link the build scripts
|
||||||
BUILDSCRIPTS="compile-innodb compile-innodb-debug"
|
BUILDSCRIPTS="compile-innodb compile-innodb-debug"
|
||||||
|
Reference in New Issue
Block a user