mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Port bug fix #53592 from mysql-5.1-innodb to mysql-trunk-innodb.
This commit is contained in:
43
mysql-test/suite/innodb/r/innodb_bug53592.result
Normal file
43
mysql-test/suite/innodb/r/innodb_bug53592.result
Normal file
@ -0,0 +1,43 @@
|
||||
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;
|
||||
CREATE TABLE bug53592_1(
|
||||
col1 int, col2 int,
|
||||
PRIMARY KEY (col1, col2)
|
||||
) ENGINE=InnoDB;
|
||||
CREATE TABLE bug53592_2 (
|
||||
col int PRIMARY KEY,
|
||||
FOREIGN KEY (col) REFERENCES bug53592_1 (col1)
|
||||
ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB;
|
||||
INSERT INTO bug53592_1 VALUES (1, 2);
|
||||
INSERT INTO bug53592_1 VALUES (3, 4);
|
||||
INSERT INTO bug53592_2 VALUES (1);
|
||||
INSERT INTO bug53592_2 VALUES (3);
|
||||
UPDATE bug53592_1 SET col1 = 3 WHERE col2 = 2;
|
||||
ERROR 23000: Upholding foreign key constraints for table 'bug53592_1', entry '3-2', key 1 would lead to a duplicate entry
|
||||
drop table bug53592_2;
|
||||
drop table bug53592_1;
|
82
mysql-test/suite/innodb/t/innodb_bug53592.test
Normal file
82
mysql-test/suite/innodb/t/innodb_bug53592.test
Normal file
@ -0,0 +1,82 @@
|
||||
# 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;
|
||||
|
||||
# Test a dup key reported by foreign key constriant.
|
||||
CREATE TABLE bug53592_1(
|
||||
col1 int, col2 int,
|
||||
PRIMARY KEY (col1, col2)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE bug53592_2 (
|
||||
col int PRIMARY KEY,
|
||||
FOREIGN KEY (col) REFERENCES bug53592_1 (col1)
|
||||
ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO bug53592_1 VALUES (1, 2);
|
||||
INSERT INTO bug53592_1 VALUES (3, 4);
|
||||
|
||||
INSERT INTO bug53592_2 VALUES (1);
|
||||
INSERT INTO bug53592_2 VALUES (3);
|
||||
|
||||
--error ER_FOREIGN_DUPLICATE_KEY
|
||||
UPDATE bug53592_1 SET col1 = 3 WHERE col2 = 2;
|
||||
|
||||
drop table bug53592_2;
|
||||
drop table bug53592_1;
|
@ -6866,7 +6866,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);
|
||||
@ -7582,6 +7582,84 @@ 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_a(index);
|
||||
|
||||
/* If index does not belong to the table of share structure. Search
|
||||
index->table instead */
|
||||
if (index->table != ib_table
|
||||
&& innobase_strcasecmp(index->table->name, share->table_name)) {
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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 with information from mysql TABLE structure and
|
||||
InnoDB 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);
|
||||
}
|
||||
}
|
||||
|
||||
ut_error;
|
||||
|
||||
return(0);
|
||||
}
|
||||
/*********************************************************************//**
|
||||
Returns statistics information of the table to the MySQL interpreter,
|
||||
in various fields of the handle object. */
|
||||
@ -7851,8 +7929,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
|
||||
|
@ -1647,37 +1647,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. */
|
||||
|
Reference in New Issue
Block a user