List:Commits« Previous MessageNext Message »
From:Sergey Vojtovich Date:January 22 2010 9:57am
Subject:bzr commit into mysql-5.1-bugteam branch (svoj:3332) Bug#46193
View as plain text  
#At file:///home/svoj/devel/innodb-snapshots/mysql-5.1-bugteam/ based on revid:svoj@stripped

 3332 Sergey Vojtovich	2010-01-22
      Applying InnoDB snapshot, fixes BUG#46193.
      
      Detailed revision comments:
      
      r6424 | marko | 2010-01-12 12:22:19 +0200 (Tue, 12 Jan 2010) | 16 lines
      branches/5.1: In innobase_initialize_autoinc(), do not attempt to read
      the maximum auto-increment value from the table if
      innodb_force_recovery is set to at least 4, so that writes are
      disabled. (Bug #46193)
      
      innobase_get_int_col_max_value(): Move the function definition before
      ha_innobase::innobase_initialize_autoinc(), because that function now
      calls this function.
      
      ha_innobase::innobase_initialize_autoinc(): Change the return type to
      void.  Do not attempt to read the maximum auto-increment value from
      the table if innodb_force_recovery is set to at least 4.  Issue
      ER_AUTOINC_READ_FAILED to the client when the auto-increment value
      cannot be read.
      
      rb://144 by Sunny, revised by Marko

    modified:
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/handler/ha_innodb.h
=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc	2010-01-22 09:56:32 +0000
+++ b/storage/innobase/handler/ha_innodb.cc	2010-01-22 09:57:02 +0000
@@ -2576,57 +2576,150 @@ normalize_table_name(
 }
 
 /************************************************************************
+Get the upper limit of the MySQL integral and floating-point type. */
+static
+ulonglong
+innobase_get_int_col_max_value(
+/*===========================*/
+				/* out: maximum allowed value for the field */
+	const Field*	field)	/* in: MySQL field */
+{
+	ulonglong	max_value = 0;
+
+	switch(field->key_type()) {
+	/* TINY */
+	case HA_KEYTYPE_BINARY:
+		max_value = 0xFFULL;
+		break;
+	case HA_KEYTYPE_INT8:
+		max_value = 0x7FULL;
+		break;
+	/* SHORT */
+	case HA_KEYTYPE_USHORT_INT:
+		max_value = 0xFFFFULL;
+		break;
+	case HA_KEYTYPE_SHORT_INT:
+		max_value = 0x7FFFULL;
+		break;
+	/* MEDIUM */
+	case HA_KEYTYPE_UINT24:
+		max_value = 0xFFFFFFULL;
+		break;
+	case HA_KEYTYPE_INT24:
+		max_value = 0x7FFFFFULL;
+		break;
+	/* LONG */
+	case HA_KEYTYPE_ULONG_INT:
+		max_value = 0xFFFFFFFFULL;
+		break;
+	case HA_KEYTYPE_LONG_INT:
+		max_value = 0x7FFFFFFFULL;
+		break;
+	/* BIG */
+	case HA_KEYTYPE_ULONGLONG:
+		max_value = 0xFFFFFFFFFFFFFFFFULL;
+		break;
+	case HA_KEYTYPE_LONGLONG:
+		max_value = 0x7FFFFFFFFFFFFFFFULL;
+		break;
+	case HA_KEYTYPE_FLOAT:
+		/* We use the maximum as per IEEE754-2008 standard, 2^24 */
+		max_value = 0x1000000ULL;
+		break;
+	case HA_KEYTYPE_DOUBLE:
+		/* We use the maximum as per IEEE754-2008 standard, 2^53 */
+		max_value = 0x20000000000000ULL;
+		break;
+	default:
+		ut_error;
+	}
+
+	return(max_value);
+}
+
+/************************************************************************
 Set the autoinc column max value. This should only be called once from
 ha_innobase::open(). Therefore there's no need for a covering lock. */
 
-ulong
+void
 ha_innobase::innobase_initialize_autoinc()
 /*======================================*/
 {
-	dict_index_t*	index;
 	ulonglong	auto_inc;
-	const char*	col_name;
-	ulint		error = DB_SUCCESS;
-	dict_table_t*	innodb_table = prebuilt->table;
-
-	col_name = table->found_next_number_field->field_name;
-	index = innobase_get_index(table->s->next_number_index);
+	const Field*	field = table->found_next_number_field;
 
-	/* Execute SELECT MAX(col_name) FROM TABLE; */
-	error = row_search_max_autoinc(index, col_name, &auto_inc);
+	if (field != NULL) {
+		auto_inc = innobase_get_int_col_max_value(field);
+	} else {
+		/* We have no idea what's been passed in to us as the
+		autoinc column. We set it to the MAX_INT of our table
+		autoinc type. */
+		auto_inc = 0xFFFFFFFFFFFFFFFFULL;
 
-	if (error == DB_SUCCESS) {
+		ut_print_timestamp(stderr);
+		fprintf(stderr, "  InnoDB: Unable to determine the AUTOINC "
+				"column name\n");
+	}
 
-		/* At the this stage we dont' know the increment
-		or the offset, so use default inrement of 1. */
-		++auto_inc;
+	if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
+		/* If the recovery level is set so high that writes
+		are disabled we force the AUTOINC counter to the MAX
+		value effectively disabling writes to the table.
+		Secondly, we avoid reading the table in case the read
+		results in failure due to a corrupted table/index.
+
+		We will not return an error to the client, so that the
+		tables can be dumped with minimal hassle.  If an error
+		were returned in this case, the first attempt to read
+		the table would fail and subsequent SELECTs would succeed. */
+	} else if (field == NULL) {
+		my_error(ER_AUTOINC_READ_FAILED, MYF(0));
+	} else {
+		dict_index_t*	index;
+		const char*	col_name;
+		ulonglong	read_auto_inc;
+		ulint		err;
 
-		dict_table_autoinc_initialize(innodb_table, auto_inc);
+		update_thd(ha_thd());
+		col_name = field->field_name;
+		index = innobase_get_index(table->s->next_number_index);
 
-	} else if (error == DB_RECORD_NOT_FOUND) {
-		ut_print_timestamp(stderr);
-		fprintf(stderr, "  InnoDB: MySQL and InnoDB data "
-			"dictionaries are out of sync.\n"
-			"InnoDB: Unable to find the AUTOINC column %s in the "
-			"InnoDB table %s.\n"
-			"InnoDB: We set the next AUTOINC column value to the "
-			"maximum possible value,\n"
-			"InnoDB: in effect disabling the AUTOINC next value "
-			"generation.\n"
-			"InnoDB: You can either set the next AUTOINC value "
-			"explicitly using ALTER TABLE\n"
-			"InnoDB: or fix the data dictionary by recreating "
-			"the table.\n",
-			col_name, index->table->name);
+		/* Execute SELECT MAX(col_name) FROM TABLE; */
+		err = row_search_max_autoinc(index, col_name, &read_auto_inc);
 
-		auto_inc = 0xFFFFFFFFFFFFFFFFULL;
+		switch (err) {
+		case DB_SUCCESS:
+			/* At the this stage we do not know the increment
+			or the offset, so use a default increment of 1. */
+			auto_inc = read_auto_inc + 1;
+			break;
 
-		dict_table_autoinc_initialize(innodb_table, auto_inc);
+		case DB_RECORD_NOT_FOUND:
+			ut_print_timestamp(stderr);
+			fprintf(stderr, "  InnoDB: MySQL and InnoDB data "
+				"dictionaries are out of sync.\n"
+				"InnoDB: Unable to find the AUTOINC column "
+				"%s in the InnoDB table %s.\n"
+				"InnoDB: We set the next AUTOINC column "
+				"value to the maximum possible value,\n"
+				"InnoDB: in effect disabling the AUTOINC "
+				"next value generation.\n"
+				"InnoDB: You can either set the next "
+				"AUTOINC value explicitly using ALTER TABLE\n"
+				"InnoDB: or fix the data dictionary by "
+				"recreating the table.\n",
+				col_name, index->table->name);
 
-		error = DB_SUCCESS;
-	} /* else other errors are still fatal */
+			my_error(ER_AUTOINC_READ_FAILED, MYF(0));
+			break;
+		default:
+			/* row_search_max_autoinc() should only return
+			one of DB_SUCCESS or DB_RECORD_NOT_FOUND. */
+			ut_error;
+		}
+	}
 
-	return(ulong(error));
+	dict_table_autoinc_initialize(prebuilt->table, auto_inc);
 }
 
 /*********************************************************************
@@ -2824,8 +2917,6 @@ retry:
 
 	/* Only if the table has an AUTOINC column. */
 	if (prebuilt->table != NULL && table->found_next_number_field != NULL) {
-		ulint	error;
-
 		dict_table_autoinc_lock(prebuilt->table);
 
 		/* Since a table can already be "open" in InnoDB's internal
@@ -2834,8 +2925,7 @@ retry:
 		autoinc value from a previous MySQL open. */
 		if (dict_table_autoinc_read(prebuilt->table) == 0) {
 
-			error = innobase_initialize_autoinc();
-			ut_a(error == DB_SUCCESS);
+			innobase_initialize_autoinc();
 		}
 
 		dict_table_autoinc_unlock(prebuilt->table);
@@ -3651,68 +3741,6 @@ skip_field:
 }
 
 /************************************************************************
-Get the upper limit of the MySQL integral and floating-point type. */
-static
-ulonglong
-innobase_get_int_col_max_value(
-/*===========================*/
-				/* out: maximum allowed value for the field */
-	const Field*	field)	/* in: MySQL field */
-{
-	ulonglong	max_value = 0;
-
-	switch(field->key_type()) {
-	/* TINY */
-	case HA_KEYTYPE_BINARY:
-		max_value = 0xFFULL;
-		break;
-	case HA_KEYTYPE_INT8:
-		max_value = 0x7FULL;
-		break;
-	/* SHORT */
-	case HA_KEYTYPE_USHORT_INT:
-		max_value = 0xFFFFULL;
-		break;
-	case HA_KEYTYPE_SHORT_INT:
-		max_value = 0x7FFFULL;
-		break;
-	/* MEDIUM */
-	case HA_KEYTYPE_UINT24:
-		max_value = 0xFFFFFFULL;
-		break;
-	case HA_KEYTYPE_INT24:
-		max_value = 0x7FFFFFULL;
-		break;
-	/* LONG */
-	case HA_KEYTYPE_ULONG_INT:
-		max_value = 0xFFFFFFFFULL;
-		break;
-	case HA_KEYTYPE_LONG_INT:
-		max_value = 0x7FFFFFFFULL;
-		break;
-	/* BIG */
-	case HA_KEYTYPE_ULONGLONG:
-		max_value = 0xFFFFFFFFFFFFFFFFULL;
-		break;
-	case HA_KEYTYPE_LONGLONG:
-		max_value = 0x7FFFFFFFFFFFFFFFULL;
-		break;
-	case HA_KEYTYPE_FLOAT:
-		/* We use the maximum as per IEEE754-2008 standard, 2^24 */
-		max_value = 0x1000000ULL;
-		break;
-	case HA_KEYTYPE_DOUBLE:
-		/* We use the maximum as per IEEE754-2008 standard, 2^53 */
-		max_value = 0x20000000000000ULL;
-		break;
-	default:
-		ut_error;
-	}
-
-	return(max_value);
-}
-
-/************************************************************************
 This special handling is really to overcome the limitations of MySQL's
 binlogging. We need to eliminate the non-determinism that will arise in
 INSERT ... SELECT type of statements, since MySQL binlog only stores the

=== modified file 'storage/innobase/handler/ha_innodb.h'
--- a/storage/innobase/handler/ha_innodb.h	2010-01-22 09:56:32 +0000
+++ b/storage/innobase/handler/ha_innodb.h	2010-01-22 09:57:02 +0000
@@ -78,7 +78,7 @@ class ha_innobase: public handler
 	ulong innobase_reset_autoinc(ulonglong auto_inc);
 	ulong innobase_get_autoinc(ulonglong* value);
 	ulong innobase_update_autoinc(ulonglong	auto_inc);
-	ulong innobase_initialize_autoinc();
+	void innobase_initialize_autoinc();
 	dict_index_t* innobase_get_index(uint keynr);
 
 	/* Init values for the class: */


Attachment: [text/bzr-bundle] bzr/svoj@sun.com-20100122095702-e18xzhmyll1e5s25.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (svoj:3332) Bug#46193Sergey Vojtovich22 Jan