From 31143f1cf82648076cb8ab7c68653e113ce0ba31 Mon Sep 17 00:00:00 2001
From: Sergey Vojtovich <svoj@sun.com>
Date: Thu, 1 Apr 2010 14:45:58 +0400
Subject: [PATCH] Applying InnoDB snapshot, fixes BUG#41609.

Detailed revision comments:

r6252 | marko | 2009-11-30 12:50:11 +0200 (Mon, 30 Nov 2009) | 23 lines
branches/zip: Suppress errors about non-found temporary tables.
Write the is_temp flag to SYS_TABLES.MIX_LEN.

dict_table_t::flags: Add a flag for is_temporary, DICT_TF2_TEMPORARY.
Unlike other flags, this will not be written to the tablespace flags
or SYS_TABLES.TYPE, but only to SYS_TABLES.MIX_LEN.

dict_build_table_def_step(): Only pass DICT_TF_BITS to tablespaces.

dict_check_tablespaces_and_store_max_id(), dict_load_table():
Suppress errors about temporary tables not being found.

dict_create_sys_tables_tuple(): Write the DICT_TF2_TEMPORARY flag
to SYS_TABLES.MIX_LEN.

fil_space_create(), fil_create_new_single_table_tablespace(): Add assertions
about space->flags.

row_drop_table_for_mysql(): Do not complain about non-found temporary tables.

rb://160 approved by Heikki Tuuri.  This addresses the second part of
Bug #41609 Crash recovery does not work for InnoDB temporary tables.
---
 storage/innodb_plugin/ChangeLog            |  10 ++
 storage/innodb_plugin/dict/dict0boot.c     |   3 +
 storage/innodb_plugin/dict/dict0crea.c     |  17 ++--
 storage/innodb_plugin/dict/dict0load.c     | 113 +++++++++++++++------
 storage/innodb_plugin/dict/dict0mem.c      |   2 +-
 storage/innodb_plugin/fil/fil0fil.c        |   9 +-
 storage/innodb_plugin/handler/ha_innodb.cc |   4 +
 storage/innodb_plugin/include/dict0mem.h   |  24 ++++-
 storage/innodb_plugin/row/row0mysql.c      |  11 +-
 9 files changed, 143 insertions(+), 50 deletions(-)

diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog
index 5ea2995a97..ac66ff1096 100644
--- a/storage/innodb_plugin/ChangeLog
+++ b/storage/innodb_plugin/ChangeLog
@@ -1,3 +1,13 @@
+2009-11-30	The InnoDB Team
+
+	* dict/dict0crea.c, dict/dict0mem.c, dict/dict0load.c,
+	dict/dict0boot.c, fil/fil0fil.c, handler/ha_innodb.cc,
+	include/dict0mem.h, row/row0mysql.c:
+	Fix the bogus warning messages for non-existing temporary
+	tables that were reported in
+	Bug#41609 Crash recovery does not work for InnoDB temporary tables.
+	The actual crash recovery bug was corrected on 2009-04-29.
+
 2009-11-20	The InnoDB Team
 
 	* handler/ha_innodb.cc:
diff --git a/storage/innodb_plugin/dict/dict0boot.c b/storage/innodb_plugin/dict/dict0boot.c
index e55de30481..8f948c06c5 100644
--- a/storage/innodb_plugin/dict/dict0boot.c
+++ b/storage/innodb_plugin/dict/dict0boot.c
@@ -274,6 +274,9 @@ dict_boot(void)
 	and (TYPE & DICT_TF_FORMAT_MASK) are nonzero and TYPE = table->flags */
 	dict_mem_table_add_col(table, heap, "TYPE", DATA_INT, 0, 4);
 	dict_mem_table_add_col(table, heap, "MIX_ID", DATA_BINARY, 0, 0);
+	/* MIX_LEN may contain additional table flags when
+	ROW_FORMAT!=REDUNDANT.  Currently, these flags include
+	DICT_TF2_TEMPORARY. */
 	dict_mem_table_add_col(table, heap, "MIX_LEN", DATA_INT, 0, 4);
 	dict_mem_table_add_col(table, heap, "CLUSTER_NAME", DATA_BINARY, 0, 0);
 	dict_mem_table_add_col(table, heap, "SPACE", DATA_INT, 0, 4);
