List:Commits« Previous MessageNext Message »
From:Jimmy Yang Date:June 2 2010 11:12am
Subject:bzr push into mysql-trunk-innodb branch (jimmy.yang:3134 to 3135)
View as plain text  
 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 Yang2 Jun