List:Commits« Previous MessageNext Message »
From:Jimmy Yang Date:May 26 2010 1:59am
Subject:bzr push into mysql-trunk-innodb branch (jimmy.yang:3119 to 3120)
View as plain text  
 3120 Jimmy Yang	2010-05-25
      Check in the support for Information Schema System Table Views. Users
      can now view the content of InnoDB System Tables through following
      information schema tables:
      
      information_schema.INNODB_SYS_TABLES
      information_schema.INNODB_SYS_INDEXES
      information_schema.INNODB_SYS_COUMNS
      information_schema.INNODB_SYS_FIELDS
      information_schema.INNODB_SYS_FOREIGN
      information_schema.INNODB_SYS_FOREIGN_COLS
      information_schema.INNODB_SYS_TABLESTATS
      
      rb://330 Approved by Marko

    added:
      mysql-test/suite/innodb/r/innodb-system-table-view.result
      mysql-test/suite/innodb/t/innodb-system-table-view.test
    modified:
      mysql-test/r/mysqlshow.result
      storage/innobase/dict/dict0load.c
      storage/innobase/dict/dict0mem.c
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/handler/i_s.cc
      storage/innobase/handler/i_s.h
      storage/innobase/include/dict0dict.ic
      storage/innobase/include/dict0load.h
      storage/innobase/include/dict0mem.h
      storage/innobase/include/dict0mem.ic
      storage/innobase/row/row0mysql.c
 3119 Vasil Dimov	2010-05-25
      (second attempt) Disable the tests on embedded windows that fail due to
      
      Bug #53947 InnoDB: Assertion failure in thread 4224 in file
      .\sync\sync0sync.c line 324
      
      This changeset should be reverted once the bug is fixed.

    modified:
      mysql-test/suite/innodb/t/innodb.test
      mysql-test/suite/sys_vars/t/identity_func.test
      mysql-test/suite/sys_vars/t/innodb_autoinc_lock_mode_func.test
      mysql-test/suite/sys_vars/t/last_insert_id_func.test
      mysql-test/suite/sys_vars/t/storage_engine_basic.test
      mysql-test/suite/sys_vars/t/tx_isolation_func.test
      mysql-test/t/bug46760.test
      mysql-test/t/innodb_autoinc_lock_mode_zero.test
      mysql-test/t/innodb_bug30919.test
      mysql-test/t/lock_tables_lost_commit.test
=== modified file 'mysql-test/r/mysqlshow.result'
--- a/mysql-test/r/mysqlshow.result	revid:vasil.dimov@stripped
+++ b/mysql-test/r/mysqlshow.result	revid:jimmy.yang@stripped
@@ -109,13 +109,20 @@ Database: information_schema
 | TRIGGERS                              |
 | USER_PRIVILEGES                       |
 | VIEWS                                 |
-| INNODB_CMP_RESET                      |
+| INNODB_SYS_FIELDS                     |
 | INNODB_TRX                            |
-| INNODB_CMPMEM_RESET                   |
+| INNODB_SYS_INDEXES                    |
 | INNODB_LOCK_WAITS                     |
-| INNODB_CMPMEM                         |
+| INNODB_SYS_TABLESTATS                 |
 | INNODB_CMP                            |
+| INNODB_SYS_COLUMNS                    |
+| INNODB_CMP_RESET                      |
+| INNODB_SYS_FOREIGN_COLS               |
 | INNODB_LOCKS                          |
+| INNODB_CMPMEM_RESET                   |
+| INNODB_CMPMEM                         |
+| INNODB_SYS_FOREIGN                    |
+| INNODB_SYS_TABLES                     |
 +---------------------------------------+
 Database: INFORMATION_SCHEMA
 +---------------------------------------+
@@ -151,13 +158,20 @@ Database: INFORMATION_SCHEMA
 | TRIGGERS                              |
 | USER_PRIVILEGES                       |
 | VIEWS                                 |
-| INNODB_CMP_RESET                      |
+| INNODB_SYS_FIELDS                     |
 | INNODB_TRX                            |
-| INNODB_CMPMEM_RESET                   |
+| INNODB_SYS_INDEXES                    |
 | INNODB_LOCK_WAITS                     |
-| INNODB_CMPMEM                         |
+| INNODB_SYS_TABLESTATS                 |
 | INNODB_CMP                            |
+| INNODB_SYS_COLUMNS                    |
+| INNODB_CMP_RESET                      |
+| INNODB_SYS_FOREIGN_COLS               |
 | INNODB_LOCKS                          |
+| INNODB_CMPMEM_RESET                   |
+| INNODB_CMPMEM                         |
+| INNODB_SYS_FOREIGN                    |
+| INNODB_SYS_TABLES                     |
 +---------------------------------------+
 Wildcard: inf_rmation_schema
 +--------------------+

=== added file 'mysql-test/suite/innodb/r/innodb-system-table-view.result'
--- a/mysql-test/suite/innodb/r/innodb-system-table-view.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/r/innodb-system-table-view.result	revid:jimmy.yang@stripped
@@ -0,0 +1,110 @@
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES;
+TABLE_ID	NAME	FLAG	N_COLS	SPACE
+11	SYS_FOREIGN	0	7	0
+12	SYS_FOREIGN_COLS	0	7	0
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES;
+INDEX_ID	NAME	TABLE_ID	TYPE	N_FIELDS	PAGE_NO	SPACE
+11	ID_IND	11	3	1	302	0
+12	FOR_IND	11	0	1	303	0
+13	REF_IND	11	0	1	304	0
+14	ID_IND	12	3	2	305	0
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS;
+TABLE_ID	NAME	POS	MTYPE	PRTYPE	LEN
+11	ID	0	1	524292	0
+11	FOR_NAME	1	1	524292	0
+11	REF_NAME	2	1	524292	0
+11	N_COLS	3	6	0	4
+12	ID	0	1	524292	0
+12	POS	1	6	0	4
+12	FOR_COL_NAME	2	1	524292	0
+12	REF_COL_NAME	3	1	524292	0
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FIELDS;
+INDEX_ID	NAME	POS
+11	ID	0
+12	FOR_NAME	0
+13	REF_NAME	0
+14	ID	0
+14	POS	1
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
+ID	FOR_NAME	REF_NAME	N_COLS	TYPE
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
+ID	FOR_COL_NAME	REF_COL_NAME	POS
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS;
+TABLE_ID	NAME	STATS_INITIALIZED	NUM_ROWS	CLUST_INDEX_SIZE	OTHER_INDEX_SIZE	MODIFIED_COUNTER	AUTOINC	MYSQL_HANDLES_OPENED
+11	SYS_FOREIGN	Uninitialized	0	0	0	0	0	0
+12	SYS_FOREIGN_COLS	Uninitialized	0	0	0	0	0	0
+CREATE TABLE parent (id INT NOT NULL,
+PRIMARY KEY (id)) ENGINE=INNODB;
+CREATE TABLE child (id INT, parent_id INT,
+INDEX par_ind (parent_id),
+CONSTRAINT constraint_test
+FOREIGN KEY (parent_id) REFERENCES parent(id)
+ON DELETE CASCADE) ENGINE=INNODB;
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
+ID	FOR_NAME	REF_NAME	N_COLS	TYPE
+test/constraint_test	test/child	test/parent	1	1
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
+ID	FOR_COL_NAME	REF_COL_NAME	POS
+test/constraint_test	parent_id	id	0
+INSERT INTO parent VALUES(1);
+SELECT name, num_rows, mysql_handles_opened
+FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS
+WHERE name LIKE "%parent";
+name	num_rows	mysql_handles_opened
+test/parent	1	1
+SELECT NAME, FLAG, N_COLS, SPACE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES;
+NAME	FLAG	N_COLS	SPACE
+SYS_FOREIGN	0	7	0
+SYS_FOREIGN_COLS	0	7	0
+test/child	1	5	0
+test/parent	1	4	0
+SELECT name, n_fields
+from INFORMATION_SCHEMA.INNODB_SYS_INDEXES
+WHERE table_id In (SELECT table_id from
+INFORMATION_SCHEMA.INNODB_SYS_TABLES
+WHERE name LIKE "%parent%");
+name	n_fields
+PRIMARY	1
+SELECT name, n_fields
+from INFORMATION_SCHEMA.INNODB_SYS_INDEXES
+WHERE table_id In (SELECT table_id from
+INFORMATION_SCHEMA.INNODB_SYS_TABLES
+WHERE name LIKE "%child%");
+name	n_fields
+GEN_CLUST_INDEX	0
+par_ind	1
+SELECT name, pos, mtype, len
+from INFORMATION_SCHEMA.INNODB_SYS_COLUMNS
+WHERE table_id In (SELECT table_id from
+INFORMATION_SCHEMA.INNODB_SYS_TABLES
+WHERE name LIKE "%child%");
+name	pos	mtype	len
+id	0	6	4
+parent_id	1	6	4
+DROP TABLE child;
+DROP TABLE parent;
+CREATE TABLE parent (id INT NOT NULL, newid INT NOT NULL,
+PRIMARY KEY (id, newid)) ENGINE=INNODB;
+CREATE TABLE child (id INT, parent_id INT,
+INDEX par_ind (parent_id),
+CONSTRAINT constraint_test
+FOREIGN KEY (id, parent_id) REFERENCES parent(id, newid)
+ON DELETE CASCADE) ENGINE=INNODB;
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
+ID	FOR_NAME	REF_NAME	N_COLS	TYPE
+test/constraint_test	test/child	test/parent	2	1
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
+ID	FOR_COL_NAME	REF_COL_NAME	POS
+test/constraint_test	id	id	0
+test/constraint_test	parent_id	newid	1
+INSERT INTO parent VALUES(1, 9);
+SELECT * FROM parent WHERE id IN (SELECT id FROM parent);
+id	newid
+1	9
+SELECT name, num_rows, mysql_handles_opened
+FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS
+WHERE name LIKE "%parent";
+name	num_rows	mysql_handles_opened
+test/parent	1	2
+DROP TABLE child;
+DROP TABLE parent;

=== added file 'mysql-test/suite/innodb/t/innodb-system-table-view.test'
--- a/mysql-test/suite/innodb/t/innodb-system-table-view.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/t/innodb-system-table-view.test	revid:jimmy.yang@stripped
@@ -0,0 +1,94 @@
+# This is the test for Information Schema System Table View
+# that displays the InnoDB system table content through
+# information schema tables.
+
+--source include/have_innodb.inc
+
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES;
+
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES;
+
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS;
+
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FIELDS;
+
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
+
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
+
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS;
+
+# Create a foreign key constraint, and verify the information
+# in INFORMATION_SCHEMA.INNODB_SYS_FOREIGN and
+# INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS
+CREATE TABLE parent (id INT NOT NULL,
+                     PRIMARY KEY (id)) ENGINE=INNODB;
+
+CREATE TABLE child (id INT, parent_id INT,
+                    INDEX par_ind (parent_id),
+		    CONSTRAINT constraint_test
+                    FOREIGN KEY (parent_id) REFERENCES parent(id)
+                      ON DELETE CASCADE) ENGINE=INNODB;
+
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
+
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
+
+# Insert a row in the table "parent", and see whether that reflected in
+# INNODB_SYS_TABLESTATS
+INSERT INTO parent VALUES(1);
+
+SELECT name, num_rows, mysql_handles_opened
+FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS
+WHERE name LIKE "%parent";
+
+SELECT NAME, FLAG, N_COLS, SPACE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES;
+
+SELECT name, n_fields
+from INFORMATION_SCHEMA.INNODB_SYS_INDEXES
+WHERE table_id In (SELECT table_id from
+	INFORMATION_SCHEMA.INNODB_SYS_TABLES
+	WHERE name LIKE "%parent%");
+
+SELECT name, n_fields
+from INFORMATION_SCHEMA.INNODB_SYS_INDEXES
+WHERE table_id In (SELECT table_id from
+	INFORMATION_SCHEMA.INNODB_SYS_TABLES
+	WHERE name LIKE "%child%");
+
+SELECT name, pos, mtype, len
+from INFORMATION_SCHEMA.INNODB_SYS_COLUMNS
+WHERE table_id In (SELECT table_id from
+	INFORMATION_SCHEMA.INNODB_SYS_TABLES
+	WHERE name LIKE "%child%");
+
+DROP TABLE child;
+
+DROP TABLE parent;
+
+# Create table with 2 columns in the foreign key constraint
+CREATE TABLE parent (id INT NOT NULL, newid INT NOT NULL,
+                     PRIMARY KEY (id, newid)) ENGINE=INNODB;
+
+CREATE TABLE child (id INT, parent_id INT,
+                    INDEX par_ind (parent_id),
+		    CONSTRAINT constraint_test
+                    FOREIGN KEY (id, parent_id) REFERENCES parent(id, newid)
+                      ON DELETE CASCADE) ENGINE=INNODB;
+
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
+
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
+
+INSERT INTO parent VALUES(1, 9);
+
+# Nested query will open the table handle twice
+SELECT * FROM parent WHERE id IN (SELECT id FROM parent);
+
+SELECT name, num_rows, mysql_handles_opened
+FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS
+WHERE name LIKE "%parent";
+
+DROP TABLE child;
+
+DROP TABLE parent;

=== modified file 'storage/innobase/dict/dict0load.c'
--- a/storage/innobase/dict/dict0load.c	revid:vasil.dimov@stripped
+++ b/storage/innobase/dict/dict0load.c	revid:jimmy.yang@stripped
@@ -41,6 +41,16 @@ Created 4/24/1996 Heikki Tuuri
 #include "srv0start.h"
 #include "srv0srv.h"
 
+
+/** Following are six InnoDB system tables */
+static const char* SYSTEM_TABLE_NAME[] = {
+	"SYS_TABLES",
+	"SYS_INDEXES",
+	"SYS_COLUMNS",
+	"SYS_FIELDS",
+	"SYS_FOREIGN",
+	"SYS_FOREIGN_COLS"
+};
 /****************************************************************//**
 Compare the name of an index column.
 @return	TRUE if the i'th column of index is 'name'. */
@@ -151,13 +161,10 @@ void
 dict_print(void)
 /*============*/
 {
-	dict_table_t*	sys_tables;
-	dict_index_t*	sys_index;
 	dict_table_t*	table;
 	btr_pcur_t	pcur;
 	const rec_t*	rec;
-	const byte*	field;
-	ulint		len;
+	mem_heap_t*	heap;
 	mtr_t		mtr;
 
 	/* Enlarge the fatal semaphore wait timeout during the InnoDB table
@@ -167,75 +174,396 @@ dict_print(void)
 	srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
 	mutex_exit(&kernel_mutex);
 
+	heap = mem_heap_create(1000);
 	mutex_enter(&(dict_sys->mutex));
-
 	mtr_start(&mtr);
 
-	sys_tables = dict_table_get_low("SYS_TABLES");
-	sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
-
-	btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
-				    TRUE, &mtr);
-loop:
-	btr_pcur_move_to_next_user_rec(&pcur, &mtr);
+	rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
 
-	rec = btr_pcur_get_rec(&pcur);
+	while (rec) {
+		const char* err_msg;
 
-	if (!btr_pcur_is_on_user_rec(&pcur)) {
-		/* end of index */
+		err_msg = dict_process_sys_tables_rec(
+			heap, rec, &table, DICT_TABLE_LOAD_FROM_CACHE
+			| DICT_TABLE_UPDATE_STATS);
 
-		btr_pcur_close(&pcur);
 		mtr_commit(&mtr);
 
-		mutex_exit(&(dict_sys->mutex));
+		if (!err_msg) {
+			dict_table_print_low(table);
+		} else {
+			ut_print_timestamp(stderr);
+			fprintf(stderr, "  InnoDB: %s\n", err_msg);
+		}
 
-		/* Restore the fatal semaphore wait timeout */
+		mem_heap_empty(heap);
 
-		mutex_enter(&kernel_mutex);
-		srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
-		mutex_exit(&kernel_mutex);
+		mtr_start(&mtr);
+		rec = dict_getnext_system(&pcur, &mtr);
+	}
 