diff --git a/storage/innodb_plugin/dict/dict0crea.c b/storage/innodb_plugin/dict/dict0crea.c
index 96a9bd8152..b0341e5eea 100644
--- a/storage/innodb_plugin/dict/dict0crea.c
+++ b/storage/innodb_plugin/dict/dict0crea.c
@@ -94,13 +94,13 @@ dict_create_sys_tables_tuple(
 	dfield = dtuple_get_nth_field(entry, 3);
 
 	ptr = mem_heap_alloc(heap, 4);
-	if (table->flags & ~DICT_TF_COMPACT) {
+	if (table->flags & (~DICT_TF_COMPACT & ~(~0 << DICT_TF_BITS))) {
 		ut_a(table->flags & DICT_TF_COMPACT);
 		ut_a(dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP);
 		ut_a((table->flags & DICT_TF_ZSSIZE_MASK)
 		     <= (DICT_TF_ZSSIZE_MAX << DICT_TF_ZSSIZE_SHIFT));
-		ut_a(!(table->flags & (~0 << DICT_TF_BITS)));
-		mach_write_to_4(ptr, table->flags);
+		ut_a(!(table->flags & (~0 << DICT_TF2_BITS)));
+		mach_write_to_4(ptr, table->flags & ~(~0 << DICT_TF_BITS));
 	} else {
 		mach_write_to_4(ptr, DICT_TABLE_ORDINARY);
 	}
@@ -112,11 +112,12 @@ dict_create_sys_tables_tuple(
 	ptr = mem_heap_zalloc(heap, 8);
 
 	dfield_set_data(dfield, ptr, 8);
-	/* 7: MIX_LEN (obsolete) --------------------------*/
+	/* 7: MIX_LEN (additional flags) --------------------------*/
 
 	dfield = dtuple_get_nth_field(entry, 5);
 
-	ptr = mem_heap_zalloc(heap, 4);
+	ptr = mem_heap_alloc(heap, 4);
+	mach_write_to_4(ptr, table->flags >> DICT_TF2_SHIFT);
 
 	dfield_set_data(dfield, ptr, 4);
 	/* 8: CLUSTER_NAME ---------------------*/
@@ -230,6 +231,7 @@ dict_build_table_def_step(
 	dict_table_t*	table;
 	dtuple_t*	row;
 	ulint		error;
+	ulint		flags;
 	const char*	path_or_name;
 	ibool		is_path;
 	mtr_t		mtr;
@@ -268,9 +270,10 @@ dict_build_table_def_step(
 		ut_ad(!dict_table_zip_size(table)
 		      || dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP);
 
+		flags = table->flags & ~(~0 << DICT_TF_BITS);
 		error = fil_create_new_single_table_tablespace(
 			&space, path_or_name, is_path,
-			table->flags == DICT_TF_COMPACT ? 0 : table->flags,
+			flags == DICT_TF_COMPACT ? 0 : flags,
 			FIL_IBD_FILE_INITIAL_SIZE);
 		table->space = (unsigned int) space;
 
@@ -286,7 +289,7 @@ dict_build_table_def_step(
 		mtr_commit(&mtr);
 	} else {
 		/* Create in the system tablespace: disallow new features */
-		table->flags &= DICT_TF_COMPACT;
+		table->flags &= (~0 << DICT_TF_BITS) | DICT_TF_COMPACT;
 	}
 
 	row = dict_create_sys_tables_tuple(table, node->heap);
diff --git a/storage/innodb_plugin/dict/dict0load.c b/storage/innodb_plugin/dict/dict0load.c
index 842a129c1a..2867125e39 100644
--- a/storage/innodb_plugin/dict/dict0load.c
+++ b/storage/innodb_plugin/dict/dict0load.c
@@ -390,15 +390,35 @@ loop:
 
 		mtr_commit(&mtr);
 
-		if (space_id != 0 && in_crash_recovery) {
+		if (space_id == 0) {
+			/* The system tablespace always exists. */
+		} else if (in_crash_recovery) {
 			/* Check that the tablespace (the .ibd file) really
-			exists; print a warning to the .err log if not */
-
-			fil_space_for_table_exists_in_mem(space_id, name,
-							  FALSE, TRUE, TRUE);
-		}
+			exists; print a warning to the .err log if not.
+			Do not print warnings for temporary tables. */
+			ibool	is_temp;
+
+			field = rec_get_nth_field_old(rec, 4, &len);
+			if (0x80000000UL &  mach_read_from_4(field)) {
+				/* ROW_FORMAT=COMPACT: read the is_temp
+				flag from SYS_TABLES.MIX_LEN. */
+				field = rec_get_nth_field_old(rec, 7, &len);
+				is_temp = mach_read_from_4(field)
+					& DICT_TF2_TEMPORARY;
+			} else {
+				/* For tables created with old versions
+				of InnoDB, SYS_TABLES.MIX_LEN may contain
+				garbage.  Such tables would always be
+				in ROW_FORMAT=REDUNDANT.  Pretend that
+				all such tables are non-temporary.  That is,
+				do not suppress error printouts about
+				temporary tables not being found. */
+				is_temp = FALSE;
+			}
 
-		if (space_id != 0 && !in_crash_recovery) {
+			fil_space_for_table_exists_in_mem(
+				space_id, name, is_temp, TRUE, !is_temp);
+		} else {
 			/* It is a normal database startup: create the space
 			object and check that the .ibd file exists. */
 
@@ -894,43 +914,72 @@ err_exit:
 				(ulong) flags);
 			goto err_exit;
 		}
+	} else {
+		flags = 0;
+	}
 
-		if (fil_space_for_table_exists_in_mem(space, name, FALSE,
-						      FALSE, FALSE)) {
-			/* Ok; (if we did a crash recovery then the tablespace
-			can already be in the memory cache) */
-		} else {
-			/* In >= 4.1.9, InnoDB scans the data dictionary also
-			at a normal mysqld startup. It is an error if the
-			space object does not exist in memory. */
+	ut_a(name_of_col_is(sys_tables, sys_index, 4, "N_COLS"));
+
+	field = rec_get_nth_field_old(rec, 4, &len);
+	n_cols = mach_read_from_4(field);
+
+	/* The high-order bit of N_COLS is the "compact format" flag.
+	For tables in that format, MIX_LEN may hold additional flags. */
+	if (n_cols & 0x80000000UL) {
+		ulint	flags2;
+
+		flags |= DICT_TF_COMPACT;
+
+		ut_a(name_of_col_is(sys_tables, sys_index, 7, "MIX_LEN"));
+		field = rec_get_nth_field_old(rec, 7, &len);
+
+		flags2 = mach_read_from_4(field);
+
+		if (flags2 & (~0 << (DICT_TF2_BITS - DICT_TF2_SHIFT))) {
+			ut_print_timestamp(stderr);
+			fputs("  InnoDB: Warning: table ", stderr);
+			ut_print_filename(stderr, name);
+			fprintf(stderr, "\n"
+				"InnoDB: in InnoDB data dictionary"
+				" has unknown flags %lx.\n",
+				(ulong) flags2);
+
+			flags2 &= ~(~0 << (DICT_TF2_BITS - DICT_TF2_SHIFT));
+		}
 
+		flags |= flags2 << DICT_TF2_SHIFT;
+	}
+
+	/* See if the tablespace is available. */
+	if (space == 0) {
+		/* The system tablespace is always available. */
+	} else if (!fil_space_for_table_exists_in_mem(
+			   space, name,
+			   (flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY,
+			   FALSE, FALSE)) {
+
+		if ((flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY) {
+			/* Do not bother to retry opening temporary tables. */
+			ibd_file_missing = TRUE;
+		} else {
 			ut_print_timestamp(stderr);
 			fprintf(stderr,
-				"  InnoDB: error: space object of table %s,\n"
+				"  InnoDB: error: space object of table");
+			ut_print_filename(stderr, name);
+			fprintf(stderr, ",\n"
 				"InnoDB: space id %lu did not exist in memory."
 				" Retrying an open.\n",
-				name, (ulong)space);
+				(ulong) space);
 			/* Try to open the tablespace */
 			if (!fil_open_single_table_tablespace(
-				    TRUE, space, flags, name)) {
-				/* We failed to find a sensible tablespace
-				file */
+				    TRUE, space,
+				    flags & ~(~0 << DICT_TF_BITS), name)) {
+				/* We failed to find a sensible
+				tablespace file */
 
 				ibd_file_missing = TRUE;
 			}
 		}
-	} else {
-		flags = 0;
-	}
-
-	ut_a(name_of_col_is(sys_tables, sys_index, 4, "N_COLS"));
-
-	field = rec_get_nth_field_old(rec, 4, &len);
-	n_cols = mach_read_from_4(field);
-
-	/* The high-order bit of N_COLS is the "compact format" flag. */
-	if (n_cols & 0x80000000UL) {
-		flags |= DICT_TF_COMPACT;
 	}
 
 	table = dict_mem_table_create(name, space, n_cols & ~0x80000000UL,
diff --git a/storage/innodb_plugin/dict/dict0mem.c b/storage/innodb_plugin/dict/dict0mem.c
index 6458cbab92..66b4b43f29 100644
--- a/storage/innodb_plugin/dict/dict0mem.c
+++ b/storage/innodb_plugin/dict/dict0mem.c
@@ -59,7 +59,7 @@ dict_mem_table_create(
 	mem_heap_t*	heap;
 
 	ut_ad(name);
-	ut_a(!(flags & (~0 << DICT_TF_BITS)));
+	ut_a(!(flags & (~0 << DICT_TF2_BITS)));
 
 	heap = mem_heap_create(DICT_HEAP_SIZE);
 
diff --git a/storage/innodb_plugin/fil/fil0fil.c b/storage/innodb_plugin/fil/fil0fil.c
index 112a0e27d5..b2593765af 100644
--- a/storage/innodb_plugin/fil/fil0fil.c
+++ b/storage/innodb_plugin/fil/fil0fil.c
@@ -1101,6 +1101,7 @@ fil_space_create(
 	ROW_FORMAT=REDUNDANT (table->flags == 0).  For any other
 	format, the tablespace flags should equal table->flags. */
 	ut_a(flags != DICT_TF_COMPACT);
+	ut_a(!(flags & (~0UL << DICT_TF_BITS)));
 
 try_again:
 	/*printf(
@@ -2586,6 +2587,7 @@ fil_create_new_single_table_tablespace(
 	ROW_FORMAT=REDUNDANT (table->flags == 0).  For any other
 	format, the tablespace flags should equal table->flags. */
 	ut_a(flags != DICT_TF_COMPACT);
+	ut_a(!(flags & (~0UL << DICT_TF_BITS)));
 
 	path = fil_make_ibd_name(tablename, is_temp);
 
@@ -2958,8 +2960,10 @@ fil_open_single_table_tablespace(
 	/* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
 	ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and
 	ROW_FORMAT=REDUNDANT (table->flags == 0).  For any other
-	format, the tablespace flags should equal table->flags. */
+	format, the tablespace flags should be equal to
+	table->flags & ~(~0 << DICT_TF_BITS). */
 	ut_a(flags != DICT_TF_COMPACT);
+	ut_a(!(flags & (~0UL << DICT_TF_BITS)));
 
 	file = os_file_create_simple_no_error_handling(
 		filepath, OS_FILE_OPEN, OS_FILE_READ_ONLY, &success);
@@ -3011,7 +3015,8 @@ fil_open_single_table_tablespace(
 
 	ut_free(buf2);
 
-	if (UNIV_UNLIKELY(space_id != id || space_flags != flags)) {
+	if (UNIV_UNLIKELY(space_id != id
+			  || space_flags != (flags & ~(~0 << DICT_TF_BITS)))) {
 		ut_print_timestamp(stderr);
 
 		fputs("  InnoDB: Error: tablespace id and flags in file ",
diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc
index 47b8203091..f67334ac45 100644
--- a/storage/innodb_plugin/handler/ha_innodb.cc
+++ b/storage/innodb_plugin/handler/ha_innodb.cc
@@ -6333,6 +6333,10 @@ ha_innobase::create(
 		goto cleanup;
 	}
 
+	if (create_info->options & HA_LEX_CREATE_TMP_TABLE) {
+		flags |= DICT_TF2_TEMPORARY << DICT_TF2_SHIFT;
+	}
+
 	error = create_table_def(trx, form, norm_name,
 		create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL,
 		flags);
diff --git a/storage/innodb_plugin/include/dict0mem.h b/storage/innodb_plugin/include/dict0mem.h
index 2d00111193..9996fb59a7 100644
--- a/storage/innodb_plugin/include/dict0mem.h
+++ b/storage/innodb_plugin/include/dict0mem.h
@@ -80,21 +80,39 @@ combination of types */
 /** File format */
 /* @{ */
 #define DICT_TF_FORMAT_SHIFT		5	/* file format */
-#define DICT_TF_FORMAT_MASK		(127 << DICT_TF_FORMAT_SHIFT)
+#define DICT_TF_FORMAT_MASK		\
+((~(~0 << (DICT_TF_BITS - DICT_TF_FORMAT_SHIFT))) << DICT_TF_FORMAT_SHIFT)
 #define DICT_TF_FORMAT_51		0	/*!< InnoDB/MySQL up to 5.1 */
 #define DICT_TF_FORMAT_ZIP		1	/*!< InnoDB plugin for 5.1:
 						compressed tables,
 						new BLOB treatment */
 /** Maximum supported file format */
 #define DICT_TF_FORMAT_MAX		DICT_TF_FORMAT_ZIP
-
+/* @} */
 #define DICT_TF_BITS			6	/*!< number of flag bits */
 #if (1 << (DICT_TF_BITS - DICT_TF_FORMAT_SHIFT)) <= DICT_TF_FORMAT_MAX
 # error "DICT_TF_BITS is insufficient for DICT_TF_FORMAT_MAX"
 #endif
 /* @} */
+
+/** @brief Additional table flags.
+
+These flags will be stored in SYS_TABLES.MIX_LEN.  All unused flags
+will be written as 0.  The column may contain garbage for tables
+created with old versions of InnoDB that only implemented
+ROW_FORMAT=REDUNDANT. */
+/* @{ */
+#define DICT_TF2_SHIFT			DICT_TF_BITS
+						/*!< Shift value for
+						table->flags. */
+#define DICT_TF2_TEMPORARY		1	/*!< TRUE for tables from
+						CREATE TEMPORARY TABLE. */
+#define DICT_TF2_BITS			(DICT_TF2_SHIFT + 1)
+						/*!< Total number of bits
+						in table->flags. */
 /* @} */
 
+
 /**********************************************************************//**
 Creates a table memory object.
 @return	own: table object */
@@ -374,7 +392,7 @@ struct dict_table_struct{
 	unsigned	space:32;
 				/*!< space where the clustered index of the
 				table is placed */
-	unsigned	flags:DICT_TF_BITS;/*!< DICT_TF_COMPACT, ... */
+	unsigned	flags:DICT_TF2_BITS;/*!< DICT_TF_COMPACT, ... */
 	unsigned	ibd_file_missing:1;
 				/*!< TRUE if this is in a single-table
 				tablespace and the .ibd file is missing; then
diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c
index 181c39de88..7a43d0f3b9 100644
--- a/storage/innodb_plugin/row/row0mysql.c
+++ b/storage/innodb_plugin/row/row0mysql.c
@@ -3264,7 +3264,7 @@ check_next_foreign:
 
 		ut_error;
 	} else {
-		ibool		is_path;
+		ibool		is_temp;
 		const char*	name_or_path;
 		mem_heap_t*	heap;
 
@@ -3277,12 +3277,13 @@ check_next_foreign:
 		space_id = table->space;
 
 		if (table->dir_path_of_temp_table != NULL) {
-			is_path = TRUE;
 			name_or_path = mem_heap_strdup(
 				heap, table->dir_path_of_temp_table);
+			is_temp = TRUE;
 		} else {
-			is_path = FALSE;
 			name_or_path = name;
+			is_temp = (table->flags >> DICT_TF2_SHIFT)
+				& DICT_TF2_TEMPORARY;
 		}
 
 		dict_table_remove_from_cache(table);
@@ -3302,8 +3303,8 @@ check_next_foreign:
 		if (err == DB_SUCCESS && space_id > 0) {
 			if (!fil_space_for_table_exists_in_mem(space_id,
 							       name_or_path,
-							       is_path,
-							       FALSE, TRUE)) {
+							       is_temp, FALSE,
+							       !is_temp)) {
 				err = DB_SUCCESS;
 
 				fprintf(stderr,
-- 
2.30.9