3135 Jimmy Yang 2010-06-02
Port bug fix #53592 from mysql-5.1-innodb to mysql-trunk-innodb.
added:
mysql-test/suite/innodb/r/innodb_bug53592.result
mysql-test/suite/innodb/t/innodb_bug53592.test
modified:
storage/innobase/handler/ha_innodb.cc
storage/innobase/include/row0mysql.h
storage/innobase/row/row0mysql.c
3134 Jimmy Yang 2010-06-01
Fix bug #54159 InnoDB: New warnings on Windows. Provide "signed/unsigned"
parameter to virtual function store() for longlong data type.
rb://371 approved by Sunny.
modified:
storage/innobase/handler/i_s.cc
=== added file 'mysql-test/suite/innodb/r/innodb_bug53592.result'
--- a/mysql-test/suite/innodb/r/innodb_bug53592.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/r/innodb_bug53592.result revid:jimmy.yang@stripped
@@ -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;
=== added file 'mysql-test/suite/innodb/t/innodb_bug53592.test'
--- a/mysql-test/suite/innodb/t/innodb_bug53592.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/t/innodb_bug53592.test revid:jimmy.yang@stripped
@@ -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;
=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc revid:jimmy.yang@stripped
+++ b/storage/innobase/handler/ha_innodb.cc revid:jimmy.yang@stripped
@@ -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);
@@ -7583,6 +7583,84 @@ ha_innobase::read_time(
}
/*********************************************************************//**
+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. */
UNIV_INTERN
@@ -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;
}
=== modified file 'storage/innobase/include/row0mysql.h'
--- a/storage/innobase/include/row0mysql.h revid:jimmy.yang@stripped
+++ b/storage/innobase/include/row0mysql.h revid:jimmy.yang@stripped
@@ -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
=== modified file 'storage/innobase/row/row0mysql.c'
--- a/storage/innobase/row/row0mysql.c revid:jimmy.yang@stripped
+++ b/storage/innobase/row/row0mysql.c revid:jimmy.yang@stripped
@@ -1648,37 +1648,6 @@ row_table_got_default_clust_index(
}
/*********************************************************************//**
-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. */
UNIV_INTERN
Attachment: [text/bzr-bundle] bzr/jimmy.yang@oracle.com-20100602110400-568a3b2gd9uxxxvg.bundle
| Thread |
|---|
| • bzr push into mysql-trunk-innodb branch (jimmy.yang:3134 to 3135) | Jimmy Yang | 2 Jun |