-		return;
+	mtr_commit(&mtr);
+	mutex_exit(&(dict_sys->mutex));
+	mem_heap_free(heap);
+
+	/* Restore the fatal semaphore wait timeout */
+	mutex_enter(&kernel_mutex);
+	srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
+	mutex_exit(&kernel_mutex);
+}
+
+
+/********************************************************************//**
+This function gets the next system table record as it scans the table.
+@return	the next record if found, NULL if end of scan */
+static
+const rec_t*
+dict_getnext_system_low(
+/*====================*/
+	btr_pcur_t*	pcur,		/*!< in/out: persistent cursor to the
+					record*/
+	mtr_t*		mtr)		/*!< in: the mini-transaction */
+{
+	rec_t*	rec = NULL;
+
+	while (!rec || rec_get_deleted_flag(rec, 0)) {
+		btr_pcur_move_to_next_user_rec(pcur, mtr);
+
+		rec = btr_pcur_get_rec(pcur);
+
+		if (!btr_pcur_is_on_user_rec(pcur)) {
+			/* end of index */
+			btr_pcur_close(pcur);
+
+			return(NULL);
+		}
 	}
 
-	field = rec_get_nth_field_old(rec, 0, &len);
+	/* Get a record, let's save the position */
+	btr_pcur_store_position(pcur, mtr);
 
-	if (!rec_get_deleted_flag(rec, 0)) {
+	return(rec);
+}
 
-		/* We found one */
+/********************************************************************//**
+This function opens a system table, and return the first record.
+@return	first record of the system table */
+UNIV_INTERN
+const rec_t*
+dict_startscan_system(
+/*==================*/
+	btr_pcur_t*	pcur,		/*!< out: persistent cursor to
+					the record */
+	mtr_t*		mtr,		/*!< in: the mini-transaction */
+	dict_system_id_t system_id)	/*!< in: which system table to open */
+{
+	dict_table_t*	system_table;
+	dict_index_t*	clust_index;
+	const rec_t*	rec;
 
-		char*	table_name = mem_strdupl((char*) field, len);
+	ut_a(system_id < SYS_NUM_SYSTEM_TABLES);
 
-		btr_pcur_store_position(&pcur, &mtr);
+	system_table = dict_table_get_low(SYSTEM_TABLE_NAME[system_id]);
 
-		mtr_commit(&mtr);
+	clust_index = UT_LIST_GET_FIRST(system_table->indexes);
 
-		table = dict_table_get_low(table_name);
-		mem_free(table_name);
+	btr_pcur_open_at_index_side(TRUE, clust_index, BTR_SEARCH_LEAF, pcur,
+				    TRUE, mtr);
 
-		if (table == NULL) {
-			fputs("InnoDB: Failed to load table ", stderr);
-			ut_print_namel(stderr, NULL, TRUE, (char*) field, len);
-			putc('\n', stderr);
-		} else {
-			/* The table definition was corrupt if there
-			is no index */
+	rec = dict_getnext_system_low(pcur, mtr);
 
-			if (dict_table_get_first_index(table)) {
-				dict_update_statistics_low(table, TRUE);
-			}
+	return(rec);
+}
 
-			dict_table_print_low(table);
+/********************************************************************//**
+This function gets the next system table record as it scans the table.
+@return	the next record if found, NULL if end of scan */
+UNIV_INTERN
+const rec_t*
+dict_getnext_system(
+/*================*/
+	btr_pcur_t*	pcur,		/*!< in/out: persistent cursor
+					to the record */
+	mtr_t*		mtr)		/*!< in: the mini-transaction */
+{
+        const rec_t*	rec;
+
+	/* Restore the position */
+        btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
+
+	/* Get the next record */
+        rec = dict_getnext_system_low(pcur, mtr);
+
+	return(rec);
+}
+/********************************************************************//**
+This function processes one SYS_TABLES record and populate the dict_table_t
+struct for the table. Extracted out of dict_print() to be used by
+both monitor table output and information schema innodb_sys_tables output.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_tables_rec(
+/*========================*/
+	mem_heap_t*	heap,		/*!< in/out: temporary memory heap */
+	const rec_t*	rec,		/*!< in: SYS_TABLES record */
+	dict_table_t**	table,		/*!< out: dict_table_t to fill */
+	dict_table_info_t status)	/*!< in: status bit controls
+					options such as whether we shall
+					look for dict_table_t from cache
+					first */
+{
+	ulint		len;
+	const byte*	field;
+	const char*	err_msg = NULL;
+	char*		table_name;
+
+	field = rec_get_nth_field_old(rec, 0, &len);
+
+	ut_a(!rec_get_deleted_flag(rec, 0));
+
+	/* Get the table name */
+	table_name = mem_heap_strdupl(heap, field, len);
+
+	/* If DICT_TABLE_LOAD_FROM_CACHE is set, first check
+	whether there is cached dict_table_t struct first */
+	if (status & DICT_TABLE_LOAD_FROM_CACHE) {
+		*table = dict_table_get_low(table_name);
+
+		if (!(*table)) {
+			err_msg = "Table not found in cache";
 		}
+	} else {
+		err_msg = dict_load_table_low(table_name, rec, table);
+	}
 
-		mtr_start(&mtr);
+	if (err_msg) {
+		return(err_msg);
+	}
 
-		btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
+	if ((status & DICT_TABLE_UPDATE_STATS)
+	    && dict_table_get_first_index(*table)) {
+
+		/* Update statistics if DICT_TABLE_UPDATE_STATS
+		is set */
+		dict_update_statistics_low(*table, TRUE);
 	}
 
-	goto loop;
+	return(NULL);
+}
+
+/********************************************************************//**
+This function parses a SYS_INDEXES record and populate a dict_index_t
+structure with the information from the record. For detail information
+about SYS_INDEXES fields, please refer to dict_boot() function.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_indexes_rec(
+/*=========================*/
+	mem_heap_t*	heap,		/*!< in/out: heap memory */
+	const rec_t*	rec,		/*!< in: current SYS_INDEXES rec */
+	dict_index_t*	index,		/*!< out: index to be filled */
+	dulint*		table_id)	/*!< out: index table id */
+{
+	const char*	err_msg;
+	byte*		buf;
+
+	buf = mem_heap_alloc(heap, 8);
+
+	/* Parse the record, and get "dict_index_t" struct filled */
+	err_msg = dict_load_index_low(buf, NULL,
+				      heap, rec, FALSE, &index);
+
+	*table_id = mach_read_from_8(buf);
+
+	return(err_msg);
+}
+/********************************************************************//**
+This function parses a SYS_COLUMNS record and populate a dict_column_t
+structure with the information from the record.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_columns_rec(
+/*=========================*/
+	mem_heap_t*	heap,		/*!< in/out: heap memory */
+	const rec_t*	rec,		/*!< in: current SYS_COLUMNS rec */
+	dict_col_t*	column,		/*!< out: dict_col_t to be filled */
+	dulint*		table_id,	/*!< out: table id */
+	const char**	col_name)	/*!< out: column name */
+{
+	const char*	err_msg;
+
+	/* Parse the record, and get "dict_col_t" struct filled */
+	err_msg = dict_load_column_low(NULL, heap, column,
+				       table_id, col_name, rec);
+
+	return(err_msg);
+}
+/********************************************************************//**
+This function parses a SYS_FIELDS record and populates a dict_field_t
+structure with the information from the record.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_fields_rec(
+/*========================*/
+	mem_heap_t*	heap,		/*!< in/out: heap memory */
+	const rec_t*	rec,		/*!< in: current SYS_FIELDS rec */
+	dict_field_t*	sys_field,	/*!< out: dict_field_t to be
+					filled */
+	ulint*		pos,		/*!< out: Field position */
+	dulint*		index_id,	/*!< out: current index id */
+	dulint		last_id)	/*!< in: previous index id */
+{
+	byte*		buf;
+	byte*		last_index_id;
+	const char*	err_msg;
+
+	buf = mem_heap_alloc(heap, 8);
+
+	last_index_id = mem_heap_alloc(heap, 8);
+	mach_write_to_8(last_index_id, last_id);
+
+	err_msg = dict_load_field_low(buf, NULL, sys_field,
+				      pos, last_index_id, heap, rec);
+
+	*index_id = mach_read_from_8(buf);
+
+	return(err_msg);
+
+}
+/********************************************************************//**
+This function parses a SYS_FOREIGN record and populate a dict_foreign_t
+structure with the information from the record. For detail information
+about SYS_FOREIGN fields, please refer to dict_load_foreign() function
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_foreign_rec(
+/*=========================*/
+	mem_heap_t*	heap,		/*!< in/out: heap memory */
+	const rec_t*	rec,		/*!< in: current SYS_FOREIGN rec */
+	dict_foreign_t*	foreign)	/*!< out: dict_foreign_t struct
+					to be filled */
+{
+	ulint		len;
+	const byte*	field;
+	ulint		n_fields_and_type;
+
+	if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
+		return("delete-marked record in SYS_FOREIGN");
+	}
+
+	if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 6)) {
+		return("wrong number of columns in SYS_FOREIGN record");
+	}
+
+	field = rec_get_nth_field_old(rec, 0/*ID*/, &len);
+	if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+err_len:
+		return("incorrect column length in SYS_FOREIGN");
+	}
+	foreign->id = mem_heap_strdupl(heap, (const char*) field, len);
+
+	rec_get_nth_field_offs_old(rec, 1/*DB_TRX_ID*/, &len);
+	if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
+		goto err_len;
+	}
+	rec_get_nth_field_offs_old(rec, 2/*DB_ROLL_PTR*/, &len);
+	if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
+		goto err_len;
+	}
+
+	field = rec_get_nth_field_old(rec, 3/*FOR_NAME*/, &len);
+	if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+		goto err_len;
+	}
+	foreign->foreign_table_name = mem_heap_strdupl(
+		heap, (const char*) field, len);
+
+	field = rec_get_nth_field_old(rec, 4/*REF_NAME*/, &len);
+	if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+		goto err_len;
+	}
+	foreign->referenced_table_name = mem_heap_strdupl(
+		heap, (const char*) field, len);
+
+	field = rec_get_nth_field_old(rec, 5/*N_COLS*/, &len);
+	if (UNIV_UNLIKELY(len != 4)) {
+		goto err_len;
+	}
+	n_fields_and_type = mach_read_from_4(field);
+
+	foreign->type = (unsigned int) (n_fields_and_type >> 24);
+	foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL);
+
+	return(NULL);
 }
+/********************************************************************//**
+This function parses a SYS_FOREIGN_COLS record and extract necessary
+information from the record and return to caller.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_foreign_col_rec(
+/*=============================*/
+	mem_heap_t*	heap,		/*!< in/out: heap memory */
+	const rec_t*	rec,		/*!< in: current SYS_FOREIGN_COLS rec */
+	const char**	name,		/*!< out: foreign key constraint name */
+	const char**	for_col_name,	/*!< out: referencing column name */
+	const char**	ref_col_name,	/*!< out: referenced column name
+					in referenced table */
+	ulint*		pos)		/*!< out: column position */
+{
+	ulint		len;
+	const byte*	field;
+
+	if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
+		return("delete-marked record in SYS_FOREIGN_COLS");
+	}
+
+	if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 6)) {
+		return("wrong number of columns in SYS_FOREIGN_COLS record");
+	}
+
+	field = rec_get_nth_field_old(rec, 0/*ID*/, &len);
+	if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+err_len:
+		return("incorrect column length in SYS_FOREIGN_COLS");
+	}
+	*name = mem_heap_strdupl(heap, (char*) field, len);
+
+	field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
+	if (UNIV_UNLIKELY(len != 4)) {
+		goto err_len;
+	}
+	*pos = mach_read_from_4(field);
+
+	rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
+	if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
+		goto err_len;
+	}
+	rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
+	if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
+		goto err_len;
+	}
+
+	field = rec_get_nth_field_old(rec, 4/*FOR_COL_NAME*/, &len);
+	if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+		goto err_len;
+	}
+	*for_col_name = mem_heap_strdupl(heap, (char*) field, len);
 
+	field = rec_get_nth_field_old(rec, 5/*REF_COL_NAME*/, &len);
+	if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+		goto err_len;
+	}
+	*ref_col_name = mem_heap_strdupl(heap, (char*) field, len);
+
+	return(NULL);
+}
 /********************************************************************//**
 Determine the flags of a table described in SYS_TABLES.
 @return compressed page size in kilobytes; or 0 if the tablespace is
@@ -441,130 +769,156 @@ loop:
 }
 
 /********************************************************************//**
-Loads definitions for table columns. */
-static
-void
-dict_load_columns(
-/*==============*/
-	dict_table_t*	table,	/*!< in: table */
-	mem_heap_t*	heap)	/*!< in: memory heap for temporary storage */
+Loads a table column definition from a SYS_COLUMNS record to
+dict_table_t.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_load_column_low(
+/*=================*/
+	dict_table_t*	table,		/*!< in/out: table, could be NULL
+					if we just polulate a dict_column_t
+					struct with information from
+					a SYS_COLUMNS record */
+	mem_heap_t*	heap,		/*!< in/out: memory heap
+					for temporary storage */
+	dict_col_t*	column,		/*!< out: dict_column_t to fill */
+	dulint*		table_id,	/*!< out: table id */
+	const char**	col_name,	/*!< out: column name */
+	const rec_t*	rec)		/*!< in: SYS_COLUMNS record */
 {
-	dict_table_t*	sys_columns;
-	dict_index_t*	sys_index;
-	btr_pcur_t	pcur;
-	dtuple_t*	tuple;
-	dfield_t*	dfield;
-	const rec_t*	rec;
+	char*		name;
 	const byte*	field;
 	ulint		len;
-	byte*		buf;
-	char*		name;
 	ulint		mtype;
 	ulint		prtype;
 	ulint		col_len;
-	ulint		i;
-	mtr_t		mtr;
+	ulint		pos;
 
-	ut_ad(mutex_own(&(dict_sys->mutex)));
+	if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
+		return("delete-marked record in SYS_COLUMNS");
+	}
 
-	mtr_start(&mtr);
+	if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 9)) {
+		return("wrong number of columns in SYS_COLUMNS record");
+	}
 
-	sys_columns = dict_table_get_low("SYS_COLUMNS");
-	sys_index = UT_LIST_GET_FIRST(sys_columns->indexes);
-	ut_a(!dict_table_is_comp(sys_columns));
+	field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len);
+	if (UNIV_UNLIKELY(len != 8)) {
+err_len:
+		return("incorrect column length in SYS_COLUMNS");
+	}
 
-	tuple = dtuple_create(heap, 1);
-	dfield = dtuple_get_nth_field(tuple, 0);
+	if (table_id) {
+		*table_id = mach_read_from_8(field);
+	} else if (UNIV_UNLIKELY(ut_dulint_cmp(table->id,
+				 mach_read_from_8(field)))) {
+		return("SYS_COLUMNS.TABLE_ID mismatch");
+	}
 
-	buf = mem_heap_alloc(heap, 8);
-	mach_write_to_8(buf, table->id);
+	field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
+	if (UNIV_UNLIKELY(len != 4)) {
 
-	dfield_set_data(dfield, buf, 8);
-	dict_index_copy_types(tuple, sys_index, 1);
+		goto err_len;
+	}
 
-	btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
-				  BTR_SEARCH_LEAF, &pcur, &mtr);
-	for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
+	if (!table) {
+		pos = mach_read_from_4(field);
+	} else if (UNIV_UNLIKELY(table->n_def != mach_read_from_4(field))) {
+		return("SYS_COLUMNS.POS mismatch");
+	}
 
-		rec = btr_pcur_get_rec(&pcur);
+	rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
+	if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
+		goto err_len;
+	}
+	rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
+	if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
+		goto err_len;
+	}
 
-		ut_a(btr_pcur_is_on_user_rec(&pcur));
+	field = rec_get_nth_field_old(rec, 4/*NAME*/, &len);
+	if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+		goto err_len;
+	}
 
-		ut_a(!rec_get_deleted_flag(rec, 0));
+	name = mem_heap_strdupl(heap, (const char*) field, len);
 
-		field = rec_get_nth_field_old(rec, 0, &len);
-		ut_ad(len == 8);
-		ut_a(ut_dulint_cmp(table->id, mach_read_from_8(field)) == 0);
+	if (col_name) {
+		*col_name = name;
+	}
 
-		field = rec_get_nth_field_old(rec, 1, &len);
-		ut_ad(len == 4);
-		ut_a(i == mach_read_from_4(field));
+	field = rec_get_nth_field_old(rec, 5/*MTYPE*/, &len);
+	if (UNIV_UNLIKELY(len != 4)) {
+		goto err_len;
+	}
 
-		ut_a(name_of_col_is(sys_columns, sys_index, 4, "NAME"));
+	mtype = mach_read_from_4(field);
 
-		field = rec_get_nth_field_old(rec, 4, &len);
-		name = mem_heap_strdupl(heap, (char*) field, len);
+	field = rec_get_nth_field_old(rec, 6/*PRTYPE*/, &len);
+	if (UNIV_UNLIKELY(len != 4)) {
+		goto err_len;
+	}
+	prtype = mach_read_from_4(field);
 
-		field = rec_get_nth_field_old(rec, 5, &len);
-		mtype = mach_read_from_4(field);
+	if (dtype_get_charset_coll(prtype) == 0
+	    && dtype_is_string_type(mtype)) {
+		/* The table was created with < 4.1.2. */
 
-		field = rec_get_nth_field_old(rec, 6, &len);
-		prtype = mach_read_from_4(field);
+		if (dtype_is_binary_string_type(mtype, prtype)) {
+			/* Use the binary collation for
+			string columns of binary type. */
 
-		if (dtype_get_charset_coll(prtype) == 0
-		    && dtype_is_string_type(mtype)) {
-			/* The table was created with < 4.1.2. */
-
-			if (dtype_is_binary_string_type(mtype, prtype)) {
-				/* Use the binary collation for
-				string columns of binary type. */
-
-				prtype = dtype_form_prtype(
-					prtype,
-					DATA_MYSQL_BINARY_CHARSET_COLL);
-			} else {
-				/* Use the default charset for
-				other than binary columns. */
+			prtype = dtype_form_prtype(
+				prtype,
+				DATA_MYSQL_BINARY_CHARSET_COLL);
+		} else {
+			/* Use the default charset for
+			other than binary columns. */
 
-				prtype = dtype_form_prtype(
-					prtype,
-					data_mysql_default_charset_coll);
-			}
+			prtype = dtype_form_prtype(
+				prtype,
+				data_mysql_default_charset_coll);
 		}
+	}
 
-		field = rec_get_nth_field_old(rec, 7, &len);
-		col_len = mach_read_from_4(field);
-
-		ut_a(name_of_col_is(sys_columns, sys_index, 8, "PREC"));
+	field = rec_get_nth_field_old(rec, 7/*LEN*/, &len);
+	if (UNIV_UNLIKELY(len != 4)) {
+		goto err_len;
+	}
+	col_len = mach_read_from_4(field);
+	field = rec_get_nth_field_old(rec, 8/*PREC*/, &len);
+	if (UNIV_UNLIKELY(len != 4)) {
+		goto err_len;
+	}
 
-		dict_mem_table_add_col(table, heap, name,
-				       mtype, prtype, col_len);
-		btr_pcur_move_to_next_user_rec(&pcur, &mtr);
+	if (!column) {
+		dict_mem_table_add_col(table, heap, name, mtype,
+				       prtype, col_len);
+	} else {
+		dict_mem_fill_column_struct(column, pos, mtype,
+					    prtype, col_len);
 	}
 
-	btr_pcur_close(&pcur);
-	mtr_commit(&mtr);
+	return(NULL);
 }
 
 /********************************************************************//**
-Loads definitions for index fields. */
+Loads definitions for table columns. */
 static
 void
-dict_load_fields(
-/*=============*/
-	dict_index_t*	index,	/*!< in: index whose fields to load */
-	mem_heap_t*	heap)	/*!< in: memory heap for temporary storage */
+dict_load_columns(
+/*==============*/
+	dict_table_t*	table,	/*!< in/out: table */
+	mem_heap_t*	heap)	/*!< in/out: memory heap
+				for temporary storage */
 {
-	dict_table_t*	sys_fields;
+	dict_table_t*	sys_columns;
 	dict_index_t*	sys_index;
 	btr_pcur_t	pcur;
 	dtuple_t*	tuple;
 	dfield_t*	dfield;
-	ulint		pos_and_prefix_len;
-	ulint		prefix_len;
 	const rec_t*	rec;
-	const byte*	field;
-	ulint		len;
 	byte*		buf;
 	ulint		i;
 	mtr_t		mtr;
@@ -573,78 +927,356 @@ dict_load_fields(
 
 	mtr_start(&mtr);
 
-	sys_fields = dict_table_get_low("SYS_FIELDS");
-	sys_index = UT_LIST_GET_FIRST(sys_fields->indexes);
-	ut_a(!dict_table_is_comp(sys_fields));
+	sys_columns = dict_table_get_low("SYS_COLUMNS");
+	sys_index = UT_LIST_GET_FIRST(sys_columns->indexes);
+	ut_a(!dict_table_is_comp(sys_columns));
+
+	ut_a(name_of_col_is(sys_columns, sys_index, 4, "NAME"));
+	ut_a(name_of_col_is(sys_columns, sys_index, 8, "PREC"));
 
 	tuple = dtuple_create(heap, 1);
 	dfield = dtuple_get_nth_field(tuple, 0);
 
 	buf = mem_heap_alloc(heap, 8);
-	mach_write_to_8(buf, index->id);
+	mach_write_to_8(buf, table->id);
 
 	dfield_set_data(dfield, buf, 8);
 	dict_index_copy_types(tuple, sys_index, 1);
 
 	btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
 				  BTR_SEARCH_LEAF, &pcur, &mtr);
-	for (i = 0; i < index->n_fields; i++) {
+	for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
+		const char* err_msg;
 
 		rec = btr_pcur_get_rec(&pcur);
 
 		ut_a(btr_pcur_is_on_user_rec(&pcur));
 
-		/* There could be delete marked records in SYS_FIELDS
-		because SYS_FIELDS.INDEX_ID can be updated
-		by ALTER TABLE ADD INDEX. */
-
-		if (rec_get_deleted_flag(rec, 0)) {
+		err_msg = dict_load_column_low(table, heap, NULL, NULL,
+					       NULL, rec);
 
-			goto next_rec;
+		if (err_msg) {
+			fprintf(stderr, "InnoDB: %s\n", err_msg);
+			ut_error;
 		}
 
-		field = rec_get_nth_field_old(rec, 0, &len);
-		ut_ad(len == 8);
+		btr_pcur_move_to_next_user_rec(&pcur, &mtr);
+	}
 
-		field = rec_get_nth_field_old(rec, 1, &len);
-		ut_a(len == 4);
+	btr_pcur_close(&pcur);
+	mtr_commit(&mtr);
+}
 
-		/* The next field stores the field position in the index
-		and a possible column prefix length if the index field
-		does not contain the whole column. The storage format is
-		like this: if there is at least one prefix field in the index,
-		then the HIGH 2 bytes contain the field number (== i) and the
-		low 2 bytes the prefix length for the field. Otherwise the
-		field number (== i) is contained in the 2 LOW bytes. */
-
-		pos_and_prefix_len = mach_read_from_4(field);
+/** Error message for a delete-marked record in dict_load_field_low() */
+static const char* dict_load_field_del = "delete-marked record in SYS_FIELDS";
 
-		ut_a((pos_and_prefix_len & 0xFFFFUL) == i
-		     || (pos_and_prefix_len & 0xFFFF0000UL) == (i << 16));
+/********************************************************************//**
+Loads an index field definition from a SYS_FIELDS record to
+dict_index_t.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_load_field_low(
+/*================*/
+	byte*		index_id,	/*!< in/out: index id (8 bytes)
+					an "in" value if index != NULL
+                                        and "out" if index == NULL */
+	dict_index_t*	index,		/*!< in/out: index, could be NULL
+					if we just populate a dict_field_t
+					struct with information from
+					a SYS_FIELDSS record */
+	dict_field_t*	sys_field,	/*!< out: dict_field_t to be
+					filled */
+	ulint*		pos,		/*!< out: Field position */
+	byte*		last_index_id,	/*!< in: last index id */
+	mem_heap_t*	heap,		/*!< in/out: memory heap
+					for temporary storage */
+	const rec_t*	rec)		/*!< in: SYS_FIELDS record */
+{
+	const byte*	field;
+	ulint		len;
+	ulint		pos_and_prefix_len;
+	ulint		prefix_len;
+	ibool		first_field;
+	ulint		position;
 
-		if ((i == 0 && pos_and_prefix_len > 0)
-		    || (pos_and_prefix_len & 0xFFFF0000UL) > 0) {
+	/* Either index or sys_field is supplied, not both */
+	ut_a((!index) || (!sys_field));
 
-			prefix_len = pos_and_prefix_len & 0xFFFFUL;
-		} else {
-			prefix_len = 0;
+	if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
+		return(dict_load_field_del);
+	}
+
+	if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 5)) {
+		return("wrong number of columns in SYS_FIELDS record");
+	}
+
+	field = rec_get_nth_field_old(rec, 0/*INDEX_ID*/, &len);
+	if (UNIV_UNLIKELY(len != 8)) {
+err_len:
+		return("incorrect column length in SYS_FIELDS");
+	}
+
+	if (!index) {
+		ut_a(last_index_id);
+		memcpy(index_id, (const char*)field, 8);
+		first_field = memcmp(index_id, last_index_id, 8);
+	} else {
+		first_field = (index->n_def == 0);
+		if (memcmp(field, index_id, 8)) {
+			return("SYS_FIELDS.INDEX_ID mismatch");
 		}
+	}
 
-		ut_a(name_of_col_is(sys_fields, sys_index, 4, "COL_NAME"));
+	field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
+	if (UNIV_UNLIKELY(len != 4)) {
+		goto err_len;
+	}
 
-		field = rec_get_nth_field_old(rec, 4, &len);
+	rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
+	if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
+		goto err_len;
+	}
+	rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
+	if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
+		goto err_len;
+	}
+
+	/* The next field stores the field position in the index and a
+	possible column prefix length if the index field does not
+	contain the whole column. The storage format is like this: if
+	there is at least one prefix field in the index, then the HIGH
+	2 bytes contain the field number (index->n_def) and the low 2
+	bytes the prefix length for the field. Otherwise the field
+	number (index->n_def) is contained in the 2 LOW bytes. */
+
+	pos_and_prefix_len = mach_read_from_4(field);
+
+	if (index && UNIV_UNLIKELY
+	    ((pos_and_prefix_len & 0xFFFFUL) != index->n_def
+	     && (pos_and_prefix_len >> 16 & 0xFFFF) != index->n_def)) {
+		return("SYS_FIELDS.POS mismatch");
+	}
+
+	if (first_field || pos_and_prefix_len > 0xFFFFUL) {
+		prefix_len = pos_and_prefix_len & 0xFFFFUL;
+		position = (pos_and_prefix_len & 0xFFFF0000UL)  >> 16;
+	} else {
+		prefix_len = 0;
+		position = pos_and_prefix_len & 0xFFFFUL;
+	}
+
+	field = rec_get_nth_field_old(rec, 4, &len);
+	if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+		goto err_len;
+	}
+
+	if (index) {
+		dict_mem_index_add_field(
+			index, mem_heap_strdupl(heap, (const char*) field, len),
+			prefix_len);
+	} else {
+		ut_a(sys_field);
+		ut_a(pos);
+
+		sys_field->name = mem_heap_strdupl(
+			heap, (const char*) field, len);
+		sys_field->prefix_len = prefix_len;
+		*pos = position;
+	}
+
+	return(NULL);
+}
+
+/********************************************************************//**
+Loads definitions for index fields.
+@return DB_SUCCESS if ok, DB_CORRUPTION if corruption */
+static
+ulint
+dict_load_fields(
+/*=============*/
+	dict_index_t*	index,	/*!< in/out: index whose fields to load */
+	mem_heap_t*	heap)	/*!< in: memory heap for temporary storage */
+{
+	dict_table_t*	sys_fields;
+	dict_index_t*	sys_index;
+	btr_pcur_t	pcur;
+	dtuple_t*	tuple;
+	dfield_t*	dfield;
+	const rec_t*	rec;
+	byte*		buf;
+	ulint		i;
+	mtr_t		mtr;
+	ulint		error;
+
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	mtr_start(&mtr);
+
+	sys_fields = dict_table_get_low("SYS_FIELDS");
+	sys_index = UT_LIST_GET_FIRST(sys_fields->indexes);
+	ut_a(!dict_table_is_comp(sys_fields));
+	ut_a(name_of_col_is(sys_fields, sys_index, 4, "COL_NAME"));
+
+	tuple = dtuple_create(heap, 1);
+	dfield = dtuple_get_nth_field(tuple, 0);
+
+	buf = mem_heap_alloc(heap, 8);
+	mach_write_to_8(buf, index->id);
+
+	dfield_set_data(dfield, buf, 8);
+	dict_index_copy_types(tuple, sys_index, 1);
+
+	btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
+				  BTR_SEARCH_LEAF, &pcur, &mtr);
+	for (i = 0; i < index->n_fields; i++) {
+		const char* err_msg;
+
+		rec = btr_pcur_get_rec(&pcur);
+
+		ut_a(btr_pcur_is_on_user_rec(&pcur));
+
+		err_msg = dict_load_field_low(buf, index, NULL, NULL, NULL,
+					      heap, rec);
 
-		dict_mem_index_add_field(index,
-					 mem_heap_strdupl(heap,
-							  (char*) field, len),
-					 prefix_len);
+		if (err_msg == dict_load_field_del) {
+			/* There could be delete marked records in
+			SYS_FIELDS because SYS_FIELDS.INDEX_ID can be
+			updated by ALTER TABLE ADD INDEX. */
 
+			goto next_rec;
+		} else if (err_msg) {
+			fprintf(stderr, "InnoDB: %s\n", err_msg);
+			error = DB_CORRUPTION;
+			goto func_exit;
+		}
 next_rec:
 		btr_pcur_move_to_next_user_rec(&pcur, &mtr);
 	}
 
+	error = DB_SUCCESS;
+func_exit:
 	btr_pcur_close(&pcur);
 	mtr_commit(&mtr);
+	return(error);
+}
+
+/** Error message for a delete-marked record in dict_load_index_low() */
+static const char* dict_load_index_del = "delete-marked record in SYS_INDEXES";
+/** Error message for table->id mismatch in dict_load_index_low() */
+static const char* dict_load_index_id_err = "SYS_INDEXES.TABLE_ID mismatch";
+
+/********************************************************************//**
+Loads an index definition from a SYS_INDEXES record to dict_index_t.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_load_index_low(
+/*================*/
+	byte*		table_id,	/*!< in/out: table id (8 bytes),
+					an "in" value if cached=TRUE
+					and "out" when cached=FALSE */
+	const char*	table_name,	/*!< in: table name */
+	mem_heap_t*	heap,		/*!< in/out: temporary memory heap */
+	const rec_t*	rec,		/*!< in: SYS_INDEXES record */
+	ibool		cached,		/*!< in: TRUE = add to cache,
+					FALSE = do not */
+	dict_index_t**	index)		/*!< out,own: index, or NULL */
+{
+	const byte*	field;
+	ulint		len;
+	ulint		name_len;
+	char*		name_buf;
+	dulint		id;
+	ulint		n_fields;
+	ulint		type;
+	ulint		space;
+
+	if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
+		return(dict_load_index_del);
+	}
+
+	if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 9)) {
+		return("wrong number of columns in SYS_INDEXES record");
+	}
+
+	field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len);
+	if (UNIV_UNLIKELY(len != 8)) {
+err_len:
+		return("incorrect column length in SYS_INDEXES");
+	}
+
+	if (!cached) {
+		/* We are reading a SYS_INDEXES record. Copy the table_id */
+		memcpy(table_id, (const char*)field, 8);
+	} else if (memcmp(field, table_id, 8)) {
+		/* Caller supplied table_id, verify it is the same
+		id as on the index record */
+		return(dict_load_index_id_err);
+	}
+
+	field = rec_get_nth_field_old(rec, 1/*ID*/, &len);
+	if (UNIV_UNLIKELY(len != 8)) {
+		goto err_len;
+	}
+
+	id = mach_read_from_8(field);
+
+	rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
+	if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
+		goto err_len;
+	}
+	rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
+	if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
+		goto err_len;
+	}
+
+	field = rec_get_nth_field_old(rec, 4/*NAME*/, &name_len);
+	if (UNIV_UNLIKELY(name_len == UNIV_SQL_NULL)) {
+		goto err_len;
+	}
+
+	name_buf = mem_heap_strdupl(heap, (const char*) field,
+				    name_len);
+
+	field = rec_get_nth_field_old(rec, 5/*N_FIELDS*/, &len);
+	if (UNIV_UNLIKELY(len != 4)) {
+		goto err_len;
+	}
+	n_fields = mach_read_from_4(field);
+
+	field = rec_get_nth_field_old(rec, 6/*TYPE*/, &len);
+	if (UNIV_UNLIKELY(len != 4)) {
+		goto err_len;
+	}
+	type = mach_read_from_4(field);
+
+	field = rec_get_nth_field_old(rec, 7/*SPACE*/, &len);
+	if (UNIV_UNLIKELY(len != 4)) {
+		goto err_len;
+	}
+	space = mach_read_from_4(field);
+
+	field = rec_get_nth_field_old(rec, 8/*PAGE_NO*/, &len);
+	if (UNIV_UNLIKELY(len != 4)) {
+		goto err_len;
+	}
+
+	if (cached) {
+		*index = dict_mem_index_create(table_name, name_buf,
+					       space, type, n_fields);
+	} else {
+		ut_a(*index);
+
+		dict_mem_fill_index_struct(*index, NULL, NULL, name_buf,
+					   space, type, n_fields);
+	}
+
+	(*index)->id = id;
+	(*index)->page = mach_read_from_4(field);
+	ut_ad((*index)->page);
+
+	return(NULL);
 }
 
 /********************************************************************//**
@@ -656,27 +1288,17 @@ static
 ulint
 dict_load_indexes(
 /*==============*/
-	dict_table_t*	table,	/*!< in: table */
+	dict_table_t*	table,	/*!< in/out: table */
 	mem_heap_t*	heap)	/*!< in: memory heap for temporary storage */
 {
 	dict_table_t*	sys_indexes;
 	dict_index_t*	sys_index;
-	dict_index_t*	index;
 	btr_pcur_t	pcur;
 	dtuple_t*	tuple;
 	dfield_t*	dfield;
 	const rec_t*	rec;
-	const byte*	field;
-	ulint		len;
-	ulint		name_len;
-	char*		name_buf;
-	ulint		type;
-	ulint		space;
-	ulint		page_no;
-	ulint		n_fields;
 	byte*		buf;
 	ibool		is_sys_table;
-	dulint		id;
 	mtr_t		mtr;
 	ulint		error = DB_SUCCESS;
 
@@ -694,6 +1316,8 @@ dict_load_indexes(
 	sys_indexes = dict_table_get_low("SYS_INDEXES");
 	sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes);
 	ut_a(!dict_table_is_comp(sys_indexes));
+	ut_a(name_of_col_is(sys_indexes, sys_index, 4, "NAME"));
+	ut_a(name_of_col_is(sys_indexes, sys_index, 8, "PAGE_NO"));
 
 	tuple = dtuple_create(heap, 1);
 	dfield = dtuple_get_nth_field(tuple, 0);
@@ -707,6 +1331,9 @@ dict_load_indexes(
 	btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
 				  BTR_SEARCH_LEAF, &pcur, &mtr);
 	for (;;) {
+		dict_index_t*	index;
+		const char*	err_msg;
+
 		if (!btr_pcur_is_on_user_rec(&pcur)) {
 
 			break;
@@ -714,90 +1341,73 @@ dict_load_indexes(
 
 		rec = btr_pcur_get_rec(&pcur);
 
-		field = rec_get_nth_field_old(rec, 0, &len);
-		ut_ad(len == 8);
-
-		if (ut_memcmp(buf, field, len) != 0) {
+		err_msg = dict_load_index_low(buf, table->name, heap, rec,
+					      TRUE, &index);
+		ut_ad((index == NULL) == (err_msg != NULL));
+
+		if (err_msg == dict_load_index_id_err) {
+			/* TABLE_ID mismatch means that we have
+			run out of index definitions for the table. */
 			break;
-		} else if (rec_get_deleted_flag(rec, 0)) {
-			/* Skip delete marked records */
+		} else if (err_msg == dict_load_index_del) {
+			/* Skip delete-marked records. */
 			goto next_rec;
+		} else if (err_msg) {
+			fprintf(stderr, "InnoDB: %s\n", err_msg);
+			error = DB_CORRUPTION;
+			goto func_exit;
 		}
 
-		field = rec_get_nth_field_old(rec, 1, &len);
-		ut_ad(len == 8);
-		id = mach_read_from_8(field);
-
-		ut_a(name_of_col_is(sys_indexes, sys_index, 4, "NAME"));
-
-		field = rec_get_nth_field_old(rec, 4, &name_len);
-		name_buf = mem_heap_strdupl(heap, (char*) field, name_len);
-
-		field = rec_get_nth_field_old(rec, 5, &len);
-		n_fields = mach_read_from_4(field);
-
-		field = rec_get_nth_field_old(rec, 6, &len);
-		type = mach_read_from_4(field);
-
-		field = rec_get_nth_field_old(rec, 7, &len);
-		space = mach_read_from_4(field);
-
-		ut_a(name_of_col_is(sys_indexes, sys_index, 8, "PAGE_NO"));
-
-		field = rec_get_nth_field_old(rec, 8, &len);
-		page_no = mach_read_from_4(field);
+		ut_ad(index);
 
 		/* We check for unsupported types first, so that the
 		subsequent checks are relevant for the supported types. */
-		if (type & ~(DICT_CLUSTERED | DICT_UNIQUE)) {
+		if (index->type & ~(DICT_CLUSTERED | DICT_UNIQUE)) {
 
 			fprintf(stderr,
 				"InnoDB: Error: unknown type %lu"
 				" of index %s of table %s\n",
-				(ulong) type, name_buf, table->name);
+				(ulong) index->type, index->name, table->name);
 
 			error = DB_UNSUPPORTED;
+			dict_mem_index_free(index);
 			goto func_exit;
-		} else if (page_no == FIL_NULL) {
+		} else if (index->page == FIL_NULL) {
 
 			fprintf(stderr,
 				"InnoDB: Error: trying to load index %s"
 				" for table %s\n"
 				"InnoDB: but the index tree has been freed!\n",
-				name_buf, table->name);
+				index->name, table->name);
 
+corrupted:
+			dict_mem_index_free(index);
 			error = DB_CORRUPTION;
 			goto func_exit;
-		} else if ((type & DICT_CLUSTERED) == 0
-			    && NULL == dict_table_get_first_index(table)) {
+		} else if (!dict_index_is_clust(index)
+			   && NULL == dict_table_get_first_index(table)) {
 
 			fputs("InnoDB: Error: trying to load index ",
 			      stderr);
-			ut_print_name(stderr, NULL, FALSE, name_buf);
+			ut_print_name(stderr, NULL, FALSE, index->name);
 			fputs(" for table ", stderr);
 			ut_print_name(stderr, NULL, TRUE, table->name);
 			fputs("\nInnoDB: but the first index"
 			      " is not clustered!\n", stderr);
 
-			error = DB_CORRUPTION;
-			goto func_exit;
+			goto corrupted;
 		} else if (is_sys_table
-			   && ((type & DICT_CLUSTERED)
+			   && (dict_index_is_clust(index)
 			       || ((table == dict_sys->sys_tables)
-				   && (name_len == (sizeof "ID_IND") - 1)
-				   && (0 == ut_memcmp(name_buf,
-						      "ID_IND", name_len))))) {
+				   && !strcmp("ID_IND", index->name)))) {
 
 			/* The index was created in memory already at booting
 			of the database server */
+			dict_mem_index_free(index);
 		} else {
-			index = dict_mem_index_create(table->name, name_buf,
-						      space, type, n_fields);
-			index->id = id;
-
 			dict_load_fields(index, heap);
-			error = dict_index_add_to_cache(table, index, page_no,
-							FALSE);
+			error = dict_index_add_to_cache(table, index,
+							index->page, FALSE);
 			/* The data dictionary tables should never contain
 			invalid index definitions.  If we ignored this error
 			and simply did not load this index definition, the
@@ -821,80 +1431,83 @@ func_exit:
 }
 
 /********************************************************************//**
-Loads a table definition and also all its index definitions, and also
-the cluster definition if the table is a member in a cluster. Also loads
-all foreign key constraints where the foreign key is in the table or where
-a foreign key references columns in this table. Adds all these to the data
-dictionary cache.
-@return table, NULL if does not exist; if the table is stored in an
-.ibd file, but the file does not exist, then we set the
-ibd_file_missing flag TRUE in the table object we return */
+Loads a table definition from a SYS_TABLES record to dict_table_t.
+Does not load any columns or indexes.
+@return error message, or NULL on success */
 UNIV_INTERN
-dict_table_t*
-dict_load_table(
-/*============*/
-	const char*	name)	/*!< in: table name in the
-				databasename/tablename format */
+const char*
+dict_load_table_low(
+/*================*/
+	const char*	name,		/*!< in: table name */
+	const rec_t*	rec,		/*!< in: SYS_TABLES record */
+	dict_table_t**	table)		/*!< out,own: table, or NULL */
 {
-	ibool		ibd_file_missing	= FALSE;
-	dict_table_t*	table;
-	dict_table_t*	sys_tables;
-	btr_pcur_t	pcur;
-	dict_index_t*	sys_index;
-	dtuple_t*	tuple;
-	mem_heap_t*	heap;
-	dfield_t*	dfield;
-	const rec_t*	rec;
 	const byte*	field;
 	ulint		len;
 	ulint		space;
 	ulint		n_cols;
 	ulint		flags;
-	ulint		err;
-	mtr_t		mtr;
 
-	ut_ad(mutex_own(&(dict_sys->mutex)));
+	if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
+		return("delete-marked record in SYS_TABLES");
+	}
 
-	heap = mem_heap_create(32000);
+	if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 10)) {
+		return("wrong number of columns in SYS_TABLES record");
+	}
 
-	mtr_start(&mtr);
+	rec_get_nth_field_offs_old(rec, 0/*NAME*/, &len);
+	if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
+err_len:
+		return("incorrect column length in SYS_TABLES");
+	}
+	rec_get_nth_field_offs_old(rec, 1/*DB_TRX_ID*/, &len);
+	if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
+		goto err_len;
+	}
+	rec_get_nth_field_offs_old(rec, 2/*DB_ROLL_PTR*/, &len);
+	if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
+		goto err_len;
+	}
 
-	sys_tables = dict_table_get_low("SYS_TABLES");
-	sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
-	ut_a(!dict_table_is_comp(sys_tables));
+	rec_get_nth_field_offs_old(rec, 3/*ID*/, &len);
+	if (UNIV_UNLIKELY(len != 8)) {
+		goto err_len;
+	}
 
-	tuple = dtuple_create(heap, 1);
-	dfield = dtuple_get_nth_field(tuple, 0);
+	field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
+	if (UNIV_UNLIKELY(len != 4)) {
+		goto err_len;
+	}
 
-	dfield_set_data(dfield, name, ut_strlen(name));
-	dict_index_copy_types(tuple, sys_index, 1);
+	n_cols = mach_read_from_4(field);
 
-	btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
-				  BTR_SEARCH_LEAF, &pcur, &mtr);
-	rec = btr_pcur_get_rec(&pcur);
+	rec_get_nth_field_offs_old(rec, 5/*TYPE*/, &len);
+	if (UNIV_UNLIKELY(len != 4)) {
+		goto err_len;
+	}
 
-	if (!btr_pcur_is_on_user_rec(&pcur)
-	    || rec_get_deleted_flag(rec, 0)) {
-		/* Not found */
-err_exit:
-		btr_pcur_close(&pcur);
-		mtr_commit(&mtr);
-		mem_heap_free(heap);
+	rec_get_nth_field_offs_old(rec, 6/*MIX_ID*/, &len);
+	if (UNIV_UNLIKELY(len != 8)) {
+		goto err_len;
+	}
 
-		return(NULL);
+	rec_get_nth_field_offs_old(rec, 7/*MIX_LEN*/, &len);
+	if (UNIV_UNLIKELY(len != 4)) {
+		goto err_len;
 	}
 
-	field = rec_get_nth_field_old(rec, 0, &len);
+	rec_get_nth_field_offs_old(rec, 8/*CLUSTER_ID*/, &len);
+	if (UNIV_UNLIKELY(len != UNIV_SQL_NULL)) {
+		goto err_len;
+	}
 
-	/* Check if the table name in record is the searched one */
-	if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) {
+	field = rec_get_nth_field_old(rec, 9/*SPACE*/, &len);
 
-		goto err_exit;
+	if (UNIV_UNLIKELY(len != 4)) {
+		goto err_len;
 	}
 
-	ut_a(name_of_col_is(sys_tables, sys_index, 9, "SPACE"));
-
-	field = rec_get_nth_field_old(rec, 9, &len);
 	space = mach_read_from_4(field);
 
 	/* Check if the tablespace exists and has the right name */
@@ -902,7 +1515,8 @@ err_exit:
 		flags = dict_sys_tables_get_flags(rec);
 
 		if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) {
-			field = rec_get_nth_field_old(rec, 5, &len);
+			field = rec_get_nth_field_old(rec, 5/*TYPE*/, &len);
+			ut_ad(len == 4); /* this was checked earlier */
 			flags = mach_read_from_4(field);
 
 			ut_print_timestamp(stderr);
@@ -912,17 +1526,12 @@ err_exit:
 				"InnoDB: in InnoDB data dictionary"
 				" has unknown type %lx.\n",
 				(ulong) flags);
-			goto err_exit;
+			return(NULL);
 		}
 	} 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.
 	For tables in that format, MIX_LEN may hold additional flags. */
 	if (n_cols & 0x80000000UL) {
@@ -930,9 +1539,13 @@ err_exit:
 
 		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);
 
+		if (UNIV_UNLIKELY(len != 4)) {
+
+			goto err_len;
+		}
+
 		flags2 = mach_read_from_4(field);
 
 		if (flags2 & (~0 << (DICT_TF2_BITS - DICT_TF2_SHIFT))) {
@@ -951,53 +1564,145 @@ err_exit:
 	}
 
 	/* See if the tablespace is available. */
-	if (space == 0) {
+	*table = dict_mem_table_create(name, space, n_cols & ~0x80000000UL,
+				       flags);
+
+	field = rec_get_nth_field_old(rec, 3/*ID*/, &len);
+	ut_ad(len == 8); /* this was checked earlier */
+
+	(*table)->id = mach_read_from_8(field);
+
+	(*table)->ibd_file_missing = FALSE;
+
+	return(NULL);
+}
+
+/********************************************************************//**
+Loads a table definition and also all its index definitions, and also
+the cluster definition if the table is a member in a cluster. Also loads
+all foreign key constraints where the foreign key is in the table or where
+a foreign key references columns in this table. Adds all these to the data
+dictionary cache.
+@return table, NULL if does not exist; if the table is stored in an
+.ibd file, but the file does not exist, then we set the
+ibd_file_missing flag TRUE in the table object we return */
+UNIV_INTERN
+dict_table_t*
+dict_load_table(
+/*============*/
+	const char*	name,	/*!< in: table name in the
+				databasename/tablename format */
+	ibool		cached)	/*!< in: TRUE=add to cache, FALSE=do not */
+{
+	dict_table_t*	table;
+	dict_table_t*	sys_tables;
+	btr_pcur_t	pcur;
+	dict_index_t*	sys_index;
+	dtuple_t*	tuple;
+	mem_heap_t*	heap;
+	dfield_t*	dfield;
+	const rec_t*	rec;
+	const byte*	field;
+	ulint		len;
+	ulint		err;
+	const char*	err_msg;
+	mtr_t		mtr;
+
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	heap = mem_heap_create(32000);
+
+	mtr_start(&mtr);
+
+	sys_tables = dict_table_get_low("SYS_TABLES");
+	sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
+	ut_a(!dict_table_is_comp(sys_tables));
+	ut_a(name_of_col_is(sys_tables, sys_index, 3, "ID"));
+	ut_a(name_of_col_is(sys_tables, sys_index, 4, "N_COLS"));
+	ut_a(name_of_col_is(sys_tables, sys_index, 5, "TYPE"));
+	ut_a(name_of_col_is(sys_tables, sys_index, 7, "MIX_LEN"));
+	ut_a(name_of_col_is(sys_tables, sys_index, 9, "SPACE"));
+
+	tuple = dtuple_create(heap, 1);
+	dfield = dtuple_get_nth_field(tuple, 0);
+
+	dfield_set_data(dfield, name, ut_strlen(name));
+	dict_index_copy_types(tuple, sys_index, 1);
+
+	btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
+				  BTR_SEARCH_LEAF, &pcur, &mtr);
+	rec = btr_pcur_get_rec(&pcur);
+
+	if (!btr_pcur_is_on_user_rec(&pcur)
+	    || rec_get_deleted_flag(rec, 0)) {
+		/* Not found */
+err_exit:
+		btr_pcur_close(&pcur);
+		mtr_commit(&mtr);
+		mem_heap_free(heap);
+
+		return(NULL);
+	}
+
+	field = rec_get_nth_field_old(rec, 0, &len);
+
+	/* Check if the table name in record is the searched one */
+	if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) {
+
+		goto err_exit;
+	}
+
+	err_msg = dict_load_table_low(name, rec, &table);
+
+	if (err_msg) {
+
+		ut_print_timestamp(stderr);
+		fprintf(stderr, "  InnoDB: %s\n", err_msg);
+		goto err_exit;
+	}
+
+	if (table->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,
+			   table->space, name,
+			   (table->flags >> DICT_TF2_SHIFT)
+			   & DICT_TF2_TEMPORARY,
 			   FALSE, FALSE)) {
 
-		if ((flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY) {
+		if (table->flags & (DICT_TF2_TEMPORARY << DICT_TF2_SHIFT)) {
 			/* Do not bother to retry opening temporary tables. */
-			ibd_file_missing = TRUE;
+			table->ibd_file_missing = TRUE;
 		} else {
 			ut_print_timestamp(stderr);
 			fprintf(stderr,
-				"  InnoDB: error: space object of table");
+				"  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",
-				(ulong) space);
+				(ulong) table->space);
 			/* Try to open the tablespace */
 			if (!fil_open_single_table_tablespace(
-				    TRUE, space,
-				    flags & ~(~0 << DICT_TF_BITS), name)) {
+				TRUE, table->space,
+				table->flags & ~(~0 << DICT_TF_BITS), name)) {
 				/* We failed to find a sensible
 				tablespace file */
 
-				ibd_file_missing = TRUE;
+				table->ibd_file_missing = TRUE;
 			}
 		}
 	}
 
-	table = dict_mem_table_create(name, space, n_cols & ~0x80000000UL,
-				      flags);
-
-	table->ibd_file_missing = (unsigned int) ibd_file_missing;
-
-	ut_a(name_of_col_is(sys_tables, sys_index, 3, "ID"));
-
-	field = rec_get_nth_field_old(rec, 3, &len);
-	table->id = mach_read_from_8(field);
-
 	btr_pcur_close(&pcur);
 	mtr_commit(&mtr);
 
 	dict_load_columns(table, heap);
 
-	dict_table_add_to_cache(table, heap);
+	if (cached) {
+		dict_table_add_to_cache(table, heap);
+	} else {
+		dict_table_add_system_columns(table, heap);
+	}
 
 	mem_heap_empty(heap);
 
@@ -1007,7 +1712,8 @@ err_exit:
 	of the error condition, since the user may want to dump data from the
 	clustered index. However we load the foreign key information only if
 	all indexes were loaded. */
-	if (err == DB_SUCCESS) {
+	if (!cached) {
+	} else if (err == DB_SUCCESS) {
 		err = dict_load_foreigns(table->name, TRUE);
 	} else if (!srv_force_recovery) {
 		dict_table_remove_from_cache(table);
@@ -1124,7 +1830,8 @@ dict_load_table_on_id(
 	/* Now we get the table name from the record */
 	field = rec_get_nth_field_old(rec, 1, &len);
 	/* Load the table definition to memory */
-	table = dict_load_table(mem_heap_strdupl(heap, (char*) field, len));
+	table = dict_load_table(mem_heap_strdupl(heap, (char*) field, len),
+				TRUE);
 
 	btr_pcur_close(&pcur);
 	mtr_commit(&mtr);

=== modified file 'storage/innobase/dict/dict0mem.c'
--- a/storage/innobase/dict/dict0mem.c	revid:vasil.dimov@stripped
+++ b/storage/innobase/dict/dict0mem.c	revid:jimmy.yang@stripped
@@ -177,10 +177,6 @@ dict_mem_table_add_col(
 	ulint		len)	/*!< in: precision */
 {
 	dict_col_t*	col;
-#ifndef UNIV_HOTBACKUP
-	ulint		mbminlen;
-	ulint		mbmaxlen;
-#endif /* !UNIV_HOTBACKUP */
 	ulint		i;
 
 	ut_ad(table);
@@ -205,19 +201,7 @@ dict_mem_table_add_col(
 
 	col = dict_table_get_nth_col(table, i);
 
-	col->ind = (unsigned int) i;
-	col->ord_part = 0;
-
-	col->mtype = (unsigned int) mtype;
-	col->prtype = (unsigned int) prtype;
-	col->len = (unsigned int) len;
-
-#ifndef UNIV_HOTBACKUP
-	dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen);
-
-	col->mbminlen = (unsigned int) mbminlen;
-	col->mbmaxlen = (unsigned int) mbmaxlen;
-#endif /* !UNIV_HOTBACKUP */
+	dict_mem_fill_column_struct(col, i, mtype, prtype, len);
 }
 
 /**********************************************************************//**
@@ -244,22 +228,9 @@ dict_mem_index_create(
 	heap = mem_heap_create(DICT_HEAP_SIZE);
 	index = mem_heap_zalloc(heap, sizeof(dict_index_t));
 
-	index->heap = heap;
+	dict_mem_fill_index_struct(index, heap, table_name, index_name,
+				   space, type, n_fields);
 
-	index->type = type;
-#ifndef UNIV_HOTBACKUP
-	index->space = (unsigned int) space;
-#endif /* !UNIV_HOTBACKUP */
-	index->name = mem_heap_strdup(heap, index_name);
-	index->table_name = table_name;
-	index->n_fields = (unsigned int) n_fields;
-	index->fields = mem_heap_alloc(heap, 1 + n_fields
-				       * sizeof(dict_field_t));
-	/* The '1 +' above prevents allocation
-	of an empty mem block */
-#ifdef UNIV_DEBUG
-	index->magic_n = DICT_INDEX_MAGIC_N;
-#endif /* UNIV_DEBUG */
 	return(index);
 }
 

=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc	revid:vasil.dimov@stripped
+++ b/storage/innobase/handler/ha_innodb.cc	revid:jimmy.yang@stripped
@@ -11105,7 +11105,15 @@ i_s_innodb_lock_waits,
 i_s_innodb_cmp,
 i_s_innodb_cmp_reset,
 i_s_innodb_cmpmem,
-i_s_innodb_cmpmem_reset
+i_s_innodb_cmpmem_reset,
+i_s_innodb_sys_tables,
+i_s_innodb_sys_tablestats,
+i_s_innodb_sys_indexes,
+i_s_innodb_sys_columns,
+i_s_innodb_sys_fields,
+i_s_innodb_sys_foreign,
+i_s_innodb_sys_foreign_cols
+
 mysql_declare_plugin_end;
 
 /** @brief Initialize the default value of innodb_commit_concurrency.

=== modified file 'storage/innobase/handler/i_s.cc'
--- a/storage/innobase/handler/i_s.cc	revid:vasil.dimov@stripped
+++ b/storage/innobase/handler/i_s.cc	revid:jimmy.yang@stripped
@@ -36,12 +36,17 @@ Created July 18, 2007 Vasil Dimov
 #include <mysql/innodb_priv.h>
 
 extern "C" {
-#include "trx0i_s.h"
-#include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */
+#include "btr0pcur.h"	/* for file sys_tables related info. */
+#include "btr0types.h"
 #include "buf0buddy.h" /* for i_s_cmpmem */
 #include "buf0buf.h" /* for buf_pool and PAGE_ZIP_MIN_SIZE */
+#include "dict0load.h"	/* for file sys_tables related info. */
+#include "dict0mem.h"
+#include "dict0types.h"
 #include "ha_prototypes.h" /* for innobase_convert_name() */
 #include "srv0start.h" /* for srv_was_started */
+#include "trx0i_s.h"
+#include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */
 }
 
 static const char plugin_author[] = "Innobase Oy";
@@ -131,7 +136,6 @@ int
 i_s_common_deinit(
 /*==============*/
 	void*	p);	/*!< in/out: table schema object */
-
 /*******************************************************************//**
 Auxiliary function to store time_t value in MYSQL_TYPE_DATETIME
 field.
@@ -1905,3 +1909,1660 @@ i_s_common_deinit(
 
 	DBUG_RETURN(0);
 }
+
+/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLES */
+static ST_FIELD_INFO    innodb_sys_tables_fields_info[] =
+{
+#define SYS_TABLE_ID		0
+	{STRUCT_FLD(field_name,		"TABLE_ID"),
+	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLE_NAME		1
+	{STRUCT_FLD(field_name,		"NAME"),
+	 STRUCT_FLD(field_length,	NAME_LEN + 1),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLE_FLAG		2
+	{STRUCT_FLD(field_name,		"FLAG"),
+	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLE_NUM_COLUMN	3
+	{STRUCT_FLD(field_name,		"N_COLS"),
+	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLE_SPACE		4
+	{STRUCT_FLD(field_name,		"SPACE"),
+	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+	END_OF_ST_FIELD_INFO
+};
+
+/**********************************************************************//**
+Populate information_schema.innodb_sys_tables table with information
+from SYS_TABLES.
+@return	0 on success */
+static
+int
+i_s_dict_fill_sys_tables(
+/*=====================*/
+	THD*		thd,		/*!< in: thread */
+	dict_table_t*	table,		/*!< in: table */
+	TABLE*		table_to_fill)  /*!< in/out: fill this table */
+{
+	longlong	table_id;
+	Field**		fields;
+
+	DBUG_ENTER("i_s_dict_fill_sys_tables");
+
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	fields = table_to_fill->field;
+
+	table_id = ut_conv_dulint_to_longlong(table->id);
+
+	OK(fields[SYS_TABLE_ID]->store(table_id));
+
+	OK(field_store_string(fields[SYS_TABLE_NAME], table->name));
+
+	OK(fields[SYS_TABLE_FLAG]->store(table->flags));
+
+	OK(fields[SYS_TABLE_NUM_COLUMN]->store(table->n_cols));
+
+	OK(fields[SYS_TABLE_SPACE]->store(table->space));
+
+	OK(schema_table_store_record(thd, table_to_fill));
+
+	DBUG_RETURN(0);
+}
+/*******************************************************************//**
+Function to go through each record in SYS_TABLES table, and fill the
+information_schema.innodb_sys_tables table with related table information
+@return 0 on success */
+static
+int
+i_s_sys_tables_fill_table(
+/*======================*/
+	THD*		thd,    /*!< in: thread */
+	TABLE_LIST*	tables, /*!< in/out: tables to fill */
+	COND*		cond)   /*!< in: condition (not used) */
+{
+        btr_pcur_t	pcur;
+	const rec_t*	rec;
+	mem_heap_t*	heap;
+	mtr_t		mtr;
+
+	DBUG_ENTER("i_s_sys_tables_fill_table");
+
+	/* deny access to non-superusers */
+	if (check_global_access(thd, PROCESS_ACL)) {
+
+                DBUG_RETURN(0);
+	}
+
+        heap = mem_heap_create(1000);
+        mutex_enter(&(dict_sys->mutex));
+        mtr_start(&mtr);
+
+	rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
+
+	while (rec) {
+		const char*	err_msg;
+		dict_table_t*	table_rec;
+
+		/* Create and populate a dict_table_t structure with
+		information from SYS_TABLES row */
+		err_msg = dict_process_sys_tables_rec(
+			heap, rec, &table_rec, DICT_TABLE_LOAD_FROM_RECORD);
+
+		mtr_commit(&mtr);
+		mutex_exit(&dict_sys->mutex);
+
+		if (!err_msg) {
+			i_s_dict_fill_sys_tables(thd, table_rec, tables->table);
+		} else {
+			push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+					    ER_CANT_FIND_SYSTEM_REC,
+					    err_msg);
+		}
+
+		/* Since dict_process_sys_tables_rec() is called with
+		DICT_TABLE_LOAD_FROM_RECORD, the table_rec is created in
+		dict_process_sys_tables_rec(), we will need to free it */
+		if (table_rec) {
+			dict_mem_table_free(table_rec);
+		}
+
+		mem_heap_empty(heap);
+
+		/* Get the next record */
+		mutex_enter(&dict_sys->mutex);
+		mtr_start(&mtr);
+		rec = dict_getnext_system(&pcur, &mtr);
+	}
+
+	mtr_commit(&mtr);
+	mutex_exit(&dict_sys->mutex);
+	mem_heap_free(heap);
+
+	DBUG_RETURN(0);
+}
+
+/*******************************************************************//**
+Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_tables
+@return 0 on success */
+static
+int
+innodb_sys_tables_init(
+/*===================*/
+        void*   p)      /*!< in/out: table schema object */
+{
+        ST_SCHEMA_TABLE*        schema;
+
+        DBUG_ENTER("innodb_sys_tables_init");
+
+        schema = (ST_SCHEMA_TABLE*) p;
+
+        schema->fields_info = innodb_sys_tables_fields_info;
+        schema->fill_table = i_s_sys_tables_fill_table;
+
+        DBUG_RETURN(0);
+}
+
+UNIV_INTERN struct st_mysql_plugin	i_s_innodb_sys_tables =
+{
+	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
+	/* int */
+	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
+
+	/* pointer to type-specific plugin descriptor */
+	/* void* */
+	STRUCT_FLD(info, &i_s_info),
+
+	/* plugin name */
+	/* const char* */
+	STRUCT_FLD(name, "INNODB_SYS_TABLES"),
+
+	/* plugin author (for SHOW PLUGINS) */
+	/* const char* */
+	STRUCT_FLD(author, plugin_author),
+
+	/* general descriptive text (for SHOW PLUGINS) */
+	/* const char* */
+	STRUCT_FLD(descr, "InnoDB SYS_TABLES"),
+
+	/* the plugin license (PLUGIN_LICENSE_XXX) */
+	/* int */
+	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
+
+	/* the function to invoke when plugin is loaded */
+	/* int (*)(void*); */
+	STRUCT_FLD(init, innodb_sys_tables_init),
+
+	/* the function to invoke when plugin is unloaded */
+	/* int (*)(void*); */
+	STRUCT_FLD(deinit, i_s_common_deinit),
+
+	/* plugin version (for SHOW PLUGINS) */
+	/* unsigned int */
+	STRUCT_FLD(version, INNODB_VERSION_SHORT),
+
+	/* struct st_mysql_show_var* */
+	STRUCT_FLD(status_vars, NULL),
+
+	/* struct st_mysql_sys_var** */
+	STRUCT_FLD(system_vars, NULL),
+
+	/* reserved for dependency checking */
+	/* void* */
+	STRUCT_FLD(__reserved1, NULL)
+};
+
+/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLESTATS */
+static ST_FIELD_INFO    innodb_sys_tablestats_fields_info[] =
+{
+#define SYS_TABLESTATS_ID		0
+	{STRUCT_FLD(field_name,		"TABLE_ID"),
+	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESTATS_NAME		1
+	{STRUCT_FLD(field_name,		"NAME"),
+	 STRUCT_FLD(field_length,	NAME_LEN + 1),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESTATS_INIT		2
+	{STRUCT_FLD(field_name,		"STATS_INITIALIZED"),
+	 STRUCT_FLD(field_length,	NAME_LEN + 1),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESTATS_NROW		3
+	{STRUCT_FLD(field_name,		"NUM_ROWS"),
+	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESTATS_CLUST_SIZE	4
+	{STRUCT_FLD(field_name,		"CLUST_INDEX_SIZE"),
+	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESTATS_INDEX_SIZE	5
+	{STRUCT_FLD(field_name,		"OTHER_INDEX_SIZE"),
+	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESTATS_MODIFIED		6
+	{STRUCT_FLD(field_name,		"MODIFIED_COUNTER"),
+	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESTATS_AUTONINC		7
+	{STRUCT_FLD(field_name,		"AUTOINC"),
+	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESTATS_MYSQL_OPEN_HANDLE	8
+	{STRUCT_FLD(field_name,		"MYSQL_HANDLES_OPENED"),
+	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+	END_OF_ST_FIELD_INFO
+};
+
+/**********************************************************************//**
+Populate information_schema.innodb_sys_tablestats table with information
+from SYS_TABLES.
+@return	0 on success */
+static
+int
+i_s_dict_fill_sys_tablestats(
+/*=========================*/
+	THD*		thd,		/*!< in: thread */
+	dict_table_t*	table,		/*!< in: table */
+	TABLE*		table_to_fill)  /*!< in/out: fill this table */
+{
+	longlong	table_id;
+	Field**		fields;
+
+	DBUG_ENTER("i_s_dict_fill_sys_tablestats");
+
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	fields = table_to_fill->field;
+
+	table_id = ut_conv_dulint_to_longlong(table->id);
+
+	OK(fields[SYS_TABLESTATS_ID]->store(table_id));
+
+	OK(field_store_string(fields[SYS_TABLESTATS_NAME], table->name));
+
+	if (table->stat_initialized) {
+		OK(field_store_string(fields[SYS_TABLESTATS_INIT],
+				      "Initialized"));
+	} else {
+		OK(field_store_string(fields[SYS_TABLESTATS_INIT],
+				      "Uninitialized"));
+	}
+
+	OK(fields[SYS_TABLESTATS_NROW]->store(table->stat_n_rows));
+
+	OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(
+		table->stat_clustered_index_size));
+
+	OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(
+		table->stat_sum_of_other_index_sizes));
+
+	OK(fields[SYS_TABLESTATS_MODIFIED]->store(
+		table->stat_modified_counter));
+
+	OK(fields[SYS_TABLESTATS_AUTONINC]->store(table->autoinc));
+
+	OK(fields[SYS_TABLESTATS_MYSQL_OPEN_HANDLE]->store(
+		table->n_mysql_handles_opened));
+
+	OK(schema_table_store_record(thd, table_to_fill));
+
+	DBUG_RETURN(0);
+}
+/*******************************************************************//**
+Function to go through each record in SYS_TABLES table, and fill the
+information_schema.innodb_sys_tablestats table with table statistics
+related information
+@return 0 on success */
+static
+int
+i_s_sys_tables_fill_table_stats(
+/*============================*/
+	THD*		thd,    /*!< in: thread */
+	TABLE_LIST*	tables, /*!< in/out: tables to fill */
+	COND*		cond)   /*!< in: condition (not used) */
+{
+        btr_pcur_t	pcur;
+	const rec_t*	rec;
+	mem_heap_t*	heap;
+	mtr_t		mtr;
+
+	DBUG_ENTER("i_s_sys_tables_fill_table_stats");
+
+	/* deny access to non-superusers */
+	if (check_global_access(thd, PROCESS_ACL)) {
+
+                DBUG_RETURN(0);
+	}
+
+        heap = mem_heap_create(1000);
+        mutex_enter(&dict_sys->mutex);
+        mtr_start(&mtr);
+
+	rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
+
+	while (rec) {
+		const char*	err_msg;
+		dict_table_t*	table_rec;
+
+		/* Fetch the dict_table_t structure corresponding to
+		this SYS_TABLES record */
+		err_msg = dict_process_sys_tables_rec(
+			heap, rec, &table_rec, DICT_TABLE_LOAD_FROM_CACHE);
+
+		mtr_commit(&mtr);
+		mutex_exit(&dict_sys->mutex);
+
+		if (!err_msg) {
+			i_s_dict_fill_sys_tablestats(thd, table_rec,
+						     tables->table);
+		} else {
+			push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+					    ER_CANT_FIND_SYSTEM_REC,
+					    err_msg);
+		}
+
+		mem_heap_empty(heap);
+
+		/* Get the next record */
+		mutex_enter(&dict_sys->mutex);
+		mtr_start(&mtr);
+		rec = dict_getnext_system(&pcur, &mtr);
+	}
+
+	mtr_commit(&mtr);
+	mutex_exit(&dict_sys->mutex);
+	mem_heap_free(heap);
+
+	DBUG_RETURN(0);
+}
+
+/*******************************************************************//**
+Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_tablestats
+@return 0 on success */
+static
+int
+innodb_sys_tablestats_init(
+/*=======================*/
+        void*   p)      /*!< in/out: table schema object */
+{
+        ST_SCHEMA_TABLE*        schema;
+
+        DBUG_ENTER("innodb_sys_tablestats_init");
+
+        schema = (ST_SCHEMA_TABLE*) p;
+
+        schema->fields_info = innodb_sys_tablestats_fields_info;
+        schema->fill_table = i_s_sys_tables_fill_table_stats;
+
+        DBUG_RETURN(0);
+}
+
+UNIV_INTERN struct st_mysql_plugin	i_s_innodb_sys_tablestats =
+{
+	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
+	/* int */
+	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
+
+	/* pointer to type-specific plugin descriptor */
+	/* void* */
+	STRUCT_FLD(info, &i_s_info),
+
+	/* plugin name */
+	/* const char* */
+	STRUCT_FLD(name, "INNODB_SYS_TABLESTATS"),
+
+	/* plugin author (for SHOW PLUGINS) */
+	/* const char* */
+	STRUCT_FLD(author, plugin_author),
+
+	/* general descriptive text (for SHOW PLUGINS) */
+	/* const char* */
+	STRUCT_FLD(descr, "InnoDB SYS_TABLESTATS"),
+
+	/* the plugin license (PLUGIN_LICENSE_XXX) */
+	/* int */
+	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
+
+	/* the function to invoke when plugin is loaded */
+	/* int (*)(void*); */
+	STRUCT_FLD(init, innodb_sys_tablestats_init),
+
+	/* the function to invoke when plugin is unloaded */
+	/* int (*)(void*); */
+	STRUCT_FLD(deinit, i_s_common_deinit),
+
+	/* plugin version (for SHOW PLUGINS) */
+	/* unsigned int */
+	STRUCT_FLD(version, INNODB_VERSION_SHORT),
+
+	/* struct st_mysql_show_var* */
+	STRUCT_FLD(status_vars, NULL),
+
+	/* struct st_mysql_sys_var** */
+	STRUCT_FLD(system_vars, NULL),
+
+	/* reserved for dependency checking */
+	/* void* */
+	STRUCT_FLD(__reserved1, NULL)
+};
+
+/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_INDEXES */
+static ST_FIELD_INFO    innodb_sysindex_fields_info[] =
+{
+#define SYS_INDEX_ID		0
+	{STRUCT_FLD(field_name,		"INDEX_ID"),
+	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_INDEX_NAME		1
+	{STRUCT_FLD(field_name,		"NAME"),
+	 STRUCT_FLD(field_length,	NAME_LEN + 1),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_INDEX_TABLE_ID	2
+	{STRUCT_FLD(field_name,		"TABLE_ID"),
+	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_INDEX_TYPE		3
+	{STRUCT_FLD(field_name,		"TYPE"),
+	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_INDEX_NUM_FIELDS	4
+	{STRUCT_FLD(field_name,		"N_FIELDS"),
+	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_INDEX_PAGE_NO	5
+	{STRUCT_FLD(field_name,		"PAGE_NO"),
+	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_INDEX_SPACE		6
+	{STRUCT_FLD(field_name,		"SPACE"),
+	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+	END_OF_ST_FIELD_INFO
+};
+
+/**********************************************************************//**
+Function to populate the information_schema.innodb_sys_indexes table with
+collected index information
+@return 0 on success */
+static
+int
+i_s_dict_fill_sys_indexes(
+/*======================*/
+	THD*		thd,		/*!< in: thread */
+	dulint		tableid,	/*!< in: table id */
+	dict_index_t*	index,		/*!< in: populated dict_index_t
+					struct with index info */
+	TABLE*		table_to_fill)  /*!< in/out: fill this table */
+{
+	longlong	table_id;
+	longlong	index_id;
+	Field**		fields;
+
+	DBUG_ENTER("i_s_dict_fill_sys_indexes");
+
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	fields = table_to_fill->field;
+
+	table_id = ut_conv_dulint_to_longlong(tableid);
+	index_id = ut_conv_dulint_to_longlong(index->id);
+
+	OK(fields[SYS_INDEX_ID]->store(index_id));
+
+	OK(field_store_string(fields[SYS_INDEX_NAME], index->name));
+
+	OK(fields[SYS_INDEX_TABLE_ID]->store(table_id));
+
+	OK(fields[SYS_INDEX_TYPE]->store(index->type));
+
+	OK(fields[SYS_INDEX_NUM_FIELDS]->store(index->n_fields));
+
+	OK(fields[SYS_INDEX_PAGE_NO]->store(index->page));
+
+	OK(fields[SYS_INDEX_SPACE]->store(index->space));
+
+	OK(schema_table_store_record(thd, table_to_fill));
+
+	DBUG_RETURN(0);
+}
+/*******************************************************************//**
+Function to go through each record in SYS_INDEXES table, and fill the
+information_schema.innodb_sys_indexes table with related index information
+@return 0 on success */
+static
+int
+i_s_sys_indexes_fill_table(
+/*=======================*/
+	THD*		thd,    /*!< in: thread */
+	TABLE_LIST*	tables, /*!< in/out: tables to fill */
+	COND*		cond)   /*!< in: condition (not used) */
+{
+        btr_pcur_t		pcur;
+	const rec_t*		rec;
+	mem_heap_t*		heap;
+	mtr_t			mtr;
+
+	DBUG_ENTER("i_s_sys_indexes_fill_table");
+
+	/* deny access to non-superusers */
+	if (check_global_access(thd, PROCESS_ACL)) {
+
+                DBUG_RETURN(0);
+	}
+
+        heap = mem_heap_create(1000);
+        mutex_enter(&dict_sys->mutex);
+        mtr_start(&mtr);
+
+	/* Start scan the SYS_INDEXES table */
+	rec = dict_startscan_system(&pcur, &mtr, SYS_INDEXES);
+
+	/* Process each record in the table */
+	while (rec) {
+		const char*	err_msg;;
+		dulint		table_id;
+		dict_index_t	index_rec;
+
+		/* Populate a dict_index_t structure with information from
+		a SYS_INDEXES row */
+		err_msg = dict_process_sys_indexes_rec(heap, rec, &index_rec,
+						       &table_id);
+
+		mtr_commit(&mtr);
+		mutex_exit(&dict_sys->mutex);
+
+		if (!err_msg) {
+			i_s_dict_fill_sys_indexes(thd, table_id, &index_rec,
+						 tables->table);
+		} else {
+			push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+					    ER_CANT_FIND_SYSTEM_REC,
+					    err_msg);
+		}
+
+		mem_heap_empty(heap);
+
+		/* Get the next record */
+		mutex_enter(&dict_sys->mutex);
+		mtr_start(&mtr);
+		rec = dict_getnext_system(&pcur, &mtr);
+	}
+
+	mtr_commit(&mtr);
+	mutex_exit(&dict_sys->mutex);
+	mem_heap_free(heap);
+
+	DBUG_RETURN(0);
+}
+/*******************************************************************//**
+Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_indexes
+@return 0 on success */
+static
+int
+innodb_sys_indexes_init(
+/*====================*/
+        void*   p)      /*!< in/out: table schema object */
+{
+        ST_SCHEMA_TABLE*        schema;
+
+        DBUG_ENTER("innodb_sys_index_init");
+
+        schema = (ST_SCHEMA_TABLE*) p;
+
+        schema->fields_info = innodb_sysindex_fields_info;
+        schema->fill_table = i_s_sys_indexes_fill_table;
+
+        DBUG_RETURN(0);
+}
+
+UNIV_INTERN struct st_mysql_plugin	i_s_innodb_sys_indexes =
+{
+	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
+	/* int */
+	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
+
+	/* pointer to type-specific plugin descriptor */
+	/* void* */
+	STRUCT_FLD(info, &i_s_info),
+
+	/* plugin name */
+	/* const char* */
+	STRUCT_FLD(name, "INNODB_SYS_INDEXES"),
+
+	/* plugin author (for SHOW PLUGINS) */
+	/* const char* */
+	STRUCT_FLD(author, plugin_author),
+
+	/* general descriptive text (for SHOW PLUGINS) */
+	/* const char* */
+	STRUCT_FLD(descr, "InnoDB SYS_INDEXES"),
+
+	/* the plugin license (PLUGIN_LICENSE_XXX) */
+	/* int */
+	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
+
+	/* the function to invoke when plugin is loaded */
+	/* int (*)(void*); */
+	STRUCT_FLD(init, innodb_sys_indexes_init),
+
+	/* the function to invoke when plugin is unloaded */
+	/* int (*)(void*); */
+	STRUCT_FLD(deinit, i_s_common_deinit),
+
+	/* plugin version (for SHOW PLUGINS) */
+	/* unsigned int */
+	STRUCT_FLD(version, INNODB_VERSION_SHORT),
+
+	/* struct st_mysql_show_var* */
+	STRUCT_FLD(status_vars, NULL),
+
+	/* struct st_mysql_sys_var** */
+	STRUCT_FLD(system_vars, NULL),
+
+	/* reserved for dependency checking */
+	/* void* */
+	STRUCT_FLD(__reserved1, NULL)
+};
+
+/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_COLUMNS */
+static ST_FIELD_INFO    innodb_sys_columns_fields_info[] =
+{
+#define SYS_COLUMN_TABLE_ID		0
+	{STRUCT_FLD(field_name,		"TABLE_ID"),
+	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_COLUMN_NAME		1
+	{STRUCT_FLD(field_name,		"NAME"),
+	 STRUCT_FLD(field_length,	NAME_LEN + 1),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_COLUMN_POSITION	2
+	{STRUCT_FLD(field_name,		"POS"),
+	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_COLUMN_MTYPE		3
+	{STRUCT_FLD(field_name,		"MTYPE"),
+	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_COLUMN__PRTYPE	4
+	{STRUCT_FLD(field_name,		"PRTYPE"),
+	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_COLUMN_COLUMN_LEN	5
+	{STRUCT_FLD(field_name,		"LEN"),
+	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+	END_OF_ST_FIELD_INFO
+};
+
+/**********************************************************************//**
+Function to populate the information_schema.innodb_sys_columns with
+related column information
+@return 0 on success */
+static
+int
+i_s_dict_fill_sys_columns(
+/*======================*/
+	THD*		thd,		/*!< in: thread */
+	dulint		tableid,	/*!< in: table ID */
+	const char*	col_name,	/*!< in: column name */
+	dict_col_t*	column,		/*!< in: dict_col_t struct holding
+					more column information */
+	TABLE*		table_to_fill)  /*!< in/out: fill this table */
+{
+	longlong	table_id;
+	Field**		fields;
+
+	DBUG_ENTER("i_s_dict_fill_sys_columns");
+
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	fields = table_to_fill->field;
+
+	table_id = ut_conv_dulint_to_longlong(tableid);
+
+	OK(fields[SYS_COLUMN_TABLE_ID]->store(table_id));
+
+	OK(field_store_string(fields[SYS_COLUMN_NAME], col_name));
+
+	OK(fields[SYS_COLUMN_POSITION]->store(column->ind));
+
+	OK(fields[SYS_COLUMN_MTYPE]->store(column->mtype));
+
+	OK(fields[SYS_COLUMN__PRTYPE]->store(column->prtype));
+
+	OK(fields[SYS_COLUMN_COLUMN_LEN]->store(column->len));
+
+	OK(schema_table_store_record(thd, table_to_fill));
+
+	DBUG_RETURN(0);
+}
+/*******************************************************************//**
+Function to fill information_schema.innodb_sys_columns with information
+collected by scanning SYS_COLUMNS table.
+@return 0 on success */
+static
+int
+i_s_sys_columns_fill_table(
+/*=======================*/
+	THD*		thd,    /*!< in: thread */
+	TABLE_LIST*	tables, /*!< in/out: tables to fill */
+	COND*		cond)   /*!< in: condition (not used) */
+{
+        btr_pcur_t	pcur;
+	const rec_t*	rec;
+	const char*	col_name;
+	mem_heap_t*	heap;
+	mtr_t		mtr;
+
+	DBUG_ENTER("i_s_sys_columns_fill_table");
+
+	/* deny access to non-superusers */
+	if (check_global_access(thd, PROCESS_ACL)) {
+
+                DBUG_RETURN(0);
+	}
+
+        heap = mem_heap_create(1000);
+        mutex_enter(&dict_sys->mutex);
+        mtr_start(&mtr);
+
+	rec = dict_startscan_system(&pcur, &mtr, SYS_COLUMNS);
+
+	while (rec) {
+		const char*	err_msg;
+		dict_col_t	column_rec;
+		dulint		table_id;
+
+		/* populate a dict_col_t structure with information from
+		a SYS_COLUMNS row */
+		err_msg = dict_process_sys_columns_rec(heap, rec, &column_rec,
+						       &table_id, &col_name);
+
+		mtr_commit(&mtr);
+		mutex_exit(&dict_sys->mutex);
+
+		if (!err_msg) {
+			i_s_dict_fill_sys_columns(thd, table_id, col_name,
+						 &column_rec,
+						 tables->table);
+		} else {
+			push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+					    ER_CANT_FIND_SYSTEM_REC,
+					    err_msg);
+		}
+
+		mem_heap_empty(heap);
+
+		/* Get the next record */
+		mutex_enter(&dict_sys->mutex);
+		mtr_start(&mtr);
+		rec = dict_getnext_system(&pcur, &mtr);
+	}
+
+	mtr_commit(&mtr);
+	mutex_exit(&dict_sys->mutex);
+	mem_heap_free(heap);
+
+	DBUG_RETURN(0);
+}
+/*******************************************************************//**
+Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_columns
+@return 0 on success */
+static
+int
+innodb_sys_columns_init(
+/*====================*/
+        void*   p)      /*!< in/out: table schema object */
+{
+        ST_SCHEMA_TABLE*        schema;
+
+        DBUG_ENTER("innodb_sys_columns_init");
+
+        schema = (ST_SCHEMA_TABLE*) p;
+
+        schema->fields_info = innodb_sys_columns_fields_info;
+        schema->fill_table = i_s_sys_columns_fill_table;
+
+        DBUG_RETURN(0);
+}
+
+UNIV_INTERN struct st_mysql_plugin	i_s_innodb_sys_columns =
+{
+	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
+	/* int */
+	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
+
+	/* pointer to type-specific plugin descriptor */
+	/* void* */
+	STRUCT_FLD(info, &i_s_info),
+
+	/* plugin name */
+	/* const char* */
+	STRUCT_FLD(name, "INNODB_SYS_COLUMNS"),
+
+	/* plugin author (for SHOW PLUGINS) */
+	/* const char* */
+	STRUCT_FLD(author, plugin_author),
+
+	/* general descriptive text (for SHOW PLUGINS) */
+	/* const char* */
+	STRUCT_FLD(descr, "InnoDB SYS_COLUMNS"),
+
+	/* the plugin license (PLUGIN_LICENSE_XXX) */
+	/* int */
+	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
+
+	/* the function to invoke when plugin is loaded */
+	/* int (*)(void*); */
+	STRUCT_FLD(init, innodb_sys_columns_init),
+
+	/* the function to invoke when plugin is unloaded */
+	/* int (*)(void*); */
+	STRUCT_FLD(deinit, i_s_common_deinit),
+
+	/* plugin version (for SHOW PLUGINS) */
+	/* unsigned int */
+	STRUCT_FLD(version, INNODB_VERSION_SHORT),
+
+	/* struct st_mysql_show_var* */
+	STRUCT_FLD(status_vars, NULL),
+
+	/* struct st_mysql_sys_var** */
+	STRUCT_FLD(system_vars, NULL),
+
+	/* reserved for dependency checking */
+	/* void* */
+	STRUCT_FLD(__reserved1, NULL)
+};
+/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_fields */
+static ST_FIELD_INFO    innodb_sys_fields_fields_info[] =
+{
+#define SYS_FIELD_INDEX_ID	0
+	{STRUCT_FLD(field_name,		"INDEX_ID"),
+	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_FIELD_NAME		1
+	{STRUCT_FLD(field_name,		"NAME"),
+	 STRUCT_FLD(field_length,	NAME_LEN + 1),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_FIELD_POS		2
+	{STRUCT_FLD(field_name,		"POS"),
+	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+	END_OF_ST_FIELD_INFO
+};
+
+/**********************************************************************//**
+Function to fill information_schema.innodb_sys_fields with information
+collected by scanning SYS_FIELDS table.
+@return 0 on success */
+static
+int
+i_s_dict_fill_sys_fields(
+/*=====================*/
+	THD*		thd,		/*!< in: thread */
+	dulint		indexid,	/*!< in: index id for the field */
+	dict_field_t*	field,		/*!< in: table */
+	ulint		pos,		/*!< in: Field position */
+	TABLE*		table_to_fill)  /*!< in/out: fill this table */
+{
+	longlong	index_id;
+	Field**		fields;
+
+	DBUG_ENTER("i_s_dict_fill_sys_fields");
+
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	fields = table_to_fill->field;
+
+	index_id = ut_conv_dulint_to_longlong(indexid);
+
+	OK(fields[SYS_FIELD_INDEX_ID]->store(index_id));
+
+	OK(field_store_string(fields[SYS_FIELD_NAME], field->name));
+
+	OK(fields[SYS_FIELD_POS]->store(pos));
+
+	OK(schema_table_store_record(thd, table_to_fill));
+
+	DBUG_RETURN(0);
+}
+/*******************************************************************//**
+Function to go through each record in SYS_FIELDS table, and fill the
+information_schema.innodb_sys_fields table with related index field
+information
+@return 0 on success */
+static
+int
+i_s_sys_fields_fill_table(
+/*======================*/
+	THD*		thd,    /*!< in: thread */
+	TABLE_LIST*	tables, /*!< in/out: tables to fill */
+	COND*		cond)   /*!< in: condition (not used) */
+{
+        btr_pcur_t	pcur;
+	const rec_t*	rec;
+	mem_heap_t*	heap;
+	dulint		last_id;
+	mtr_t		mtr;
+
+	DBUG_ENTER("i_s_sys_fields_fill_table");
+
+	/* deny access to non-superusers */
+	if (check_global_access(thd, PROCESS_ACL)) {
+
+                DBUG_RETURN(0);
+	}
+
+        heap = mem_heap_create(1000);
+        mutex_enter(&dict_sys->mutex);
+        mtr_start(&mtr);
+
+	/* will save last index id so that we know whether we move to
+	the next index. This is used to calculate prefix length */
+	last_id = ut_dulint_create(0, 0);
+
+	rec = dict_startscan_system(&pcur, &mtr, SYS_FIELDS);
+
+	while (rec) {
+		ulint		pos;
+		const char*	err_msg;
+		dulint		index_id;
+		dict_field_t	field_rec;
+
+		/* Populate a dict_field_t structure with information from
+		a SYS_FIELDS row */
+		err_msg = dict_process_sys_fields_rec(heap, rec, &field_rec,
+						      &pos, &index_id, last_id);
+
+		mtr_commit(&mtr);
+		mutex_exit(&dict_sys->mutex);
+
+		if (!err_msg) {
+			i_s_dict_fill_sys_fields(thd, index_id, &field_rec,
+						 pos, tables->table);
+			last_id = index_id;
+		} else {
+			push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+					    ER_CANT_FIND_SYSTEM_REC,
+					    err_msg);
+		}
+
+		mem_heap_empty(heap);
+
+		/* Get the next record */
+		mutex_enter(&dict_sys->mutex);
+		mtr_start(&mtr);
+		rec = dict_getnext_system(&pcur, &mtr);
+	}
+
+	mtr_commit(&mtr);
+	mutex_exit(&dict_sys->mutex);
+	mem_heap_free(heap);
+
+	DBUG_RETURN(0);
+}
+/*******************************************************************//**
+Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_fields
+@return 0 on success */
+static
+int
+innodb_sys_fields_init(
+/*===================*/
+        void*   p)      /*!< in/out: table schema object */
+{
+        ST_SCHEMA_TABLE*        schema;
+
+        DBUG_ENTER("innodb_sys_field_init");
+
+        schema = (ST_SCHEMA_TABLE*) p;
+
+        schema->fields_info = innodb_sys_fields_fields_info;
+        schema->fill_table = i_s_sys_fields_fill_table;
+
+        DBUG_RETURN(0);
+}
+
+UNIV_INTERN struct st_mysql_plugin	i_s_innodb_sys_fields =
+{
+	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
+	/* int */
+	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
+
+	/* pointer to type-specific plugin descriptor */
+	/* void* */
+	STRUCT_FLD(info, &i_s_info),
+
+	/* plugin name */
+	/* const char* */
+	STRUCT_FLD(name, "INNODB_SYS_FIELDS"),
+
+	/* plugin author (for SHOW PLUGINS) */
+	/* const char* */
+	STRUCT_FLD(author, plugin_author),
+
+	/* general descriptive text (for SHOW PLUGINS) */
+	/* const char* */
+	STRUCT_FLD(descr, "InnoDB SYS_FIELDS"),
+
+	/* the plugin license (PLUGIN_LICENSE_XXX) */
+	/* int */
+	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
+
+	/* the function to invoke when plugin is loaded */
+	/* int (*)(void*); */
+	STRUCT_FLD(init, innodb_sys_fields_init),
+
+	/* the function to invoke when plugin is unloaded */
+	/* int (*)(void*); */
+	STRUCT_FLD(deinit, i_s_common_deinit),
+
+	/* plugin version (for SHOW PLUGINS) */
+	/* unsigned int */
+	STRUCT_FLD(version, INNODB_VERSION_SHORT),
+
+	/* struct st_mysql_show_var* */
+	STRUCT_FLD(status_vars, NULL),
+
+	/* struct st_mysql_sys_var** */
+	STRUCT_FLD(system_vars, NULL),
+
+	/* reserved for dependency checking */
+	/* void* */
+	STRUCT_FLD(__reserved1, NULL)
+};
+
+/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign */
+static ST_FIELD_INFO    innodb_sys_foreign_fields_info[] =
+{
+#define SYS_FOREIGN_ID		0
+	{STRUCT_FLD(field_name,		"ID"),
+	 STRUCT_FLD(field_length,	NAME_LEN + 1),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_FOREIGN_FOR_NAME	1
+	{STRUCT_FLD(field_name,		"FOR_NAME"),
+	 STRUCT_FLD(field_length,	NAME_LEN + 1),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_FOREIGN_REF_NAME	2
+	{STRUCT_FLD(field_name,		"REF_NAME"),
+	 STRUCT_FLD(field_length,	NAME_LEN + 1),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_FOREIGN_NUM_COL	3
+	{STRUCT_FLD(field_name,		"N_COLS"),
+	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_FOREIGN_TYPE	4
+	{STRUCT_FLD(field_name,		"TYPE"),
+	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+	END_OF_ST_FIELD_INFO
+};
+
+/**********************************************************************//**
+Function to fill information_schema.innodb_sys_foreign with information
+collected by scanning SYS_FOREIGN table.
+@return 0 on success */
+static
+int
+i_s_dict_fill_sys_foreign(
+/*======================*/
+	THD*		thd,		/*!< in: thread */
+	dict_foreign_t*	foreign,	/*!< in: table */
+	TABLE*		table_to_fill)  /*!< in/out: fill this table */
+{
+	Field**		fields;
+
+	DBUG_ENTER("i_s_dict_fill_sys_foreign");
+
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	fields = table_to_fill->field;
+
+	OK(field_store_string(fields[SYS_FOREIGN_ID], foreign->id));
+
+	OK(field_store_string(fields[SYS_FOREIGN_FOR_NAME],
+			      foreign->foreign_table_name));
+
+	OK(field_store_string(fields[SYS_FOREIGN_REF_NAME],
+			      foreign->referenced_table_name));
+
+	OK(fields[SYS_FOREIGN_NUM_COL]->store(foreign->n_fields));
+
+	OK(fields[SYS_FOREIGN_TYPE]->store(foreign->type));
+
+	OK(schema_table_store_record(thd, table_to_fill));
+
+	DBUG_RETURN(0);
+}
+/*******************************************************************//**
+Function to populate INFORMATION_SCHEMA.innodb_sys_foreign table. Loop
+through each record in SYS_FOREIGN, and extract the foreign key
+information.
+@return 0 on success */
+static
+int
+i_s_sys_foreign_fill_table(
+/*=======================*/
+	THD*		thd,    /*!< in: thread */
+	TABLE_LIST*	tables, /*!< in/out: tables to fill */
+	COND*		cond)   /*!< in: condition (not used) */
+{
+        btr_pcur_t	pcur;
+	const rec_t*	rec;
+	mem_heap_t*	heap;
+	mtr_t		mtr;
+
+	DBUG_ENTER("i_s_sys_foreign_fill_table");
+
+	/* deny access to non-superusers */
+	if (check_global_access(thd, PROCESS_ACL)) {
+
+                DBUG_RETURN(0);
+	}
+
+        heap = mem_heap_create(1000);
+        mutex_enter(&dict_sys->mutex);
+        mtr_start(&mtr);
+
+	rec = dict_startscan_system(&pcur, &mtr, SYS_FOREIGN);
+
+	while (rec) {
+		const char*	err_msg;
+		dict_foreign_t	foreign_rec;
+
+		/* Populate a dict_foreign_t structure with information from
+		a SYS_FOREIGN row */
+		err_msg = dict_process_sys_foreign_rec(heap, rec, &foreign_rec);
+
+		mtr_commit(&mtr);
+		mutex_exit(&dict_sys->mutex);
+
+		if (!err_msg) {
+			i_s_dict_fill_sys_foreign(thd, &foreign_rec,
+						 tables->table);
+		} else {
+			push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+					    ER_CANT_FIND_SYSTEM_REC,
+					    err_msg);
+		}
+
+		mem_heap_empty(heap);
+
+		/* Get the next record */
+		mtr_start(&mtr);
+		mutex_enter(&dict_sys->mutex);
+		rec = dict_getnext_system(&pcur, &mtr);
+	}
+
+	mtr_commit(&mtr);
+	mutex_exit(&dict_sys->mutex);
+	mem_heap_free(heap);
+
+	DBUG_RETURN(0);
+}
+/*******************************************************************//**
+Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign
+@return 0 on success */
+static
+int
+innodb_sys_foreign_init(
+/*====================*/
+        void*   p)      /*!< in/out: table schema object */
+{
+        ST_SCHEMA_TABLE*        schema;
+
+        DBUG_ENTER("innodb_sys_foreign_init");
+
+        schema = (ST_SCHEMA_TABLE*) p;
+
+        schema->fields_info = innodb_sys_foreign_fields_info;
+        schema->fill_table = i_s_sys_foreign_fill_table;
+
+        DBUG_RETURN(0);
+}
+
+UNIV_INTERN struct st_mysql_plugin	i_s_innodb_sys_foreign =
+{
+	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
+	/* int */
+	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
+
+	/* pointer to type-specific plugin descriptor */
+	/* void* */
+	STRUCT_FLD(info, &i_s_info),
+
+	/* plugin name */
+	/* const char* */
+	STRUCT_FLD(name, "INNODB_SYS_FOREIGN"),
+
+	/* plugin author (for SHOW PLUGINS) */
+	/* const char* */
+	STRUCT_FLD(author, plugin_author),
+
+	/* general descriptive text (for SHOW PLUGINS) */
+	/* const char* */
+	STRUCT_FLD(descr, "InnoDB SYS_FOREIGN"),
+
+	/* the plugin license (PLUGIN_LICENSE_XXX) */
+	/* int */
+	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
+
+	/* the function to invoke when plugin is loaded */
+	/* int (*)(void*); */
+	STRUCT_FLD(init, innodb_sys_foreign_init),
+
+	/* the function to invoke when plugin is unloaded */
+	/* int (*)(void*); */
+	STRUCT_FLD(deinit, i_s_common_deinit),
+
+	/* plugin version (for SHOW PLUGINS) */
+	/* unsigned int */
+	STRUCT_FLD(version, INNODB_VERSION_SHORT),
+
+	/* struct st_mysql_show_var* */
+	STRUCT_FLD(status_vars, NULL),
+
+	/* struct st_mysql_sys_var** */
+	STRUCT_FLD(system_vars, NULL),
+
+	/* reserved for dependency checking */
+	/* void* */
+	STRUCT_FLD(__reserved1, NULL)
+};
+/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign_cols */
+static ST_FIELD_INFO    innodb_sys_foreign_cols_fields_info[] =
+{
+#define SYS_FOREIGN_COL_ID		0
+	{STRUCT_FLD(field_name,		"ID"),
+	 STRUCT_FLD(field_length,	NAME_LEN + 1),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_FOREIGN_COL_FOR_NAME	1
+	{STRUCT_FLD(field_name,		"FOR_COL_NAME"),
+	 STRUCT_FLD(field_length,	NAME_LEN + 1),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_FOREIGN_COL_REF_NAME	2
+	{STRUCT_FLD(field_name,		"REF_COL_NAME"),
+	 STRUCT_FLD(field_length,	NAME_LEN + 1),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	0),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_FOREIGN_COL_POS		3
+	{STRUCT_FLD(field_name,		"POS"),
+	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+	END_OF_ST_FIELD_INFO
+};
+
+/**********************************************************************//**
+Function to fill information_schema.innodb_sys_foreign_cols with information
+collected by scanning SYS_FOREIGN_COLS table.
+@return 0 on success */
+static
+int
+i_s_dict_fill_sys_foreign_cols(
+/*==========================*/
+	THD*		thd,		/*!< in: thread */
+	const char*	name,		/*!< in: foreign key constraint name */
+	const char*	for_col_name,	/*!< in: referencing column name*/
+	const char*	ref_col_name,	/*!< in: referenced column
+					name */
+	ulint		pos,		/*!< in: column position */
+	TABLE*		table_to_fill)  /*!< in/out: fill this table */
+{
+	Field**		fields;
+
+	DBUG_ENTER("i_s_dict_fill_sys_foreign_cols");
+
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	fields = table_to_fill->field;
+
+	OK(field_store_string(fields[SYS_FOREIGN_COL_ID], name));
+
+	OK(field_store_string(fields[SYS_FOREIGN_COL_FOR_NAME], for_col_name));
+
+	OK(field_store_string(fields[SYS_FOREIGN_COL_REF_NAME], ref_col_name));
+
+	OK(fields[SYS_FOREIGN_COL_POS]->store(pos));
+
+	OK(schema_table_store_record(thd, table_to_fill));
+
+	DBUG_RETURN(0);
+}
+/*******************************************************************//**
+Function to populate INFORMATION_SCHEMA.innodb_sys_foreign_cols table. Loop
+through each record in SYS_FOREIGN_COLS, and extract the foreign key column
+information and fill the INFORMATION_SCHEMA.innodb_sys_foreign_cols table.
+@return 0 on success */
+static
+int
+i_s_sys_foreign_cols_fill_table(
+/*============================*/
+	THD*		thd,    /*!< in: thread */
+	TABLE_LIST*	tables, /*!< in/out: tables to fill */
+	COND*		cond)   /*!< in: condition (not used) */
+{
+        btr_pcur_t	pcur;
+	const rec_t*	rec;
+	mem_heap_t*	heap;
+	mtr_t		mtr;
+
+	DBUG_ENTER("i_s_sys_foreign_cols_fill_table");
+
+	/* deny access to non-superusers */
+	if (check_global_access(thd, PROCESS_ACL)) {
+                DBUG_RETURN(0);
+	}
+
+        heap = mem_heap_create(1000);
+        mutex_enter(&dict_sys->mutex);
+        mtr_start(&mtr);
+
+	rec = dict_startscan_system(&pcur, &mtr, SYS_FOREIGN_COLS);
+
+	while (rec) {
+		const char*	err_msg;
+		const char*	name;
+		const char*	for_col_name;
+		const char*	ref_col_name;
+		ulint		pos;
+
+		/* Extract necessary information from a SYS_FOREIGN_COLS row */
+		err_msg = dict_process_sys_foreign_col_rec(
+			heap, rec, &name, &for_col_name, &ref_col_name, &pos);
+
+		mtr_commit(&mtr);
+		mutex_exit(&dict_sys->mutex);
+
+		if (!err_msg) {
+			i_s_dict_fill_sys_foreign_cols(
+				thd, name, for_col_name, ref_col_name, pos,
+				tables->table);
+		} else {
+			push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+					    ER_CANT_FIND_SYSTEM_REC,
+					    err_msg);
+		}
+
+		mem_heap_empty(heap);
+
+		/* Get the next record */
+		mutex_enter(&dict_sys->mutex);
+		mtr_start(&mtr);
+		rec = dict_getnext_system(&pcur, &mtr);
+	}
+
+	mtr_commit(&mtr);
+	mutex_exit(&dict_sys->mutex);
+	mem_heap_free(heap);
+
+	DBUG_RETURN(0);
+}
+/*******************************************************************//**
+Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign_cols
+@return 0 on success */
+static
+int
+innodb_sys_foreign_cols_init(
+/*========================*/
+        void*   p)      /*!< in/out: table schema object */
+{
+        ST_SCHEMA_TABLE*        schema;
+
+        DBUG_ENTER("innodb_sys_foreign_cols_init");
+
+        schema = (ST_SCHEMA_TABLE*) p;
+
+        schema->fields_info = innodb_sys_foreign_cols_fields_info;
+        schema->fill_table = i_s_sys_foreign_cols_fill_table;
+
+        DBUG_RETURN(0);
+}
+
+UNIV_INTERN struct st_mysql_plugin	i_s_innodb_sys_foreign_cols =
+{
+	/* the plugin type (a MYSQL_XXX_PLUGIN value) */
+	/* int */
+	STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
+
+	/* pointer to type-specific plugin descriptor */
+	/* void* */
+	STRUCT_FLD(info, &i_s_info),
+
+	/* plugin name */
+	/* const char* */
+	STRUCT_FLD(name, "INNODB_SYS_FOREIGN_COLS"),
+
+	/* plugin author (for SHOW PLUGINS) */
+	/* const char* */
+	STRUCT_FLD(author, plugin_author),
+
+	/* general descriptive text (for SHOW PLUGINS) */
+	/* const char* */
+	STRUCT_FLD(descr, "InnoDB SYS_FOREIGN_COLS"),
+
+	/* the plugin license (PLUGIN_LICENSE_XXX) */
+	/* int */
+	STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
+
+	/* the function to invoke when plugin is loaded */
+	/* int (*)(void*); */
+	STRUCT_FLD(init, innodb_sys_foreign_cols_init),
+
+	/* the function to invoke when plugin is unloaded */
+	/* int (*)(void*); */
+	STRUCT_FLD(deinit, i_s_common_deinit),
+
+	/* plugin version (for SHOW PLUGINS) */
+	/* unsigned int */
+	STRUCT_FLD(version, INNODB_VERSION_SHORT),
+
+	/* struct st_mysql_show_var* */
+	STRUCT_FLD(status_vars, NULL),
+
+	/* struct st_mysql_sys_var** */
+	STRUCT_FLD(system_vars, NULL),
+
+	/* reserved for dependency checking */
+	/* void* */
+	STRUCT_FLD(__reserved1, NULL)
+};
+

=== modified file 'storage/innobase/handler/i_s.h'
--- a/storage/innobase/handler/i_s.h	revid:vasil.dimov@stripped
+++ b/storage/innobase/handler/i_s.h	revid:jimmy.yang@stripped
@@ -33,5 +33,12 @@ extern struct st_mysql_plugin	i_s_innodb
 extern struct st_mysql_plugin	i_s_innodb_cmp_reset;
 extern struct st_mysql_plugin	i_s_innodb_cmpmem;
 extern struct st_mysql_plugin	i_s_innodb_cmpmem_reset;
+extern struct st_mysql_plugin	i_s_innodb_sys_tables;
+extern struct st_mysql_plugin	i_s_innodb_sys_tablestats;
+extern struct st_mysql_plugin	i_s_innodb_sys_indexes;
+extern struct st_mysql_plugin   i_s_innodb_sys_columns;
+extern struct st_mysql_plugin   i_s_innodb_sys_fields;
+extern struct st_mysql_plugin   i_s_innodb_sys_foreign;
+extern struct st_mysql_plugin   i_s_innodb_sys_foreign_cols;
 
 #endif /* i_s_h */

=== modified file 'storage/innobase/include/dict0dict.ic'
--- a/storage/innobase/include/dict0dict.ic	revid:vasil.dimov@stripped
+++ b/storage/innobase/include/dict0dict.ic	revid:jimmy.yang@stripped
@@ -765,7 +765,7 @@ dict_table_get_low(
 	table = dict_table_check_if_in_cache_low(table_name);
 
 	if (table == NULL) {
-		table = dict_load_table(table_name);
+		table = dict_load_table(table_name, TRUE);
 	}
 
 	ut_ad(!table || table->cached);

=== modified file 'storage/innobase/include/dict0load.h'
--- a/storage/innobase/include/dict0load.h	revid:vasil.dimov@stripped
+++ b/storage/innobase/include/dict0load.h	revid:jimmy.yang@stripped
@@ -31,6 +31,35 @@ Created 4/24/1996 Heikki Tuuri
 #include "dict0types.h"
 #include "ut0byte.h"
 #include "mem0mem.h"
+#include "btr0types.h"
+
+/** enum that defines all 6 system table IDs */
+enum dict_system_table_id {
+	SYS_TABLES = 0,
+	SYS_INDEXES,
+	SYS_COLUMNS,
+	SYS_FIELDS,
+	SYS_FOREIGN,
+	SYS_FOREIGN_COLS,
+
+	/* This must be last item. Defines the number of system tables. */
+	SYS_NUM_SYSTEM_TABLES
+};
+
+typedef enum dict_system_table_id	dict_system_id_t;
+
+/** Status bit for dict_process_sys_tables_rec() */
+enum dict_table_info {
+	DICT_TABLE_LOAD_FROM_RECORD = 0,/*!< Directly populate a dict_table_t
+					structure with information from
+					a SYS_TABLES record */
+	DICT_TABLE_LOAD_FROM_CACHE = 1,	/*!< Check first whether dict_table_t
+					is in the cache, if so, return it */
+	DICT_TABLE_UPDATE_STATS = 2	/*!< whether to update statistics
+					when loading SYS_TABLES information. */
+};
+
+typedef enum dict_table_info	dict_table_info_t;
 
 /********************************************************************//**
 In a crash recovery we already have all the tablespace objects created.
@@ -54,6 +83,74 @@ char*
 dict_get_first_table_name_in_db(
 /*============================*/
 	const char*	name);	/*!< in: database name which ends to '/' */
+
+/********************************************************************//**
+Loads a table definition from a SYS_TABLES record to dict_table_t.
+Does not load any columns or indexes.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_load_table_low(
+/*================*/
+	const char*	name,		/*!< in: table name */
+	const rec_t*	rec,		/*!< in: SYS_TABLES record */
+	dict_table_t**	table);		/*!< out,own: table, or NULL */
+/********************************************************************//**
+Loads a table column definition from a SYS_COLUMNS record to
+dict_table_t.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_load_column_low(
+/*=================*/
+	dict_table_t*	table,		/*!< in/out: table, could be NULL
+					if we just populate a dict_column_t
+					struct with information from
+					a SYS_COLUMNS record */
+	mem_heap_t*	heap,		/*!< in/out: memory heap
+					for temporary storage */
+	dict_col_t*	column,		/*!< out: dict_column_t to fill */
+	dulint*		table_id,	/*!< out: table id */
+	const char**	col_name,	/*!< out: column name */
+	const rec_t*	rec);		/*!< in: SYS_COLUMNS record */
+/********************************************************************//**
+Loads an index definition from a SYS_INDEXES record to dict_index_t.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_load_index_low(
+/*================*/
+	byte*		table_id,	/*!< in/out: table id (8 bytes_,
+					an "in" value if cached=TRUE
+					and "out" when cached=FALSE */
+	const char*	table_name,	/*!< in: table name */
+	mem_heap_t*	heap,		/*!< in/out: temporary memory heap */
+	const rec_t*	rec,		/*!< in: SYS_INDEXES record */
+	ibool		cached,		/*!< in: TRUE = add to cache
+					FALSE = do not */
+	dict_index_t**	index);		/*!< out,own: index, or NULL */
+/********************************************************************//**
+Loads an index field definition from a SYS_FIELDS record to
+dict_index_t.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_load_field_low(
+/*================*/
+	byte*		index_id,	/*!< in/out: index id (8 bytes)
+					an "in" value if index != NULL
+					and "out" if index == NULL */
+	dict_index_t*	index,		/*!< in/out: index, could be NULL
+					if we just populate a dict_field_t
+					struct with information from
+					a SYS_FIELDS record */
+	dict_field_t*	sys_field,	/*!< out: dict_field_t to be
+					filled */
+	ulint*		pos,		/*!< out: Field position */
+	byte*		last_index_id,	/*!< in: last index id */
+	mem_heap_t*	heap,		/*!< in/out: memory heap
+					for temporary storage */
+	const rec_t*	rec);		/*!< in: SYS_FIELDS record */
 /********************************************************************//**
 Loads a table definition and also all its index definitions, and also
 the cluster definition if the table is a member in a cluster. Also loads
@@ -66,8 +163,9 @@ UNIV_INTERN
 dict_table_t*
 dict_load_table(
 /*============*/
-	const char*	name);	/*!< in: table name in the
+	const char*	name,	/*!< in: table name in the
 				databasename/tablename format */
+	ibool		cached);/*!< in: TRUE=add to cache, FALSE=do not */
 /***********************************************************************//**
 Loads a table object based on the table id.
 @return	table; NULL if table does not exist */
@@ -107,7 +205,113 @@ void
 dict_print(void);
 /*============*/
 
-
+/********************************************************************//**
+This function opens a system table, and return the first record.
+@return	first record of the system table */
+UNIV_INTERN
+const rec_t*
+dict_startscan_system(
+/*==================*/
+	btr_pcur_t*	pcur,		/*!< out: persistent cursor to
+					the record */
+	mtr_t*		mtr,		/*!< in: the mini-transaction */
+	dict_system_id_t system_id);	/*!< in: which system table to open */
+/********************************************************************//**
+This function get the next system table record as we scan the table.
+@return	the record if found, NULL if end of scan. */
+UNIV_INTERN
+const rec_t*
+dict_getnext_system(
+/*================*/
+	btr_pcur_t*	pcur,		/*!< in/out: persistent cursor
+					to the record */
+	mtr_t*		mtr);		/*!< in: the mini-transaction */
+/********************************************************************//**
+This function processes one SYS_TABLES record and populate the dict_table_t
+struct for the table. Extracted out of dict_print() to be used by
+both monitor table output and information schema innodb_sys_tables output.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_tables_rec(
+/*========================*/
+	mem_heap_t*	heap,		/*!< in: temporary memory heap */
+	const rec_t*	rec,		/*!< in: SYS_TABLES record */
+	dict_table_t**	table,		/*!< out: dict_table_t to fill */
+	dict_table_info_t status);	/*!< in: status bit controls
+					options such as whether we shall
+					look for dict_table_t from cache
+					first */
+/********************************************************************//**
+This function parses a SYS_INDEXES record and populate a dict_index_t
+structure with the information from the record. For detail information
+about SYS_INDEXES fields, please refer to dict_boot() function.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_indexes_rec(
+/*=========================*/
+	mem_heap_t*	heap,		/*!< in/out: heap memory */
+	const rec_t*	rec,		/*!< in: current SYS_INDEXES rec */
+	dict_index_t*	index,		/*!< out: dict_index_t to be
+					filled */
+	dulint*		table_id);	/*!< out: table id */
+/********************************************************************//**
+This function parses a SYS_COLUMNS record and populate a dict_column_t
+structure with the information from the record.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_columns_rec(
+/*=========================*/
+	mem_heap_t*	heap,		/*!< in/out: heap memory */
+	const rec_t*	rec,		/*!< in: current SYS_COLUMNS rec */
+	dict_col_t*	column,		/*!< out: dict_col_t to be filled */
+	dulint*		table_id,	/*!< out: table id */
+	const char**	col_name);	/*!< out: column name */
+/********************************************************************//**
+This function parses a SYS_FIELDS record and populate a dict_field_t
+structure with the information from the record.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_fields_rec(
+/*========================*/
+	mem_heap_t*	heap,		/*!< in/out: heap memory */
+	const rec_t*	rec,		/*!< in: current SYS_FIELDS rec */
+	dict_field_t*	sys_field,	/*!< out: dict_field_t to be
+					filled */
+	ulint*		pos,		/*!< out: Field position */
+	dulint*		index_id,	/*!< out: current index id */
+	dulint		last_id);	/*!< in: previous index id */
+/********************************************************************//**
+This function parses a SYS_FOREIGN record and populate a dict_foreign_t
+structure with the information from the record. For detail information
+about SYS_FOREIGN fields, please refer to dict_load_foreign() function
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_foreign_rec(
+/*=========================*/
+	mem_heap_t*	heap,		/*!< in/out: heap memory */
+	const rec_t*	rec,		/*!< in: current SYS_FOREIGN rec */
+	dict_foreign_t*	foreign);	/*!< out: dict_foreign_t to be
+					filled */
+/********************************************************************//**
+This function parses a SYS_FOREIGN_COLS record and extract necessary
+information from the record and return to caller.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_foreign_col_rec(
+/*=============================*/
+	mem_heap_t*	heap,		/*!< in/out: heap memory */
+	const rec_t*	rec,		/*!< in: current SYS_FOREIGN_COLS rec */
+	const char**	name,		/*!< out: foreign key constraint name */
+	const char**	for_col_name,	/*!< out: referencing column name */
+	const char**	ref_col_name,	/*!< out: referenced column name
+					in referenced table */
+	ulint*		pos);		/*!< out: column position */
 #ifndef UNIV_NONINL
 #include "dict0load.ic"
 #endif

=== modified file 'storage/innobase/include/dict0mem.h'
--- a/storage/innobase/include/dict0mem.h	revid:vasil.dimov@stripped
+++ b/storage/innobase/include/dict0mem.h	revid:jimmy.yang@stripped
@@ -147,6 +147,36 @@ dict_mem_table_add_col(
 	ulint		prtype,	/*!< in: precise type */
 	ulint		len);	/*!< in: precision */
 /**********************************************************************//**
+This function poplulates a dict_col_t memory structure with
+supplied information. */
+UNIV_INLINE
+void
+dict_mem_fill_column_struct(
+/*========================*/
+	dict_col_t*	column,		/*!< out: column struct to be
+					filled */
+	ulint		col_pos,	/*!< in: column position */
+	ulint		mtype,		/*!< in: main data type */
+	ulint		prtype,		/*!< in: precise type */
+	ulint		col_len);	/*!< in: column lenght */
+/**********************************************************************//**
+This function poplulates a dict_index_t index memory structure with
+supplied information. */
+UNIV_INLINE
+void
+dict_mem_fill_index_struct(
+/*=======================*/
+	dict_index_t*	index,		/*!< out: index to be filled */
+	mem_heap_t*	heap,		/*!< in: memory heap */
+	const char*	table_name,	/*!< in: table name */
+	const char*	index_name,	/*!< in: index name */
+	ulint		space,		/*!< in: space where the index tree is
+					placed, ignored if the index is of
+					the clustered type */
+	ulint		type,		/*!< in: DICT_UNIQUE,
+					DICT_CLUSTERED, ... ORed */
+	ulint		n_fields);	/*!< in: number of fields */
+/**********************************************************************//**
 Creates an index memory object.
 @return	own: index object */
 UNIV_INTERN

=== modified file 'storage/innobase/include/dict0mem.ic'
--- a/storage/innobase/include/dict0mem.ic	revid:vasil.dimov@stripped
+++ b/storage/innobase/include/dict0mem.ic	revid:jimmy.yang@stripped
@@ -23,4 +23,82 @@ Data dictionary memory object creation
 Created 1/8/1996 Heikki Tuuri
 ***********************************************************************/
 
+#include "data0type.h"
+#include "dict0mem.h"
+#include "fil0fil.h"
 
+/**********************************************************************//**
+This function poplulates a dict_index_t index memory structure with
+supplied information. */
+UNIV_INLINE
+void
+dict_mem_fill_index_struct(
+/*=======================*/
+	dict_index_t*	index,		/*!< out: index to be filled */
+	mem_heap_t*	heap,		/*!< in: memory heap */
+	const char*	table_name,	/*!< in: table name */
+	const char*	index_name,	/*!< in: index name */
+	ulint		space,		/*!< in: space where the index tree is
+					placed, ignored if the index is of
+					the clustered type */
+	ulint		type,		/*!< in: DICT_UNIQUE,
+					DICT_CLUSTERED, ... ORed */
+	ulint		n_fields)	/*!< in: number of fields */
+{
+
+	if (heap) {
+		index->heap = heap;
+		index->name = mem_heap_strdup(heap, index_name);
+		index->fields = (dict_field_t*) mem_heap_alloc(
+			heap, 1 + n_fields * sizeof(dict_field_t));
+	} else {
+		index->name = index_name;
+		index->heap = NULL;
+		index->fields = NULL;
+	}
+
+        index->type = type;
+#ifndef UNIV_HOTBACKUP
+        index->space = (unsigned int) space;
+        index->page = FIL_NULL;
+#endif /* !UNIV_HOTBACKUP */
+        index->table_name = table_name;
+        index->n_fields = (unsigned int) n_fields;
+        /* The '1 +' above prevents allocation
+        of an empty mem block */
+#ifdef UNIV_DEBUG
+        index->magic_n = DICT_INDEX_MAGIC_N;
+#endif /* UNIV_DEBUG */
+}
+
+/**********************************************************************//**
+This function poplulates a dict_col_t memory structure with
+supplied information. */
+UNIV_INLINE
+void
+dict_mem_fill_column_struct(
+/*========================*/
+	dict_col_t*	column,		/*!< out: column struct to be
+					filled */
+	ulint		col_pos,	/*!< in: column position */
+	ulint		mtype,		/*!< in: main data type */
+	ulint		prtype,		/*!< in: precise type */
+	ulint		col_len)	/*!< in: column lenght */
+{
+#ifndef UNIV_HOTBACKUP
+	ulint	mbminlen;
+	ulint	mbmaxlen;
+#endif /* !UNIV_HOTBACKUP */
+
+	column->ind = (unsigned int) col_pos;
+	column->ord_part = 0;
+	column->mtype = (unsigned int) mtype;
+	column->prtype = (unsigned int) prtype;
+	column->len = (unsigned int) col_len;
+#ifndef UNIV_HOTBACKUP
+        dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen);
+
+        column->mbminlen = (unsigned int) mbminlen;
+        column->mbmaxlen = (unsigned int) mbmaxlen;
+#endif /* !UNIV_HOTBACKUP */
+}

=== modified file 'storage/innobase/row/row0mysql.c'
--- a/storage/innobase/row/row0mysql.c	revid:vasil.dimov@stripped
+++ b/storage/innobase/row/row0mysql.c	revid:jimmy.yang@stripped
@@ -3285,7 +3285,7 @@ check_next_foreign:
 
 		dict_table_remove_from_cache(table);
 
-		if (dict_load_table(name) != NULL) {
+		if (dict_load_table(name, TRUE) != NULL) {
 			ut_print_timestamp(stderr);
 			fputs("  InnoDB: Error: not able to remove table ",
 			      stderr);
@@ -3431,7 +3431,7 @@ row_mysql_drop_temp_tables(void)
 		btr_pcur_store_position(&pcur, &mtr);
 		btr_pcur_commit_specify_mtr(&pcur, &mtr);
 
-		table = dict_load_table(table_name);
+		table = dict_load_table(table_name, TRUE);
 
 		if (table) {
 			row_drop_table_for_mysql(table_name, trx, FALSE);


Attachment: [text/bzr-bundle] bzr/jimmy.yang@oracle.com-20100526014433-bx0t9794mnvkiaft.bundle
Thread
bzr push into mysql-trunk-innodb branch (jimmy.yang:3119 to 3120) Jimmy Yang26 May