List:Commits« Previous MessageNext Message »
From:kevin.lewis Date:May 9 2012 1:19pm
Subject:bzr push into mysql-trunk branch (kevin.lewis:3802 to 3803)
View as plain text  
 3803 kevin.lewis@stripped	2012-05-09
      full 5980 patch. added recovery tests for code coverage.

    modified:
      include/my_base.h
      mysql-test/r/mysqlshow.result
      mysql-test/suite/innodb/r/innodb-restart.result
      mysql-test/suite/innodb/r/innodb-system-table-view.result
      mysql-test/suite/innodb/r/innodb_16k.result
      mysql-test/suite/innodb/r/innodb_4k.result
      mysql-test/suite/innodb/r/innodb_8k.result
      mysql-test/suite/innodb/t/innodb-restart.test
      mysql-test/suite/innodb/t/innodb-system-table-view.test
      mysql-test/suite/innodb/t/innodb_16k.test
      mysql-test/suite/innodb/t/innodb_4k.test
      mysql-test/suite/innodb/t/innodb_8k.test
      mysql-test/suite/parts/r/partition_basic_symlink_innodb.result
      mysql-test/suite/parts/t/partition_basic_symlink_innodb.test
      mysys/my_handler_errors.h
      sql/ha_partition.cc
      sql/ha_partition.h
      sql/handler.cc
      sql/share/errmsg-utf8.txt
      sql/sql_partition.cc
      sql/sql_partition.h
      sql/sql_table.cc
      storage/innobase/dict/dict0boot.cc
      storage/innobase/dict/dict0crea.cc
      storage/innobase/dict/dict0dict.cc
      storage/innobase/dict/dict0load.cc
      storage/innobase/fil/fil0fil.cc
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/handler/ha_innodb.h
      storage/innobase/handler/handler0alter.cc
      storage/innobase/handler/i_s.cc
      storage/innobase/handler/i_s.h
      storage/innobase/include/db0err.h
      storage/innobase/include/dict0boot.h
      storage/innobase/include/dict0crea.h
      storage/innobase/include/dict0dict.h
      storage/innobase/include/dict0dict.ic
      storage/innobase/include/dict0load.h
      storage/innobase/include/dict0mem.h
      storage/innobase/include/fil0fil.h
      storage/innobase/include/os0file.h
      storage/innobase/include/read0read.h
      storage/innobase/include/row0merge.h
      storage/innobase/include/trx0trx.h
      storage/innobase/lock/lock0lock.cc
      storage/innobase/os/os0file.cc
      storage/innobase/row/row0merge.cc
      storage/innobase/row/row0mysql.cc
      storage/innobase/srv/srv0start.cc
      storage/innobase/sync/sync0sync.cc
      storage/innobase/ut/ut0ut.cc
 3802 Andrei Elkin	2012-05-08
      rpl_stm_mts_crash_safe.test is done runnable with mixed format as well.
      The previous change to the test got ineffective on PB2 because it does 
      not run per push as it was supposed to.
     @ mysql-test/suite/rpl/t/rpl_stm_mts_crash_safe.test
        Making the test runnable with mixed format as well.

    modified:
      mysql-test/suite/rpl/t/rpl_stm_mts_crash_safe.test
=== modified file 'include/my_base.h'
--- a/include/my_base.h	revid:andrei.elkin@stripped
+++ b/include/my_base.h	revid:kevin.lewis@stripped
@@ -386,11 +386,11 @@ is the global server default. */
   Do not add error numbers before HA_ERR_FIRST.
   If necessary to add lower numbers, change HA_ERR_FIRST accordingly.
 */
-#define HA_ERR_FIRST            120     /* Copy of first error nr.*/
+#define HA_ERR_FIRST            120	/* Copy of first error nr.*/
 
 #define HA_ERR_KEY_NOT_FOUND	120	/* Didn't find key on read or update */
 #define HA_ERR_FOUND_DUPP_KEY	121	/* Dupplicate key on write */
-#define HA_ERR_INTERNAL_ERROR   122     /* Internal error */
+#define HA_ERR_INTERNAL_ERROR   122	/* Internal error */
 #define HA_ERR_RECORD_CHANGED	123	/* Uppdate with is recoverable */
 #define HA_ERR_WRONG_INDEX	124	/* Wrong index given to function */
 #define HA_ERR_CRASHED		126	/* Indexfile is crashed */
@@ -409,7 +409,7 @@ is the global server default. */
 #define HA_WRONG_CREATE_OPTION	140	/* Wrong create option */
 #define HA_ERR_FOUND_DUPP_UNIQUE 141	/* Dupplicate unique on write */
 #define HA_ERR_UNKNOWN_CHARSET	 142	/* Can't open charset */
-#define HA_ERR_WRONG_MRG_TABLE_DEF 143  /* conflicting tables in MERGE */
+#define HA_ERR_WRONG_MRG_TABLE_DEF 143	/* conflicting tables in MERGE */
 #define HA_ERR_CRASHED_ON_REPAIR 144	/* Last (automatic?) repair failed */
 #define HA_ERR_CRASHED_ON_USAGE  145	/* Table must be repaired */
 #define HA_ERR_LOCK_WAIT_TIMEOUT 146
@@ -421,16 +421,16 @@ is the global server default. */
 #define HA_ERR_ROW_IS_REFERENCED 152     /* Cannot delete a parent row */
 #define HA_ERR_NO_SAVEPOINT	 153     /* No savepoint with that name */
 #define HA_ERR_NON_UNIQUE_BLOCK_SIZE 154 /* Non unique key block size */
-#define HA_ERR_NO_SUCH_TABLE     155  /* The table does not exist in engine */
-#define HA_ERR_TABLE_EXIST       156  /* The table existed in storage engine */
-#define HA_ERR_NO_CONNECTION     157  /* Could not connect to storage engine */
+#define HA_ERR_NO_SUCH_TABLE     155     /* The table does not exist in engine */
+#define HA_ERR_TABLE_EXIST       156     /* The table existed in storage engine */
+#define HA_ERR_NO_CONNECTION     157     /* Could not connect to storage engine */
 /* NULLs are not supported in spatial index */
 #define HA_ERR_NULL_IN_SPATIAL   158
-#define HA_ERR_TABLE_DEF_CHANGED 159  /* The table changed in storage engine */
+#define HA_ERR_TABLE_DEF_CHANGED 159     /* The table changed in storage engine */
 /* There's no partition in table for given value */
 #define HA_ERR_NO_PARTITION_FOUND 160
-#define HA_ERR_RBR_LOGGING_FAILED 161  /* Row-based binlogging of row failed */
-#define HA_ERR_DROP_INDEX_FK      162  /* Index needed in foreign key constr */
+#define HA_ERR_RBR_LOGGING_FAILED 161    /* Row-based binlogging of row failed */
+#define HA_ERR_DROP_INDEX_FK      162    /* Index needed in foreign key constr */
 /*
   Upholding foreign key constraints would lead to a duplicate key error
   in some other table.
@@ -450,20 +450,21 @@ is the global server default. */
                                             statement */
 #define HA_ERR_CORRUPT_EVENT      171    /* The event was corrupt, leading to
                                             illegal data being read */
-#define HA_ERR_NEW_FILE	          172	 /* New file format */
+#define HA_ERR_NEW_FILE	          172    /* New file format */
 #define HA_ERR_ROWS_EVENT_APPLY   173    /* The event could not be processed
                                             no other hanlder error happened */
 #define HA_ERR_INITIALIZATION     174    /* Error during initialization */
-#define HA_ERR_FILE_TOO_SHORT	  175	 /* File too short */
-#define HA_ERR_WRONG_CRC	  176	 /* Wrong CRC on page */
+#define HA_ERR_FILE_TOO_SHORT	  175    /* File too short */
+#define HA_ERR_WRONG_CRC	  176    /* Wrong CRC on page */
 #define HA_ERR_TOO_MANY_CONCURRENT_TRXS 177 /*Too many active concurrent transactions */
 /* There's no explicitly listed partition in table for the given value */
 #define HA_ERR_NOT_IN_LOCK_PARTITIONS 178
-#define HA_ERR_INDEX_COL_TOO_LONG 179	 /* Index column length exceeds limit */
-#define HA_ERR_INDEX_CORRUPT      180	 /* InnoDB index corrupted */
+#define HA_ERR_INDEX_COL_TOO_LONG 179    /* Index column length exceeds limit */
+#define HA_ERR_INDEX_CORRUPT      180    /* InnoDB index corrupted */
 #define HA_ERR_UNDO_REC_TOO_BIG   181    /* Undo log record too big */
-#define HA_FTS_INVALID_DOCID      182	/* Invalid InnoDB Doc ID */
-#define HA_ERR_LAST               182    /* Copy of last error nr */
+#define HA_FTS_INVALID_DOCID      182    /* Invalid InnoDB Doc ID */
+#define HA_ERR_TABLESPACE_EXISTS  183    /* The tablespace existed in storage engine */
+#define HA_ERR_LAST               183    /* Copy of last error nr */
 
 /* Number of different errors */
 #define HA_ERR_ERRORS            (HA_ERR_LAST - HA_ERR_FIRST + 1)

=== modified file 'mysql-test/r/mysqlshow.result'
--- a/mysql-test/r/mysqlshow.result	revid:andrei.elkin@stripped
+++ b/mysql-test/r/mysqlshow.result	revid:kevin.lewis@stripped
@@ -112,7 +112,7 @@ Database: information_schema
 | VIEWS                                 |
 | INNODB_LOCKS                          |
 | INNODB_TRX                            |
-| INNODB_FT_CONFIG                      |
+| INNODB_SYS_DATAFILES                  |
 | INNODB_LOCK_WAITS                     |
 | INNODB_SYS_TABLESTATS                 |
 | INNODB_CMP                            |
@@ -123,7 +123,7 @@ Database: information_schema
 | INNODB_FT_DELETED                     |
 | INNODB_FT_DEFAULT_STOPWORD            |
 | INNODB_SYS_FOREIGN                    |
-| INNODB_BUFFER_POOL_STATS              |
+| INNODB_FT_CONFIG                      |
 | INNODB_SYS_INDEXES                    |
 | INNODB_SYS_TABLES                     |
 | INNODB_SYS_FIELDS                     |
@@ -132,9 +132,11 @@ Database: information_schema
 | INNODB_FT_BEING_DELETED               |
 | INNODB_FT_INDEX_TABLE                 |
 | INNODB_METRICS                        |
-| INNODB_SYS_COLUMNS                    |
+| INNODB_SYS_TABLESPACES                |
 | INNODB_FT_INSERTED                    |
 | INNODB_SYS_FOREIGN_COLS               |
+| INNODB_SYS_COLUMNS                    |
+| INNODB_BUFFER_POOL_STATS              |
 +---------------------------------------+
 Database: INFORMATION_SCHEMA
 +---------------------------------------+
@@ -173,7 +175,7 @@ Database: INFORMATION_SCHEMA
 | VIEWS                                 |
 | INNODB_LOCKS                          |
 | INNODB_TRX                            |
-| INNODB_FT_CONFIG                      |
+| INNODB_SYS_DATAFILES                  |
 | INNODB_LOCK_WAITS                     |
 | INNODB_SYS_TABLESTATS                 |
 | INNODB_CMP                            |
@@ -184,7 +186,7 @@ Database: INFORMATION_SCHEMA
 | INNODB_FT_DELETED                     |
 | INNODB_FT_DEFAULT_STOPWORD            |
 | INNODB_SYS_FOREIGN                    |
-| INNODB_BUFFER_POOL_STATS              |
+| INNODB_FT_CONFIG                      |
 | INNODB_SYS_INDEXES                    |
 | INNODB_SYS_TABLES                     |
 | INNODB_SYS_FIELDS                     |
@@ -193,9 +195,11 @@ Database: INFORMATION_SCHEMA
 | INNODB_FT_BEING_DELETED               |
 | INNODB_FT_INDEX_TABLE                 |
 | INNODB_METRICS                        |
-| INNODB_SYS_COLUMNS                    |
+| INNODB_SYS_TABLESPACES                |
 | INNODB_FT_INSERTED                    |
 | INNODB_SYS_FOREIGN_COLS               |
+| INNODB_SYS_COLUMNS                    |
+| INNODB_BUFFER_POOL_STATS              |
 +---------------------------------------+
 Wildcard: inf_rmation_schema
 +--------------------+

=== modified file 'mysql-test/suite/innodb/r/innodb-restart.result'
--- a/mysql-test/suite/innodb/r/innodb-restart.result	revid:andrei.elkin@stripped
+++ b/mysql-test/suite/innodb/r/innodb-restart.result	revid:kevin.lewis@stripped
@@ -1,6 +1,13 @@
+SET default_storage_engine=InnoDB;
+#
+# A series of tests to make sure tables are opened after restart.
 # Bug#13357607 Compressed file-per-table tablespaces fail to open
+#
 set global innodb_file_per_table=on;
 set global innodb_file_format='Barracuda';
+#
+# Create and insert records into a DYNAMIC row formatted table.
+#
 CREATE TABLE t1(c1 DOUBLE AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
 ROW_FORMAT=REDUNDANT  ENGINE=InnoDB;
 INSERT INTO t1 VALUES (1000000000, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot');
@@ -8,6 +15,22 @@ INSERT INTO t1 (SELECT 0, c2, c3, c4, c5
 INSERT INTO t1 (SELECT 0, c2, c3, c4, c5 FROM t1);
 INSERT INTO t1 (SELECT 0, c2, c3, c4, c5 FROM t1);
 INSERT INTO t1 (SELECT 0, c2, c3, c4, c5 FROM t1);
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `c1` double NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=1000000027 DEFAULT CHARSET=latin1 ROW_FORMAT=REDUNDANT
+SELECT count(*) FROM t1;
+count(*)
+16
+#
+# Create and insert records into a COMPACT row formatted table.
+#
 CREATE TABLE t2(c1 DOUBLE AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
 ROW_FORMAT=COMPACT  ENGINE=InnoDB;
 INSERT INTO t2 VALUES (1000000000, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot');
@@ -15,6 +38,22 @@ INSERT INTO t2 (SELECT 0, c2, c3, c4, c5
 INSERT INTO t2 (SELECT 0, c2, c3, c4, c5 FROM t2);
 INSERT INTO t2 (SELECT 0, c2, c3, c4, c5 FROM t2);
 INSERT INTO t2 (SELECT 0, c2, c3, c4, c5 FROM t2);
+SHOW CREATE TABLE t2;
+Table	Create Table
+t2	CREATE TABLE `t2` (
+  `c1` double NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=1000000027 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT
+SELECT count(*) FROM t2;
+count(*)
+16
+#
+# Create and insert records into a COMPRESSED row formatted table.
+#
 CREATE TABLE t3(c1 DOUBLE AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
 ROW_FORMAT=COMPRESSED  KEY_BLOCK_SIZE=4  ENGINE=InnoDB;
 INSERT INTO t3 VALUES (1000000000, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot');
@@ -22,6 +61,22 @@ INSERT INTO t3 (SELECT 0, c2, c3, c4, c5
 INSERT INTO t3 (SELECT 0, c2, c3, c4, c5 FROM t3);
 INSERT INTO t3 (SELECT 0, c2, c3, c4, c5 FROM t3);
 INSERT INTO t3 (SELECT 0, c2, c3, c4, c5 FROM t3);
+SHOW CREATE TABLE t3;
+Table	Create Table
+t3	CREATE TABLE `t3` (
+  `c1` double NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=1000000027 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4
+SELECT count(*) FROM t3;
+count(*)
+16
+#
+# Create and insert records into a DYNAMIC row formatted table.
+#
 CREATE TABLE t4(c1 DOUBLE AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
 ROW_FORMAT=DYNAMIC  ENGINE=InnoDB;
 INSERT INTO t4 VALUES (1000000000, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot');
@@ -29,7 +84,204 @@ INSERT INTO t4 (SELECT 0, c2, c3, c4, c5
 INSERT INTO t4 (SELECT 0, c2, c3, c4, c5 FROM t4);
 INSERT INTO t4 (SELECT 0, c2, c3, c4, c5 FROM t4);
 INSERT INTO t4 (SELECT 0, c2, c3, c4, c5 FROM t4);
-# Restart the server
+SHOW CREATE TABLE t4;
+Table	Create Table
+t4	CREATE TABLE `t4` (
+  `c1` double NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=1000000027 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+SELECT count(*) FROM t4;
+count(*)
+16
+#
+# Create and insert records into a table that uses a remote DATA DIRECTORY.
+#
+CREATE TABLE t5(c1 DOUBLE AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
+ROW_FORMAT=DYNAMIC  ENGINE=InnoDB  DATA DIRECTORY='MYSQL_TMP_DIR/alt_dir';
+INSERT INTO t5 VALUES (1000000000, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot');
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+SHOW CREATE TABLE t5;
+Table	Create Table
+t5	CREATE TABLE `t5` (
+  `c1` double NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=1000000027 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC DATA DIRECTORY='MYSQL_TMP_DIR/alt_dir/'
+SELECT count(*) FROM t5;
+count(*)
+16
+#
+# Create and insert records into a partitioned table that uses
+# a remote DATA DIRECTORY for each partition.
+#
+CREATE TABLE t6(
+c1 INT AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
+ROW_FORMAT=COMPRESSED  ENGINE=InnoDB
+PARTITION BY HASH(c1) (
+PARTITION p0  DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir',
+PARTITION p1  DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir',
+PARTITION p2  DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir');
+INSERT INTO t6 VALUES (0, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot');
+INSERT INTO t6 (SELECT 0, c2, c3, c4, c5 FROM t6);
+INSERT INTO t6 (SELECT 0, c2, c3, c4, c5 FROM t6);
+INSERT INTO t6 (SELECT 0, c2, c3, c4, c5 FROM t6);
+INSERT INTO t6 (SELECT 0, c2, c3, c4, c5 FROM t6);
+SHOW CREATE TABLE t6;
+Table	Create Table
+t6	CREATE TABLE `t6` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED
+/*!50100 PARTITION BY HASH (c1)
+(PARTITION p0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+ PARTITION p1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+ PARTITION p2 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB) */
+SELECT count(*) FROM t6;
+count(*)
+16
+#
+# Create and insert records into a subpartitioned table that uses
+# a remote DATA DIRECTORY for each subpartition.
+#
+CREATE TABLE t7(
+c1 INT AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
+ROW_FORMAT=DYNAMIC  ENGINE=InnoDB
+PARTITION BY RANGE(c1) SUBPARTITION BY HASH(c1) (
+PARTITION p0 VALUES LESS THAN (10) (
+SUBPARTITION s0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir',
+SUBPARTITION s1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir'),
+PARTITION p1 VALUES LESS THAN MAXVALUE (
+SUBPARTITION s2 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir',
+SUBPARTITION s3 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir'));
+INSERT INTO t7 VALUES (0, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot');
+INSERT INTO t7 (SELECT 0, c2, c3, c4, c5 FROM t7);
+INSERT INTO t7 (SELECT 0, c2, c3, c4, c5 FROM t7);
+INSERT INTO t7 (SELECT 0, c2, c3, c4, c5 FROM t7);
+INSERT INTO t7 (SELECT 0, c2, c3, c4, c5 FROM t7);
+SHOW CREATE TABLE t7;
+Table	Create Table
+t7	CREATE TABLE `t7` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+/*!50100 PARTITION BY RANGE (c1)
+SUBPARTITION BY HASH (c1)
+(PARTITION p0 VALUES LESS THAN (10)
+ (SUBPARTITION s0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+  SUBPARTITION s1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB),
+ PARTITION p1 VALUES LESS THAN MAXVALUE
+ (SUBPARTITION s2 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+  SUBPARTITION s3 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB)) */
+SELECT count(*) FROM t7;
+count(*)
+16
+#
+# Show these tables in information_schema.
+#
+SELECT name,n_cols,file_format,row_format
+FROM information_schema.innodb_sys_tables WHERE name like 'test%';
+name	n_cols	file_format	row_format
+test/t1	8	Antelope	Redundant
+test/t2	8	Antelope	Compact
+test/t3	8	Barracuda	Compressed
+test/t4	8	Barracuda	Dynamic
+test/t5	8	Barracuda	Dynamic
+test/t6#p#p0	8	Barracuda	Compressed
+test/t6#p#p1	8	Barracuda	Compressed
+test/t6#p#p2	8	Barracuda	Compressed
+test/t7#p#p0#sp#s0	8	Barracuda	Dynamic
+test/t7#p#p0#sp#s1	8	Barracuda	Dynamic
+test/t7#p#p1#sp#s2	8	Barracuda	Dynamic
+test/t7#p#p1#sp#s3	8	Barracuda	Dynamic
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces;
+name	file_format	row_format
+test/t1	Antelope	Compact or Redundant
+test/t2	Antelope	Compact or Redundant
+test/t3	Barracuda	Compressed
+test/t4	Barracuda	Dynamic
+test/t5	Barracuda	Dynamic
+test/t6#p#p0	Barracuda	Compressed
+test/t6#p#p1	Barracuda	Compressed
+test/t6#p#p2	Barracuda	Compressed
+test/t7#p#p0#sp#s0	Barracuda	Dynamic
+test/t7#p#p0#sp#s1	Barracuda	Dynamic
+test/t7#p#p1#sp#s2	Barracuda	Dynamic
+test/t7#p#p1#sp#s3	Barracuda	Dynamic
+SELECT path FROM information_schema.innodb_sys_datafiles ORDER BY path;
+path
+MYSQLD_DATADIR/test/t1.ibd
+MYSQLD_DATADIR/test/t2.ibd
+MYSQLD_DATADIR/test/t3.ibd
+MYSQLD_DATADIR/test/t4.ibd
+MYSQL_TMP_DIR/alt_dir/test/t5.ibd
+MYSQL_TMP_DIR/alt_dir/test/t6#p#p0.ibd
+MYSQL_TMP_DIR/alt_dir/test/t6#p#p1.ibd
+MYSQL_TMP_DIR/alt_dir/test/t6#p#p2.ibd
+MYSQL_TMP_DIR/alt_dir/test/t7#p#p0#sp#s0.ibd
+MYSQL_TMP_DIR/alt_dir/test/t7#p#p0#sp#s1.ibd
+MYSQL_TMP_DIR/alt_dir/test/t7#p#p1#sp#s2.ibd
+MYSQL_TMP_DIR/alt_dir/test/t7#p#p1#sp#s3.ibd
+#
+# Shutdown the server and list the tablespace OS files
+#
+---- MYSQLD_DATADIR/test
+t1.frm
+t1.ibd
+t2.frm
+t2.ibd
+t3.frm
+t3.ibd
+t4.frm
+t4.ibd
+t5.frm
+t5.isl
+t6#p#p0.isl
+t6#p#p1.isl
+t6#p#p2.isl
+t6.frm
+t6.par
+t7#p#p0#sp#s0.isl
+t7#p#p0#sp#s1.isl
+t7#p#p1#sp#s2.isl
+t7#p#p1#sp#s3.isl
+t7.frm
+t7.par
+---- MYSQL_TMP_DIR/alt_dir
+test
+---- MYSQL_TMP_DIR/alt_dir/test
+t5.ibd
+t6#p#p0.ibd
+t6#p#p1.ibd
+t6#p#p2.ibd
+t7#p#p0#sp#s0.ibd
+t7#p#p0#sp#s1.ibd
+t7#p#p1#sp#s2.ibd
+t7#p#p1#sp#s3.ibd
+#
+# Start the server and show that tables are still visible and accessible.
+#
+SHOW VARIABLES LIKE 'innodb_file_per_table';
+Variable_name	Value
+innodb_file_per_table	OFF
 SHOW CREATE TABLE t1;
 Table	Create Table
 t1	CREATE TABLE `t1` (
@@ -70,11 +322,725 @@ t4	CREATE TABLE `t4` (
   `c5` text,
   PRIMARY KEY (`c1`)
 ) ENGINE=InnoDB AUTO_INCREMENT=1000000020 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+SHOW CREATE TABLE t5;
+Table	Create Table
+t5	CREATE TABLE `t5` (
+  `c1` double NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=1000000020 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC DATA DIRECTORY='MYSQL_TMP_DIR/alt_dir/'
+SHOW CREATE TABLE t6;
+Table	Create Table
+t6	CREATE TABLE `t6` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED
+/*!50100 PARTITION BY HASH (c1)
+(PARTITION p0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+ PARTITION p1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+ PARTITION p2 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB) */
+SHOW CREATE TABLE t7;
+Table	Create Table
+t7	CREATE TABLE `t7` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+/*!50100 PARTITION BY RANGE (c1)
+SUBPARTITION BY HASH (c1)
+(PARTITION p0 VALUES LESS THAN (10)
+ (SUBPARTITION s0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+  SUBPARTITION s1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB),
+ PARTITION p1 VALUES LESS THAN MAXVALUE
+ (SUBPARTITION s2 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+  SUBPARTITION s3 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB)) */
 INSERT INTO t1 (SELECT 0, c2, c3, c4, c5 FROM t1);
 INSERT INTO t2 (SELECT 0, c2, c3, c4, c5 FROM t2);
 INSERT INTO t3 (SELECT 0, c2, c3, c4, c5 FROM t3);
 INSERT INTO t4 (SELECT 0, c2, c3, c4, c5 FROM t4);
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+INSERT INTO t6 (SELECT 0, c2, c3, c4, c5 FROM t6);
+INSERT INTO t7 (SELECT 0, c2, c3, c4, c5 FROM t7);
+SELECT count(*) FROM t1;
+count(*)
+32
+SELECT count(*) FROM t2;
+count(*)
+32
+SELECT count(*) FROM t3;
+count(*)
+32
+SELECT count(*) FROM t4;
+count(*)
+32
+SELECT count(*) FROM t5;
+count(*)
+32
+SELECT count(*) FROM t6;
+count(*)
+32
+SELECT count(*) FROM t7;
+count(*)
+32
+SELECT name,n_cols,file_format,row_format
+FROM information_schema.innodb_sys_tables WHERE name like 'test%';
+name	n_cols	file_format	row_format
+test/t1	8	Antelope	Redundant
+test/t2	8	Antelope	Compact
+test/t3	8	Barracuda	Compressed
+test/t4	8	Barracuda	Dynamic
+test/t5	8	Barracuda	Dynamic
+test/t6#p#p0	8	Barracuda	Compressed
+test/t6#p#p1	8	Barracuda	Compressed
+test/t6#p#p2	8	Barracuda	Compressed
+test/t7#p#p0#sp#s0	8	Barracuda	Dynamic
+test/t7#p#p0#sp#s1	8	Barracuda	Dynamic
+test/t7#p#p1#sp#s2	8	Barracuda	Dynamic
+test/t7#p#p1#sp#s3	8	Barracuda	Dynamic
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces;
+name	file_format	row_format
+test/t1	Antelope	Compact or Redundant
+test/t2	Antelope	Compact or Redundant
+test/t3	Barracuda	Compressed
+test/t4	Barracuda	Dynamic
+test/t5	Barracuda	Dynamic
+test/t6#p#p0	Barracuda	Compressed
+test/t6#p#p1	Barracuda	Compressed
+test/t6#p#p2	Barracuda	Compressed
+test/t7#p#p0#sp#s0	Barracuda	Dynamic
+test/t7#p#p0#sp#s1	Barracuda	Dynamic
+test/t7#p#p1#sp#s2	Barracuda	Dynamic
+test/t7#p#p1#sp#s3	Barracuda	Dynamic
+SELECT path FROM information_schema.innodb_sys_datafiles ORDER BY path;
+path
+MYSQLD_DATADIR/test/t1.ibd
+MYSQLD_DATADIR/test/t2.ibd
+MYSQLD_DATADIR/test/t3.ibd
+MYSQLD_DATADIR/test/t4.ibd
+MYSQL_TMP_DIR/alt_dir/test/t5.ibd
+MYSQL_TMP_DIR/alt_dir/test/t6#p#p0.ibd
+MYSQL_TMP_DIR/alt_dir/test/t6#p#p1.ibd
+MYSQL_TMP_DIR/alt_dir/test/t6#p#p2.ibd
+MYSQL_TMP_DIR/alt_dir/test/t7#p#p0#sp#s0.ibd
+MYSQL_TMP_DIR/alt_dir/test/t7#p#p0#sp#s1.ibd
+MYSQL_TMP_DIR/alt_dir/test/t7#p#p1#sp#s2.ibd
+MYSQL_TMP_DIR/alt_dir/test/t7#p#p1#sp#s3.ibd
 DROP TABLE t1;
 DROP TABLE t2;
 DROP TABLE t3;
 DROP TABLE t4;
+#
+# Truncate the remote tablespaces.
+#
+TRUNCATE TABLE t5;
+ALTER TABLE t6 TRUNCATE PARTITION p2;
+ALTER TABLE t7 TRUNCATE PARTITION p1;
+SELECT path FROM information_schema.innodb_sys_datafiles ORDER BY path;
+path
+MYSQL_TMP_DIR/alt_dir/test/t5.ibd
+MYSQL_TMP_DIR/alt_dir/test/t6#p#p0.ibd
+MYSQL_TMP_DIR/alt_dir/test/t6#p#p1.ibd
+MYSQL_TMP_DIR/alt_dir/test/t6#p#p2.ibd
+MYSQL_TMP_DIR/alt_dir/test/t7#p#p0#sp#s0.ibd
+MYSQL_TMP_DIR/alt_dir/test/t7#p#p0#sp#s1.ibd
+MYSQL_TMP_DIR/alt_dir/test/t7#p#p1#sp#s2.ibd
+MYSQL_TMP_DIR/alt_dir/test/t7#p#p1#sp#s3.ibd
+INSERT INTO t5 VALUES (1000000000, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot');
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+SELECT count(*) FROM t5;
+count(*)
+8
+SHOW CREATE TABLE t5;
+Table	Create Table
+t5	CREATE TABLE `t5` (
+  `c1` double NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=1000000012 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC DATA DIRECTORY='MYSQL_TMP_DIR/alt_dir/'
+SELECT count(*) FROM t6;
+count(*)
+21
+SHOW CREATE TABLE t6;
+Table	Create Table
+t6	CREATE TABLE `t6` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED
+/*!50100 PARTITION BY HASH (c1)
+(PARTITION p0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+ PARTITION p1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+ PARTITION p2 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB) */
+SELECT count(*) FROM t7;
+count(*)
+9
+SHOW CREATE TABLE t7;
+Table	Create Table
+t7	CREATE TABLE `t7` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+/*!50100 PARTITION BY RANGE (c1)
+SUBPARTITION BY HASH (c1)
+(PARTITION p0 VALUES LESS THAN (10)
+ (SUBPARTITION s0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+  SUBPARTITION s1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB),
+ PARTITION p1 VALUES LESS THAN MAXVALUE
+ (SUBPARTITION s2 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+  SUBPARTITION s3 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB)) */
+#
+# Shutdown the server and make a backup of a tablespace
+#
+---- MYSQLD_DATADIR/test
+t5.frm
+t5.frm.bak
+t5.isl
+t5.isl.bak
+t6#p#p0.isl
+t6#p#p1.isl
+t6#p#p2.isl
+t6.frm
+t6.par
+t7#p#p0#sp#s0.isl
+t7#p#p0#sp#s1.isl
+t7#p#p1#sp#s2.isl
+t7#p#p1#sp#s3.isl
+t7.frm
+t7.par
+---- MYSQL_TMP_DIR/alt_dir/test
+t5.ibd
+t5.ibd.bak
+t6#p#p0.ibd
+t6#p#p1.ibd
+t6#p#p2.ibd
+t7#p#p0#sp#s0.ibd
+t7#p#p0#sp#s1.ibd
+t7#p#p1#sp#s2.ibd
+t7#p#p1#sp#s3.ibd
+#
+# Start the server and show the tablespaces.
+#
+SHOW VARIABLES LIKE 'innodb_file_per_table';
+Variable_name	Value
+innodb_file_per_table	OFF
+SELECT path FROM information_schema.innodb_sys_datafiles ORDER BY path;
+path
+MYSQL_TMP_DIR/alt_dir/test/t5.ibd
+MYSQL_TMP_DIR/alt_dir/test/t6#p#p0.ibd
+MYSQL_TMP_DIR/alt_dir/test/t6#p#p1.ibd
+MYSQL_TMP_DIR/alt_dir/test/t6#p#p2.ibd
+MYSQL_TMP_DIR/alt_dir/test/t7#p#p0#sp#s0.ibd
+MYSQL_TMP_DIR/alt_dir/test/t7#p#p0#sp#s1.ibd
+MYSQL_TMP_DIR/alt_dir/test/t7#p#p1#sp#s2.ibd
+MYSQL_TMP_DIR/alt_dir/test/t7#p#p1#sp#s3.ibd
+SELECT count(*) FROM t5;
+count(*)
+8
+SHOW CREATE TABLE t5;
+Table	Create Table
+t5	CREATE TABLE `t5` (
+  `c1` double NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=1000000009 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC DATA DIRECTORY='MYSQL_TMP_DIR/alt_dir/'
+SELECT count(*) FROM t6;
+count(*)
+21
+SHOW CREATE TABLE t6;
+Table	Create Table
+t6	CREATE TABLE `t6` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED
+/*!50100 PARTITION BY HASH (c1)
+(PARTITION p0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+ PARTITION p1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+ PARTITION p2 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB) */
+SELECT count(*) FROM t7;
+count(*)
+9
+SHOW CREATE TABLE t7;
+Table	Create Table
+t7	CREATE TABLE `t7` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+/*!50100 PARTITION BY RANGE (c1)
+SUBPARTITION BY HASH (c1)
+(PARTITION p0 VALUES LESS THAN (10)
+ (SUBPARTITION s0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+  SUBPARTITION s1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB),
+ PARTITION p1 VALUES LESS THAN MAXVALUE
+ (SUBPARTITION s2 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+  SUBPARTITION s3 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB)) */
+#
+# Try to rename a tablespace to a file that already exists
+#
+RENAME TABLE t5 TO t55;
+ERROR 42S01: Table 't55' already exists
+RENAME TABLE t5 TO t55;
+ERROR HY000: Error on rename of './test/t5' to './test/t55' (errno: 183 - Tablespace already exists)
+---- MYSQLD_DATADIR/test
+t5.frm
+t5.isl
+t6#p#p0.isl
+t6#p#p1.isl
+t6#p#p2.isl
+t6.frm
+t6.par
+t7#p#p0#sp#s0.isl
+t7#p#p0#sp#s1.isl
+t7#p#p1#sp#s2.isl
+t7#p#p1#sp#s3.isl
+t7.frm
+t7.par
+---- MYSQL_TMP_DIR/alt_dir/test
+t5.ibd
+t6#p#p0.ibd
+t6#p#p1.ibd
+t6#p#p2.ibd
+t7#p#p0#sp#s0.ibd
+t7#p#p0#sp#s1.ibd
+t7#p#p1#sp#s2.ibd
+t7#p#p1#sp#s3.ibd
+#
+# Rename file table and tablespace
+#
+RENAME TABLE t5 TO t55;
+RENAME TABLE t6 TO t66;
+RENAME TABLE t7 TO t77;
+SELECT path FROM information_schema.innodb_sys_datafiles ORDER BY path;
+path
+MYSQL_TMP_DIR/alt_dir/test/t55.ibd
+MYSQL_TMP_DIR/alt_dir/test/t66#p#p0.ibd
+MYSQL_TMP_DIR/alt_dir/test/t66#p#p1.ibd
+MYSQL_TMP_DIR/alt_dir/test/t66#p#p2.ibd
+MYSQL_TMP_DIR/alt_dir/test/t77#p#p0#sp#s0.ibd
+MYSQL_TMP_DIR/alt_dir/test/t77#p#p0#sp#s1.ibd
+MYSQL_TMP_DIR/alt_dir/test/t77#p#p1#sp#s2.ibd
+MYSQL_TMP_DIR/alt_dir/test/t77#p#p1#sp#s3.ibd
+INSERT INTO t55 (SELECT 0, c2, c3, c4, c5 FROM t55);
+SELECT count(*) FROM t55;
+count(*)
+16
+SHOW CREATE TABLE t55;
+Table	Create Table
+t55	CREATE TABLE `t55` (
+  `c1` double NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=1000000024 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC DATA DIRECTORY='MYSQL_TMP_DIR/alt_dir/'
+INSERT INTO t66 (SELECT 0, c2, c3, c4, c5 FROM t66);
+SELECT count(*) FROM t66;
+count(*)
+42
+SHOW CREATE TABLE t66;
+Table	Create Table
+t66	CREATE TABLE `t66` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED
+/*!50100 PARTITION BY HASH (c1)
+(PARTITION p0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+ PARTITION p1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+ PARTITION p2 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB) */
+INSERT INTO t77 (SELECT 0, c2, c3, c4, c5 FROM t77);
+SELECT count(*) FROM t77;
+count(*)
+18
+SHOW CREATE TABLE t77;
+Table	Create Table
+t77	CREATE TABLE `t77` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+/*!50100 PARTITION BY RANGE (c1)
+SUBPARTITION BY HASH (c1)
+(PARTITION p0 VALUES LESS THAN (10)
+ (SUBPARTITION s0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+  SUBPARTITION s1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB),
+ PARTITION p1 VALUES LESS THAN MAXVALUE
+ (SUBPARTITION s2 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+  SUBPARTITION s3 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB)) */
+---- MYSQLD_DATADIR/test
+t55.frm
+t55.isl
+t66#p#p0.isl
+t66#p#p1.isl
+t66#p#p2.isl
+t66.frm
+t66.par
+t77#p#p0#sp#s0.isl
+t77#p#p0#sp#s1.isl
+t77#p#p1#sp#s2.isl
+t77#p#p1#sp#s3.isl
+t77.frm
+t77.par
+---- MYSQL_TMP_DIR/alt_dir/test
+t55.ibd
+t66#p#p0.ibd
+t66#p#p1.ibd
+t66#p#p2.ibd
+t77#p#p0#sp#s0.ibd
+t77#p#p0#sp#s1.ibd
+t77#p#p1#sp#s2.ibd
+t77#p#p1#sp#s3.ibd
+#
+# Restart the server
+#
+SHOW VARIABLES LIKE 'innodb_file_per_table';
+Variable_name	Value
+innodb_file_per_table	OFF
+SELECT path FROM information_schema.innodb_sys_datafiles ORDER BY path;
+path
+MYSQL_TMP_DIR/alt_dir/test/t55.ibd
+MYSQL_TMP_DIR/alt_dir/test/t66#p#p0.ibd
+MYSQL_TMP_DIR/alt_dir/test/t66#p#p1.ibd
+MYSQL_TMP_DIR/alt_dir/test/t66#p#p2.ibd
+MYSQL_TMP_DIR/alt_dir/test/t77#p#p0#sp#s0.ibd
+MYSQL_TMP_DIR/alt_dir/test/t77#p#p0#sp#s1.ibd
+MYSQL_TMP_DIR/alt_dir/test/t77#p#p1#sp#s2.ibd
+MYSQL_TMP_DIR/alt_dir/test/t77#p#p1#sp#s3.ibd
+INSERT INTO t55 (SELECT 0, c2, c3, c4, c5 FROM t55);
+SELECT count(*) FROM t55;
+count(*)
+32
+SHOW CREATE TABLE t55;
+Table	Create Table
+t55	CREATE TABLE `t55` (
+  `c1` double NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=1000000048 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC DATA DIRECTORY='MYSQL_TMP_DIR/alt_dir/'
+INSERT INTO t66 (SELECT 0, c2, c3, c4, c5 FROM t66);
+SELECT count(*) FROM t66;
+count(*)
+84
+SHOW CREATE TABLE t66;
+Table	Create Table
+t66	CREATE TABLE `t66` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=95 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED
+/*!50100 PARTITION BY HASH (c1)
+(PARTITION p0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+ PARTITION p1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+ PARTITION p2 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB) */
+INSERT INTO t77 (SELECT 0, c2, c3, c4, c5 FROM t77);
+SELECT count(*) FROM t77;
+count(*)
+36
+SHOW CREATE TABLE t77;
+Table	Create Table
+t77	CREATE TABLE `t77` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+/*!50100 PARTITION BY RANGE (c1)
+SUBPARTITION BY HASH (c1)
+(PARTITION p0 VALUES LESS THAN (10)
+ (SUBPARTITION s0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+  SUBPARTITION s1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB),
+ PARTITION p1 VALUES LESS THAN MAXVALUE
+ (SUBPARTITION s2 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB,
+  SUBPARTITION s3 DATA DIRECTORY = 'MYSQL_TMP_DIR/alt_dir' ENGINE = InnoDB)) */
+#
+# Shutdown the server
+#
+#
+# Move the remote tablespaces to a new location and change the ISL files
+#
+---- MYSQLD_DATADIR/test
+t55.frm
+t55.isl
+t66#p#p0.isl
+t66#p#p1.isl
+t66#p#p2.isl
+t66.frm
+t66.par
+t77#p#p0#sp#s0.isl
+t77#p#p0#sp#s1.isl
+t77#p#p1#sp#s2.isl
+t77#p#p1#sp#s3.isl
+t77.frm
+t77.par
+---- MYSQL_TMP_DIR/alt_dir/test
+t55.ibd
+t66#p#p0.ibd
+t66#p#p1.ibd
+t66#p#p2.ibd
+t77#p#p0#sp#s0.ibd
+t77#p#p0#sp#s1.ibd
+t77#p#p1#sp#s2.ibd
+t77#p#p1#sp#s3.ibd
+---- MYSQL_TMP_DIR/new_dir/test
+# Moving tablespace 't55' from MYSQL_TMP_DIR/alt_dir to MYSQL_TMP_DIR/new_dir
+# Moving tablespace 't66' from MYSQL_TMP_DIR/alt_dir to MYSQL_TMP_DIR/new_dir
+# Moving tablespace 't77' from MYSQL_TMP_DIR/alt_dir to MYSQL_TMP_DIR/new_dir
+---- MYSQLD_DATADIR/test
+t55.frm
+t55.isl
+t66#p#p0.isl
+t66#p#p1.isl
+t66#p#p2.isl
+t66.frm
+t66.par
+t77#p#p0#sp#s0.isl
+t77#p#p0#sp#s1.isl
+t77#p#p1#sp#s2.isl
+t77#p#p1#sp#s3.isl
+t77.frm
+t77.par
+---- MYSQL_TMP_DIR/alt_dir/test
+---- MYSQL_TMP_DIR/new_dir/test
+t55.ibd
+t66#p#p0.ibd
+t66#p#p1.ibd
+t66#p#p2.ibd
+t77#p#p0#sp#s0.ibd
+t77#p#p0#sp#s1.ibd
+t77#p#p1#sp#s2.ibd
+t77#p#p1#sp#s3.ibd
+#
+# Start the server and check tablespaces.
+#
+SELECT path FROM information_schema.innodb_sys_datafiles ORDER BY path;
+path
+MYSQL_TMP_DIR/new_dir/test/t55.ibd
+MYSQL_TMP_DIR/new_dir/test/t66#p#p0.ibd
+MYSQL_TMP_DIR/new_dir/test/t66#p#p1.ibd
+MYSQL_TMP_DIR/new_dir/test/t66#p#p2.ibd
+MYSQL_TMP_DIR/new_dir/test/t77#p#p0#sp#s0.ibd
+MYSQL_TMP_DIR/new_dir/test/t77#p#p0#sp#s1.ibd
+MYSQL_TMP_DIR/new_dir/test/t77#p#p1#sp#s2.ibd
+MYSQL_TMP_DIR/new_dir/test/t77#p#p1#sp#s3.ibd
+INSERT INTO t55 (SELECT 0, c2, c3, c4, c5 FROM t55);
+SELECT count(*) FROM t55;
+count(*)
+64
+SHOW CREATE TABLE t55;
+Table	Create Table
+t55	CREATE TABLE `t55` (
+  `c1` double NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=1000000096 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC DATA DIRECTORY='MYSQL_TMP_DIR/new_dir/'
+INSERT INTO t66 (SELECT 0, c2, c3, c4, c5 FROM t66);
+SELECT count(*) FROM t66;
+count(*)
+168
+SHOW CREATE TABLE t66;
+Table	Create Table
+t66	CREATE TABLE `t66` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=179 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED
+/*!50100 PARTITION BY HASH (c1)
+(PARTITION p0 DATA DIRECTORY = 'MYSQL_TMP_DIR/new_dir' ENGINE = InnoDB,
+ PARTITION p1 DATA DIRECTORY = 'MYSQL_TMP_DIR/new_dir' ENGINE = InnoDB,
+ PARTITION p2 DATA DIRECTORY = 'MYSQL_TMP_DIR/new_dir' ENGINE = InnoDB) */
+INSERT INTO t77 (SELECT 0, c2, c3, c4, c5 FROM t77);
+SELECT count(*) FROM t77;
+count(*)
+72
+SHOW CREATE TABLE t77;
+Table	Create Table
+t77	CREATE TABLE `t77` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=73 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+/*!50100 PARTITION BY RANGE (c1)
+SUBPARTITION BY HASH (c1)
+(PARTITION p0 VALUES LESS THAN (10)
+ (SUBPARTITION s0 DATA DIRECTORY = 'MYSQL_TMP_DIR/new_dir' ENGINE = InnoDB,
+  SUBPARTITION s1 DATA DIRECTORY = 'MYSQL_TMP_DIR/new_dir' ENGINE = InnoDB),
+ PARTITION p1 VALUES LESS THAN MAXVALUE
+ (SUBPARTITION s2 DATA DIRECTORY = 'MYSQL_TMP_DIR/new_dir' ENGINE = InnoDB,
+  SUBPARTITION s3 DATA DIRECTORY = 'MYSQL_TMP_DIR/new_dir' ENGINE = InnoDB)) */
+#
+# Shutdown the server
+#
+#
+# Move the remote tablespaces back to the default datadir and delete the ISL file.
+#
+---- MYSQLD_DATADIR/test
+t55.frm
+t55.isl
+t66#p#p0.isl
+t66#p#p1.isl
+t66#p#p2.isl
+t66.frm
+t66.par
+t77#p#p0#sp#s0.isl
+t77#p#p0#sp#s1.isl
+t77#p#p1#sp#s2.isl
+t77#p#p1#sp#s3.isl
+t77.frm
+t77.par
+---- MYSQL_TMP_DIR/new_dir/test
+t55.ibd
+t66#p#p0.ibd
+t66#p#p1.ibd
+t66#p#p2.ibd
+t77#p#p0#sp#s0.ibd
+t77#p#p0#sp#s1.ibd
+t77#p#p1#sp#s2.ibd
+t77#p#p1#sp#s3.ibd
+# Moving 't55' from MYSQL_TMP_DIR/new_dir to MYSQLD_DATADIR
+# Moving 't66' from MYSQL_TMP_DIR/new_dir to MYSQLD_DATADIR
+# Moving 't77' from MYSQL_TMP_DIR/new_dir to MYSQLD_DATADIR
+---- MYSQLD_DATADIR/test
+t55.frm
+t55.ibd
+t66#p#p0.ibd
+t66#p#p1.ibd
+t66#p#p2.ibd
+t66.frm
+t66.par
+t77#p#p0#sp#s0.ibd
+t77#p#p0#sp#s1.ibd
+t77#p#p1#sp#s2.ibd
+t77#p#p1#sp#s3.ibd
+t77.frm
+t77.par
+---- MYSQL_TMP_DIR/new_dir/test
+# 
+# Start the server and check tablespaces.
+# 
+SELECT path FROM information_schema.innodb_sys_datafiles ORDER BY path;
+path
+MYSQLD_DATADIR/test/t55.ibd
+MYSQLD_DATADIR/test/t66#p#p0.ibd
+MYSQLD_DATADIR/test/t66#p#p1.ibd
+MYSQLD_DATADIR/test/t66#p#p2.ibd
+MYSQLD_DATADIR/test/t77#p#p0#sp#s0.ibd
+MYSQLD_DATADIR/test/t77#p#p0#sp#s1.ibd
+MYSQLD_DATADIR/test/t77#p#p1#sp#s2.ibd
+MYSQLD_DATADIR/test/t77#p#p1#sp#s3.ibd
+INSERT INTO t55 (SELECT 0, c2, c3, c4, c5 FROM t55);
+SELECT count(*) FROM t55;
+count(*)
+128
+SHOW CREATE TABLE t55;
+Table	Create Table
+t55	CREATE TABLE `t55` (
+  `c1` double NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=1000000192 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+INSERT INTO t66 (SELECT 0, c2, c3, c4, c5 FROM t66);
+SELECT count(*) FROM t66;
+count(*)
+336
+SHOW CREATE TABLE t66;
+Table	Create Table
+t66	CREATE TABLE `t66` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=347 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED
+/*!50100 PARTITION BY HASH (c1)
+(PARTITION p0 ENGINE = InnoDB,
+ PARTITION p1 ENGINE = InnoDB,
+ PARTITION p2 ENGINE = InnoDB) */
+INSERT INTO t77 (SELECT 0, c2, c3, c4, c5 FROM t77);
+SELECT count(*) FROM t77;
+count(*)
+144
+SHOW CREATE TABLE t77;
+Table	Create Table
+t77	CREATE TABLE `t77` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` char(10) DEFAULT NULL,
+  `c3` varchar(100) DEFAULT NULL,
+  `c4` date DEFAULT NULL,
+  `c5` text,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB AUTO_INCREMENT=145 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+/*!50100 PARTITION BY RANGE (c1)
+SUBPARTITION BY HASH (c1)
+(PARTITION p0 VALUES LESS THAN (10)
+ (SUBPARTITION s0 ENGINE = InnoDB,
+  SUBPARTITION s1 ENGINE = InnoDB),
+ PARTITION p1 VALUES LESS THAN MAXVALUE
+ (SUBPARTITION s2 ENGINE = InnoDB,
+  SUBPARTITION s3 ENGINE = InnoDB)) */
+#
+# Cleanup
+#
+DROP TABLE t55;
+DROP TABLE t66;
+DROP TABLE t77;

=== modified file 'mysql-test/suite/innodb/r/innodb-system-table-view.result'
--- a/mysql-test/suite/innodb/r/innodb-system-table-view.result	revid:andrei.elkin@stripped
+++ b/mysql-test/suite/innodb/r/innodb-system-table-view.result	revid:kevin.lewis@stripped
@@ -1,22 +1,40 @@
-TABLE_ID	NAME	FLAG	N_COLS	SPACE
-11	SYS_FOREIGN	0	7	0
-12	SYS_FOREIGN_COLS	0	7	0
-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 WHERE name NOT IN ('database_name', 'table_name', 'index_name', 'stat_name', 'Master_Id', 'Worker_Id');;
-INDEX_ID	NAME	POS
-11	ID	0
-12	FOR_NAME	0
-13	REF_NAME	0
-14	ID	0
-14	POS	1
+TABLE_ID	NAME	FLAG	N_COLS	SPACE	FILE_FORMAT	ROW_FORMAT	ZIP_PAGE_SIZE
+11	SYS_FOREIGN	0	7	0	Antelope	Redundant	0
+12	SYS_FOREIGN_COLS	0	7	0	Antelope	Redundant	0
+13	SYS_TABLESPACES	0	6	0	Antelope	Redundant	0
+14	SYS_DATAFILES	0	5	0	Antelope	Redundant	0
+table_id	pos	mtype	prtype	len	name
+11	0	1	524292	0	ID
+11	1	1	524292	0	FOR_NAME
+11	2	1	524292	0	REF_NAME
+11	3	6	0	4	N_COLS
+12	0	1	524292	0	ID
+12	1	6	0	4	POS
+12	2	1	524292	0	FOR_COL_NAME
+12	3	1	524292	0	REF_COL_NAME
+13	0	6	0	4	SPACE
+13	1	1	524292	0	NAME
+13	2	6	0	4	FLAGS
+14	0	6	0	4	SPACE
+14	1	1	524292	0	PATH
+index_id	table_id	type	n_fields	space	name
+11	11	3	1	0	ID_IND
+12	11	0	1	0	FOR_IND
+13	11	0	1	0	REF_IND
+14	12	3	2	0	ID_IND
+15	13	3	1	0	SYS_TABLESPACES_SPACE
+16	14	3	1	0	SYS_DATAFILES_SPACE
+SELECT index_id,pos,name FROM INFORMATION_SCHEMA.INNODB_SYS_FIELDS
+WHERE name NOT IN ('database_name', 'table_name', 'index_name', 'stat_name', 'Master_Id', 'Worker_Id')
+ORDER BY index_id, pos;
+index_id	pos	name
+11	0	ID
+12	0	FOR_NAME
+13	0	REF_NAME
+14	0	ID
+14	1	POS
+15	0	SPACE
+16	0	SPACE
 SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
 ID	FOR_NAME	REF_NAME	N_COLS	TYPE
 mysql/innodb_index_stats_ibfk_1	mysql/innodb_index_stats	mysql/innodb_table_stats	2	0
@@ -24,9 +42,37 @@ SELECT * FROM INFORMATION_SCHEMA.INNODB_
 ID	FOR_COL_NAME	REF_COL_NAME	POS
 mysql/innodb_index_stats_ibfk_1	database_name	database_name	0
 mysql/innodb_index_stats_ibfk_1	table_name	table_name	1
+SET GLOBAL innodb_file_format=`Barracuda`;
+SET GLOBAL innodb_file_per_table=ON;
+CREATE TABLE t1 (a INT KEY, b TEXT) ROW_FORMAT=REDUNDANT ENGINE=innodb;
+CREATE TABLE t2 (a INT KEY, b TEXT) ROW_FORMAT=COMPACT ENGINE=innodb;
+CREATE TABLE t3 (a INT KEY, b TEXT) ROW_FORMAT=COMPRESSED ENGINE=innodb;
+CREATE TABLE t4 (a INT KEY, b TEXT) ROW_FORMAT=DYNAMIC ENGINE=innodb;
+SELECT name, n_cols, file_format, row_format
+FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
+WHERE space > 0 ORDER BY table_id;
+name	n_cols	file_format	row_format
+test/t1	5	Antelope	Redundant
+test/t2	5	Antelope	Compact
+test/t3	5	Barracuda	Compressed
+test/t4	5	Barracuda	Dynamic
+SELECT name, file_format, row_format
+FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES;
+name	file_format	row_format
+test/t1	Antelope	Compact or Redundant
+test/t2	Antelope	Compact or Redundant
+test/t3	Barracuda	Compressed
+test/t4	Barracuda	Dynamic
+SELECT path FROM INFORMATION_SCHEMA.INNODB_SYS_DATAFILES;
+path
+MYSQLD_DATADIR/test/t1.ibd
+MYSQLD_DATADIR/test/t2.ibd
+MYSQLD_DATADIR/test/t3.ibd
+MYSQLD_DATADIR/test/t4.ibd
+DROP TABLE t1, t2, t3, t4;
 SELECT count(*) FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS;
 count(*)
-7
+9
 CREATE TABLE parent (id INT NOT NULL,
 PRIMARY KEY (id)) ENGINE=INNODB;
 CREATE TABLE child (id INT, parent_id INT,
@@ -51,8 +97,10 @@ name	num_rows	ref_count
 test/parent	1	1
 SELECT NAME, FLAG, N_COLS, SPACE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES;
 NAME	FLAG	N_COLS	SPACE
+SYS_DATAFILES	0	5	0
 SYS_FOREIGN	0	7	0
 SYS_FOREIGN_COLS	0	7	0
+SYS_TABLESPACES	0	6	0
 mysql/innodb_index_stats	1	11	0
 mysql/innodb_table_stats	1	9	0
 mysql/slave_master_info	1	27	0

=== modified file 'mysql-test/suite/innodb/r/innodb_16k.result'
--- a/mysql-test/suite/innodb/r/innodb_16k.result	revid:andrei.elkin@stripped
+++ b/mysql-test/suite/innodb/r/innodb_16k.result	revid:kevin.lewis@stripped
@@ -11,13 +11,39 @@ SELECT variable_value FROM information_s
 WHERE LOWER(variable_name) = 'innodb_buffer_pool_pages_total';
 variable_value
 {511_or_512}
-# Test 3) The root page numbers are dependent upon the page size.
-#         Pulled from innodb-system-table-view.test
+# Test 3) Query some information_shema tables that are dependent upon
+#         the page size.
 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
+15	SYS_TABLESPACES_SPACE	13	3	1	307	0
+16	SYS_DATAFILES_SPACE	14	3	1	308	0
+CREATE TABLE t1 (a INT KEY, b TEXT) ROW_FORMAT=REDUNDANT ENGINE=innodb;
+CREATE TABLE t2 (a INT KEY, b TEXT) ROW_FORMAT=COMPACT ENGINE=innodb;
+CREATE TABLE t3 (a INT KEY, b TEXT) ROW_FORMAT=COMPRESSED ENGINE=innodb;
+CREATE TABLE t4 (a INT KEY, b TEXT) ROW_FORMAT=DYNAMIC ENGINE=innodb;
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
+WHERE space > 0 ORDER BY table_id;
+TABLE_ID	NAME	FLAG	N_COLS	SPACE	FILE_FORMAT	ROW_FORMAT	ZIP_PAGE_SIZE
+{id}	test/t1	0	5	{id}	Antelope	Redundant	0
+{id}	test/t2	1	5	{id}	Antelope	Compact	0
+{id}	test/t3	41	5	{id}	Barracuda	Compressed	8192
+{id}	test/t4	33	5	{id}	Barracuda	Dynamic	0
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES;
+SPACE	NAME	FLAG	FILE_FORMAT	ROW_FORMAT	PAGE_SIZE	ZIP_PAGE_SIZE
+{id}	test/t1	0	Antelope	Compact or Redundant	16384	0
+{id}	test/t2	0	Antelope	Compact or Redundant	16384	0
+{id}	test/t3	41	Barracuda	Compressed	16384	8192
+{id}	test/t4	33	Barracuda	Dynamic	16384	0
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_DATAFILES;
+SPACE	PATH
+{id}	MYSQLD_DATADIR/test/t1.ibd
+{id}	MYSQLD_DATADIR/test/t2.ibd
+{id}	MYSQLD_DATADIR/test/t3.ibd
+{id}	MYSQLD_DATADIR/test/t4.ibd
+DROP TABLE t1, t2, t3, t4;
 # Test 4) The maximum row size is dependent upon the page size.
 #         Redundant: 8123, Compact: 8126.
 #         Compressed: 8126, Dynamic: 8126.

=== modified file 'mysql-test/suite/innodb/r/innodb_4k.result'
--- a/mysql-test/suite/innodb/r/innodb_4k.result	revid:andrei.elkin@stripped
+++ b/mysql-test/suite/innodb/r/innodb_4k.result	revid:kevin.lewis@stripped
@@ -11,13 +11,39 @@ SELECT variable_value FROM information_s
 WHERE LOWER(variable_name) = 'innodb_buffer_pool_pages_total';
 variable_value
 2048
-# Test 3) The root page numbers are dependent upon the page size.
-#         Pulled from innodb-system-table-view.test
+# Test 3) Query some information_shema tables that are dependent upon
+#         the page size.
 INDEX_ID	NAME	TABLE_ID	TYPE	N_FIELDS	PAGE_NO	SPACE
 11	ID_IND	11	3	1	801	0
 12	FOR_IND	11	0	1	802	0
 13	REF_IND	11	0	1	804	0
 14	ID_IND	12	3	2	805	0
+15	SYS_TABLESPACES_SPACE	13	3	1	807	0
+16	SYS_DATAFILES_SPACE	14	3	1	809	0
+CREATE TABLE t1 (a INT KEY, b TEXT) ROW_FORMAT=REDUNDANT ENGINE=innodb;
+CREATE TABLE t2 (a INT KEY, b TEXT) ROW_FORMAT=COMPACT ENGINE=innodb;
+CREATE TABLE t3 (a INT KEY, b TEXT) ROW_FORMAT=COMPRESSED ENGINE=innodb;
+CREATE TABLE t4 (a INT KEY, b TEXT) ROW_FORMAT=DYNAMIC ENGINE=innodb;
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
+WHERE space > 0 ORDER BY table_id;
+TABLE_ID	NAME	FLAG	N_COLS	SPACE	FILE_FORMAT	ROW_FORMAT	ZIP_PAGE_SIZE
+{id}	test/t1	0	5	{id}	Antelope	Redundant	0
+{id}	test/t2	1	5	{id}	Antelope	Compact	0
+{id}	test/t3	37	5	{id}	Barracuda	Compressed	2048
+{id}	test/t4	33	5	{id}	Barracuda	Dynamic	0
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES;
+SPACE	NAME	FLAG	FILE_FORMAT	ROW_FORMAT	PAGE_SIZE	ZIP_PAGE_SIZE
+{id}	test/t1	192	Antelope	Compact or Redundant	4096	0
+{id}	test/t2	192	Antelope	Compact or Redundant	4096	0
+{id}	test/t3	229	Barracuda	Compressed	4096	2048
+{id}	test/t4	225	Barracuda	Dynamic	4096	0
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_DATAFILES;
+SPACE	PATH
+{id}	MYSQLD_DATADIR/test/t1.ibd
+{id}	MYSQLD_DATADIR/test/t2.ibd
+{id}	MYSQLD_DATADIR/test/t3.ibd
+{id}	MYSQLD_DATADIR/test/t4.ibd
+DROP TABLE t1, t2, t3, t4;
 # Test 4) The maximum row size is dependent upon the page size.
 #         Redundant: 1979, Compact: 1982.
 #         Compressed: 1982, Dynamic: 1982.

=== modified file 'mysql-test/suite/innodb/r/innodb_8k.result'
--- a/mysql-test/suite/innodb/r/innodb_8k.result	revid:andrei.elkin@stripped
+++ b/mysql-test/suite/innodb/r/innodb_8k.result	revid:kevin.lewis@stripped
@@ -11,13 +11,39 @@ SELECT variable_value FROM information_s
 WHERE LOWER(variable_name) = 'innodb_buffer_pool_pages_total';
 variable_value
 {1023_or_1024}
-# Test 3) The root page numbers are dependent upon the page size.
-#         Pulled from innodb-system-table-view.test
+# Test 3) Query some information_shema tables that are dependent upon
+#         the page size.
 INDEX_ID	NAME	TABLE_ID	TYPE	N_FIELDS	PAGE_NO	SPACE
 11	ID_IND	11	3	1	466	0
 12	FOR_IND	11	0	1	467	0
 13	REF_IND	11	0	1	468	0
 14	ID_IND	12	3	2	469	0
+15	SYS_TABLESPACES_SPACE	13	3	1	472	0
+16	SYS_DATAFILES_SPACE	14	3	1	473	0
+CREATE TABLE t1 (a INT KEY, b TEXT) ROW_FORMAT=REDUNDANT ENGINE=innodb;
+CREATE TABLE t2 (a INT KEY, b TEXT) ROW_FORMAT=COMPACT ENGINE=innodb;
+CREATE TABLE t3 (a INT KEY, b TEXT) ROW_FORMAT=COMPRESSED ENGINE=innodb;
+CREATE TABLE t4 (a INT KEY, b TEXT) ROW_FORMAT=DYNAMIC ENGINE=innodb;
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
+WHERE space > 0 ORDER BY table_id;
+TABLE_ID	NAME	FLAG	N_COLS	SPACE	FILE_FORMAT	ROW_FORMAT	ZIP_PAGE_SIZE
+{id}	test/t1	0	5	{id}	Antelope	Redundant	0
+{id}	test/t2	1	5	{id}	Antelope	Compact	0
+{id}	test/t3	39	5	{id}	Barracuda	Compressed	4096
+{id}	test/t4	33	5	{id}	Barracuda	Dynamic	0
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES;
+SPACE	NAME	FLAG	FILE_FORMAT	ROW_FORMAT	PAGE_SIZE	ZIP_PAGE_SIZE
+{id}	test/t1	256	Antelope	Compact or Redundant	8192	0
+{id}	test/t2	256	Antelope	Compact or Redundant	8192	0
+{id}	test/t3	295	Barracuda	Compressed	8192	4096
+{id}	test/t4	289	Barracuda	Dynamic	8192	0
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_DATAFILES;
+SPACE	PATH
+{id}	MYSQLD_DATADIR/test/t1.ibd
+{id}	MYSQLD_DATADIR/test/t2.ibd
+{id}	MYSQLD_DATADIR/test/t3.ibd
+{id}	MYSQLD_DATADIR/test/t4.ibd
+DROP TABLE t1, t2, t3, t4;
 # Test 4) The maximum row size is dependent upon the page size.
 #         Redundant: 4027, Compact: 4030.
 #         Compressed: 4030, Dynamic: 4030.

=== modified file 'mysql-test/suite/innodb/t/innodb-restart.test'
--- a/mysql-test/suite/innodb/t/innodb-restart.test	revid:andrei.elkin@stripped
+++ b/mysql-test/suite/innodb/t/innodb-restart.test	revid:kevin.lewis@stripped
@@ -2,24 +2,34 @@
 # These test make sure that tables are visible after rebooting
 #
 
--- source include/have_innodb.inc
--- source include/not_embedded.inc
-
-#
--- echo # Bug#13357607 Compressed file-per-table tablespaces fail to open
+--source include/have_innodb.inc
+--source include/have_partition.inc
+--source include/not_embedded.inc
+SET default_storage_engine=InnoDB;
+
+--echo #
+--echo # A series of tests to make sure tables are opened after restart.
+--echo # Bug#13357607 Compressed file-per-table tablespaces fail to open
+--echo #
 # This bug was introduced without a regression test failing since
 # there were no tests showing that tablespaces could e created and
 # then read after reboot.
 #
 
--- disable_query_log
+--disable_query_log
+let $MYSQLD_DATADIR= `select @@datadir`;
+let $data_directory = DATA DIRECTORY='$MYSQL_TMP_DIR/alt_dir';
+
 let $innodb_file_per_table=`select @@innodb_file_per_table`;
 let $innodb_file_format=`select @@innodb_file_format`;
--- enable_query_log
+--enable_query_log
 
 set global innodb_file_per_table=on;
 set global innodb_file_format='Barracuda';
 
+--echo #
+--echo # Create and insert records into a DYNAMIC row formatted table.
+--echo #
 CREATE TABLE t1(c1 DOUBLE AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
 	ROW_FORMAT=REDUNDANT  ENGINE=InnoDB;
 INSERT INTO t1 VALUES (1000000000, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot');
@@ -27,7 +37,12 @@ INSERT INTO t1 (SELECT 0, c2, c3, c4, c5
 INSERT INTO t1 (SELECT 0, c2, c3, c4, c5 FROM t1);
 INSERT INTO t1 (SELECT 0, c2, c3, c4, c5 FROM t1);
 INSERT INTO t1 (SELECT 0, c2, c3, c4, c5 FROM t1);
+SHOW CREATE TABLE t1;
+SELECT count(*) FROM t1;
 
+--echo #
+--echo # Create and insert records into a COMPACT row formatted table.
+--echo #
 CREATE TABLE t2(c1 DOUBLE AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
 	ROW_FORMAT=COMPACT  ENGINE=InnoDB;
 INSERT INTO t2 VALUES (1000000000, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot');
@@ -35,8 +50,12 @@ INSERT INTO t2 (SELECT 0, c2, c3, c4, c5
 INSERT INTO t2 (SELECT 0, c2, c3, c4, c5 FROM t2);
 INSERT INTO t2 (SELECT 0, c2, c3, c4, c5 FROM t2);
 INSERT INTO t2 (SELECT 0, c2, c3, c4, c5 FROM t2);
+SHOW CREATE TABLE t2;
+SELECT count(*) FROM t2;
 
-
+--echo #
+--echo # Create and insert records into a COMPRESSED row formatted table.
+--echo #
 CREATE TABLE t3(c1 DOUBLE AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
 	ROW_FORMAT=COMPRESSED  KEY_BLOCK_SIZE=4  ENGINE=InnoDB;
 INSERT INTO t3 VALUES (1000000000, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot');
@@ -44,7 +63,12 @@ INSERT INTO t3 (SELECT 0, c2, c3, c4, c5
 INSERT INTO t3 (SELECT 0, c2, c3, c4, c5 FROM t3);
 INSERT INTO t3 (SELECT 0, c2, c3, c4, c5 FROM t3);
 INSERT INTO t3 (SELECT 0, c2, c3, c4, c5 FROM t3);
+SHOW CREATE TABLE t3;
+SELECT count(*) FROM t3;
 
+--echo #
+--echo # Create and insert records into a DYNAMIC row formatted table.
+--echo #
 CREATE TABLE t4(c1 DOUBLE AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
 	ROW_FORMAT=DYNAMIC  ENGINE=InnoDB;
 INSERT INTO t4 VALUES (1000000000, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot');
@@ -52,24 +76,486 @@ INSERT INTO t4 (SELECT 0, c2, c3, c4, c5
 INSERT INTO t4 (SELECT 0, c2, c3, c4, c5 FROM t4);
 INSERT INTO t4 (SELECT 0, c2, c3, c4, c5 FROM t4);
 INSERT INTO t4 (SELECT 0, c2, c3, c4, c5 FROM t4);
+SHOW CREATE TABLE t4;
+SELECT count(*) FROM t4;
 
--- echo # Restart the server
--- source include/restart_mysqld.inc
+--echo #
+--echo # Create and insert records into a table that uses a remote DATA DIRECTORY.
+--echo #
+--mkdir $MYSQL_TMP_DIR/alt_dir
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval CREATE TABLE t5(c1 DOUBLE AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
+	ROW_FORMAT=DYNAMIC  ENGINE=InnoDB  $data_directory;
+INSERT INTO t5 VALUES (1000000000, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot');
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t5;
+SELECT count(*) FROM t5;
+
+--echo #
+--echo # Create and insert records into a partitioned table that uses
+--echo # a remote DATA DIRECTORY for each partition.
+--echo #
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval CREATE TABLE t6(
+  c1 INT AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
+  ROW_FORMAT=COMPRESSED  ENGINE=InnoDB
+  PARTITION BY HASH(c1) (
+    PARTITION p0  DATA DIRECTORY = '$MYSQL_TMP_DIR/alt_dir',
+    PARTITION p1  DATA DIRECTORY = '$MYSQL_TMP_DIR/alt_dir',
+    PARTITION p2  DATA DIRECTORY = '$MYSQL_TMP_DIR/alt_dir');
+INSERT INTO t6 VALUES (0, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot');
+INSERT INTO t6 (SELECT 0, c2, c3, c4, c5 FROM t6);
+INSERT INTO t6 (SELECT 0, c2, c3, c4, c5 FROM t6);
+INSERT INTO t6 (SELECT 0, c2, c3, c4, c5 FROM t6);
+INSERT INTO t6 (SELECT 0, c2, c3, c4, c5 FROM t6);
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t6;
+SELECT count(*) FROM t6;
+
+--echo #
+--echo # Create and insert records into a subpartitioned table that uses
+--echo # a remote DATA DIRECTORY for each subpartition.
+--echo #
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval CREATE TABLE t7(
+	c1 INT AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
+	ROW_FORMAT=DYNAMIC  ENGINE=InnoDB
+        PARTITION BY RANGE(c1) SUBPARTITION BY HASH(c1) (
+          PARTITION p0 VALUES LESS THAN (10) (
+	    SUBPARTITION s0 DATA DIRECTORY = '$MYSQL_TMP_DIR/alt_dir',
+	    SUBPARTITION s1 DATA DIRECTORY = '$MYSQL_TMP_DIR/alt_dir'),
+	  PARTITION p1 VALUES LESS THAN MAXVALUE (
+	    SUBPARTITION s2 DATA DIRECTORY = '$MYSQL_TMP_DIR/alt_dir',
+	    SUBPARTITION s3 DATA DIRECTORY = '$MYSQL_TMP_DIR/alt_dir'));
+INSERT INTO t7 VALUES (0, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot');
+INSERT INTO t7 (SELECT 0, c2, c3, c4, c5 FROM t7);
+INSERT INTO t7 (SELECT 0, c2, c3, c4, c5 FROM t7);
+INSERT INTO t7 (SELECT 0, c2, c3, c4, c5 FROM t7);
+INSERT INTO t7 (SELECT 0, c2, c3, c4, c5 FROM t7);
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t7;
+SELECT count(*) FROM t7;
+
+--echo #
+--echo # Show these tables in information_schema.
+--echo #
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name like 'test%';
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--replace_result ./ MYSQLD_DATADIR/  $MYSQLD_DATADIR MYSQLD_DATADIR  $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles ORDER BY path;
+
+--echo #
+--echo # Shutdown the server and list the tablespace OS files
+--echo #
+--source include/shutdown_mysqld.inc
+
+--echo ---- MYSQLD_DATADIR/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQLD_DATADIR/test
+--echo ---- MYSQL_TMP_DIR/alt_dir
+--list_files $MYSQL_TMP_DIR/alt_dir
+--echo ---- MYSQL_TMP_DIR/alt_dir/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQL_TMP_DIR/alt_dir/test
+
+--echo #
+--echo # Start the server and show that tables are still visible and accessible.
+--echo #
+--source include/start_mysqld.inc
+
+SHOW VARIABLES LIKE 'innodb_file_per_table';
 SHOW CREATE TABLE t1;
 SHOW CREATE TABLE t2;
 SHOW CREATE TABLE t3;
 SHOW CREATE TABLE t4;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t5;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t6;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t7;
 
 INSERT INTO t1 (SELECT 0, c2, c3, c4, c5 FROM t1);
 INSERT INTO t2 (SELECT 0, c2, c3, c4, c5 FROM t2);
 INSERT INTO t3 (SELECT 0, c2, c3, c4, c5 FROM t3);
 INSERT INTO t4 (SELECT 0, c2, c3, c4, c5 FROM t4);
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+INSERT INTO t6 (SELECT 0, c2, c3, c4, c5 FROM t6);
+INSERT INTO t7 (SELECT 0, c2, c3, c4, c5 FROM t7);
+
+SELECT count(*) FROM t1;
+SELECT count(*) FROM t2;
+SELECT count(*) FROM t3;
+SELECT count(*) FROM t4;
+SELECT count(*) FROM t5;
+SELECT count(*) FROM t6;
+SELECT count(*) FROM t7;
+
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name like 'test%';
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--replace_result ./ MYSQLD_DATADIR/  $MYSQLD_DATADIR MYSQLD_DATADIR  $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles ORDER BY path;
 
 DROP TABLE t1;
 DROP TABLE t2;
 DROP TABLE t3;
 DROP TABLE t4;
 
+--echo #
+--echo # Truncate the remote tablespaces.
+--echo #
+TRUNCATE TABLE t5;
+ALTER TABLE t6 TRUNCATE PARTITION p2;
+ALTER TABLE t7 TRUNCATE PARTITION p1;
+
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles ORDER BY path;
+
+INSERT INTO t5 VALUES (1000000000, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot');
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+
+SELECT count(*) FROM t5;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t5;
+
+SELECT count(*) FROM t6;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t6;
+
+SELECT count(*) FROM t7;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t7;
+
+--echo #
+--echo # Shutdown the server and make a backup of a tablespace
+--echo #
+--source include/shutdown_mysqld.inc
+
+--copy_file $MYSQL_TMP_DIR/alt_dir/test/t5.ibd $MYSQL_TMP_DIR/alt_dir/test/t5.ibd.bak
+--copy_file $MYSQLD_DATADIR/test/t5.isl $MYSQLD_DATADIR/test/t5.isl.bak
+--copy_file $MYSQLD_DATADIR/test/t5.frm $MYSQLD_DATADIR/test/t5.frm.bak
+
+--echo ---- MYSQLD_DATADIR/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/  /#SP#/#sp#/
+--list_files $MYSQLD_DATADIR/test
+--echo ---- MYSQL_TMP_DIR/alt_dir/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQL_TMP_DIR/alt_dir/test
+
+--echo #
+--echo # Start the server and show the tablespaces.
+--echo #
+--source include/start_mysqld.inc
+
+SHOW VARIABLES LIKE 'innodb_file_per_table';
+
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles ORDER BY path;
+
+SELECT count(*) FROM t5;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t5;
+
+SELECT count(*) FROM t6;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t6;
+
+SELECT count(*) FROM t7;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t7;
+
+--echo #
+--echo # Try to rename a tablespace to a file that already exists
+--echo #
+
+--copy_file $MYSQLD_DATADIR/test/t5.frm.bak $MYSQLD_DATADIR/test/t55.frm
+--error ER_TABLE_EXISTS_ERROR
+RENAME TABLE t5 TO t55;
+--remove_file $MYSQLD_DATADIR/test/t55.frm
+--remove_file $MYSQLD_DATADIR/test/t5.frm.bak
+
+--copy_file $MYSQLD_DATADIR/test/t5.isl.bak $MYSQLD_DATADIR/test/t55.isl
+--error ER_ERROR_ON_RENAME
+RENAME TABLE t5 TO t55;
+--remove_file $MYSQLD_DATADIR/test/t55.isl
+--remove_file $MYSQLD_DATADIR/test/t5.isl.bak
+
+--copy_file $MYSQL_TMP_DIR/alt_dir/test/t5.ibd.bak $MYSQL_TMP_DIR/alt_dir/test/t55.ibd
+# This RENAME TABLE works of Linux but gets ER_ERROR_ON_RENAME on Windows
+#--error ER_ERROR_ON_RENAME
+#RENAME TABLE t5 TO t55;
+--remove_file $MYSQL_TMP_DIR/alt_dir/test/t55.ibd
+--remove_file $MYSQL_TMP_DIR/alt_dir/test/t5.ibd.bak
+
+--echo ---- MYSQLD_DATADIR/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQLD_DATADIR/test
+--echo ---- MYSQL_TMP_DIR/alt_dir/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQL_TMP_DIR/alt_dir/test
+
+--echo #
+--echo # Rename file table and tablespace
+--echo #
+
+RENAME TABLE t5 TO t55;
+RENAME TABLE t6 TO t66;
+RENAME TABLE t7 TO t77;
+
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles ORDER BY path;
+
+INSERT INTO t55 (SELECT 0, c2, c3, c4, c5 FROM t55);
+SELECT count(*) FROM t55;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t55;
+
+INSERT INTO t66 (SELECT 0, c2, c3, c4, c5 FROM t66);
+SELECT count(*) FROM t66;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t66;
+
+INSERT INTO t77 (SELECT 0, c2, c3, c4, c5 FROM t77);
+SELECT count(*) FROM t77;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t77;
+
+--echo ---- MYSQLD_DATADIR/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQLD_DATADIR/test
+--echo ---- MYSQL_TMP_DIR/alt_dir/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQL_TMP_DIR/alt_dir/test
+
+--echo #
+--echo # Restart the server
+--echo #
+--source include/restart_mysqld.inc
+SHOW VARIABLES LIKE 'innodb_file_per_table';
+
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR  $MYSQLD_DATADIR MYSQLD_DATADIR  ./ MYSQLD_DATADIR/
+SELECT path FROM information_schema.innodb_sys_datafiles ORDER BY path;
+
+INSERT INTO t55 (SELECT 0, c2, c3, c4, c5 FROM t55);
+SELECT count(*) FROM t55;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t55;
+
+INSERT INTO t66 (SELECT 0, c2, c3, c4, c5 FROM t66);
+SELECT count(*) FROM t66;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t66;
+
+INSERT INTO t77 (SELECT 0, c2, c3, c4, c5 FROM t77);
+SELECT count(*) FROM t77;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t77;
+
+--echo #
+--echo # Shutdown the server
+--echo #
+--source include/shutdown_mysqld.inc
+
+--echo #
+--echo # Move the remote tablespaces to a new location and change the ISL files
+--echo #
+--mkdir $MYSQL_TMP_DIR/new_dir
+--mkdir $MYSQL_TMP_DIR/new_dir/test
+--echo ---- MYSQLD_DATADIR/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQLD_DATADIR/test
+--echo ---- MYSQL_TMP_DIR/alt_dir/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQL_TMP_DIR/alt_dir/test
+--echo ---- MYSQL_TMP_DIR/new_dir/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQL_TMP_DIR/new_dir/test
+
+--echo # Moving tablespace 't55' from MYSQL_TMP_DIR/alt_dir to MYSQL_TMP_DIR/new_dir
+--copy_file $MYSQL_TMP_DIR/alt_dir/test/t55.ibd $MYSQL_TMP_DIR/new_dir/test/t55.ibd
+--remove_file $MYSQL_TMP_DIR/alt_dir/test/t55.ibd
+--remove_file $MYSQLD_DATADIR/test/t55.isl
+--exec echo $MYSQL_TMP_DIR/new_dir/test/t55.ibd > $MYSQLD_DATADIR/test/t55.isl
+
+--echo # Moving tablespace 't66' from MYSQL_TMP_DIR/alt_dir to MYSQL_TMP_DIR/new_dir
+--copy_file $MYSQL_TMP_DIR/alt_dir/test/t66#P#p0.ibd $MYSQL_TMP_DIR/new_dir/test/t66#P#p0.ibd
+--copy_file $MYSQL_TMP_DIR/alt_dir/test/t66#P#p1.ibd $MYSQL_TMP_DIR/new_dir/test/t66#P#p1.ibd
+--copy_file $MYSQL_TMP_DIR/alt_dir/test/t66#P#p2.ibd $MYSQL_TMP_DIR/new_dir/test/t66#P#p2.ibd
+--remove_file $MYSQL_TMP_DIR/alt_dir/test/t66#P#p0.ibd
+--remove_file $MYSQL_TMP_DIR/alt_dir/test/t66#P#p1.ibd
+--remove_file $MYSQL_TMP_DIR/alt_dir/test/t66#P#p2.ibd
+--remove_file $MYSQLD_DATADIR/test/t66#P#p0.isl
+--remove_file $MYSQLD_DATADIR/test/t66#P#p1.isl
+--remove_file $MYSQLD_DATADIR/test/t66#P#p2.isl
+--exec echo $MYSQL_TMP_DIR/new_dir/test/t66#P#p0.ibd > $MYSQLD_DATADIR/test/t66#P#p0.isl
+--exec echo $MYSQL_TMP_DIR/new_dir/test/t66#P#p1.ibd > $MYSQLD_DATADIR/test/t66#P#p1.isl
+--exec echo $MYSQL_TMP_DIR/new_dir/test/t66#P#p2.ibd > $MYSQLD_DATADIR/test/t66#P#p2.isl
+
+--echo # Moving tablespace 't77' from MYSQL_TMP_DIR/alt_dir to MYSQL_TMP_DIR/new_dir
+--copy_file $MYSQL_TMP_DIR/alt_dir/test/t77#P#p0#SP#s0.ibd $MYSQL_TMP_DIR/new_dir/test/t77#P#p0#SP#s0.ibd
+--copy_file $MYSQL_TMP_DIR/alt_dir/test/t77#P#p0#SP#s1.ibd $MYSQL_TMP_DIR/new_dir/test/t77#P#p0#SP#s1.ibd
+--copy_file $MYSQL_TMP_DIR/alt_dir/test/t77#P#p1#SP#s2.ibd $MYSQL_TMP_DIR/new_dir/test/t77#P#p1#SP#s2.ibd
+--copy_file $MYSQL_TMP_DIR/alt_dir/test/t77#P#p1#SP#s3.ibd $MYSQL_TMP_DIR/new_dir/test/t77#P#p1#SP#s3.ibd
+--remove_file $MYSQL_TMP_DIR/alt_dir/test/t77#P#p0#SP#s0.ibd
+--remove_file $MYSQL_TMP_DIR/alt_dir/test/t77#P#p0#SP#s1.ibd
+--remove_file $MYSQL_TMP_DIR/alt_dir/test/t77#P#p1#SP#s2.ibd
+--remove_file $MYSQL_TMP_DIR/alt_dir/test/t77#P#p1#SP#s3.ibd
+--remove_file $MYSQLD_DATADIR/test/t77#P#p0#SP#s0.isl
+--remove_file $MYSQLD_DATADIR/test/t77#P#p0#SP#s1.isl
+--remove_file $MYSQLD_DATADIR/test/t77#P#p1#SP#s2.isl
+--remove_file $MYSQLD_DATADIR/test/t77#P#p1#SP#s3.isl
+--exec echo $MYSQL_TMP_DIR/new_dir/test/t77#P#p0#SP#s0.ibd > $MYSQLD_DATADIR/test/t77#P#p0#SP#s0.isl
+--exec echo $MYSQL_TMP_DIR/new_dir/test/t77#P#p0#SP#s1.ibd > $MYSQLD_DATADIR/test/t77#P#p0#SP#s1.isl
+--exec echo $MYSQL_TMP_DIR/new_dir/test/t77#P#p1#SP#s2.ibd > $MYSQLD_DATADIR/test/t77#P#p1#SP#s2.isl
+--exec echo $MYSQL_TMP_DIR/new_dir/test/t77#P#p1#SP#s3.ibd > $MYSQLD_DATADIR/test/t77#P#p1#SP#s3.isl
+
+
+--echo ---- MYSQLD_DATADIR/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQLD_DATADIR/test
+--echo ---- MYSQL_TMP_DIR/alt_dir/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQL_TMP_DIR/alt_dir/test
+--echo ---- MYSQL_TMP_DIR/new_dir/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQL_TMP_DIR/new_dir/test
+
+--echo #
+--echo # Start the server and check tablespaces.
+--echo #
+--source include/start_mysqld.inc
+
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles ORDER BY path;
+
+INSERT INTO t55 (SELECT 0, c2, c3, c4, c5 FROM t55);
+SELECT count(*) FROM t55;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t55;
+
+INSERT INTO t66 (SELECT 0, c2, c3, c4, c5 FROM t66);
+SELECT count(*) FROM t66;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t66;
+
+INSERT INTO t77 (SELECT 0, c2, c3, c4, c5 FROM t77);
+SELECT count(*) FROM t77;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t77;
+
+
+--echo #
+--echo # Shutdown the server
+--echo #
+--source include/shutdown_mysqld.inc
+
+--echo #
+--echo # Move the remote tablespaces back to the default datadir and delete the ISL file.
+--echo #
+
+--echo ---- MYSQLD_DATADIR/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQLD_DATADIR/test
+--echo ---- MYSQL_TMP_DIR/new_dir/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQL_TMP_DIR/new_dir/test
+
+--echo # Moving 't55' from MYSQL_TMP_DIR/new_dir to MYSQLD_DATADIR
+--copy_file $MYSQL_TMP_DIR/new_dir/test/t55.ibd $MYSQLD_DATADIR/test/t55.ibd
+--remove_file $MYSQL_TMP_DIR/new_dir/test/t55.ibd
+--remove_file $MYSQLD_DATADIR/test/t55.isl
+
+--echo # Moving 't66' from MYSQL_TMP_DIR/new_dir to MYSQLD_DATADIR
+--copy_file $MYSQL_TMP_DIR/new_dir/test/t66#P#p0.ibd $MYSQLD_DATADIR/test/t66#P#p0.ibd
+--copy_file $MYSQL_TMP_DIR/new_dir/test/t66#P#p1.ibd $MYSQLD_DATADIR/test/t66#P#p1.ibd
+--copy_file $MYSQL_TMP_DIR/new_dir/test/t66#P#p2.ibd $MYSQLD_DATADIR/test/t66#P#p2.ibd
+--remove_file $MYSQL_TMP_DIR/new_dir/test/t66#P#p0.ibd
+--remove_file $MYSQL_TMP_DIR/new_dir/test/t66#P#p1.ibd
+--remove_file $MYSQL_TMP_DIR/new_dir/test/t66#P#p2.ibd
+--remove_file $MYSQLD_DATADIR/test/t66#P#p0.isl
+--remove_file $MYSQLD_DATADIR/test/t66#P#p1.isl
+--remove_file $MYSQLD_DATADIR/test/t66#P#p2.isl
+
+--echo # Moving 't77' from MYSQL_TMP_DIR/new_dir to MYSQLD_DATADIR
+--copy_file $MYSQL_TMP_DIR/new_dir/test/t77#P#p0#SP#s0.ibd $MYSQLD_DATADIR/test/t77#P#p0#SP#s0.ibd
+--copy_file $MYSQL_TMP_DIR/new_dir/test/t77#P#p0#SP#s1.ibd $MYSQLD_DATADIR/test/t77#P#p0#SP#s1.ibd
+--copy_file $MYSQL_TMP_DIR/new_dir/test/t77#P#p1#SP#s2.ibd $MYSQLD_DATADIR/test/t77#P#p1#SP#s2.ibd
+--copy_file $MYSQL_TMP_DIR/new_dir/test/t77#P#p1#SP#s3.ibd $MYSQLD_DATADIR/test/t77#P#p1#SP#s3.ibd
+--remove_file $MYSQL_TMP_DIR/new_dir/test/t77#P#p0#SP#s0.ibd
+--remove_file $MYSQL_TMP_DIR/new_dir/test/t77#P#p0#SP#s1.ibd
+--remove_file $MYSQL_TMP_DIR/new_dir/test/t77#P#p1#SP#s2.ibd
+--remove_file $MYSQL_TMP_DIR/new_dir/test/t77#P#p1#SP#s3.ibd
+--remove_file $MYSQLD_DATADIR/test/t77#P#p0#SP#s0.isl
+--remove_file $MYSQLD_DATADIR/test/t77#P#p0#SP#s1.isl
+--remove_file $MYSQLD_DATADIR/test/t77#P#p1#SP#s2.isl
+--remove_file $MYSQLD_DATADIR/test/t77#P#p1#SP#s3.isl
+
+--echo ---- MYSQLD_DATADIR/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQLD_DATADIR/test
+--echo ---- MYSQL_TMP_DIR/new_dir/test
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--list_files $MYSQL_TMP_DIR/new_dir/test
+
+--echo # 
+--echo # Start the server and check tablespaces.
+--echo # 
+-- source include/start_mysqld.inc
+
+--replace_regex  /#P#/#p#/  /#SP#/#sp#/
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR ./ MYSQLD_DATADIR/
+SELECT path FROM information_schema.innodb_sys_datafiles ORDER BY path;
+
+INSERT INTO t55 (SELECT 0, c2, c3, c4, c5 FROM t55);
+SELECT count(*) FROM t55;
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR ./ MYSQLD_DATADIR/
+SHOW CREATE TABLE t55;
+
+INSERT INTO t66 (SELECT 0, c2, c3, c4, c5 FROM t66);
+SELECT count(*) FROM t66;
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR ./ MYSQLD_DATADIR/
+SHOW CREATE TABLE t66;
+
+INSERT INTO t77 (SELECT 0, c2, c3, c4, c5 FROM t77);
+SELECT count(*) FROM t77;
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR ./ MYSQLD_DATADIR/
+SHOW CREATE TABLE t77;
+
+
+--echo #
+--echo # Cleanup
+--echo #
+
+DROP TABLE t55;
+DROP TABLE t66;
+DROP TABLE t77;
+
+--rmdir $MYSQL_TMP_DIR/alt_dir/test
+--rmdir $MYSQL_TMP_DIR/alt_dir
+--rmdir $MYSQL_TMP_DIR/new_dir/test
+--rmdir $MYSQL_TMP_DIR/new_dir
+
 -- disable_query_log
 eval set global innodb_file_format=$innodb_file_format;
 eval set global innodb_file_per_table=$innodb_file_per_table;

=== modified file 'mysql-test/suite/innodb/t/innodb-system-table-view.test'
--- a/mysql-test/suite/innodb/t/innodb-system-table-view.test	revid:andrei.elkin@stripped
+++ b/mysql-test/suite/innodb/t/innodb-system-table-view.test	revid:kevin.lewis@stripped
@@ -4,6 +4,14 @@
 
 --source include/have_innodb.inc
 
+--disable_query_log
+SET default_storage_engine=InnoDB;
+let $MYSQLD_DATADIR= `select @@datadir`;
+# These values can change during the test
+LET $innodb_file_format_orig=`select @@innodb_file_format`;
+LET $innodb_file_per_table_orig=`select @@innodb_file_per_table`;
+--enable_query_log
+
 # The IDs of mysql.innodb_table_stats and mysql.innodb_index_stats are
 # unpredictable, probably they on whether mtr has created the database for
 # this test from scratch or is using a previously created database where
@@ -18,21 +26,44 @@
 --let $rep_table_3 = `SELECT table_id FROM information_schema.innodb_sys_tables WHERE name = 'mysql/slave_worker_info'`
 
 --disable_query_log
---eval SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE table_id NOT IN ($table_stats_id, $index_stats_id, $rep_table_1, $rep_table_2, $rep_table_3)
+--eval SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE table_id NOT IN ($table_stats_id, $index_stats_id, $rep_table_1, $rep_table_2, $rep_table_3) ORDER BY table_id;
 
-# This has been moved to innodb_4k, innodb_8k & innodb_16k
-# since the root page number changes with page size.
-#--eval SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES WHERE table_id NOT IN ($table_stats_id, $index_stats_id, $rep_table_1, $rep_table_2, $rep_table_3)
+--eval SELECT table_id,pos,mtype,prtype,len,name FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS WHERE table_id NOT IN ($table_stats_id, $index_stats_id, $rep_table_1, $rep_table_2, $rep_table_3) ORDER BY table_id, pos;
 
---eval SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS WHERE table_id NOT IN ($table_stats_id, $index_stats_id, $rep_table_1, $rep_table_2, $rep_table_3)
+# The SELECT * version of the query below has been moved to innodb_4k,
+# innodb_8k & innodb_16k since the root page number changes with page size.
+--eval SELECT index_id,table_id,type,n_fields,space,name FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES WHERE table_id NOT IN ($table_stats_id, $index_stats_id, $rep_table_1, $rep_table_2, $rep_table_3) ORDER BY index_id;
 --enable_query_log
 
---eval SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FIELDS WHERE name NOT IN ('database_name', 'table_name', 'index_name', 'stat_name', 'Master_Id', 'Worker_Id');
+SELECT index_id,pos,name FROM INFORMATION_SCHEMA.INNODB_SYS_FIELDS
+       WHERE name NOT IN ('database_name', 'table_name', 'index_name', 'stat_name', 'Master_Id', 'Worker_Id')
+       ORDER BY index_id, pos;
 
 SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
 
 SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
 
+SET GLOBAL innodb_file_format=`Barracuda`;
+SET GLOBAL innodb_file_per_table=ON;
+CREATE TABLE t1 (a INT KEY, b TEXT) ROW_FORMAT=REDUNDANT ENGINE=innodb;
+CREATE TABLE t2 (a INT KEY, b TEXT) ROW_FORMAT=COMPACT ENGINE=innodb;
+CREATE TABLE t3 (a INT KEY, b TEXT) ROW_FORMAT=COMPRESSED ENGINE=innodb;
+CREATE TABLE t4 (a INT KEY, b TEXT) ROW_FORMAT=DYNAMIC ENGINE=innodb;
+
+SELECT name, n_cols, file_format, row_format
+       FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
+       WHERE space > 0 ORDER BY table_id;
+SELECT name, file_format, row_format
+       FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES;
+--replace_result  ./ MYSQLD_DATADIR/  $MYSQLD_DATADIR MYSQLD_DATADIR
+SELECT path FROM INFORMATION_SCHEMA.INNODB_SYS_DATAFILES;
+
+DROP TABLE t1, t2, t3, t4;
+--disable_query_log
+EVAL SET GLOBAL innodb_file_format=$innodb_file_format_orig;
+EVAL SET GLOBAL innodb_file_per_table=$innodb_file_per_table_orig;
+--enable_query_log
+
 SELECT count(*) FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS;
 
 # Create a foreign key constraint, and verify the information
@@ -109,3 +140,9 @@ WHERE name LIKE "%parent";
 DROP TABLE child;
 
 DROP TABLE parent;
+
+--disable_query_log
+EVAL SET GLOBAL innodb_file_format=$innodb_file_format_orig;
+EVAL SET GLOBAL innodb_file_per_table=$innodb_file_per_table_orig;
+--enable_query_log
+

=== modified file 'mysql-test/suite/innodb/t/innodb_16k.test'
--- a/mysql-test/suite/innodb/t/innodb_16k.test	revid:andrei.elkin@stripped
+++ b/mysql-test/suite/innodb/t/innodb_16k.test	revid:kevin.lewis@stripped
@@ -7,6 +7,8 @@
 SET default_storage_engine=InnoDB;
 
 --disable_query_log
+let $MYSQLD_DATADIR= `select @@datadir`;
+
 # These values can change during the test
 let $innodb_file_format_orig = `SELECT @@innodb_file_format`;
 let $innodb_file_format_max_orig = `SELECT @@innodb_file_format_max`;
@@ -27,8 +29,9 @@ SELECT variable_value FROM information_s
 SELECT variable_value FROM information_schema.global_status
        WHERE LOWER(variable_name) = 'innodb_buffer_pool_pages_total';
 
---echo # Test 3) The root page numbers are dependent upon the page size.
---echo #         Pulled from innodb-system-table-view.test
+--echo # Test 3) Query some information_shema tables that are dependent upon
+--echo #         the page size.
+# Pulled from innodb-system-table-view.test
 # The IDs of mysql.innodb_table_stats and mysql.innodb_index_stats are
 # unpredictable, probably they on whether mtr has created the database for
 # this test from scratch or is using a previously created database where
@@ -44,6 +47,19 @@ SELECT variable_value FROM information_s
 --let $rep_table_3 = `SELECT table_id FROM information_schema.innodb_sys_tables WHERE name = 'mysql/slave_worker_info'`
 --eval SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES WHERE table_id NOT IN ($table_stats_id, $index_stats_id, $rep_table_1, $rep_table_2, $rep_table_3)
 --enable_query_log
+CREATE TABLE t1 (a INT KEY, b TEXT) ROW_FORMAT=REDUNDANT ENGINE=innodb;
+CREATE TABLE t2 (a INT KEY, b TEXT) ROW_FORMAT=COMPACT ENGINE=innodb;
+CREATE TABLE t3 (a INT KEY, b TEXT) ROW_FORMAT=COMPRESSED ENGINE=innodb;
+CREATE TABLE t4 (a INT KEY, b TEXT) ROW_FORMAT=DYNAMIC ENGINE=innodb;
+--replace_column 1 {id} 5 {id}
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
+       WHERE space > 0 ORDER BY table_id;
+--replace_column 1 {id}
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES;
+--replace_column 1 {id}
+--replace_result  ./ MYSQLD_DATADIR/  $MYSQLD_DATADIR MYSQLD_DATADIR
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_DATAFILES;
+DROP TABLE t1, t2, t3, t4;
 
 --echo # Test 4) The maximum row size is dependent upon the page size.
 --echo #         Redundant: 8123, Compact: 8126.

=== modified file 'mysql-test/suite/innodb/t/innodb_4k.test'
--- a/mysql-test/suite/innodb/t/innodb_4k.test	revid:andrei.elkin@stripped
+++ b/mysql-test/suite/innodb/t/innodb_4k.test	revid:kevin.lewis@stripped
@@ -5,6 +5,8 @@
 SET default_storage_engine=InnoDB;
 
 --disable_query_log
+let $MYSQLD_DATADIR= `select @@datadir`;
+
 # These values can change during the test
 let $innodb_file_format_orig = `SELECT @@innodb_file_format`;
 let $innodb_file_format_max_orig = `SELECT @@innodb_file_format_max`;
@@ -24,8 +26,9 @@ SELECT variable_value FROM information_s
 SELECT variable_value FROM information_schema.global_status
        WHERE LOWER(variable_name) = 'innodb_buffer_pool_pages_total';
 
---echo # Test 3) The root page numbers are dependent upon the page size.
---echo #         Pulled from innodb-system-table-view.test
+--echo # Test 3) Query some information_shema tables that are dependent upon
+--echo #         the page size.
+# Pulled from innodb-system-table-view.test
 # The IDs of mysql.innodb_table_stats and mysql.innodb_index_stats are
 # unpredictable, probably they on whether mtr has created the database for
 # this test from scratch or is using a previously created database where
@@ -41,6 +44,19 @@ SELECT variable_value FROM information_s
 --let $rep_table_3 = `SELECT table_id FROM information_schema.innodb_sys_tables WHERE name = 'mysql/slave_worker_info'`
 --eval SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES WHERE table_id NOT IN ($table_stats_id, $index_stats_id, $rep_table_1, $rep_table_2, $rep_table_3)
 --enable_query_log
+CREATE TABLE t1 (a INT KEY, b TEXT) ROW_FORMAT=REDUNDANT ENGINE=innodb;
+CREATE TABLE t2 (a INT KEY, b TEXT) ROW_FORMAT=COMPACT ENGINE=innodb;
+CREATE TABLE t3 (a INT KEY, b TEXT) ROW_FORMAT=COMPRESSED ENGINE=innodb;
+CREATE TABLE t4 (a INT KEY, b TEXT) ROW_FORMAT=DYNAMIC ENGINE=innodb;
+--replace_column 1 {id} 5 {id}
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
+       WHERE space > 0 ORDER BY table_id;
+--replace_column 1 {id}
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES;
+--replace_column 1 {id}
+--replace_result  ./ MYSQLD_DATADIR/  $MYSQLD_DATADIR MYSQLD_DATADIR
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_DATAFILES;
+DROP TABLE t1, t2, t3, t4;
 
 --echo # Test 4) The maximum row size is dependent upon the page size.
 --echo #         Redundant: 1979, Compact: 1982.

=== modified file 'mysql-test/suite/innodb/t/innodb_8k.test'
--- a/mysql-test/suite/innodb/t/innodb_8k.test	revid:andrei.elkin@stripped
+++ b/mysql-test/suite/innodb/t/innodb_8k.test	revid:kevin.lewis@stripped
@@ -5,6 +5,8 @@
 SET default_storage_engine=InnoDB;
 
 --disable_query_log
+let $MYSQLD_DATADIR= `select @@datadir`;
+
 # These values can change during the test
 let $innodb_file_format_orig = `SELECT @@innodb_file_format`;
 let $innodb_file_format_max_orig = `SELECT @@innodb_file_format_max`;
@@ -25,8 +27,9 @@ SELECT variable_value FROM information_s
 SELECT variable_value FROM information_schema.global_status
        WHERE LOWER(variable_name) = 'innodb_buffer_pool_pages_total';
 
---echo # Test 3) The root page numbers are dependent upon the page size.
---echo #         Pulled from innodb-system-table-view.test
+--echo # Test 3) Query some information_shema tables that are dependent upon
+--echo #         the page size.
+# Pulled from innodb-system-table-view.test
 # The IDs of mysql.innodb_table_stats and mysql.innodb_index_stats are
 # unpredictable, probably they on whether mtr has created the database for
 # this test from scratch or is using a previously created database where
@@ -42,6 +45,19 @@ SELECT variable_value FROM information_s
 --let $rep_table_3 = `SELECT table_id FROM information_schema.innodb_sys_tables WHERE name = 'mysql/slave_worker_info'`
 --eval SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES WHERE table_id NOT IN ($table_stats_id, $index_stats_id, $rep_table_1, $rep_table_2, $rep_table_3)
 --enable_query_log
+CREATE TABLE t1 (a INT KEY, b TEXT) ROW_FORMAT=REDUNDANT ENGINE=innodb;
+CREATE TABLE t2 (a INT KEY, b TEXT) ROW_FORMAT=COMPACT ENGINE=innodb;
+CREATE TABLE t3 (a INT KEY, b TEXT) ROW_FORMAT=COMPRESSED ENGINE=innodb;
+CREATE TABLE t4 (a INT KEY, b TEXT) ROW_FORMAT=DYNAMIC ENGINE=innodb;
+--replace_column 1 {id} 5 {id}
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
+       WHERE space > 0 ORDER BY table_id;
+--replace_column 1 {id}
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES;
+--replace_column 1 {id}
+--replace_result  ./ MYSQLD_DATADIR/  $MYSQLD_DATADIR MYSQLD_DATADIR
+SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_DATAFILES;
+DROP TABLE t1, t2, t3, t4;
 
 --echo # Test 4) The maximum row size is dependent upon the page size.
 --echo #         Redundant: 4027, Compact: 4030.

=== modified file 'mysql-test/suite/parts/r/partition_basic_symlink_innodb.result'
--- a/mysql-test/suite/parts/r/partition_basic_symlink_innodb.result	revid:andrei.elkin@stripped
+++ b/mysql-test/suite/parts/r/partition_basic_symlink_innodb.result	revid:kevin.lewis@stripped
@@ -1,10 +1,40 @@
-# Will not run partition_basic_symlink on InnoDB, since it is the same
-# as partition_basic, since InnoDB does not support DATA/INDEX DIR
-# Will only verify that the DATA/INDEX DIR is stored and used if
-# ALTER to MyISAM.
+#
+# Verify that the DATA/INDEX DIR is stored and used if ALTER to MyISAM.
+#
 DROP TABLE IF EXISTS t1;
-CREATE TABLE t1 (c1 INT)
-ENGINE = InnoDB
+SET SESSION innodb_strict_mode = ON;
+#
+# InnoDB only supports DATA DIRECTORY with innodb_file_per_table=ON
+#
+SET GLOBAL innodb_file_per_table = OFF;
+CREATE TABLE t1 (c1 INT)  ENGINE = InnoDB
+PARTITION BY HASH (c1) (
+PARTITION p0
+DATA DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-data-dir'
+    INDEX DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-idx-dir',
+PARTITION p1
+DATA DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-data-dir'
+    INDEX DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-idx-dir'
+);
+ERROR HY000: Can't create table 'test.t1' (errno: 1478)
+SHOW WARNINGS;
+Level	Code	Message
+Warning	1478	InnoDB: DATA DIRECTORY requires innodb_file_per_table.
+Warning	1478	InnoDB: INDEX DIRECTORY is not supported
+Error	1005	Can't create table 'test.t1' (errno: 1478)
+Error	6	Error on delete of 'MYSQLD_DATADIR/test/t1.par' (Errcode: 2 - No such file or directory)
+#
+# InnoDB is different from MyISAM in that it uses a text file
+# with an '.isl' extension instead of a symbolic link so that
+# the tablespace can be re-located on any OS. Also, instead of
+# putting the file directly into the DATA DIRECTORY,
+# it adds a folder under it with the name of the database.
+# Since strict mode is off, InnoDB ignores the INDEX DIRECTORY
+# and it is no longer part of the definition.
+#
+SET SESSION innodb_strict_mode = OFF;
+SET GLOBAL innodb_file_per_table = ON;
+CREATE TABLE t1 (c1 INT) ENGINE = InnoDB
 PARTITION BY HASH (c1)
 (PARTITION p0
 DATA DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-data-dir'
@@ -13,8 +43,26 @@ PARTITION p1
 DATA DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-data-dir'
  INDEX DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-idx-dir'
 );
-# Verifying .frm and .par files
-# Verifying that there are no MyISAM files
+Warnings:
+Warning	1618	<INDEX DIRECTORY> option ignored
+Warning	1618	<INDEX DIRECTORY> option ignored
+SHOW WARNINGS;
+Level	Code	Message
+Warning	1618	<INDEX DIRECTORY> option ignored
+Warning	1618	<INDEX DIRECTORY> option ignored
+# Verifying .frm, .par, .isl & .ibd files
+---- MYSQLD_DATADIR/test
+t1#P#p0.isl
+t1#P#p1.isl
+t1.frm
+t1.par
+---- MYSQLTEST_VARDIR/mysql-test-data-dir/test
+t1#P#p0.ibd
+t1#P#p1.ibd
+# The ibd tablespaces should not be directly under the DATA DIRECTORY
+---- MYSQLTEST_VARDIR/mysql-test-data-dir
+test
+---- MYSQLTEST_VARDIR/mysql-test-idx-dir
 FLUSH TABLES;
 SHOW CREATE TABLE t1;
 Table	Create Table
@@ -22,17 +70,61 @@ t1	CREATE TABLE `t1` (
   `c1` int(11) DEFAULT NULL
 ) ENGINE=InnoDB DEFAULT CHARSET=latin1
 /*!50100 PARTITION BY HASH (c1)
-(PARTITION p0 DATA DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-data-dir' INDEX DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-idx-dir' ENGINE = InnoDB,
- PARTITION p1 DATA DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-data-dir' INDEX DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-idx-dir' ENGINE = InnoDB) */
-ALTER TABLE t1 ENGINE = MyISAM;
-# Verifying .frm, .par and MyISAM files (.MYD, MYI)
-FLUSH TABLES;
+(PARTITION p0 DATA DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-data-dir' ENGINE = InnoDB,
+ PARTITION p1 DATA DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-data-dir' ENGINE = InnoDB) */
+#
+# Verify that the DATA/INDEX DIRECTORY is stored and used if we
+# ALTER TABLE to MyISAM.
+#
+ALTER TABLE t1 engine=MyISAM;
 SHOW CREATE TABLE t1;
 Table	Create Table
 t1	CREATE TABLE `t1` (
   `c1` int(11) DEFAULT NULL
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
 /*!50100 PARTITION BY HASH (c1)
-(PARTITION p0 DATA DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-data-dir' INDEX DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-idx-dir' ENGINE = MyISAM,
- PARTITION p1 DATA DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-data-dir' INDEX DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-idx-dir' ENGINE = MyISAM) */
+(PARTITION p0 DATA DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-data-dir' ENGINE = MyISAM,
+ PARTITION p1 DATA DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-data-dir' ENGINE = MyISAM) */
+# Verifying .frm, .par and MyISAM files (.MYD, MYI)
+---- MYSQLD_DATADIR/test
+t1#P#p0.MYD
+t1#P#p0.MYI
+t1#P#p1.MYD
+t1#P#p1.MYI
+t1.frm
+t1.par
+---- MYSQLTEST_VARDIR/mysql-test-data-dir
+t1#P#p0.MYD
+t1#P#p1.MYD
+test
+---- MYSQLTEST_VARDIR/mysql-test-idx-dir
+#
+# Now verify that the DATA DIRECTORY is used again if we
+# ALTER TABLE back to InnoDB.
+#
+SET SESSION innodb_strict_mode = ON;
+ALTER TABLE t1 engine=InnoDB;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `c1` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (c1)
+(PARTITION p0 DATA DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-data-dir' ENGINE = InnoDB,
+ PARTITION p1 DATA DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-data-dir' ENGINE = InnoDB) */
+# Verifying .frm, .par, .isl and InnoDB .ibd files
+---- MYSQLD_DATADIR/test
+t1#P#p0.isl
+t1#P#p1.isl
+t1.frm
+t1.par
+---- MYSQLTEST_VARDIR/mysql-test-data-dir
+test
+---- MYSQLTEST_VARDIR/mysql-test-idx-dir
+---- MYSQLTEST_VARDIR/mysql-test-data-dir/test
+t1#P#p0.ibd
+t1#P#p1.ibd
 DROP TABLE t1;
+#
+# Cleanup
+#

=== modified file 'mysql-test/suite/parts/t/partition_basic_symlink_innodb.test'
--- a/mysql-test/suite/parts/t/partition_basic_symlink_innodb.test	revid:andrei.elkin@stripped
+++ b/mysql-test/suite/parts/t/partition_basic_symlink_innodb.test	revid:kevin.lewis@stripped
@@ -14,16 +14,20 @@
 # Change Author: mattiasj                                                      #
 # Change Date: 2008-03-16                                                      #
 # Change: Replaced all test with alter -> myisam, since innodb does not support#
-#         DATA/INDEX DIRECTORY                                                 #
+# Change Author: Kevin lewis                                                   #
+# Change Date: 2012-03-02                                                      #
+# Change: WL5980 activates DATA DIRECTORY for InnoDB                           #
 ################################################################################
 
-# NOTE: Until InnoDB supports DATA/INDEX DIR, test that a partitioned table
-#       remembers the DATA/INDEX DIR and it is used if altered to MyISAM
+# NOTE: As of WL5980, InnoDB supports DATA DIRECTORY, but not INDEX DIRECTORY.
+#       See innodb.innodb-tablespace for tests using partition engine, innodb
+#       and DATADIRECTORY.  The purpose of this test is to show that a
+#       partitioned table remembers the DATA/INDEX DIR and it is used if
+#       altered to MyISAM
 #
---echo # Will not run partition_basic_symlink on InnoDB, since it is the same
---echo # as partition_basic, since InnoDB does not support DATA/INDEX DIR
---echo # Will only verify that the DATA/INDEX DIR is stored and used if
---echo # ALTER to MyISAM.
+--echo #
+--echo # Verify that the DATA/INDEX DIR is stored and used if ALTER to MyISAM.
+--echo #
 --source include/have_innodb.inc
 # The server must support partitioning.
 --source include/have_partition.inc
@@ -35,17 +39,54 @@
 # Does not work with --embedded
 --source include/not_embedded.inc
 
+--disable_query_log
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+# These values can change during the test
+LET $innodb_file_per_table_orig=`select @@innodb_file_per_table`;
+LET $innodb_strict_mode_orig=`select @@session.innodb_strict_mode`;
+--enable_query_log
+
 --disable_warnings
 DROP TABLE IF EXISTS t1;
 --enable_warnings
 
-let $MYSQLD_DATADIR= `select @@datadir`;
-
 --mkdir $MYSQLTEST_VARDIR/mysql-test-data-dir
 --mkdir $MYSQLTEST_VARDIR/mysql-test-idx-dir
+
+SET SESSION innodb_strict_mode = ON;
+
+--echo #
+--echo # InnoDB only supports DATA DIRECTORY with innodb_file_per_table=ON
+--echo #
+SET GLOBAL innodb_file_per_table = OFF;
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--error ER_CANT_CREATE_TABLE
+eval CREATE TABLE t1 (c1 INT)  ENGINE = InnoDB
+PARTITION BY HASH (c1) (
+  PARTITION p0
+    DATA DIRECTORY = '$MYSQLTEST_VARDIR/mysql-test-data-dir'
+    INDEX DIRECTORY = '$MYSQLTEST_VARDIR/mysql-test-idx-dir',
+  PARTITION p1
+    DATA DIRECTORY = '$MYSQLTEST_VARDIR/mysql-test-data-dir'
+    INDEX DIRECTORY = '$MYSQLTEST_VARDIR/mysql-test-idx-dir'
+);
+--replace_result ./ MYSQLD_DATADIR/  $MYSQLD_DATADIR MYSQLD_DATADIR
+SHOW WARNINGS;
+
+--echo #
+--echo # InnoDB is different from MyISAM in that it uses a text file
+--echo # with an '.isl' extension instead of a symbolic link so that
+--echo # the tablespace can be re-located on any OS. Also, instead of
+--echo # putting the file directly into the DATA DIRECTORY,
+--echo # it adds a folder under it with the name of the database.
+--echo # Since strict mode is off, InnoDB ignores the INDEX DIRECTORY
+--echo # and it is no longer part of the definition.
+--echo #
+SET SESSION innodb_strict_mode = OFF;
+SET GLOBAL innodb_file_per_table = ON;
 --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
-eval CREATE TABLE t1 (c1 INT)
-ENGINE = InnoDB
+eval CREATE TABLE t1 (c1 INT) ENGINE = InnoDB
 PARTITION BY HASH (c1)
 (PARTITION p0
  DATA DIRECTORY = '$MYSQLTEST_VARDIR/mysql-test-data-dir'
@@ -54,116 +95,70 @@ PARTITION BY HASH (c1)
  DATA DIRECTORY = '$MYSQLTEST_VARDIR/mysql-test-data-dir'
  INDEX DIRECTORY = '$MYSQLTEST_VARDIR/mysql-test-idx-dir'
 );
---echo # Verifying .frm and .par files
---file_exists $MYSQLD_DATADIR/test/t1.frm
---file_exists $MYSQLD_DATADIR/test/t1.par
---echo # Verifying that there are no MyISAM files
---error 1
---file_exists $MYSQLD_DATADIR/test/t1#P#p0.MYD
---error 1
---file_exists $MYSQLD_DATADIR/test/t1#P#p0.MYI
---error 1
---file_exists $MYSQLD_DATADIR/test/t1#P#p1.MYD
---error 1
---file_exists $MYSQLD_DATADIR/test/t1#P#p1.MYI
---error 1
---file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/t1#P#p0.MYD
---error 1
---file_exists $MYSQLTEST_VARDIR/mysql-test-idx-dir/t1#P#p0.MYI
---error 1
---file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/t1#P#p1.MYD
---error 1
---file_exists $MYSQLTEST_VARDIR/mysql-test-idx-dir/t1#P#p1.MYI
+SHOW WARNINGS;
+
+--echo # Verifying .frm, .par, .isl & .ibd files
+--echo ---- MYSQLD_DATADIR/test
+--list_files $MYSQLD_DATADIR/test
+--echo ---- MYSQLTEST_VARDIR/mysql-test-data-dir/test
+--list_files $MYSQLTEST_VARDIR/mysql-test-data-dir/test
+--echo # The ibd tablespaces should not be directly under the DATA DIRECTORY
+--echo ---- MYSQLTEST_VARDIR/mysql-test-data-dir
+--list_files $MYSQLTEST_VARDIR/mysql-test-data-dir
+--echo ---- MYSQLTEST_VARDIR/mysql-test-idx-dir
+--list_files $MYSQLTEST_VARDIR/mysql-test-idx-dir
+
 FLUSH TABLES;
 --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
 SHOW CREATE TABLE t1;
-ALTER TABLE t1 ENGINE = MyISAM;
+
+--echo #
+--echo # Verify that the DATA/INDEX DIRECTORY is stored and used if we
+--echo # ALTER TABLE to MyISAM.
+--echo #
+ALTER TABLE t1 engine=MyISAM;
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+SHOW CREATE TABLE t1;
 --echo # Verifying .frm, .par and MyISAM files (.MYD, MYI)
---file_exists $MYSQLD_DATADIR/test/t1.frm
---file_exists $MYSQLD_DATADIR/test/t1.par
---file_exists $MYSQLD_DATADIR/test/t1#P#p0.MYD
---file_exists $MYSQLD_DATADIR/test/t1#P#p0.MYI
---file_exists $MYSQLD_DATADIR/test/t1#P#p1.MYD
---file_exists $MYSQLD_DATADIR/test/t1#P#p1.MYI
---file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/t1#P#p0.MYD
---file_exists $MYSQLTEST_VARDIR/mysql-test-idx-dir/t1#P#p0.MYI
---file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/t1#P#p1.MYD
---file_exists $MYSQLTEST_VARDIR/mysql-test-idx-dir/t1#P#p1.MYI
-FLUSH TABLES;
+--echo ---- MYSQLD_DATADIR/test
+--list_files $MYSQLD_DATADIR/test
+--echo ---- MYSQLTEST_VARDIR/mysql-test-data-dir
+--list_files $MYSQLTEST_VARDIR/mysql-test-data-dir
+--echo ---- MYSQLTEST_VARDIR/mysql-test-idx-dir
+--list_files $MYSQLTEST_VARDIR/mysql-test-idx-dir
+
+--echo #
+--echo # Now verify that the DATA DIRECTORY is used again if we
+--echo # ALTER TABLE back to InnoDB.
+--echo #
+SET SESSION innodb_strict_mode = ON;
+ALTER TABLE t1 engine=InnoDB;
 --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
 SHOW CREATE TABLE t1;
-DROP TABLE t1;
---rmdir $MYSQLTEST_VARDIR/mysql-test-data-dir
---rmdir $MYSQLTEST_VARDIR/mysql-test-idx-dir
---exit
-# here is the old test, which is tested by partition_basic_innodb
+--echo # Verifying .frm, .par, .isl and InnoDB .ibd files
+--echo ---- MYSQLD_DATADIR/test
+--list_files $MYSQLD_DATADIR/test
+--echo ---- MYSQLTEST_VARDIR/mysql-test-data-dir
+--list_files $MYSQLTEST_VARDIR/mysql-test-data-dir
+--echo ---- MYSQLTEST_VARDIR/mysql-test-idx-dir
+--list_files $MYSQLTEST_VARDIR/mysql-test-idx-dir
+--echo ---- MYSQLTEST_VARDIR/mysql-test-data-dir/test
+--list_files $MYSQLTEST_VARDIR/mysql-test-data-dir/test
 
-#
-# NOTE: PLEASE DO NOT ADD NOT INNODB SPECIFIC TESTCASES HERE !
-#       TESTCASES WHICH MUST BE APPLIED TO ALL STORAGE ENGINES MUST BE ADDED IN
-#       THE SOURCED FILES ONLY.
-#
-# Please read the README at the end of inc/partition.pre before changing
-# any of the variables.
-#
-
-#------------------------------------------------------------------------------#
-# General not engine specific settings and requirements
-
-##### Options, for debugging support #####
-let $debug= 0;
-let $with_partitioning= 1;
-
-##### Option, for displaying files #####
-let $ls= 1;
-
-##### Number of rows for the INSERT/UPDATE/DELETE/SELECT experiments #####
-#     on partioned tables
-SET @max_row = 20;
-
-##### Execute more tests                                             #####
-let $more_trigger_tests= 0;
-let $more_pk_ui_tests= 0;
-
-# The server must support partitioning.
---source include/have_partition.inc
-# The server must support symlink for DATA/INDEX DIRECTORY.
---source include/have_symlink.inc
-# windows does not support symlink for DATA/INDEX DIRECTORY.
---source include/not_windows.inc
-
-#------------------------------------------------------------------------------#
-# Engine specific settings and requirements
-
-##### Storage engine to be tested
---source include/have_innodb.inc
-let $engine= 'InnoDB';
-
-##### Execute the test of "table" files
-# InnoDB has no files per PK, UI, ...
-let $do_file_tests= 0;
-
-##### Execute PRIMARY KEY tests                                      #####
-# AFAIK InnoDB clusters the table around PRIMARY KEYs.
-let $do_pk_tests= 1;
+DROP TABLE t1;
 
-##### Assign a big number smaller than the maximum value for partitions  #####
-#     and smaller than the maximum value of SIGNED INTEGER
-let $MAX_VALUE= (2147483646);
+--echo #
+--echo # Cleanup
+--echo #
 
-# Generate the prerequisites ($variables, @variables, tables) needed
---source suite/parts/inc/partition.pre
+--rmdir $MYSQLTEST_VARDIR/mysql-test-data-dir/test
+--rmdir $MYSQLTEST_VARDIR/mysql-test-data-dir
+--rmdir $MYSQLTEST_VARDIR/mysql-test-idx-dir
 
-##### Workarounds for known open engine specific bugs
-#     none
+--disable_query_log
+EVAL SET GLOBAL innodb_file_per_table=$innodb_file_per_table_orig;
+EVAL SET SESSION innodb_strict_mode=$innodb_strict_mode_orig;
+--enable_query_log
 
-#------------------------------------------------------------------------------#
-# Execute the tests to be applied to all storage engines
---source suite/parts/inc/partition_basic_symlink.inc
 
-#------------------------------------------------------------------------------#
-# Execute storage engine specific tests
 
-#------------------------------------------------------------------------------#
-# Cleanup
---source suite/parts/inc/partition_cleanup.inc

=== modified file 'mysys/my_handler_errors.h'
--- a/mysys/my_handler_errors.h	revid:andrei.elkin@stripped
+++ b/mysys/my_handler_errors.h	revid:kevin.lewis@stripped
@@ -85,7 +85,8 @@ static const char *handler_error_message
   "Index column length exceeds limit",
   "Index corrupted",
   "Undo record too big",
-  "Invalid InnoDB FTS Doc ID"
+  "Invalid InnoDB FTS Doc ID",
+  "Tablespace already exists"
 };
 
 extern void my_handler_error_register(void);

=== modified file 'sql/ha_partition.cc'
--- a/sql/ha_partition.cc	revid:andrei.elkin@stripped
+++ b/sql/ha_partition.cc	revid:kevin.lewis@stripped
@@ -58,6 +58,7 @@
 #include "sql_table.h"                        // tablename_to_filename
 #include "key.h"
 #include "sql_plugin.h"
+#include "sql_partition.h"
 
 #include "debug_sync.h"
 
@@ -687,7 +688,7 @@ int ha_partition::create(const char *nam
       List_iterator_fast <partition_element> sub_it(part_elem->subpartitions);
       for (j= 0; j < m_part_info->num_subparts; j++)
       {
-	part_elem= sub_it++;
+        part_elem= sub_it++;
         create_partition_name(name_buff, path, name_buffer_ptr,
                               NORMAL_PART_NAME, FALSE);
         if ((error= set_up_table_before_create(table_arg, name_buff,
@@ -1435,8 +1436,25 @@ int ha_partition::prepare_new_partition(
   int error;
   DBUG_ENTER("prepare_new_partition");
 
+  /*
+    This call to set_up_table_before_create() is done for an alter table.
+    So this may be the second time around for this partition_element,
+    depending on how many partitions and subpartitions there were before,
+    and how many there are now.
+    The first time, on the CREATE, data_file_name and index_file_name
+    came from the parser.  They did not have the file name attached to
+    the end.  But if this partition is less than the total number of
+    previous partitions, it's data_file_name has the filename attached.
+    So we need to take the partition filename off if it exists.
+    That file name may be different from part_name, which will be
+    attached in append_file_to_dir().
+  */
+  truncate_partition_filename(p_elem->data_file_name);
+  truncate_partition_filename(p_elem->index_file_name);
+
   if ((error= set_up_table_before_create(tbl, part_name, create_info, p_elem)))
     goto error_create;
+
   if ((error= file->ha_create(part_name, tbl, create_info)))
   {
     /*
@@ -1945,7 +1963,6 @@ init_error:
   DBUG_RETURN(result);
 }
 
-
 /*
   Update create info as part of ALTER TABLE
 
@@ -1957,11 +1974,16 @@ init_error:
     NONE
 
   DESCRIPTION
-    Method empty so far
+  Forward this handler call to the storage engine foreach
+  partition handler.  The data_file_name for each partition may
+  need to be reset if the tablespace was moved.  Use a dummy
+  HA_CREATE_INFO structure and transfer necessary data.
 */
 
 void ha_partition::update_create_info(HA_CREATE_INFO *create_info)
 {
+  DBUG_ENTER("ha_partition::update_create_info");
+
   /*
     Fix for bug#38751, some engines needs info-calls in ALTER.
     Archive need this since it flushes in ::info.
@@ -1975,8 +1997,114 @@ void ha_partition::update_create_info(HA
   if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
     create_info->auto_increment_value= stats.auto_increment_value;
 
+  /*
+    DATA DIRECTORY and INDEX DIRECTORY are never applied to the whole
+    partitioned table, only its parts.
+  */
+  my_bool from_alter = (create_info->data_file_name == (const char*) -1);
   create_info->data_file_name= create_info->index_file_name = NULL;
-  return;
+
+  /*
+  We do not need to update the individual partition DATA DIRECTORY settings
+  since they can be changed by ALTER TABLE ... REORGANIZE PARTITIONS.
+  */
+  if (from_alter)
+    DBUG_VOID_RETURN;
+
+  /*
+    send Handler::update_create_info() to the storage engine for each
+    partition that currently has a handler object.  Using a dummy
+    HA_CREATE_INFO structure to collect DATA and INDEX DIRECTORYs.
+  */
+
+  List_iterator<partition_element> part_it(m_part_info->partitions);
+  partition_element *part_elem, *sub_elem;
+  uint num_subparts= m_part_info->num_subparts;
+  uint num_parts = num_subparts ? m_file_tot_parts / num_subparts
+                                : m_file_tot_parts;
+  HA_CREATE_INFO dummy_info;
+  memset(&dummy_info, 0, sizeof(dummy_info));
+
+  /*
+  Since update_create_info() can be called from mysql_prepare_alter_table()
+  when not all handlers are set up, we look for that condition first.
+  If all handlers are not available, do not call update_create_indfo for any.
+  */
+  uint i, j, part;
+  for (i= 0; i < num_parts; i++)
+  {
+    part_elem= part_it++;
+    if (!part_elem)
+      DBUG_VOID_RETURN;
+    if (m_is_sub_partitioned)
+    {
+      List_iterator<partition_element> subpart_it(part_elem->subpartitions);
+      for (j= 0; j < num_subparts; j++)
+      {
+        sub_elem= subpart_it++;
+        if (!sub_elem)
+          DBUG_VOID_RETURN;
+        part= i * num_subparts + j;
+        if (part >= m_file_tot_parts || !m_file[part])
+          DBUG_VOID_RETURN;
+      }
+    }
+    else
+    {
+      if (!m_file[i])
+        DBUG_VOID_RETURN;
+    }
+  }
+  part_it.rewind();
+
+  for (i= 0; i < num_parts; i++)
+  {
+    part_elem= part_it++;
+    DBUG_ASSERT(part_elem);
+    if (m_is_sub_partitioned)
+    {
+      List_iterator<partition_element> subpart_it(part_elem->subpartitions);
+      for (j= 0; j < num_subparts; j++)
+      {
+        sub_elem= subpart_it++;
+        DBUG_ASSERT(sub_elem);
+        part= i * num_subparts + j;
+        DBUG_ASSERT(part < m_file_tot_parts && m_file[part]);
+        if (ha_legacy_type(m_file[part]->ht) == DB_TYPE_INNODB)
+        {
+          dummy_info.data_file_name= dummy_info.index_file_name = NULL;
+          m_file[part]->update_create_info(&dummy_info);
+
+          if (dummy_info.data_file_name || sub_elem->data_file_name)
+          {
+            sub_elem->data_file_name = (char*) dummy_info.data_file_name;
+          }
+          if (dummy_info.index_file_name || sub_elem->index_file_name)
+          {
+            sub_elem->index_file_name = (char*) dummy_info.index_file_name;
+          }
+        }
+      }
+    }
+    else
+    {
+      DBUG_ASSERT(m_file[i]);
+      if (ha_legacy_type(m_file[i]->ht) == DB_TYPE_INNODB)
+      {
+        dummy_info.data_file_name= dummy_info.index_file_name= NULL;
+        m_file[i]->update_create_info(&dummy_info);
+        if (dummy_info.data_file_name || part_elem->data_file_name)
+        {
+          part_elem->data_file_name = (char*) dummy_info.data_file_name;
+        }
+        if (dummy_info.index_file_name || part_elem->index_file_name)
+        {
+          part_elem->index_file_name = (char*) dummy_info.index_file_name;
+        }
+      }
+    }
+  }
+  DBUG_VOID_RETURN;
 }
 
 

=== modified file 'sql/ha_partition.h'
--- a/sql/ha_partition.h	revid:andrei.elkin@stripped
+++ b/sql/ha_partition.h	revid:kevin.lewis@stripped
@@ -381,6 +381,7 @@ private:
   bool populate_partition_name_hash();
   Partition_share *get_share();
   bool set_ha_share_ref(Handler_share **ha_share);
+  void fix_data_dir(char* path);
 
 public:
 

=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	revid:andrei.elkin@stripped
+++ b/sql/handler.cc	revid:kevin.lewis@stripped
@@ -181,7 +181,7 @@ struct st_sys_tbl_chk_params
       and is supported by SE.
     */
     SUPPORTED_SYSTEM_TABLE
-  }status;                                    // OUT param
+  } status;                                    // OUT param
 };
 
 
@@ -482,9 +482,10 @@ int ha_init_errors(void)
   SETMSG(HA_ERR_AUTOINC_READ_FAILED,    ER_DEFAULT(ER_AUTOINC_READ_FAILED));
   SETMSG(HA_ERR_AUTOINC_ERANGE,         ER_DEFAULT(ER_WARN_DATA_OUT_OF_RANGE));
   SETMSG(HA_ERR_TOO_MANY_CONCURRENT_TRXS, ER_DEFAULT(ER_TOO_MANY_CONCURRENT_TRXS));
-  SETMSG(HA_ERR_INDEX_COL_TOO_LONG,	ER_DEFAULT(ER_INDEX_COLUMN_TOO_LONG));
-  SETMSG(HA_ERR_INDEX_CORRUPT,		ER_DEFAULT(ER_INDEX_CORRUPT));
-  SETMSG(HA_FTS_INVALID_DOCID,		"Invalid InnoDB FTS Doc ID");
+  SETMSG(HA_ERR_INDEX_COL_TOO_LONG,     ER_DEFAULT(ER_INDEX_COLUMN_TOO_LONG));
+  SETMSG(HA_ERR_INDEX_CORRUPT,          ER_DEFAULT(ER_INDEX_CORRUPT));
+  SETMSG(HA_FTS_INVALID_DOCID,          "Invalid InnoDB FTS Doc ID");
+  SETMSG(HA_ERR_TABLESPACE_EXISTS,      "Tablespace already exists");
 
   /* Register the error messages for use with my_error(). */
   return my_error_register(get_handler_errmsgs, HA_ERR_FIRST, HA_ERR_LAST);

=== modified file 'sql/share/errmsg-utf8.txt'
--- a/sql/share/errmsg-utf8.txt	revid:andrei.elkin@stripped
+++ b/sql/share/errmsg-utf8.txt	revid:kevin.lewis@stripped
@@ -6746,15 +6746,22 @@ ER_INNODB_ONLINE_LOG_TOO_BIG
 
 ER_UNKNOWN_ALTER_ALGORITHM
   eng "Unknown ALGORITHM '%s'"
+
 ER_UNKNOWN_ALTER_LOCK
   eng "Unknown LOCK type '%s'"
 
 ER_MTS_CHANGE_MASTER_CANT_RUN_WITH_GAPS
   eng "CHANGE MASTER cannot be executed when the slave was stopped with an error or killed in MTS mode. Consider using RESET SLAVE or START SLAVE UNTIL."
+
 ER_MTS_RECOVERY_FAILURE
   eng "Cannot recover after SLAVE errored out in parallel execution mode. Additional error messages can be found in the MySQL error log."
+
 ER_MTS_RESET_WORKERS
   eng "Cannot clean up worker info tables. Additional error messages can be found in the MySQL error log."
+
+ER_TABLESPACE_EXISTS
+  eng "Can't create tablespace '%s'; tablespace exists"
+
 #
 #  End of 5.6 error messages.
 #

=== modified file 'sql/sql_partition.cc'
--- a/sql/sql_partition.cc	revid:andrei.elkin@stripped
+++ b/sql/sql_partition.cc	revid:kevin.lewis@stripped
@@ -2070,6 +2070,86 @@ static int add_quoted_string(File fptr, 
   return err + add_string(fptr, "'");
 }
 
+/**
+  @brief  Truncate the partition file name from a path it it exists.
+
+  @note  A partition file name will contian one or more '#' characters.
+One of the occurances of '#' will be either "#P#" or "#p#" depending
+on whether the storage engine has converted the filename to lower case.
+*/
+void truncate_partition_filename(char *path)
+{
+  if (path)
+  {
+    char* last_slash= strrchr(path, FN_LIBCHAR);
+
+    if (!last_slash)
+      last_slash= strrchr(path, FN_LIBCHAR2);
+
+    if (last_slash)
+    {
+      /* Look for a partition-type filename */
+      for (char* pound= strchr(last_slash, '#');
+           pound; pound = strchr(pound + 1, '#'))
+      {
+        if ((pound[1] == 'P' || pound[1] == 'p') && pound[2] == '#')
+        {
+          last_slash[0] = '\0';	/* truncate the file name */
+          break;
+        }
+      }
+    }
+  }
+}
+
+
+/**
+  @brief  Output a filepath.  Similar to add_keyword_string except it
+also converts \ to / on Windows and skips the partition file name at
+the end if found.
+
+  @note  When Mysql sends a DATA DIRECTORY from SQL for partitions it does
+not use a file name, but it does for DATA DIRECTORY on a non-partitioned
+table.  So when the storage engine is asked for the DATA DIRECTORY string
+after a restart through Handler::update_create_options(), the storage
+engine may include the filename.
+*/
+static int add_keyword_path(File fptr, const char *keyword,
+                            bool should_use_quotes,
+                            const char *path)
+{
+  int err= add_string(fptr, keyword);
+
+  err+= add_space(fptr);
+  err+= add_equal(fptr);
+  err+= add_space(fptr);
+
+  char temp_path[FN_REFLEN];
+  strcpy(temp_path, path);
+#ifdef __WIN__
+  /* Convert \ to / to be able to create table on unix */
+  char *pos, *end;
+  uint length= strlen(temp_path);
+  for (pos= temp_path, end= pos+length ; pos < end ; pos++)
+  {
+    if (*pos == '\\')
+      *pos = '/';
+  }
+#endif
+
+  /*
+  If the partition file name with its "#P#" identifier
+  is found after the last slash, truncate that filename.
+  */
+  truncate_partition_filename(temp_path);
+
+  if (should_use_quotes)
+    err+= add_quoted_string(fptr, temp_path);
+  else
+    err+= add_string(fptr, temp_path);
+  return err + add_space(fptr);
+}
+
 static int add_keyword_string(File fptr, const char *keyword,
                               bool should_use_quotes, 
                               const char *keystr)
@@ -2122,11 +2202,11 @@ static int add_partition_options(File fp
   if (!(current_thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
   {
     if (p_elem->data_file_name)
-      err+= add_keyword_string(fptr, "DATA DIRECTORY", TRUE, 
-                               p_elem->data_file_name);
+      err+= add_keyword_path(fptr, "DATA DIRECTORY", TRUE, 
+                             p_elem->data_file_name);
     if (p_elem->index_file_name)
-      err+= add_keyword_string(fptr, "INDEX DIRECTORY", TRUE, 
-                               p_elem->index_file_name);
+      err+= add_keyword_path(fptr, "INDEX DIRECTORY", TRUE, 
+                             p_elem->index_file_name);
   }
   if (p_elem->part_comment)
     err+= add_keyword_string(fptr, "COMMENT", TRUE, p_elem->part_comment);

=== modified file 'sql/sql_partition.h'
--- a/sql/sql_partition.h	revid:andrei.elkin@stripped
+++ b/sql/sql_partition.h	revid:kevin.lewis@stripped
@@ -124,6 +124,7 @@ bool check_part_func_fields(Field **ptr,
 bool field_is_partition_charset(Field *field);
 Item* convert_charset_partition_constant(Item *item, const CHARSET_INFO *cs);
 void mem_alloc_error(size_t size);
+void truncate_partition_filename(char *path);
 
 /*
   A "Get next" function for partition iterator.

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	revid:andrei.elkin@stripped
+++ b/sql/sql_table.cc	revid:kevin.lewis@stripped
@@ -6568,6 +6568,10 @@ mysql_prepare_alter_table(THD *thd, TABL
     create_info->comment.length= table->s->comment.length;
   }
 
+  /* Do not pass the update_create_info through to each partition. */
+  if (table->file->ht->db_type == DB_TYPE_PARTITION_DB)
+	  create_info->data_file_name = (char*) -1;
+
   table->file->update_create_info(create_info);
   if ((create_info->table_options &
        (HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||

=== modified file 'storage/innobase/dict/dict0boot.cc'
--- a/storage/innobase/dict/dict0boot.cc	revid:andrei.elkin@stripped
+++ b/storage/innobase/dict/dict0boot.cc	revid:kevin.lewis@stripped
@@ -307,9 +307,7 @@ dict_boot(void)
 	dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0);
 	/* ROW_FORMAT = (N_COLS >> 31) ? COMPACT : REDUNDANT */
 	dict_mem_table_add_col(table, heap, "N_COLS", DATA_INT, 0, 4);
-	/* If the format is UNIV_FORMAT_A, table->flags == 0, and
-	TYPE == 1, which is defined as SYS_TABLE_TYPE_ANTELOPE.
-	The low order bit of TYPE is always set to 1.  If the format
+	/* The low order bit of TYPE is always set to 1.  If the format
 	is UNIV_FORMAT_B or higher, this field matches table->flags. */
 	dict_mem_table_add_col(table, heap, "TYPE", DATA_INT, 0, 4);
 	dict_mem_table_add_col(table, heap, "MIX_ID", DATA_BINARY, 0, 0);
@@ -476,7 +474,7 @@ dict_insert_initial_data(void)
 }
 
 /*****************************************************************//**
-Creates and initializes the data dictionary at the database creation. */
+Creates and initializes the data dictionary at the server bootstrap. */
 UNIV_INTERN
 void
 dict_create(void)

=== modified file 'storage/innobase/dict/dict0crea.cc'
--- a/storage/innobase/dict/dict0crea.cc	revid:andrei.elkin@stripped
+++ b/storage/innobase/dict/dict0crea.cc	revid:kevin.lewis@stripped
@@ -254,8 +254,7 @@ dict_build_table_def_step(
 	dict_table_t*	table;
 	dtuple_t*	row;
 	dberr_t		error;
-	const char*	path_or_name;
-	ibool		is_path;
+	const char*	path;
 	mtr_t		mtr;
 	ulint		space = 0;
 	bool		use_tablespace;
@@ -286,23 +285,15 @@ dict_build_table_def_step(
 		- page 3 will contain the root of the clustered index of the
 		table we create here. */
 
-		if (table->dir_path_of_temp_table) {
-			/* We place tables created with CREATE TEMPORARY
-			TABLE in the tmp dir of mysqld server */
-
-			path_or_name = table->dir_path_of_temp_table;
-			is_path = TRUE;
-		} else {
-			path_or_name = table->name;
-			is_path = FALSE;
-		}
+		path = table->data_dir_path ? table->data_dir_path :
+			table->dir_path_of_temp_table;
 
 		ut_ad(dict_table_get_format(table) <= UNIV_FORMAT_MAX);
 		ut_ad(!dict_table_zip_size(table)
 		      || dict_table_get_format(table) >= UNIV_FORMAT_B);
 
 		error = fil_create_new_single_table_tablespace(
-			space, path_or_name, is_path,
+			space, table->name, path,
 			dict_tf_to_fsp_flags(table->flags),
 			table->flags2,
 			FIL_IBD_FILE_INITIAL_SIZE);
@@ -1204,48 +1195,53 @@ function_exit:
 }
 
 /****************************************************************//**
-Check whether the system foreign key tables exist. Additionally, If
-they exist then move them to non-LRU end of the table LRU list.
+Check whether a system table exists.  Additionally, if it exists,
+move it to the non-LRU end of the table LRU list.  This is oly used
+for system tables that can be upgraded or added to an older database,
+which include SYS_FOREIGN, SYS_FOREIGN_COLS, SYS_TABLESPACES and 
+SYS_DATAFILES.
 @return TRUE if they exist. */
 static
-ibool
-dict_check_sys_foreign_tables_exist(void)
-/*=====================================*/
+dberr_t
+dict_check_if_system_table_exists(
+/*==============================*/
+	const char*	tablename,	/*!< in: name of table */
+	ulint		num_fields,	/*!< in: number of fields */
+	ulint		num_indexes)	/*!< in: number of indexes */
 {
-	dict_table_t*	sys_foreign;
-	ibool		exists = FALSE;
-	dict_table_t*	sys_foreign_cols;
+	dict_table_t*	sys_table;
+	dberr_t		error = DB_SUCCESS;
 
 	ut_a(srv_get_active_thread_type() == SRV_NONE);
 
 	mutex_enter(&dict_sys->mutex);
 
-	sys_foreign = dict_table_get_low("SYS_FOREIGN");
-	sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS");
+	sys_table = dict_table_get_low(tablename);
+
+	if (sys_table == NULL) {
+		error = DB_TABLE_NOT_FOUND;
 
-	if (sys_foreign != NULL
-	    && sys_foreign_cols != NULL
-	    && UT_LIST_GET_LEN(sys_foreign->indexes) == 3
-	    && UT_LIST_GET_LEN(sys_foreign_cols->indexes) == 1) {
-
-		/* Foreign constraint system tables have already been
-		created, and they are ok. Ensure that they can't be
-		evicted from the table LRU cache.  */
+	} else if (UT_LIST_GET_LEN(sys_table->indexes) != num_indexes
+		   || sys_table->n_cols != num_fields) {
+		error = DB_CORRUPTION;
+
+	} else {
+		/* This table has already been created, and it is OK.
+		Ensure that it can't be evicted from the table LRU cache. */
 
-		dict_table_move_from_lru_to_non_lru(sys_foreign);
-		dict_table_move_from_lru_to_non_lru(sys_foreign_cols);
+		dict_table_move_from_lru_to_non_lru(sys_table);
 
-		exists = TRUE;
+		error = DB_SUCCESS;
 	}
 
 	mutex_exit(&dict_sys->mutex);
 
-	return(exists);
+	return(error);
 }
 
 /****************************************************************//**
 Creates the foreign key constraints system tables inside InnoDB
-at database creation or database start if they are not found or are
+at server bootstrap or server start if they are not found or are
 not of the right form.
 @return	DB_SUCCESS or error code */
 UNIV_INTERN
@@ -1254,15 +1250,23 @@ dict_create_or_check_foreign_constraint_
 /*================================================*/
 {
 	trx_t*		trx;
-	dberr_t		error;
-	ibool		success;
-	ibool		srv_file_per_table_backup;
+	my_bool		srv_file_per_table_backup;
+	dberr_t	error;
+	dberr_t	sys_foreign_ok;
+	dberr_t	sys_foreign_cols_ok;
 
 	ut_a(srv_get_active_thread_type() == SRV_NONE);
 
 	/* Note: The master thread has not been started at this point. */
 
-	if (dict_check_sys_foreign_tables_exist()) {
+
+	sys_foreign_ok = dict_check_if_system_table_exists(
+		"SYS_FOREIGN", DICT_NUM_FIELDS__SYS_FOREIGN + 1, 3);
+	sys_foreign_cols_ok = dict_check_if_system_table_exists(
+		"SYS_FOREIGN_COLS", DICT_NUM_FIELDS__SYS_FOREIGN_COLS + 1, 1);
+
+	if (sys_foreign_ok == DB_SUCCESS
+	    && sys_foreign_cols_ok == DB_SUCCESS) {
 		return(DB_SUCCESS);
 	}
 
@@ -1274,17 +1278,17 @@ dict_create_or_check_foreign_constraint_
 
 	/* Check which incomplete table definition to drop. */
 
-	if (dict_table_get_low("SYS_FOREIGN") != NULL) {
+	if (sys_foreign_ok == DB_CORRUPTION) {
 		fprintf(stderr,
-			"InnoDB: dropping incompletely created"
-			" SYS_FOREIGN table\n");
+			"InnoDB: dropping incompletely created "
+			"SYS_FOREIGN table\n");
 		row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
 	}
 
-	if (dict_table_get_low("SYS_FOREIGN_COLS") != NULL) {
+	if (sys_foreign_cols_ok == DB_CORRUPTION) {
 		fprintf(stderr,
-			"InnoDB: dropping incompletely created"
-			" SYS_FOREIGN_COLS table\n");
+			"InnoDB: dropping incompletely created "
+			"SYS_FOREIGN_COLS table\n");
 
 		row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
 	}
@@ -1302,32 +1306,33 @@ dict_create_or_check_foreign_constraint_
 	VARBINARY, like in other InnoDB system tables, to get a clean
 	design. */
 
-	srv_file_per_table_backup = (ibool) srv_file_per_table;
+	srv_file_per_table_backup = srv_file_per_table;
 
 	/* We always want SYSTEM tables to be created inside the system
 	tablespace. */
 
 	srv_file_per_table = 0;
 
-	error = que_eval_sql(NULL,
-			     "PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n"
-			     "BEGIN\n"
-			     "CREATE TABLE\n"
-			     "SYS_FOREIGN(ID CHAR, FOR_NAME CHAR,"
-			     " REF_NAME CHAR, N_COLS INT);\n"
-			     "CREATE UNIQUE CLUSTERED INDEX ID_IND"
-			     " ON SYS_FOREIGN (ID);\n"
-			     "CREATE INDEX FOR_IND"
-			     " ON SYS_FOREIGN (FOR_NAME);\n"
-			     "CREATE INDEX REF_IND"
-			     " ON SYS_FOREIGN (REF_NAME);\n"
-			     "CREATE TABLE\n"
-			     "SYS_FOREIGN_COLS(ID CHAR, POS INT,"
-			     " FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n"
-			     "CREATE UNIQUE CLUSTERED INDEX ID_IND"
-			     " ON SYS_FOREIGN_COLS (ID, POS);\n"
-			     "END;\n"
-			     , FALSE, trx);
+	error = que_eval_sql(
+		NULL,
+		"PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n"
+		"BEGIN\n"
+		"CREATE TABLE\n"
+		"SYS_FOREIGN(ID CHAR, FOR_NAME CHAR,"
+		" REF_NAME CHAR, N_COLS INT);\n"
+		"CREATE UNIQUE CLUSTERED INDEX ID_IND"
+		" ON SYS_FOREIGN (ID);\n"
+		"CREATE INDEX FOR_IND"
+		" ON SYS_FOREIGN (FOR_NAME);\n"
+		"CREATE INDEX REF_IND"
+		" ON SYS_FOREIGN (REF_NAME);\n"
+		"CREATE TABLE\n"
+		"SYS_FOREIGN_COLS(ID CHAR, POS INT,"
+		" FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n"
+		"CREATE UNIQUE CLUSTERED INDEX ID_IND"
+		" ON SYS_FOREIGN_COLS (ID, POS);\n"
+		"END;\n",
+		FALSE, trx);
 
 	if (error != DB_SUCCESS) {
 		fprintf(stderr, "InnoDB: error %lu in creation\n",
@@ -1354,6 +1359,8 @@ dict_create_or_check_foreign_constraint_
 
 	trx_free_for_mysql(trx);
 
+	srv_file_per_table = srv_file_per_table_backup;
+
 	if (error == DB_SUCCESS) {
 		fprintf(stderr,
 			"InnoDB: Foreign key constraint system tables"
@@ -1362,11 +1369,13 @@ dict_create_or_check_foreign_constraint_
 
 	/* Note: The master thread has not been started at this point. */
 	/* Confirm and move to the non-LRU part of the table LRU list. */
-
-	success = dict_check_sys_foreign_tables_exist();
-	ut_a(success);
-
-	srv_file_per_table = (my_bool) srv_file_per_table_backup;
+	sys_foreign_ok = dict_check_if_system_table_exists(
+		"SYS_FOREIGN", DICT_NUM_FIELDS__SYS_FOREIGN + 1, 3);
+	ut_a(sys_foreign_ok == DB_SUCCESS);
+
+	sys_foreign_cols_ok = dict_check_if_system_table_exists(
+		"SYS_FOREIGN_COLS", DICT_NUM_FIELDS__SYS_FOREIGN_COLS + 1, 1);
+	ut_a(sys_foreign_cols_ok == DB_SUCCESS);
 
 	return(error);
 }
@@ -1596,3 +1605,177 @@ dict_create_add_foreigns_to_dictionary(
 
 	return(DB_SUCCESS);
 }
+
+/****************************************************************//**
+Creates the tablespaces and datafiles system tables inside InnoDB
+at server bootstrap or server start if they are not found or are
+not of the right form.
+@return	DB_SUCCESS or error code */
+UNIV_INTERN
+dberr_t
+dict_create_or_check_sys_tablespace(void)
+/*=====================================*/
+{
+	trx_t*		trx;
+	my_bool		srv_file_per_table_backup;
+	dberr_t		error;
+	dberr_t		sys_tablespaces_ok;
+	dberr_t		sys_datafiles_ok;
+
+	ut_a(srv_get_active_thread_type() == SRV_NONE);
+
+	/* Note: The master thread has not been started at this point. */
+
+	sys_tablespaces_ok = dict_check_if_system_table_exists(
+		"SYS_TABLESPACES", DICT_NUM_FIELDS__SYS_TABLESPACES + 1, 1);
+	sys_datafiles_ok = dict_check_if_system_table_exists(
+		"SYS_DATAFILES", DICT_NUM_FIELDS__SYS_DATAFILES + 1, 1);
+
+	if (sys_tablespaces_ok == DB_SUCCESS
+	    && sys_datafiles_ok == DB_SUCCESS) {
+		return(DB_SUCCESS);
+	}
+
+	trx = trx_allocate_for_mysql();
+
+	trx->op_info = "creating tablepace and datafile sys tables";
+
+	row_mysql_lock_data_dictionary(trx);
+
+	/* Check which incomplete table definition to drop. */
+
+	if (sys_tablespaces_ok == DB_CORRUPTION) {
+		fprintf(stderr,
+			"InnoDB: dropping incompletely created"
+			" SYS_TABLESPACES table\n");
+		row_drop_table_for_mysql("SYS_TABLESPACES", trx, TRUE);
+	}
+
+	if (sys_datafiles_ok == DB_CORRUPTION) {
+		fprintf(stderr,
+			"InnoDB: dropping incompletely created"
+			" SYS_DATAFILES table\n");
+
+		row_drop_table_for_mysql("SYS_DATAFILES", trx, TRUE);
+	}
+
+	fprintf(stderr,
+		"InnoDB: Creating tablespace and datafile system tables\n");
+
+	/* We always want SYSTEM tables to be created inside the system
+	tablespace. */
+	srv_file_per_table_backup = srv_file_per_table;
+	srv_file_per_table = 0;
+
+	error = que_eval_sql(
+		NULL,
+		"PROCEDURE CREATE_SYS_TABLESPACE_PROC () IS\n"
+		"BEGIN\n"
+		"CREATE TABLE SYS_TABLESPACES(\n"
+		" SPACE INT, NAME CHAR, FLAGS INT);\n"
+		"CREATE UNIQUE CLUSTERED INDEX SYS_TABLESPACES_SPACE"
+		" ON SYS_TABLESPACES (SPACE);\n"
+		"CREATE TABLE SYS_DATAFILES(\n"
+		" SPACE INT, PATH CHAR);\n"
+		"CREATE UNIQUE CLUSTERED INDEX SYS_DATAFILES_SPACE"
+		" ON SYS_DATAFILES (SPACE);\n"
+		"END;\n",
+		FALSE, trx);
+
+	if (error != DB_SUCCESS) {
+		fprintf(stderr,
+			"InnoDB: error %lu in creating SYS_TABLESPACES\n",
+			(ulong) error);
+
+		ut_a(error == DB_OUT_OF_FILE_SPACE
+		     || error == DB_TOO_MANY_CONCURRENT_TRXS);
+
+		fprintf(stderr,
+			"InnoDB: Creation failed, tablespace is full\n"
+			"InnoDB: dropping incompletely created"
+			" SYS_TABLESPACE and SYS_DATAFILES tables\n");
+
+		row_drop_table_for_mysql("SYS_TABLESPACES", trx, TRUE);
+		row_drop_table_for_mysql("SYS_DATAFILES", trx, TRUE);
+
+		error = DB_MUST_GET_MORE_FILE_SPACE;
+	}
+
+	trx_commit_for_mysql(trx);
+
+	row_mysql_unlock_data_dictionary(trx);
+
+	trx_free_for_mysql(trx);
+
+	srv_file_per_table = srv_file_per_table_backup;
+
+	if (error == DB_SUCCESS) {
+		fprintf(stderr,
+			"InnoDB: System tables for Tablespaces and "
+			"Datafiles created\n");
+	}
+
+	/* Note: The master thread has not been started at this point. */
+	/* Confirm and move to the non-LRU part of the table LRU list. */
+
+	sys_tablespaces_ok = dict_check_if_system_table_exists(
+		"SYS_TABLESPACES", DICT_NUM_FIELDS__SYS_TABLESPACES + 1, 1);
+	ut_a(sys_tablespaces_ok == DB_SUCCESS);
+
+	sys_datafiles_ok = dict_check_if_system_table_exists(
+		"SYS_DATAFILES", DICT_NUM_FIELDS__SYS_DATAFILES + 1, 1);
+	ut_a(sys_datafiles_ok == DB_SUCCESS);
+
+	return(error);
+}
+
+/********************************************************************//**
+Add a single tablespace definition to the data dictionary tables in the
+database.
+@return	error code or DB_SUCCESS */
+UNIV_INTERN
+dberr_t
+dict_create_add_tablespace_to_dictionary(
+/*=====================================*/
+	ulint		space,		/*!< in: tablespace id */
+	const char*	name,		/*!< in: tablespace name */
+	ulint		flags,		/*!< in: tablespace flags */
+	const char*	path,		/*!< in: tablespace path */
+	trx_t*		trx)		/*!< in: transaction */
+{
+	dberr_t		error;
+
+	pars_info_t*	info = pars_info_create();
+
+	ut_a(space > 0);
+
+	pars_info_add_int4_literal(info, "space", space);
+
+	pars_info_add_str_literal(info, "name", name);
+
+	pars_info_add_int4_literal(info, "flags", flags);
+
+	pars_info_add_str_literal(info, "path", path);
+
+	error = que_eval_sql(info,
+			     "PROCEDURE P () IS\n"
+			     "BEGIN\n"
+			     "INSERT INTO SYS_TABLESPACES VALUES"
+			     "(:space, :name, :flags);\n"
+			     "INSERT INTO SYS_DATAFILES VALUES"
+			     "(:space, :path);\n"
+			     "END;\n",
+			     FALSE, trx);
+
+	if (error != DB_SUCCESS) {
+		return(error);
+	}
+
+	trx->op_info = "committing tablespace and datafile definition";
+
+	trx_commit(trx);
+
+	trx->op_info = "";
+
+	return(error);
+}

=== modified file 'storage/innobase/dict/dict0dict.cc'
--- a/storage/innobase/dict/dict0dict.cc	revid:andrei.elkin@stripped
+++ b/storage/innobase/dict/dict0dict.cc	revid:kevin.lewis@stripped
@@ -25,6 +25,7 @@ Created 1/8/1996 Heikki Tuuri
 
 #include "dict0dict.h"
 #include "fts0fts.h"
+#include "fil0fil.h"
 
 #ifdef UNIV_NONINL
 #include "dict0dict.ic"
@@ -1373,7 +1374,7 @@ dict_index_find_on_id_low(
 Renames a table object.
 @return	TRUE if success */
 UNIV_INTERN
-ibool
+dberr_t
 dict_table_rename_in_cache(
 /*=======================*/
 	dict_table_t*	table,		/*!< in/out: table */
@@ -1404,28 +1405,29 @@ dict_table_rename_in_cache(
 	fold = ut_fold_string(new_name);
 
 	/* Look for a table with the same name: error if such exists */
-	{
-		dict_table_t*	table2;
-		HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
-			    dict_table_t*, table2, ut_ad(table2->cached),
-			    (ut_strcmp(table2->name, new_name) == 0));
-		if (UNIV_LIKELY_NULL(table2)) {
-			ut_print_timestamp(stderr);
-			fputs("  InnoDB: Error: dictionary cache"
-			      " already contains a table ", stderr);
-			ut_print_name(stderr, NULL, TRUE, new_name);
-			fputs("\n"
-			      "InnoDB: cannot rename table ", stderr);
-			ut_print_name(stderr, NULL, TRUE, old_name);
-			putc('\n', stderr);
-			return(FALSE);
-		}
+	dict_table_t*	table2;
+	HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
+			dict_table_t*, table2, ut_ad(table2->cached),
+			(ut_strcmp(table2->name, new_name) == 0));
+	if (UNIV_LIKELY_NULL(table2)) {
+		ut_print_timestamp(stderr);
+		fputs("  InnoDB: Error: dictionary cache"
+			" already contains a table ", stderr);
+		ut_print_name(stderr, NULL, TRUE, new_name);
+		fputs("\n"
+			"InnoDB: cannot rename table ", stderr);
+		ut_print_name(stderr, NULL, TRUE, old_name);
+		putc('\n', stderr);
+		return(DB_ERROR);
 	}
 
 	/* If the table is stored in a single-table tablespace, rename the
-	.ibd file */
+	.ibd file and rebuild the .isl file if needed. */
 
 	if (table->space != 0) {
+		ibool	success;
+		char*	new_path = NULL;
+
 		if (table->dir_path_of_temp_table != NULL) {
 			ut_print_timestamp(stderr);
 			fputs("  InnoDB: Error: trying to rename a"
@@ -1435,10 +1437,41 @@ dict_table_rename_in_cache(
 			ut_print_filename(stderr,
 					  table->dir_path_of_temp_table);
 			fputs(" )\n", stderr);
-			return(FALSE);
-		} else if (!fil_rename_tablespace(old_name, table->space,
-						  new_name)) {
-			return(FALSE);
+			return(DB_ERROR);
+		}
+
+		if (DICT_TF_HAS_DATA_DIR(table->flags)) {
+			char*		old_path;
+
+			old_path = fil_space_get_first_path(table->space);
+
+			new_path = os_file_make_new_pathname(
+				old_path, new_name);
+			mem_free(old_path);
+
+			dberr_t	err = fil_create_link_file(
+				new_name, new_path);
+
+			if (err != DB_SUCCESS) {
+				mem_free(new_path);
+				return(DB_TABLESPACE_EXISTS);
+			}
+		}
+
+		success = fil_rename_tablespace(
+			old_name, table->space, new_name, new_path);
+
+		if (new_path) {
+			mem_free(new_path);
+			if (success) {
+				fil_delete_link_file(old_name);
+			} else {
+				fil_delete_link_file(new_name);
+			}
+		}
+
+		if (!success) {
+			return(DB_ERROR);
 		}
 	}
 
@@ -1505,7 +1538,7 @@ dict_table_rename_in_cache(
 
 		UT_LIST_INIT(table->referenced_list);
 
-		return(TRUE);
+		return(DB_SUCCESS);
 	}
 
 	/* Update the table name fields in foreign constraints, and update also
@@ -1605,7 +1638,7 @@ dict_table_rename_in_cache(
 		foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
 	}
 
-	return(TRUE);
+	return(DB_SUCCESS);
 }
 
 /**********************************************************************//**

=== modified file 'storage/innobase/dict/dict0load.cc'
--- a/storage/innobase/dict/dict0load.cc	revid:andrei.elkin@stripped
+++ b/storage/innobase/dict/dict0load.cc	revid:kevin.lewis@stripped
@@ -41,19 +41,23 @@ Created 4/24/1996 Heikki Tuuri
 #include "rem0cmp.h"
 #include "srv0start.h"
 #include "srv0srv.h"
+#include "dict0crea.h"
 #include "dict0priv.h"
 #include "ha_prototypes.h" /* innobase_casedn_str() */
 #include "fts0priv.h"
 
 
-/** Following are six InnoDB system tables */
+/** Following are the InnoDB system tables.  The positions in
+this array are referenced by enum dict_system_table_id. */
 static const char* SYSTEM_TABLE_NAME[] = {
 	"SYS_TABLES",
 	"SYS_INDEXES",
 	"SYS_COLUMNS",
 	"SYS_FIELDS",
 	"SYS_FOREIGN",
-	"SYS_FOREIGN_COLS"
+	"SYS_FOREIGN_COLS",
+	"SYS_TABLESPACES",
+	"SYS_DATAFILES"
 };
 
 /* If this flag is TRUE, then we will load the cluster index's (and tables')
@@ -620,6 +624,123 @@ err_len:
 }
 
 /********************************************************************//**
+This function parses a SYS_TABLESPACES record, extracts necessary
+information from the record and returns to caller.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_tablespaces(
+/*=========================*/
+	mem_heap_t*	heap,		/*!< in/out: heap memory */
+	const rec_t*	rec,		/*!< in: current SYS_TABLESPACES rec */
+	ulint*		space,		/*!< out: space id */
+	const char**	name,		/*!< out: tablespace name */
+	ulint*		flags)		/*!< out: tablespace flags */
+{
+	ulint		len;
+	const byte*	field;
+
+	if (rec_get_deleted_flag(rec, 0)) {
+		return("delete-marked record in SYS_TABLESPACES");
+	}
+
+	if (rec_get_n_fields_old(rec) != DICT_NUM_FIELDS__SYS_TABLESPACES) {
+		return("wrong number of columns in SYS_TABLESPACES record");
+	}
+
+	field = rec_get_nth_field_old(
+		rec, DICT_FLD__SYS_TABLESPACES__SPACE, &len);
+	if (len != DICT_FLD_LEN_SPACE) {
+err_len:
+		return("incorrect column length in SYS_TABLESPACES");
+	}
+	*space = mach_read_from_4(field);
+
+	rec_get_nth_field_offs_old(
+		rec, DICT_FLD__SYS_TABLESPACES__DB_TRX_ID, &len);
+	if (len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL) {
+		goto err_len;
+	}
+
+	rec_get_nth_field_offs_old(
+		rec, DICT_FLD__SYS_TABLESPACES__DB_ROLL_PTR, &len);
+	if (len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL) {
+		goto err_len;
+	}
+
+	field = rec_get_nth_field_old(
+		rec, DICT_FLD__SYS_TABLESPACES__NAME, &len);
+	if (len < 1 || len == UNIV_SQL_NULL) {
+		goto err_len;
+	}
+	*name = mem_heap_strdupl(heap, (char*) field, len);
+
+
+	field = rec_get_nth_field_old(
+		rec, DICT_FLD__SYS_TABLESPACES__FLAGS, &len);
+	if (len != DICT_FLD_LEN_FLAGS) {
+		goto err_len;
+	}
+	*flags = mach_read_from_4(field);
+
+	return(NULL);
+}
+
+/********************************************************************//**
+This function parses a SYS_DATAFILES record, extracts necessary
+information from the record and returns it to the caller.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_datafiles(
+/*=======================*/
+	mem_heap_t*	heap,		/*!< in/out: heap memory */
+	const rec_t*	rec,		/*!< in: current SYS_DATAFILES rec */
+	ulint*		space,		/*!< out: space id */
+	const char**	path)		/*!< out: datafile paths */
+{
+	ulint		len;
+	const byte*	field;
+
+	if (rec_get_deleted_flag(rec, 0)) {
+		return("delete-marked record in SYS_DATAFILES");
+	}
+
+	if (rec_get_n_fields_old(rec) != DICT_NUM_FIELDS__SYS_DATAFILES) {
+		return("wrong number of columns in SYS_DATAFILES record");
+	}
+
+	field = rec_get_nth_field_old(
+		rec, DICT_FLD__SYS_DATAFILES__SPACE, &len);
+	if (len != DICT_FLD_LEN_SPACE) {
+err_len:
+		return("incorrect column length in SYS_DATAFILES");
+	}
+	*space = mach_read_from_4(field);
+
+	rec_get_nth_field_offs_old(
+		rec, DICT_FLD__SYS_DATAFILES__DB_TRX_ID, &len);
+	if (len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL) {
+		goto err_len;
+	}
+
+	rec_get_nth_field_offs_old(
+		rec, DICT_FLD__SYS_DATAFILES__DB_ROLL_PTR, &len);
+	if (len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL) {
+		goto err_len;
+	}
+
+	field = rec_get_nth_field_old(
+		rec, DICT_FLD__SYS_DATAFILES__PATH, &len);
+	if (len < 1 || len == UNIV_SQL_NULL) {
+		goto err_len;
+	}
+	*path = mem_heap_strdupl(heap, (char*) field, len);
+
+	return(NULL);
+}
+
+/********************************************************************//**
 Determine the flags of a table as stored in SYS_TABLES.TYPE and N_COLS.
 @return  ULINT_UNDEFINED if error, else a valid dict_table_t::flags. */
 static
@@ -639,11 +760,9 @@ dict_sys_tables_get_flags(
 	ut_a(len == 4);
 	type = mach_read_from_4(field);
 
-	/* The low order bit of SYS_TABLES.TYPE is always set to 1. If no
-	other bits are used, that is defined as SYS_TABLE_TYPE_ANTELOPE.
-	But in dict_table_t::flags the low order bit is used to determine
-	if the row format is Redundant or Compact when the format is
-	Antelope.
+	/* The low order bit of SYS_TABLES.TYPE is always set to 1. But in
+	dict_table_t::flags the low order bit is used to determine if the
+	row format is Redundant or Compact when the format is Antelope.
 	Read the 4 byte N_COLS field and look at the high order bit.  It
 	should be set for COMPACT and later.  It should not be set for
 	REDUNDANT. */
@@ -655,10 +774,248 @@ dict_sys_tables_get_flags(
 	/* This validation function also combines the DICT_N_COLS_COMPACT
 	flag in n_cols into the type field to effectively make it a
 	dict_table_t::flags. */
-	return(dict_sys_tables_type_validate(type, n_cols));
+
+	if (ULINT_UNDEFINED == dict_sys_tables_type_validate(type, n_cols)) {
+		return(ULINT_UNDEFINED);
+	}
+
+	return(dict_sys_tables_type_to_tf(type, n_cols));
+}
+
+/********************************************************************//**
+Look up a tablename in SYS_TABLES and return the space ID.
+@return TRUE if tablename was found and space ID is set, FALSE if not. */
+UNIV_INTERN
+bool
+dict_get_space_from_sys_tables(
+/*===========================*/
+	const char*	name,		/*!< in: table name */
+	ulint*		space)		/*!< out: space ID */
+{
+	bool		found;
+	mem_heap_t*	heap;
+	mtr_t		mtr;
+	dict_table_t*	sys_tables;
+	dict_index_t*	sys_index;
+	dtuple_t*	tuple;
+	dfield_t*	dfield;
+	btr_pcur_t	pcur;
+	const rec_t*	rec;
+	const byte*	field;
+	ulint		len;
+
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	heap = mem_heap_create(1024);
+
+	mtr_start(&mtr);
+
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	mtr_start(&mtr);
+
+	sys_tables = dict_table_get_low("SYS_TABLES");
+	sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
+
+	ut_ad(!dict_table_is_comp(sys_tables));
+	ut_ad(name_of_col_is(sys_tables, sys_index,
+			     DICT_FLD__SYS_TABLES__TYPE, "TYPE"));
+	ut_ad(name_of_col_is(sys_tables, sys_index,
+			     DICT_FLD__SYS_TABLES__SPACE, "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)) {
+		found = false;
+		goto exit_func;
+	}
+
+	field = rec_get_nth_field_old(
+		rec, DICT_FLD__SYS_TABLES__SPACE, &len);
+	ut_a(len == 4);
+
+	*space = mach_read_from_4(field);
+	found = true;
+
+exit_func:
+	btr_pcur_close(&pcur);
+	mtr_commit(&mtr);
+	mem_heap_free(heap);
+
+	return(found);
 }
 
 /********************************************************************//**
+Gets the filepath for a spaceid from SYS_DATAFILES and checks it against
+the contents of a link file. This function is called when there is no
+fil_node_t entry for this space ID so both durable locations on  disk
+must be checked and compared.
+We use a temporary heap here for the table lookup, but not for the path
+returned which the caller must free.
+This function can return NULL if the space ID is not found in SYS_DATAFILES,
+then the caller will assume that the ibd file is in the normal datadir.
+@return	own: A copy of the first datafile found in SYS_DATAFILES.PATH for
+the given space ID. NULL if space ID is zero or not found. */
+UNIV_INTERN
+char*
+dict_get_first_path(
+/*================*/
+	ulint		space,	/*!< in: space id */
+	const char*	name)	/*!< in: tablespace name */
+{
+	mtr_t		mtr;
+	dict_table_t*	sys_datafiles;
+	dict_index_t*	sys_index;
+	dtuple_t*	tuple;
+	dfield_t*	dfield;
+	byte*		buf;
+	btr_pcur_t	pcur;
+	const rec_t*	rec;
+	const byte*	field;
+	ulint		len;
+	char*		dict_filepath = NULL;
+	mem_heap_t*	heap = mem_heap_create(1024);
+
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	mtr_start(&mtr);
+
+	sys_datafiles = dict_table_get_low("SYS_DATAFILES");
+	sys_index = UT_LIST_GET_FIRST(sys_datafiles->indexes);
+	ut_ad(!dict_table_is_comp(sys_datafiles));
+	ut_ad(name_of_col_is(sys_datafiles, sys_index,
+			     DICT_FLD__SYS_DATAFILES__SPACE, "SPACE"));
+	ut_ad(name_of_col_is(sys_datafiles, sys_index,
+			     DICT_FLD__SYS_DATAFILES__PATH, "PATH"));
+
+	tuple = dtuple_create(heap, 1);
+	dfield = dtuple_get_nth_field(tuple, DICT_FLD__SYS_DATAFILES__SPACE);
+
+	buf = static_cast<byte*>(mem_heap_alloc(heap, 4));
+	mach_write_to_4(buf, space);
+
+	dfield_set_data(dfield, buf, 4);
+	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 the file-per-table tablespace was created with
+	an earlier version of InnoDB, then this record is not
+	in SYS_DATAFILES.  But a link file still might exist. */
+
+	if (btr_pcur_is_on_user_rec(&pcur)) {
+		/* A record for this space ID was found. */
+		field = rec_get_nth_field_old(
+			rec, DICT_FLD__SYS_DATAFILES__PATH, &len);
+		ut_a(len > 0 || len == UNIV_SQL_NULL);
+		ut_a(len < OS_FILE_MAX_PATH);
+		dict_filepath = mem_strdupl((char*) field, len);
+		ut_a(dict_filepath);
+	}
+
+	btr_pcur_close(&pcur);
+	mtr_commit(&mtr);
+	mem_heap_free(heap);
+
+	return(dict_filepath);
+}
+
+/********************************************************************//**
+Update the record for space_id in SYS_TABLESPACES to this filepath.
+@return	DB_SUCCESS if OK, dberr_t if the insert failed */
+UNIV_INTERN
+dberr_t
+dict_update_filepath(
+/*===============*/
+	ulint		space_id,	/*!< in: space id */
+	const char*	filepath)	/*!< in: filepath */
+{
+	dberr_t		err = DB_SUCCESS;
+	trx_t*		trx;
+
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	trx = trx_allocate_for_background();
+	trx_start_if_not_started(trx);
+
+	pars_info_t*	info = pars_info_create();
+
+	pars_info_add_int4_literal(info, "space", space_id);
+	pars_info_add_str_literal(info, "path", filepath);
+
+	err = que_eval_sql(info,
+			     "PROCEDURE UPDATE_FILEPATH () IS\n"
+			     "BEGIN\n"
+			     "UPDATE SYS_DATAFILES"
+			     " SET PATH = :path\n"
+			     " WHERE SPACE = :space;\n"
+			     "END;\n", FALSE, trx);
+
+	trx_commit_for_mysql(trx);
+	trx_free_for_background(trx);
+
+	if (err == DB_SUCCESS) {
+		/* We just updated SYS_DATAFILES due to the contents in
+		a link file.  Make a note that we did this. */
+		ut_print_timestamp(stderr);
+		fprintf(stderr, "  InnoDB: The InnoDB data dictionary"
+			" table SYS_DATAFILES for tablespace ID %lu"
+			" was updated to use file %s.\n",
+			(ulong) space_id, filepath);
+	}
+
+	return(err);
+}
+
+/********************************************************************//**
+Insert records into SYS_TABLESPACES and SYS_DATAFILES.
+@return	DB_SUCCESS if OK, dberr_t if the insert failed */
+UNIV_INTERN
+dberr_t
+dict_insert_tablespace_and_filepath(
+/*================================*/
+	ulint		space,		/*!< in: space id */
+	const char*	name,		/*!< in: talespace name */
+	const char*	filepath,	/*!< in: filepath */
+	ulint		fsp_flags)	/*!< in: tablespace flags */
+{
+	dberr_t		err = DB_SUCCESS;
+	trx_t*		trx;
+
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+
+	trx = trx_allocate_for_background();
+	trx_start_if_not_started(trx);
+
+	/* A record for this space ID was not found in
+	SYS_DATAFILES. Assume the record is also missing in
+	SYS_TABLESPACES.  Insert records onto them both. */
+	err = dict_create_add_tablespace_to_dictionary(
+		space, name, fsp_flags, filepath, trx);
+
+	trx_commit_for_mysql(trx);
+	trx_free_for_background(trx);
+
+	return(err);
+}
+
+/********************************************************************//**
+This function looks at each table defined in SYS_TABLES.  It checks the
+tablespace for any table with a space_id > 0.  It looks up the tablespace
+in SYS_DATAFILES to ensure the correct path.
+
 In a crash recovery we already have all the tablespace objects created.
 This function compares the space id information in the InnoDB data dictionary
 to what we already read with fil_load_single_table_tablespaces().
@@ -762,7 +1119,9 @@ loop:
 		if (space_id == 0) {
 			/* The system tablespace always exists. */
 		} else if (in_crash_recovery) {
-			/* Check that the tablespace (the .ibd file) really
+			/* All tablespaces should have been found in
+			fil_load_single_table_tablespaces().
+			Check that the tablespace (the .ibd file) really
 			exists; print a warning to the .err log if not.
 			Do not print warnings for temporary tables. */
 			ibool	is_temp;
@@ -790,12 +1149,27 @@ loop:
 			fil_space_for_table_exists_in_mem(
 				space_id, name, TRUE, !is_temp);
 		} else {
-			/* It is a normal database startup: create the space
-			object and check that the .ibd file exists. */
+			/* It is a normal database startup: create the
+			space object and check that the .ibd file exists.
+			If the table uses a remote tablespace, look for the
+			space_id in SYS_DATAFILES to find the filepath */
+
+			/* Use the remote filepath if known. */
+			char*	filepath = NULL;
+			if (DICT_TF_HAS_DATA_DIR(flags)) {
+				filepath = dict_get_first_path(
+					space_id, name);
+			}
 
+			/* filepath can be NULL in this call. */
 			fil_open_single_table_tablespace(
 				FALSE, space_id,
-				dict_tf_to_fsp_flags(flags), name);
+				dict_tf_to_fsp_flags(flags),
+				name, filepath);
+
+			if (filepath) {
+				mem_free(filepath);
+			}
 		}
 
 		mem_free(name);
@@ -1761,6 +2135,39 @@ err_len:
 }
 
 /********************************************************************//**
+Using the table->heap, copy the null-terminated filepath into
+table->data_dir_path and replace the 'databasename/tablename.ibd'
+portion with 'tablename'.
+This allows SHOW CREATE TABLE to return the correct DATA DIRECTORY path.
+Make this data directory path only if it has not yet been saved. */
+UNIV_INTERN
+void
+dict_save_data_dir_path(
+/*====================*/
+	dict_table_t*	table,		/*!< in/out: table */
+	char*		filepath)	/*!< in: filepath of tablespace */
+{
+	ut_ad(mutex_own(&(dict_sys->mutex)));
+	ut_a(DICT_TF_HAS_DATA_DIR(table->flags));
+
+	if (table->data_dir_path || filepath == NULL) {
+		return;
+	}
+
+	/* Be sure this filepath is not the default filepath. */
+	char*	default_filepath = fil_make_ibd_name(table->name, FALSE);
+	if (strcmp(filepath, default_filepath)) {
+		ulint pathlen = strlen(filepath);
+		ut_a(pathlen < OS_FILE_MAX_PATH);
+		ut_a(0 == strcmp(filepath + pathlen - 4, ".ibd"));
+
+		table->data_dir_path = mem_heap_strdup(table->heap, filepath);
+		os_file_make_data_dir_path(table->data_dir_path);
+	}
+	mem_free(default_filepath);
+}
+
+/********************************************************************//**
 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
@@ -1790,6 +2197,7 @@ dict_load_table(
 	const rec_t*	rec;
 	const byte*	field;
 	ulint		len;
+	char*		filepath = NULL;
 	dberr_t		err;
 	const char*	err_msg;
 	mtr_t		mtr;
@@ -1870,16 +2278,27 @@ err_exit:
 				"InnoDB: space id %lu did not exist in memory."
 				" Retrying an open.\n",
 				(ulong) table->space);
+
+			/* Use the remote filepath if needed. */
+			if (DICT_TF_HAS_DATA_DIR(table->flags)) {
+				filepath = dict_get_first_path(
+					table->space, name);
+				dict_save_data_dir_path(table, filepath);
+			}
+
 			/* Try to open the tablespace */
 			if (!fil_open_single_table_tablespace(
 				TRUE, table->space,
 				dict_tf_to_fsp_flags(table->flags),
-				name)) {
+				name, filepath)) {
 				/* We failed to find a sensible
 				tablespace file */
 
 				table->ibd_file_missing = TRUE;
 			}
+			if (filepath) {
+				mem_free(filepath);
+			}
 		}
 	}
 

=== modified file 'storage/innobase/fil/fil0fil.cc'
--- a/storage/innobase/fil/fil0fil.cc	revid:andrei.elkin@stripped
+++ b/storage/innobase/fil/fil0fil.cc	revid:kevin.lewis@stripped
@@ -1475,34 +1475,30 @@ fil_space_free(
 }
 
 /*******************************************************************//**
-Returns the size of the space in pages. The tablespace must be cached in the
-memory cache.
-@return	space size, 0 if space not found */
-UNIV_INTERN
-ulint
-fil_space_get_size(
-/*===============*/
+Returns a pointer to the file_space_t that is in the memory cache
+associated with a space id. The caller must lock fil_system->mutex.
+@return	file_space_t pointer, NULL if space not found */
+UNIV_INLINE
+fil_space_t*
+fil_space_get_space(
+/*================*/
 	ulint	id)	/*!< in: space id */
 {
-	fil_node_t*	node;
 	fil_space_t*	space;
-	ulint		size;
+	fil_node_t*	node;
 
 	ut_ad(fil_system);
 
-	fil_mutex_enter_and_prepare_for_io(id);
-
 	space = fil_space_get_by_id(id);
-
 	if (space == NULL) {
-		mutex_exit(&fil_system->mutex);
-
-		return(0);
+		return(NULL);
 	}
 
 	if (space->size == 0 && space->purpose == FIL_TABLESPACE) {
 		ut_a(id != 0);
 
+		/* The following code must change when InnoDB supports
+		multiple datafiles per tablespace. */
 		ut_a(1 == UT_LIST_GET_LEN(space->chain));
 
 		node = UT_LIST_GET_FIRST(space->chain);
@@ -1515,7 +1511,72 @@ fil_space_get_size(
 		fil_node_complete_io(node, fil_system, OS_FILE_READ);
 	}
 
-	size = space->size;
+	return(space);
+}
+
+/*******************************************************************//**
+Returns the path from the first fil_node_t found for the space ID sent.
+The caller is responsible for freeing the memory allocated here for the
+value returned.
+@return	own: A copy of fil_node_t::path, NULL if space ID is zero
+or not found. */
+UNIV_INTERN
+char*
+fil_space_get_first_path(
+/*=====================*/
+	ulint		id)	/*!< in: space id */
+{
+	fil_space_t*	space;
+	fil_node_t*	node;
+	char*		path;
+
+	ut_ad(fil_system);
+
+	if (!id) {
+		return(NULL);
+	}
+
+	fil_mutex_enter_and_prepare_for_io(id);
+
+	space = fil_space_get_space(id);
+
+	if (space == NULL) {
+		mutex_exit(&fil_system->mutex);
+
+		return(NULL);
+	}
+
+	ut_ad(mutex_own(&fil_system->mutex));
+
+	node = UT_LIST_GET_FIRST(space->chain);
+
+	path = mem_strdup(node->name);
+
+	mutex_exit(&fil_system->mutex);
+
+	return(path);
+}
+
+/*******************************************************************//**
+Returns the size of the space in pages. The tablespace must be cached in the
+memory cache.
+@return	space size, 0 if space not found */
+UNIV_INTERN
+ulint
+fil_space_get_size(
+/*===============*/
+	ulint	id)	/*!< in: space id */
+{
+	fil_space_t*	space;
+	ulint		size;
+
+	ut_ad(fil_system);
+
+	fil_mutex_enter_and_prepare_for_io(id);
+
+	space = fil_space_get_space(id);
+
+	size = space ? space->size : 0;
 
 	mutex_exit(&fil_system->mutex);
 
@@ -1532,19 +1593,18 @@ fil_space_get_flags(
 /*================*/
 	ulint	id)	/*!< in: space id */
 {
-	fil_node_t*	node;
 	fil_space_t*	space;
 	ulint		flags;
 
 	ut_ad(fil_system);
 
-	if (UNIV_UNLIKELY(!id)) {
+	if (!id) {
 		return(0);
 	}
 
 	fil_mutex_enter_and_prepare_for_io(id);
 
-	space = fil_space_get_by_id(id);
+	space = fil_space_get_space(id);
 
 	if (space == NULL) {
 		mutex_exit(&fil_system->mutex);
@@ -1552,21 +1612,6 @@ fil_space_get_flags(
 		return(ULINT_UNDEFINED);
 	}
 
-	if (space->size == 0 && space->purpose == FIL_TABLESPACE) {
-		ut_a(id != 0);
-
-		ut_a(1 == UT_LIST_GET_LEN(space->chain));
-
-		node = UT_LIST_GET_FIRST(space->chain);
-
-		/* It must be a single-table tablespace and we have not opened
-		the file yet; the following calls will open it and update the
-		size fields */
-
-		fil_node_prepare_for_io(node, fil_system, space);
-		fil_node_complete_io(node, fil_system, OS_FILE_READ);
-	}
-
 	flags = space->flags;
 
 	mutex_exit(&fil_system->mutex);
@@ -1829,8 +1874,8 @@ fil_write_flushed_lsn_to_data_files(
 		cache. Note that all data files in the system tablespace 0
 		and the UNDO log tablespaces (if separate) are always open. */
 
-		if (space->purpose == FIL_TABLESPACE
-		    && !fil_is_user_tablespace_id(space->id)) {
+		if (space->purpose == FIL_TABLESPACE) {
+//		    && !fil_is_user_tablespace_id(space->id)) {   // KLTEST
 
 			ulint	sum_of_sizes = 0;
 
@@ -1873,6 +1918,7 @@ fil_read_first_page(
 						parameters below already
 						contain sensible data */
 	ulint*		flags,			/*!< out: tablespace flags */
+	ulint*		space_id,		/*!< out: tablespace ID */
 #ifdef UNIV_LOG_ARCHIVE
 	ulint*		min_arch_log_no,	/*!< out: min of archived
 						log numbers in data files */
@@ -1898,7 +1944,9 @@ fil_read_first_page(
 
 	*flags = fsp_header_get_flags(page);
 
-	flushed_lsn = mach_read_from_8(page+ FIL_PAGE_FILE_FLUSH_LSN);
+	*space_id = fsp_header_get_space_id(page);
+
+	flushed_lsn = mach_read_from_8(page + FIL_PAGE_FILE_FLUSH_LSN);
 
 	ut_free(buf);
 
@@ -2184,7 +2232,6 @@ fil_op_log_parse_or_replay(
 	}
 	*/
 	if (!space_id) {
-
 		return(ptr);
 	}
 
@@ -2220,10 +2267,11 @@ fil_op_log_parse_or_replay(
 
 			if (fil_get_space_id_for_table(new_name)
 			    == ULINT_UNDEFINED) {
-				/* We do not care of the old name, that is
-				why we pass NULL as the first argument */
+				/* We do not care about the old name, that
+				is why we pass NULL as the first argument.
+				TODO: If file is remote, we do not know the path */
 				if (!fil_rename_tablespace(NULL, space_id,
-							   new_name)) {
+							   new_name, NULL)) {
 					ut_error;
 				}
 			}
@@ -2241,12 +2289,14 @@ fil_op_log_parse_or_replay(
 		} else if (log_flags & MLOG_FILE_FLAG_TEMP) {
 			/* Temporary table, do nothing */
 		} else {
+			const char*	path = NULL;
+
 			/* Create the database directory for name, if it does
 			not exist yet */
 			fil_create_directory_for_tablename(name);
 
 			if (fil_create_new_single_table_tablespace(
-				    space_id, name, FALSE, flags,
+				    space_id, name, path, flags,
 				    DICT_TF2_USE_TABLESPACE,
 				    FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
 				ut_error;
@@ -2345,7 +2395,7 @@ try_again:
 
 	space->is_being_deleted = TRUE;
 
-	/* TODO: The following code must change when InnoDB supports
+	/* The following code must change when InnoDB supports
 	multiple datafiles per tablespace. */
 	ut_a(UT_LIST_GET_LEN(space->chain) == 1);
 
@@ -2561,30 +2611,27 @@ fil_rename_tablespace_in_mem(
 Allocates a file name for a single-table tablespace. The string must be freed
 by caller with mem_free().
 @return	own: file name */
-static
+UNIV_INTERN
 char*
 fil_make_ibd_name(
 /*==============*/
-	const char*	name,		/*!< in: table name or a dir path of a
-					TEMPORARY table */
-	ibool		is_temp)	/*!< in: TRUE if it is a dir path */
+	const char*	name,		/*!< in: table name or a dir path */
+	ibool		is_full_path)	/*!< in: TRUE if it is a dir path */
 {
 	char*	filename;
 	ulint	namelen		= strlen(name);
 	ulint	dirlen		= strlen(fil_path_to_mysql_datadir);
+	ulint	pathlen		= dirlen + namelen + sizeof "/.ibd";
 
-	filename = static_cast<char*>(
-		mem_alloc(namelen + dirlen + sizeof "/.ibd"));
+	filename = static_cast<char*>(mem_alloc(pathlen));
 
-	if (is_temp) {
+	if (is_full_path) {
 		memcpy(filename, name, namelen);
 		memcpy(filename + namelen, ".ibd", sizeof ".ibd");
 	} else {
-		memcpy(filename, fil_path_to_mysql_datadir, dirlen);
-		filename[dirlen] = '/';
+		ut_snprintf(filename, pathlen, "%s/%s.ibd",
+			fil_path_to_mysql_datadir, name);
 
-		memcpy(filename + dirlen + 1, name, namelen);
-		memcpy(filename + dirlen + namelen + 1, ".ibd", sizeof ".ibd");
 	}
 
 	srv_normalize_path_for_win(filename);
@@ -2593,6 +2640,31 @@ fil_make_ibd_name(
 }
 
 /*******************************************************************//**
+Allocates a file name for a tablespace ISL file (InnoDB Symbolic Link).
+The string must be freed by caller with mem_free().
+@return	own: file name */
+UNIV_INTERN
+char*
+fil_make_isl_name(
+/*==============*/
+	const char*	name)	/*!< in: table name */
+{
+	char*	filename;
+	ulint	namelen		= strlen(name);
+	ulint	dirlen		= strlen(fil_path_to_mysql_datadir);
+	ulint	pathlen		= dirlen + namelen + sizeof "/.isl";
+
+	filename = static_cast<char*>(mem_alloc(pathlen));
+
+	ut_snprintf(filename, pathlen, "%s/%s.isl",
+		fil_path_to_mysql_datadir, name);
+
+	srv_normalize_path_for_win(filename);
+
+	return(filename);
+}
+
+/*******************************************************************//**
 Renames a single-table tablespace. The tablespace must be cached in the
 tablespace memory cache.
 @return	TRUE if success */
@@ -2600,14 +2672,19 @@ UNIV_INTERN
 ibool
 fil_rename_tablespace(
 /*==================*/
-	const char*	old_name_in,	/*!< in: old table name in the standard
-					databasename/tablename format of
-					InnoDB, or NULL if we do the rename
-					based on the space id only */
+	const char*	old_name_in,	/*!< in: old table name in the
+					standard databasename/tablename
+					format of InnoDB, or NULL if we
+					do the rename based on the space
+					id only */
 	ulint		id,		/*!< in: space id */
-	const char*	new_name)	/*!< in: new table name in the standard
-					databasename/tablename format
-					of InnoDB */
+	const char*	new_name,	/*!< in: new table name in the
+					standard databasename/tablename
+					format of InnoDB */
+	const char*	new_path_in)	/*!< in: new full datafile path
+					if the tablespace is remotely
+					located, or NULL if it is located
+					in the normal data directory. */
 {
 	ibool		success;
 	fil_space_t*	space;
@@ -2663,6 +2740,8 @@ retry:
 
 	space->stop_ios = TRUE;
 
+	/* The following code must change when InnoDB supports
+	multiple datafiles per tablespace. */
 	ut_a(UT_LIST_GET_LEN(space->chain) == 1);
 	node = UT_LIST_GET_FIRST(space->chain);
 
@@ -2699,17 +2778,16 @@ retry:
 
 	if (old_name_in) {
 		old_name = mem_strdup(old_name_in);
-		old_path = fil_make_ibd_name(old_name, FALSE);
-
 		ut_a(strcmp(space->name, old_name) == 0);
-		ut_a(strcmp(node->name, old_path) == 0);
 	} else {
 		old_name = mem_strdup(space->name);
-		old_path = mem_strdup(node->name);
 	}
+	old_path = mem_strdup(node->name);
 
 	/* Rename the tablespace and the node in the memory cache */
-	new_path = fil_make_ibd_name(new_name, FALSE);
+	new_path = new_path_in ? mem_strdup(new_path_in)
+		: fil_make_ibd_name(new_name, FALSE);
+
 	success = fil_rename_tablespace_in_mem(
 		space, node, new_name, new_path);
 
@@ -2750,11 +2828,196 @@ retry:
 }
 
 /*******************************************************************//**
+Creates a new InnoDB Symbolic Link (ISL) file.  It is always created
+under the 'datadir' of MySQL. The datadir is the directory of a
+running mysqld program. We can refer to it by simply using the path '.'.
+@return	DB_SUCCESS or error code */
+UNIV_INTERN
+dberr_t
+fil_create_link_file(
+/*=================*/
+	const char*	tablename,	/*!< in: tablename */
+	const char*	filepath)	/*!< in: pathname of tablespace */
+{
+	os_file_t	file;
+	ibool		success;
+	dberr_t		err = DB_SUCCESS;
+
+	char*		link_filepath = fil_make_isl_name(tablename);
+
+	file = os_file_create_simple_no_error_handling(
+		innodb_file_data_key, link_filepath,
+		OS_FILE_CREATE, OS_FILE_READ_WRITE, &success);
+
+	if (!success) {
+		ut_print_timestamp(stderr);
+		fputs("  InnoDB: Cannot create file ", stderr);
+		ut_print_filename(stderr, link_filepath);
+		fputs(".\n", stderr);
+
+		/* The following call will print an error message */
+
+		ulint	error = os_file_get_last_error(TRUE);
+
+		if (error == OS_FILE_ALREADY_EXISTS) {
+			fputs("InnoDB: The link file: ", stderr);
+			ut_print_filename(stderr, filepath);
+			fputs(" already exists.\n", stderr);
+			err = DB_TABLESPACE_EXISTS;
+
+		} else if (error == OS_FILE_DISK_FULL) {
+			err = DB_OUT_OF_FILE_SPACE;
+
+		} else {
+			err = DB_ERROR;
+		}
+
+		/* file is not open, no need to close it. */
+		mem_free(link_filepath);
+		return(err);
+	}
+
+	if (!os_file_write(link_filepath, file, filepath, 0,
+			    strlen(filepath))) {
+		err = DB_ERROR;
+	}
+
+	/* Close the file, we only need it at startup */
+	os_file_close(file);
+
+	mem_free(link_filepath);
+
+	return(err);
+}
+
+/*******************************************************************//**
+Deletes an InnoDB Symbolic Link (ISL) file. */
+UNIV_INTERN
+void
+fil_delete_link_file(
+/*==================*/
+	const char*	tablename)	/*!< in: name of table */
+{
+	char* link_filepath = fil_make_isl_name(tablename);
+
+	os_file_delete(link_filepath);
+
+	mem_free(link_filepath);
+}
+
+/*******************************************************************//**
+Reads an InnoDB Symbolic Link (ISL) file.
+It is always created under the 'datadir' of MySQL.  The name is of the
+form {databasename}/{tablename}. and the isl file is expected to be in a
+'{databasename}' directory called '{tablename}.isl'. The caller must free
+the memory of the null-terminated path returned if it is not null.
+@return	own: filepath found in link file, NULL if not found. */
+UNIV_INTERN
+char*
+fil_read_link_file(
+/*===============*/
+	const char*	name)		/*!< in: tablespace name */
+{
+	char*		filepath = NULL;
+	char*		link_filepath;
+	FILE*		file = NULL;
+
+	/* The .isl file is in the 'normal' tablespace location. */
+	link_filepath = fil_make_isl_name(name);
+
+	file = fopen(link_filepath, "r+b");
+
+	mem_free(link_filepath);
+
+	if (file) {
+		filepath = static_cast<char*>(mem_alloc(OS_FILE_MAX_PATH));
+
+		os_file_read_string(file, filepath, OS_FILE_MAX_PATH);
+		fclose(file);
+
+		if (strlen(filepath)) {
+			/* Trim whitespace from end of filepath */
+			ulint lastch = strlen(filepath) - 1;
+			while (lastch > 4 && filepath[lastch] <= 0x20) {
+				filepath[lastch--] = 0x00;
+			}
+			srv_normalize_path_for_win(filepath);
+		} else {
+			mem_free(filepath);
+		}
+	}
+
+	return(filepath);
+}
+
+/*******************************************************************//**
+Opens a handle to the file linked to in an InnoDB Symbolic Link file.
+@return	TRUE if remote linked tablespace file is found and opened. */
+UNIV_INTERN
+ibool
+fil_open_linked_file(
+/*===============*/
+	const char*	tablename,	/*!< in: database/tablename */
+	char*		filepath,	/*!< in: filepath of tablename */
+	char**		remote_filepath,/*!< out: remote filepath */
+	os_file_t*	remote_file)	/*!< out: remote file handle */
+
+{
+	ibool		success;
+	ulint		err;
+
+	*remote_filepath = fil_read_link_file(tablename);
+	if (*remote_filepath == NULL) {
+		return(FALSE);
+	}
+
+	/* A link file existed, make sure it is not the file we are
+	already using. */
+	if (filepath && strcmp(filepath, *remote_filepath) == 0) {
+		mem_free(*remote_filepath);
+		*remote_filepath = NULL;
+		return (FALSE);
+	}
+
+	/* The filepath provided is different from what was
+	found in the link file. */
+	*remote_file = os_file_create_simple_no_error_handling(
+		innodb_file_data_key, *remote_filepath,
+		OS_FILE_OPEN, OS_FILE_READ_ONLY,
+		&success);
+
+	if (!success) {
+		char*	link_filepath = fil_make_isl_name(tablename);
+
+		/* The following call prints an error message */
+		err = os_file_get_last_error(TRUE);
+
+		ut_print_timestamp(stderr);
+		fputs("  InnoDB: Error: A link file was found named ",
+		      stderr);
+		ut_print_filename(stderr, link_filepath);
+		fputs(" but the linked tablespace ", stderr);
+		ut_print_filename(stderr, *remote_filepath);
+		fputs(" could not be opened.\n", stderr);
+
+		mem_free(link_filepath);
+		mem_free(*remote_filepath);
+		*remote_filepath = NULL;
+	}
+
+	return(success);
+}
+
+/*******************************************************************//**
 Creates a new single-table tablespace to a database directory of MySQL.
 Database directories are under the 'datadir' of MySQL. The datadir is the
 directory of a running mysqld program. We can refer to it by simply the
 path '.'. Tables created with CREATE TEMPORARY TABLE we place in the temp
 dir of the mysqld server.
+
+TODO: If this is being called during recovery replaying an MLOG_FILE_CREATE
+or MLOG_FILE_CREATE2 record and the DATA DICTIONARY path was used, then we
+do not have a tablename that looks like database/tablename.
 @return	DB_SUCCESS or error code */
 UNIV_INTERN
 dberr_t
@@ -2763,10 +3026,8 @@ fil_create_new_single_table_tablespace(
 	ulint		space_id,	/*!< in: space id */
 	const char*	tablename,	/*!< in: the table name in the usual
 					databasename/tablename format
-					of InnoDB, or a dir path to a temp
-					table */
-	ibool		is_temp,	/*!< in: TRUE if a table created with
-					CREATE TEMPORARY TABLE */
+					of InnoDB */
+	const char*	dir_path,	/*!< in: NULL or a dir path */
 	ulint		flags,		/*!< in: tablespace flags */
 	ulint		flags2,		/*!< in: table flags2 */
 	ulint		size)		/*!< in: the initial size of the
@@ -2775,18 +3036,40 @@ fil_create_new_single_table_tablespace(
 {
 	os_file_t	file;
 	ibool		ret;
-	ulint		err;
+	dberr_t		err;
 	byte*		buf2;
 	byte*		page;
 	char*		path;
 	ibool		success;
+	/* TRUE if a table is created with CREATE TEMPORARY TABLE */
+	bool		is_temp = !!(flags2 & DICT_TF2_TEMPORARY);
+	bool		has_data_dir = (dir_path && !is_temp);
 
 	ut_a(space_id > 0);
 	ut_a(space_id < SRV_LOG_SPACE_FIRST_ID);
 	ut_a(size >= FIL_IBD_FILE_INITIAL_SIZE);
 	fsp_flags_validate(flags);
 
-	path = fil_make_ibd_name(tablename, is_temp);
+	if (dir_path) {
+		/* Create a link file if needed. */
+		if (has_data_dir) {
+			path = os_file_make_remote_pathname(dir_path, tablename);
+
+			/* Since this tablespace file will be created in a
+			remote directory, let's create the subdirectories
+			in the path, if they are not there already. */
+			success = os_file_create_subdirs_if_needed(path);
+			if (!success) {
+				err = DB_ERROR;
+				goto error_exit_3;
+			}
+		} else {
+			/* Temporary table filepath */
+			path = fil_make_ibd_name(dir_path, TRUE);
+		}
+	} else {
+		path = fil_make_ibd_name(tablename, FALSE);
+	}
 
 	file = os_file_create(
 		innodb_file_data_key, path,
@@ -2803,9 +3086,9 @@ fil_create_new_single_table_tablespace(
 
 		/* The following call will print an error message */
 
-		err = os_file_get_last_error(TRUE);
+		ulint	error = os_file_get_last_error(TRUE);
 
-		if (err == OS_FILE_ALREADY_EXISTS) {
+		if (error == OS_FILE_ALREADY_EXISTS) {
 			fputs("InnoDB: The file already exists though"
 			      " the corresponding table did not\n"
 			      "InnoDB: exist in the InnoDB data dictionary."
@@ -2819,32 +3102,28 @@ fil_create_new_single_table_tablespace(
 			      "InnoDB: resolve the problem by"
 			      " removing the file ", stderr);
 			ut_print_filename(stderr, path);
-			fputs("\n"
+			fputs(has_data_dir ? "\n" : "\n"
 			      "InnoDB: under the 'datadir' of MySQL.\n",
 			      stderr);
 
-			mem_free(path);
-			return(DB_TABLESPACE_ALREADY_EXISTS);
+			err = DB_TABLESPACE_EXISTS;
+			goto error_exit_3;
 		}
 
-		if (err == OS_FILE_DISK_FULL) {
-
-			mem_free(path);
-			return(DB_OUT_OF_FILE_SPACE);
+		if (error == OS_FILE_DISK_FULL) {
+			err = DB_OUT_OF_FILE_SPACE;
+			goto error_exit_3;
 		}
 
-		mem_free(path);
-		return(DB_ERROR);
+		err = DB_ERROR;
+		goto error_exit_3;
 	}
 
 	ret = os_file_set_size(path, file, size * UNIV_PAGE_SIZE);
 
 	if (!ret) {
-		os_file_close(file);
-		os_file_delete(path);
-
-		mem_free(path);
-		return(DB_OUT_OF_FILE_SPACE);
+		err = DB_OUT_OF_FILE_SPACE;
+		goto error_exit_2;
 	}
 
 	/* printf("Creating tablespace %s id %lu\n", path, space_id); */
@@ -2897,11 +3176,9 @@ fil_create_new_single_table_tablespace(
 		      " to tablespace ", stderr);
 		ut_print_filename(stderr, path);
 		putc('\n', stderr);
-error_exit:
-		os_file_close(file);
-error_exit2:
-		os_file_delete(path);
-		return(DB_ERROR);
+
+		err = DB_ERROR;
+		goto error_exit_2;
 	}
 
 	ret = os_file_flush(file);
@@ -2910,15 +3187,22 @@ error_exit2:
 		fputs("InnoDB: Error: file flush of tablespace ", stderr);
 		ut_print_filename(stderr, path);
 		fputs(" failed\n", stderr);
-		goto error_exit;
+		err = DB_ERROR;
+		goto error_exit_2;
 	}
 
-	os_file_close(file);
+	if (has_data_dir) {
+		/* Now that the IBD file is created, make the ISL file. */
+		err = fil_create_link_file(tablename, path);
+		if (err != DB_SUCCESS) {
+			goto error_exit_2;
+		}
+	}
 
 	success = fil_space_create(tablename, space_id, flags, FIL_TABLESPACE);
-
 	if (!success) {
-		goto error_exit2;
+		err = DB_ERROR;
+		goto error_exit_1;
 	}
 
 	fil_node_create(path, size, space_id, FALSE);
@@ -2926,22 +3210,41 @@ error_exit2:
 #ifndef UNIV_HOTBACKUP
 	{
 		mtr_t		mtr;
+		ulint		mlog_file_flag = 0;
+
+		if (is_temp) {
+			mlog_file_flag |= MLOG_FILE_FLAG_TEMP;
+		}
 
 		mtr_start(&mtr);
 
 		fil_op_write_log(flags
 				 ? MLOG_FILE_CREATE2
 				 : MLOG_FILE_CREATE,
-				 space_id,
-				 is_temp ? MLOG_FILE_FLAG_TEMP : 0,
-				 flags,
+				 space_id, mlog_file_flag, flags,
 				 tablename, NULL, &mtr);
 
 		mtr_commit(&mtr);
 	}
 #endif
+	err = DB_SUCCESS;
+
+	/* Error code is set.  Cleanup the various variables used.
+	These labels reflect the order in which variables are assigned or
+	actions are done. */
+error_exit_1:
+	if (has_data_dir && err != DB_SUCCESS) {
+		fil_delete_link_file(tablename);
+	}
+error_exit_2:
+	os_file_close(file);
+	if (err != DB_SUCCESS) {
+		os_file_delete(path);
+	}
+error_exit_3:
 	mem_free(path);
-	return(DB_SUCCESS);
+
+	return(err);
 }
 
 #ifndef UNIV_HOTBACKUP
@@ -2959,14 +3262,12 @@ UNIV_INTERN
 ibool
 fil_reset_too_high_lsns(
 /*====================*/
-	const char*	name,		/*!< in: table name in the
-					databasename/tablename format */
+	const char*	filepath,	/*!< in: filepath of tablespace */
 	lsn_t		current_lsn)	/*!< in: reset lsn's if the lsn stamped
 					to FIL_PAGE_FILE_FLUSH_LSN in the
 					first page is too high */
 {
 	os_file_t	file;
-	char*		filepath;
 	byte*		page;
 	byte*		buf2;
 	lsn_t		flush_lsn;
@@ -2977,8 +3278,6 @@ fil_reset_too_high_lsns(
 	ibool		success;
 	page_zip_des_t	page_zip;
 
-	filepath = fil_make_ibd_name(name, FALSE);
-
 	file = os_file_create_simple_no_error_handling(
 		innodb_file_data_key, filepath, OS_FILE_OPEN,
 		OS_FILE_READ_WRITE, &success);
@@ -2993,7 +3292,6 @@ fil_reset_too_high_lsns(
 		      "InnoDB: open the tablespace file ", stderr);
 		ut_print_filename(stderr, filepath);
 		fputs("!\n", stderr);
-		mem_free(filepath);
 
 		return(FALSE);
 	}
@@ -3110,11 +3408,41 @@ fil_reset_too_high_lsns(
 func_exit:
 	os_file_close(file);
 	ut_free(buf2);
-	mem_free(filepath);
 
 	return(success);
 }
 
+
+/********************************************************************//**
+Report information about a bad tablespace.
+@return	TRUE if success */
+static
+void
+fil_report_bad_tablespace(
+/*======================*/
+	char*		filepath,	/*!< in: filepath */
+	ulint		found_id,	/*!< in: found space ID */
+	ulint		found_flags,	/*!< in: found flags */
+	ulint		expected_id,	/*!< in: expected space id */
+	ulint		expected_flags)	/*!< in: expected flags */
+{
+	ut_print_timestamp(stderr);
+
+	fputs("  InnoDB: Error: tablespace id and flags in file ", stderr);
+	ut_print_filename(stderr, filepath);
+	fprintf(stderr, " are %lu and %lu, but in the InnoDB\n"
+		"InnoDB: data dictionary they are %lu and %lu.\n"
+		"InnoDB: Have you moved InnoDB .ibd files"
+		" around without using the\n"
+		"InnoDB: commands DISCARD TABLESPACE and"
+		" IMPORT TABLESPACE?\n"
+		"InnoDB: Please refer to\n"
+		"InnoDB: " REFMAN "innodb-troubleshooting-datadict.html\n"
+		"InnoDB: for how to resolve the issue.\n",
+		(ulong) found_id, (ulong) found_flags,
+		(ulong) expected_id, (ulong) expected_flags);
+}
+
 /********************************************************************//**
 Tries to open a single-table tablespace and optionally checks the space id is
 right in it. If does not succeed, prints an error message to the .err log. This
@@ -3138,34 +3466,183 @@ fil_open_single_table_tablespace(
 					accessing the first page of the file */
 	ulint		id,		/*!< in: space id */
 	ulint		flags,		/*!< in: tablespace flags */
-	const char*	tablename)	/*!< in: table name in the
+	const char*	tablename,	/*!< in: table name in the
 					databasename/tablename format */
+	const char*	path_in)	/*!< in: tablespace filepath */
 {
-	os_file_t	file;
-	char*		filepath;
-	ibool		success;
-	byte*		buf2;
-	byte*		page;
-	ulint		space_id;
-	ulint		space_flags;
-
-	filepath = fil_make_ibd_name(tablename, FALSE);
+	ulint		err;
+	bool		dict_filepath_same_as_default = false;
+	bool		link_file_found = false;
+	bool		link_file_is_bad = false;
+	os_file_t	def_file;
+	char*		def_filepath;
+	ibool		def_success = FALSE;
+	lsn_t		def_lsn;
+	ulint		def_id;
+	ulint		def_flags;
+	os_file_t	dict_file;
+	char*		dict_filepath = NULL;
+	ibool		dict_success = FALSE;
+	lsn_t		dict_lsn;
+	ulint		dict_id;
+	ulint		dict_flags;
+	os_file_t	remote_file;
+	char*		remote_filepath = NULL;
+	ibool		remote_success = FALSE;
+	lsn_t		remote_lsn;
+	ulint		remote_id;
+	ulint		remote_flags;
+	ulint		tablespaces_found = 0;
+#ifdef UNIV_LOG_ARCHIVE
+	ulint		space_arch_log_no;
+	ulint		remote_arch_log_no;
+#endif /* UNIV_LOG_ARCHIVE */
 
 	fsp_flags_validate(flags);
 
-	file = os_file_create_simple_no_error_handling(
-		innodb_file_data_key, filepath, OS_FILE_OPEN,
-		OS_FILE_READ_ONLY, &success);
-	if (!success) {
+	/* Discover the correct filepath.  We will always look for a ibd
+	in the default location. If it is remote, it should not be here. */
+	def_filepath = fil_make_ibd_name(tablename, FALSE);
+
+	/* The path_in was read from SYS_DATAFILES. */
+	if (path_in) {
+		if (strcmp(def_filepath, path_in)) {
+			dict_filepath = mem_strdup(path_in);
+			/* possibility of multiple files. */
+			check_space_id = true;
+		} else {
+			dict_filepath_same_as_default = true;
+		}
+	}
+
+	remote_success = link_file_found = fil_open_linked_file(
+		tablename, NULL, &remote_filepath, &remote_file);
+	if (remote_success) {
+		check_space_id = true;	/* possibility of multiple files. */
+		tablespaces_found++;
+
+		/* A link file was found. MySQL does not allow a DATA
+		DIRECTORY to be be the same as the default filepath. */
+		ut_a(strcmp(def_filepath, remote_filepath));
+
+		/* If there was a filepath found in SYS_DATAFILES,
+		we hope it was the same as this remote_filepath found
+		in the ISL file. */
+		if (dict_filepath
+		    && (0 == strcmp(dict_filepath, remote_filepath))) {
+			remote_success = FALSE;
+			os_file_close(remote_file);
+			mem_free(remote_filepath);
+			remote_filepath = NULL;
+			tablespaces_found--;
+		}
+	}
+
+	/* Attempt to open the tablespace at other possible filepaths. */
+	if (dict_filepath) {
+		dict_file = os_file_create_simple_no_error_handling(
+			innodb_file_data_key, dict_filepath, OS_FILE_OPEN,
+			OS_FILE_READ_ONLY, &dict_success);
+		if (dict_success) {
+			check_space_id = true;	/* possibility of multiple files. */
+			tablespaces_found++;
+		}
+	}
+	
+	/* Always look for a file at the default location. */
+	ut_a(def_filepath);
+	def_file = os_file_create_simple_no_error_handling(
+		innodb_file_data_key, def_filepath, OS_FILE_OPEN,
+		OS_FILE_READ_ONLY, &def_success);
+	if (def_success) {
+		tablespaces_found++;
+	}
+
+	/*  We have now checked alll possible tablesapce locations and
+	have a count of how many we found.  If things are normal, we
+	only found 1. */
+	if (!check_space_id && tablespaces_found == 1) {
+		goto skip_check;
+	}
+
+	/* Read the first page of the datadir tablespace, if found. */
+	if (def_success) {
+		fil_read_first_page(
+			def_file, FALSE, &def_flags, &def_id,
+#ifdef UNIV_LOG_ARCHIVE
+			&space_arch_log_no, &space_arch_log_no,
+#endif /* UNIV_LOG_ARCHIVE */
+			&def_lsn, &def_lsn);
+
+		/* Validate this single-table-tablespace with SYS_TABLES */
+		if (def_id != id || def_flags != flags) {
+			/* Do not use this tablespace. */
+			fil_report_bad_tablespace(
+				def_filepath, def_id,
+				def_flags, id, flags);
+			def_success = FALSE;
+			os_file_close(def_file);
+			tablespaces_found--;
+		}
+	}
+
+	/* Read the first page of the remote tablespace */
+	if (remote_success) {
+		fil_read_first_page(
+			remote_file, FALSE, &remote_flags, &remote_id,
+#ifdef UNIV_LOG_ARCHIVE
+			&remote_arch_log_no, &remote_arch_log_no,
+#endif /* UNIV_LOG_ARCHIVE */
+			&remote_lsn, &remote_lsn);
+
+		/* Validate this single-table-tablespace with SYS_TABLES */
+		if (remote_id != id || remote_flags != flags) {
+			/* Do not use this linked tablespace. */
+			fil_report_bad_tablespace(
+				remote_filepath, remote_id,
+				remote_flags, id, flags);
+			remote_success = FALSE;
+			link_file_is_bad = true;
+			os_file_close(remote_file);
+			mem_free(remote_filepath);
+			remote_filepath = NULL;
+			tablespaces_found--;
+		}
+	}
+
+	/* Read the first page of the datadir tablespace, if found. */
+	if (dict_success) {
+		fil_read_first_page(
+			dict_file, FALSE, &dict_flags, &dict_id,
+#ifdef UNIV_LOG_ARCHIVE
+			&space_arch_log_no, &space_arch_log_no,
+#endif /* UNIV_LOG_ARCHIVE */
+			&dict_lsn, &dict_lsn);
+
+		/* Validate this single-table-tablespace with SYS_TABLES */
+		if (dict_id != id || dict_flags != flags) {
+			/* Do not use this tablespace. */
+			fil_report_bad_tablespace(
+				dict_filepath, dict_id,
+				dict_flags, id, flags);
+			dict_success = FALSE;
+			os_file_close(dict_file);
+			tablespaces_found--;
+		}
+	}
+
+	/* Make sense of these three possible locations.
+	First, bail out if no tablespace files were found. */
+	if (tablespaces_found == 0) {
 		/* The following call prints an error message */
-		os_file_get_last_error(TRUE);
+		err = os_file_get_last_error(TRUE);
 
 		ut_print_timestamp(stderr);
 
 		fputs("  InnoDB: Error: trying to open a table,"
 		      " but could not\n"
 		      "InnoDB: open the tablespace file ", stderr);
-		ut_print_filename(stderr, filepath);
+		ut_print_filename(stderr, def_filepath);
 		fputs("!\n"
 		      "InnoDB: Have you moved InnoDB .ibd files around"
 		      " without using the\n"
@@ -3179,71 +3656,119 @@ fil_open_single_table_tablespace(
 		      "innodb-troubleshooting-datadict.html\n"
 		      "InnoDB: for how to resolve the issue.\n", stderr);
 
-		mem_free(filepath);
+		ut_ad(!def_success);
+		ut_ad(!dict_success);
+		ut_ad(!remote_success);
+		ut_ad(remote_filepath == NULL);
+		if (dict_filepath) {
+			mem_free(dict_filepath);
+		}
+		mem_free(def_filepath);
 
 		return(FALSE);
 	}
 
-	if (!check_space_id) {
-		space_id = id;
-
-		goto skip_check;
-	}
-
-	/* Read the first page of the tablespace */
-
-	buf2 = static_cast<byte*>(ut_malloc(2 * UNIV_PAGE_SIZE));
-	/* Align the memory for file i/o if we might have O_DIRECT set */
-	page = static_cast<byte*>(ut_align(buf2, UNIV_PAGE_SIZE));
-
-	success = os_file_read(file, page, 0, UNIV_PAGE_SIZE);
-
-	/* We have to read the tablespace id and flags from the file. */
+	/* Do not open any tablespaces if more than one tablespace with
+	the correct space ID and flags were found. */
+	if (tablespaces_found > 1) {
+		fprintf(stderr,
+			"InnoDB: Error: A tablespace for %s "
+			"has been found in multiple places;\n",
+			tablename);
+		if (def_success) {
+			fprintf(stderr,
+				"InnoDB: %s, LSN=" LSN_PF "\n",
+				def_filepath, def_lsn);
+			os_file_close(def_file);
+		}
+		if (remote_success) {
+			fprintf(stderr,
+				"InnoDB: %s, LSN=" LSN_PF "\n",
+				remote_filepath, remote_lsn);
+			os_file_close(remote_file);
+		}
+		if (dict_success) {
+			fprintf(stderr,
+				"InnoDB: %s, LSN=" LSN_PF "\n",
+				dict_filepath, dict_lsn);
+			os_file_close(dict_file);
+		}
+		fprintf(stderr,
+			"InnoDB: Error: The tablespace for %s "
+			"will not be opened.\n",
+			tablename);
 
-	space_id = fsp_header_get_space_id(page);
-	space_flags = fsp_header_get_flags(page);
+		if (remote_filepath) {
+			mem_free(remote_filepath);
+		}
+		if (dict_filepath) {
+			mem_free(dict_filepath);
+		}
+		mem_free(def_filepath);
 
-	ut_free(buf2);
+		return(FALSE);
+	}
 
-	if (UNIV_UNLIKELY(space_id != id || space_flags != flags)) {
-		ut_print_timestamp(stderr);
+skip_check:
+	/* At this point, there should be only one filepath. */
+	ut_a(tablespaces_found == 1);
 
-		fputs("  InnoDB: Error: tablespace id and flags in file ",
-		      stderr);
-		ut_print_filename(stderr, filepath);
-		fprintf(stderr, " are %lu and %lu, but in the InnoDB\n"
-			"InnoDB: data dictionary they are %lu and %lu.\n"
-			"InnoDB: Have you moved InnoDB .ibd files"
-			" around without using the\n"
-			"InnoDB: commands DISCARD TABLESPACE and"
-			" IMPORT TABLESPACE?\n"
-			"InnoDB: Please refer to\n"
-			"InnoDB: " REFMAN "innodb-troubleshooting-datadict.html\n"
-			"InnoDB: for how to resolve the issue.\n",
-			(ulong) space_id, (ulong) space_flags,
-			(ulong) id, (ulong) flags);
+	/* We may need to change what is stored in SYS_DATAFILES */
+	if (dict_filepath) {
+		if (remote_success) {
+			dict_update_filepath(id, remote_filepath);
+		} else if (def_success) {
+			dict_update_filepath(id, def_filepath);
+			if (link_file_is_bad) {
+				fil_delete_link_file(tablename);
+			}
+		} else if (!link_file_found || link_file_is_bad) {
+			ut_ad(dict_success);
+			/* Fix the link file if we got our filepath
+			from the dictionary but a link file did not
+			exist or it did not point to a valid file. */
+			fil_delete_link_file(tablename);
+			fil_create_link_file(tablename, dict_filepath);
+		}
 
-		success = FALSE;
+	} else if (remote_success && dict_filepath_same_as_default) {
+		dict_update_filepath(id, remote_filepath);
 
-		goto func_exit;
+	} else if (remote_success && path_in == NULL) {
+		/* SYS_DATAFILES record for this space ID was not found. */
+		dict_insert_tablespace_and_filepath(
+			id, tablename, remote_filepath, flags);
 	}
 
-skip_check:
-	success = fil_space_create(tablename, space_id, flags, FIL_TABLESPACE);
+	ibool fil_space_success = fil_space_create(
+		tablename, id, flags, FIL_TABLESPACE);
 
-	if (!success) {
-		goto func_exit;
+	/* We do not measure the size of the file, that is why we pass
+	the 0 below */
+	if (fil_space_success) {
+		fil_node_create(remote_success ? remote_filepath :
+				dict_success ? dict_filepath :
+				def_filepath, 0, id, FALSE);
 	}
 
-	/* We do not measure the size of the file, that is why we pass the 0
-	below */
-
-	fil_node_create(filepath, 0, space_id, FALSE);
-func_exit:
-	os_file_close(file);
-	mem_free(filepath);
+	if (remote_success) {
+		os_file_close(remote_file);
+	}
+	if (remote_filepath) {
+		mem_free(remote_filepath);
+	}
+	if (dict_success) {
+		os_file_close(dict_file);
+	}
+	if (dict_filepath) {
+		mem_free(dict_filepath);
+	}
+	if (def_success) {
+		os_file_close(def_file);
+	}
+	mem_free(def_filepath);
 
-	return(success);
+	return(fil_space_success);
 }
 #endif /* !UNIV_HOTBACKUP */
 
@@ -3275,39 +3800,126 @@ fil_make_ibbackup_old_name(
 Opens an .ibd file and adds the associated single-table tablespace to the
 InnoDB fil0fil.cc data structures. */
 static
+ibool
+fil_validate_single_table_tablespace(
+/*=================================*/
+	const char*	tablename,	/*!< in: database/tablename */
+	os_file_t	file,		/*!< in: file handle */
+	char*		filepath,	/*!< in: filepath */
+	ulint*		space_id,	/*!< out: Space ID from File */
+	ulint*		flags,		/*!< out: Tablespace flags from File */
+	lsn_t*		lsn)		/*!< out: LSN from File */
+{
+#ifdef UNIV_LOG_ARCHIVE
+	ulint		arch_log_no;
+#endif /* UNIV_LOG_ARCHIVE */
+
+	*space_id = 0;
+	*flags = 0;
+	*lsn = 0;
+
+	fil_read_first_page(
+		file, FALSE, flags, space_id,
+#ifdef UNIV_LOG_ARCHIVE
+		$arch_log_no, &arch_log_no,
+#endif /* UNIV_LOG_ARCHIVE */
+		lsn, lsn);
+
+	if (*space_id == ULINT_UNDEFINED || *space_id == 0) {
+		fprintf(stderr,
+		" InnoDB: Error: Tablespace is not sensible;"
+		" Table: %s  Space ID: %lu  Filepath: %s\n",
+		tablename, (ulong) space_id, filepath);
+		return FALSE;
+	}
+
+	mutex_enter(&fil_system->mutex);
+	fil_space_t* space = fil_space_get_by_id(*space_id);
+	mutex_exit(&fil_system->mutex);
+	if (space != NULL) {
+		char* prev_filepath = fil_space_get_first_path(*space_id);
+
+		fprintf(stderr,
+			" InnoDB: Error: Attempt to open a tablespace "
+			"previously opened.\n"
+			"Previous tablespace %s uses space ID: %lu at "
+			"filepath: %s\n"
+			"Cannot open tablespace %s which uses space ID: "
+			"%lu at filepath: %s\n",
+			space->name, (ulong) space->id, prev_filepath,
+			tablename, (ulong) *space_id, filepath);
+
+		mem_free(prev_filepath);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+/********************************************************************//**
+Opens an .ibd file and adds the associated single-table tablespace to the
+InnoDB fil0fil.cc data structures. */
+static
 void
 fil_load_single_table_tablespace(
 /*=============================*/
 	const char*	dbname,		/*!< in: database name */
 	const char*	filename)	/*!< in: file name (not a path),
-					including the .ibd extension */
+					including the .ibd or .isl extension */
 {
-	os_file_t	file;
-	char*		filepath;
 	char*		tablename;
-	ibool		success;
-	byte*		buf2;
-	byte*		page;
-	ulint		space_id;
-	ulint		flags;
+	ulint		tablename_len;
+	ulint		dbname_len = strlen(dbname);
+	ulint		filename_len = strlen(filename);
+	ibool		def_success;
+	os_file_t	def_file;
+	char*		def_filepath;
+	lsn_t		def_lsn = 0;
+	ulint		def_id = 0;
+	ulint		def_flags = 0;
+	ibool		remote_success;
+	os_file_t	remote_file;
+	char*		remote_filepath;
+	lsn_t		remote_lsn = 0;
+	ulint		remote_id = 0;
+	ulint		remote_flags = 0;
 	os_offset_t	size;
 #ifdef UNIV_HOTBACKUP
 	fil_space_t*	space;
 #endif
-	filepath = static_cast<char*>(
-		mem_alloc(
-			strlen(dbname)
-			+ strlen(filename)
-			+ strlen(fil_path_to_mysql_datadir) + 3));
-
-	sprintf(filepath, "%s/%s/%s", fil_path_to_mysql_datadir, dbname,
-		filename);
-	srv_normalize_path_for_win(filepath);
 
+	/* The caller assured that the extension is ".ibd" or ".isl". */
+	ut_ad(0 == memcmp(filename + filename_len - 4, ".i", 2));
+
+	/* Build up the tablename in the standard form database/table. */
 	tablename = static_cast<char*>(
-		mem_alloc(strlen(dbname) + strlen(filename) + 2));
+		mem_alloc(dbname_len + filename_len + 2));
 	sprintf(tablename, "%s/%s", dbname, filename);
-	tablename[strlen(tablename) - strlen(".ibd")] = 0;
+	tablename_len = strlen(tablename) - strlen(".ibd");
+	tablename[tablename_len] = '\0';
+
+	/* There may be both .ibd and .isl file in the directory.
+	And it is possible that the .isl file refers to a different
+	.ibd file.  If so, we open and compare them the first time
+	one of them is sent to this function.  So if this table has
+	already been loaded, there is nothing to do.*/
+	mutex_enter(&fil_system->mutex);
+	if (fil_space_get_by_name(tablename)) {
+		mem_free(tablename);
+		mutex_exit(&fil_system->mutex);
+		return;
+	}
+	mutex_exit(&fil_system->mutex);
+
+	/* Build up the filepath of the .ibd tablespace in the datadir */
+	def_filepath = fil_make_ibd_name(tablename, FALSE);
+	def_filepath = static_cast<char*>(
+		mem_alloc(strlen(fil_path_to_mysql_datadir)
+			  + tablename_len + sizeof "/.ibd"));
+	sprintf(def_filepath, "%s/%s.ibd",
+		fil_path_to_mysql_datadir, tablename);
+	srv_normalize_path_for_win(def_filepath);
 
 #ifdef __WIN__
 # ifndef UNIV_HOTBACKUP
@@ -3317,31 +3929,62 @@ fil_load_single_table_tablespace(
 	file path to lower case, so that we are consistent with InnoDB's
 	internal data dictionary. */
 
-	dict_casedn_str(filepath);
+	dict_casedn_str(def_filepath);
 # endif /* !UNIV_HOTBACKUP */
 #endif
-	file = os_file_create_simple_no_error_handling(
-		innodb_file_data_key, filepath, OS_FILE_OPEN,
-		OS_FILE_READ_ONLY, &success);
-	if (!success) {
+
+	/* Check for a link file which locates a remote tablespace. */
+	remote_success = fil_open_linked_file(
+		tablename, def_filepath, &remote_filepath, &remote_file);
+
+	/* Read the first page of the remote tablespace */
+	if (remote_success) {
+		remote_success = fil_validate_single_table_tablespace(
+			tablename, remote_file, remote_filepath,
+			&remote_id, &remote_flags, &remote_lsn);
+		if (!remote_success) {
+			os_file_close(remote_file);
+			mem_free(remote_filepath);
+		}
+	}
+
+
+	/* Try to open the tablespace in the datadir. */
+	def_file = os_file_create_simple_no_error_handling(
+		innodb_file_data_key, def_filepath, OS_FILE_OPEN,
+		OS_FILE_READ_ONLY, &def_success);
+
+	/* Read the first page of the remote tablespace */
+	if (def_success) {
+		def_success = fil_validate_single_table_tablespace(
+			tablename, def_file, def_filepath,
+			&def_id, &def_flags, &def_lsn);
+		if (!def_success) {
+			os_file_close(def_file);
+			mem_free(def_filepath);
+		}
+	}
+
+	if (!def_success && !remote_success) {
 		/* The following call prints an error message */
 		os_file_get_last_error(TRUE);
-
 		fprintf(stderr,
-			"InnoDB: Error: could not open single-table tablespace"
-			" file\n"
-			"InnoDB: %s!\n"
+			"InnoDB: Error: could not open single-table"
+			" tablespace file %s\n", def_filepath);
+		mem_free(def_filepath);
+no_good_file:
+		fprintf(stderr,
 			"InnoDB: We do not continue the crash recovery,"
 			" because the table may become\n"
-			"InnoDB: corrupt if we cannot apply the log records"
-			" in the InnoDB log to it.\n"
+			"InnoDB: corrupt if we cannot apply the log"
+			" records in the InnoDB log to it.\n"
 			"InnoDB: To fix the problem and start mysqld:\n"
 			"InnoDB: 1) If there is a permission problem"
 			" in the file and mysqld cannot\n"
 			"InnoDB: open the file, you should"
 			" modify the permissions.\n"
-			"InnoDB: 2) If the table is not needed, or you can"
-			" restore it from a backup,\n"
+			"InnoDB: 2) If the table is not needed, or you"
+			" can restore it from a backup,\n"
 			"InnoDB: then you can remove the .ibd file,"
 			" and InnoDB will do a normal\n"
 			"InnoDB: crash recovery and ignore that table.\n"
@@ -3350,10 +3993,9 @@ fil_load_single_table_tablespace(
 			"InnoDB: the .ibd file, you can set"
 			" innodb_force_recovery > 0 in my.cnf\n"
 			"InnoDB: and force InnoDB to continue crash"
-			" recovery here.\n", filepath);
+			" recovery here.\n");
 
 		mem_free(tablename);
-		mem_free(filepath);
 
 		if (srv_force_recovery > 0) {
 			fprintf(stderr,
@@ -3368,104 +4010,92 @@ fil_load_single_table_tablespace(
 		exit(1);
 	}
 
+	if (def_success && remote_success) {
+		fprintf(stderr,
+			"InnoDB: Tablespaces for %s "
+			"have been found in two places;\n"
+			"InnoDB: 1: SpaceID: %lu  LSN: %lu  File: %s\n"
+			"InnoDB: 2: SpaceID: %lu  LSN: %lu  File: %s\n",
+			tablename,
+			(ulong) def_id, (ulong) def_lsn,
+			def_filepath,
+			(ulong) remote_id, (ulong) remote_lsn,
+			remote_filepath);
+
+		if (global_mode_is_strict() || def_id != remote_id) {
+			def_success = FALSE;
+			remote_success = FALSE;
+			os_file_close(def_file);
+			os_file_close(remote_file);
+			mem_free(def_filepath);
+			mem_free(remote_filepath);
+			goto no_good_file;
+		}
+
+		/* Figure out which tablespace is newer.  Use the remote
+		tablespace if LSNs ar the same since the ISL file existed. */
+		if (def_lsn > remote_lsn) {
+			/* Use default tablespace. */
+			fprintf(stderr, "InnoDB: Using tablespace 1\n");
+			remote_success = FALSE;
+			os_file_close(remote_file);
+			mem_free(remote_filepath);
+
+		} else {
+			/* Use the remote tablespace. */
+			fprintf(stderr, "InnoDB: Using tablespace 2\n");
+			def_success = FALSE;
+			os_file_close(def_file);
+			mem_free(def_filepath);
+		}
+	}
+
+	/* At this point, only one tablespace is open */
+	ut_a((def_success && !remote_success) || (!def_success && remote_success));
+
+	os_file_t file	= def_success ? def_file : remote_file;
+	char* filepath	= def_success ? def_filepath : remote_filepath;
+	ulint space_id	= def_success ? def_id : remote_id;
+	ulint flags	= def_success ? def_flags : remote_flags;
+
+
+	/* Get and test the file size. */
 	size = os_file_get_size(file);
 
-	if (UNIV_UNLIKELY(size == (os_offset_t) -1)) {
+	if (size == (os_offset_t) -1) {
 		/* The following call prints an error message */
 		os_file_get_last_error(TRUE);
 
 		fprintf(stderr,
 			"InnoDB: Error: could not measure the size"
-			" of single-table tablespace file\n"
-			"InnoDB: %s!\n"
-			"InnoDB: We do not continue crash recovery,"
-			" because the table will become\n"
-			"InnoDB: corrupt if we cannot apply the log records"
-			" in the InnoDB log to it.\n"
-			"InnoDB: To fix the problem and start mysqld:\n"
-			"InnoDB: 1) If there is a permission problem"
-			" in the file and mysqld cannot\n"
-			"InnoDB: access the file, you should"
-			" modify the permissions.\n"
-			"InnoDB: 2) If the table is not needed,"
-			" or you can restore it from a backup,\n"
-			"InnoDB: then you can remove the .ibd file,"
-			" and InnoDB will do a normal\n"
-			"InnoDB: crash recovery and ignore that table.\n"
-			"InnoDB: 3) If the file system or the disk is broken,"
-			" and you cannot remove\n"
-			"InnoDB: the .ibd file, you can set"
-			" innodb_force_recovery > 0 in my.cnf\n"
-			"InnoDB: and force InnoDB to continue"
-			" crash recovery here.\n", filepath);
-
+			" of single-table tablespace file %s\n",
+			filepath);
 		os_file_close(file);
-		mem_free(tablename);
 		mem_free(filepath);
-
-		if (srv_force_recovery > 0) {
-			fprintf(stderr,
-				"InnoDB: innodb_force_recovery"
-				" was set to %lu. Continuing crash recovery\n"
-				"InnoDB: even though we cannot access"
-				" the .ibd file of this table.\n",
-				srv_force_recovery);
-			return;
-		}
-
-		exit(1);
+		goto no_good_file;
 	}
 
-	/* TODO: What to do in other cases where we cannot access an .ibd
-	file during a crash recovery? */
-
 	/* Every .ibd file is created >= 4 pages in size. Smaller files
 	cannot be ok. */
-
+	ulong minimum_size = FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE;
+	if (size < minimum_size) {
 #ifndef UNIV_HOTBACKUP
-	if (size < FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE) {
 		fprintf(stderr,
 			"InnoDB: Error: the size of single-table"
 			" tablespace file %s\n"
 			"InnoDB: is only " UINT64PF
 			", should be at least %lu!\n",
-			filepath,
-			size, (ulong) (4 * UNIV_PAGE_SIZE));
+			filepath, size, minimum_size);
 		os_file_close(file);
-		mem_free(tablename);
 		mem_free(filepath);
-
-		return;
-	}
-#endif
-	/* Read the first page of the tablespace if the size is big enough */
-
-	buf2 = static_cast<byte*>(ut_malloc(2 * UNIV_PAGE_SIZE));
-	/* Align the memory for file i/o if we might have O_DIRECT set */
-	page = static_cast<byte*>(ut_align(buf2, UNIV_PAGE_SIZE));
-
-	if (size >= FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE) {
-		success = os_file_read(file, page, 0, UNIV_PAGE_SIZE);
-
-		/* We have to read the tablespace id from the file */
-
-		space_id = fsp_header_get_space_id(page);
-		flags = fsp_header_get_flags(page);
-	} else {
+		goto no_good_file;
+#else
 		space_id = ULINT_UNDEFINED;
 		flags = 0;
+#endif
 	}
 
-#ifndef UNIV_HOTBACKUP
-	if (space_id == ULINT_UNDEFINED || space_id == 0) {
-		fprintf(stderr,
-			"InnoDB: Error: tablespace id %lu in file %s"
-			" is not sensible\n",
-			(ulong) space_id,
-			filepath);
-		goto func_exit;
-	}
-#else
+#ifdef UNIV_HOTBACKUP
 	if (space_id == ULINT_UNDEFINED || space_id == 0) {
 		char*	new_path;
 
@@ -3484,7 +4114,6 @@ fil_load_single_table_tablespace(
 		new_path = fil_make_ibbackup_old_name(filepath);
 		ut_a(os_file_rename(innodb_file_data_key, filepath, new_path));
 
-		ut_free(buf2);
 		mem_free(tablename);
 		mem_free(filepath);
 		mem_free(new_path);
@@ -3523,7 +4152,6 @@ fil_load_single_table_tablespace(
 
 		ut_a(os_file_rename(innodb_file_data_key, filepath, new_path));
 
-		ut_free(buf2);
 		mem_free(tablename);
 		mem_free(filepath);
 		mem_free(new_path);
@@ -3532,16 +4160,16 @@ fil_load_single_table_tablespace(
 	}
 	mutex_exit(&fil_system->mutex);
 #endif
-	success = fil_space_create(tablename, space_id, flags, FIL_TABLESPACE);
+	ibool success = fil_space_create(
+		tablename, space_id, flags, FIL_TABLESPACE);
 
 	if (!success) {
-
 		if (srv_force_recovery > 0) {
 			fprintf(stderr,
-				"InnoDB: innodb_force_recovery"
-				" was set to %lu. Continuing crash recovery\n"
-				"InnoDB: even though the tablespace creation"
-				" of this table failed.\n",
+				"InnoDB: innodb_force_recovery was set"
+				" to %lu. Continuing crash recovery\n"
+				"InnoDB: even though the tablespace"
+				" creation of this table failed.\n",
 				srv_force_recovery);
 			goto func_exit;
 		}
@@ -3554,9 +4182,9 @@ fil_load_single_table_tablespace(
 	let fil_node_open() do that task. */
 
 	fil_node_create(filepath, 0, space_id, FALSE);
+
 func_exit:
 	os_file_close(file);
-	ut_free(buf2);
 	mem_free(tablename);
 	mem_free(filepath);
 }
@@ -3688,11 +4316,14 @@ fil_load_single_table_tablespaces(void)
 
 				/* We found a symlink or a file */
 				if (strlen(fileinfo.name) > 4
-				    && 0 == strcmp(fileinfo.name
+				    && (0 == strcmp(fileinfo.name
+						   + strlen(fileinfo.name) - 4,
+						   ".ibd")
+					|| 0 == strcmp(fileinfo.name
 						   + strlen(fileinfo.name) - 4,
-						   ".ibd")) {
-					/* The name ends in .ibd; try opening
-					the file */
+						   ".isl"))) {
+					/* The name ends in .ibd or .isl;
+					try opening the file */
 					fil_load_single_table_tablespace(
 						dbinfo.name, fileinfo.name);
 				}

=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc	revid:andrei.elkin@stripped
+++ b/storage/innobase/handler/ha_innodb.cc	revid:kevin.lewis@stripped
@@ -1397,6 +1397,8 @@ convert_error_code_to_mysql(
 		return(HA_ERR_INDEX_CORRUPT);
 	case DB_UNDO_RECORD_TOO_BIG:
 		return(HA_ERR_UNDO_REC_TOO_BIG);
+	case DB_TABLESPACE_EXISTS:
+		return(HA_ERR_TABLESPACE_EXISTS);
 	}
 }
 
@@ -2344,7 +2346,7 @@ innobase_invalidate_query_cache(
 
 	/* Argument TRUE below means we are using transactions */
 #ifdef HAVE_QUERY_CACHE
-	mysql_query_cache_invalidate4(trx->mysql_thd,
+	mysql_query_cache_invalidate4(static_cast<THD*>(trx->mysql_thd),
 				      full_name,
 				      (uint32) full_name_len,
 				      TRUE);
@@ -2528,7 +2530,8 @@ trx_is_interrupted(
 /*===============*/
 	trx_t*	trx)	/*!< in: transaction */
 {
-	return(trx && trx->mysql_thd && thd_killed(trx->mysql_thd));
+	return(trx && trx->mysql_thd
+	       && thd_killed(static_cast<THD*>(trx->mysql_thd)));
 }
 
 /**********************************************************************//**
@@ -2541,7 +2544,29 @@ trx_is_strict(
 	trx_t*	trx)	/*!< in: transaction */
 {
 	return(trx && trx->mysql_thd
-	       && THDVAR(trx->mysql_thd, strict_mode));
+	       && THDVAR(static_cast<THD*>(trx->mysql_thd), strict_mode));
+}
+
+/**********************************************************************//**
+Determines if the current MySQL thread is running in strict mode.
+@return	TRUE if strict */
+UNIV_INTERN
+ibool
+thd_is_strict(
+/*==========*/
+	THD*	thd)	/*!< in: MySQL thread descriptor */
+{
+	return(thd && THDVAR(thd, strict_mode));
+}
+
+/**********************************************************************//**
+returns the global setting for innodb_strict_mode.
+@return	TRUE if strict */
+UNIV_INTERN
+ibool
+global_mode_is_strict()
+{
+	return(THDVAR(NULL, strict_mode));
 }
 
 /**************************************************************//**
@@ -3835,11 +3860,13 @@ ha_innobase::primary_key_is_clustered()
 
 /*****************************************************************//**
 Normalizes a table name string. A normalized name consists of the
-database name catenated to '/' and table name. An example:
-test/mytable. On Windows normalization puts both the database name and the
-table name always to lower case if "set_lower_case" is set to TRUE. */
+database name catenated to '/' and table name. An example: test/mytable.
+On Windows normalization puts both the database name and the
+table name always to lower case if "set_lower_case" is set to TRUE.
+Memory for norm_name is allocated here and must be freed by the caller.
+@return	normalized name as a null-terminated string*/
 static
-void
+char*
 normalize_table_name_low(
 /*=====================*/
 	char*		norm_name,	/*!< out: normalized name as a
@@ -3849,9 +3876,11 @@ normalize_table_name_low(
 					to lower case */
 {
 	char*	name_ptr;
+	ulint	name_len;
 	char*	db_ptr;
 	ulint	db_len;
 	char*	ptr;
+	ulint	norm_len;
 
 	/* Scan name from the end */
 
@@ -3863,6 +3892,7 @@ normalize_table_name_low(
 	}
 
 	name_ptr = ptr + 1;
+	name_len = strlen(name_ptr);
 
 	/* skip any number of path separators */
 	while (ptr >= name && (*ptr == '\\' || *ptr == '/')) {
@@ -3881,15 +3911,21 @@ normalize_table_name_low(
 
 	db_ptr = ptr + 1;
 
+	norm_len = db_len + name_len + sizeof "/";
+	ut_a(norm_len < FN_REFLEN - 1);
+
 	memcpy(norm_name, db_ptr, db_len);
 
 	norm_name[db_len] = '/';
 
-	memcpy(norm_name + db_len + 1, name_ptr, strlen(name_ptr) + 1);
+	/* Copy the name and null-byte. */
+	memcpy(norm_name + db_len + 1, name_ptr, name_len + 1);
 
 	if (set_lower_case) {
 		innobase_casedn_str(norm_name);
 	}
+
+	return(norm_name);
 }
 
 #if !defined(DBUG_OFF)
@@ -3900,7 +3936,7 @@ void
 test_normalize_table_name_low()
 /*===========================*/
 {
-	char		norm_name[128];
+	char		norm_name[FN_REFLEN];
 	const char*	test_data[][2] = {
 		/* input, expected result */
 		{"./mysqltest/t1", "mysqltest/t1"},
@@ -4427,12 +4463,10 @@ ha_innobase::open(
 	uint		test_if_locked)	/*!< in: not used */
 {
 	dict_table_t*	ib_table;
-	char		norm_name[1000];
+	char		norm_name[FN_REFLEN];
 	THD*		thd;
 	ulint		retries = 0;
 	char*		is_part = NULL;
-	ibool		par_case_name_set = FALSE;
-	char		par_case_name[MAX_FULL_NAME_LEN + 1];
 
 	DBUG_ENTER("ha_innobase::open");
 
@@ -4448,8 +4482,6 @@ ha_innobase::open(
 		innobase_release_temporary_latches(ht, thd);
 	}
 
-	normalize_table_name(norm_name, name);
-
 	user_thd = NULL;
 
 	if (!(share=get_share())) {
@@ -4457,6 +4489,8 @@ ha_innobase::open(
 		DBUG_RETURN(1);
 	}
 
+	normalize_table_name(norm_name, name);
+
 	/* Will be allocated if it is needed in ::update_row() */
 	upd_buf = NULL;
 	upd_buf_size = 0;
@@ -4489,35 +4523,29 @@ retry:
 
 			1) If boot against an installation from Windows
 			platform, then its partition table name could
-			be all be in lower case in system tables. So we
-			will need to check lower case name when load table.
+			be in lower case in system tables. So we will
+			need to check lower case name when load table.
 
-			2) If  we boot an installation from other case
+			2) If we boot an installation from other case
 			sensitive platform in Windows, we might need to
-			check the existence of table name without lowering
-			case them in the system table. */
+			check the existence of table name without lower
+			case in the system table. */
 			if (innobase_get_lower_case_table_names() == 1) {
-
-				if (!par_case_name_set) {
+				char	par_case_name[FN_REFLEN];
 #ifndef __WIN__
-					/* Check for the table using lower
-					case name, including the partition
-					separator "P" */
-					memcpy(par_case_name, norm_name,
-					       strlen(norm_name));
-					par_case_name[strlen(norm_name)] = 0;
-					innobase_casedn_str(par_case_name);
+				/* Check for the table using lower
+				case name, including the partition
+				separator "P" */
+				strcpy(par_case_name, norm_name);
+				innobase_casedn_str(par_case_name);
 #else
-					/* On Windows platfrom, check
-					whether there exists table name in
-					system table whose name is
-					not being normalized to lower case */
-					normalize_table_name_low(
-						par_case_name, name, FALSE);
+				/* On Windows platfrom, check
+				whether there exists table name in
+				system table whose name is
+				not being normalized to lower case */
+				normalize_table_name_low(
+					par_case_name, name, FALSE);
 #endif
-					par_case_name_set = TRUE;
-				}
-
 				ib_table = dict_table_open_on_name(
 					par_case_name, FALSE, TRUE,
 					DICT_ERR_IGNORE_NONE);
@@ -4600,6 +4628,7 @@ table_opened:
 		my_errno = ENOENT;
 
 		dict_table_close(ib_table, FALSE, FALSE);
+
 		DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
 	}
 
@@ -8040,7 +8069,7 @@ create_table_check_doc_id_col(
 				*doc_id_col = i;
 			} else {
 				push_warning_printf(
-					trx->mysql_thd,
+					static_cast<THD*>(trx->mysql_thd),
 					Sql_condition::WARN_LEVEL_WARN,
 					ER_ILLEGAL_HA_CREATE_OPTION,
 					"InnoDB: FTS_DOC_ID column must be "
@@ -8068,20 +8097,22 @@ create_table_def(
 	const TABLE*	form,		/*!< in: information on table
 					columns and indexes */
 	const char*	table_name,	/*!< in: table name */
-	const char*	path_of_temp_table,
-					/*!< in: if this is a table explicitly
+	const char*	temp_path,	/*!< in: if this is a table explicitly
 					created by the user with the
 					TEMPORARY keyword, then this
 					parameter is the dir path where the
 					table should be placed if we create
 					an .ibd file for it (no .ibd extension
-					in the path, though) */
+					in the path, though). Otherwise this
+					is NULL */
+	const char*	remote_path,	/*!< in: NULL or a remote path */
 	ulint		flags,		/*!< in: table flags */
 	ulint		flags2)		/*!< in: table flags2 */
 {
+	THD*		thd = static_cast<THD*>(trx->mysql_thd);
 	dict_table_t*	table;
 	ulint		n_cols;
-	dberr_t		error;
+	dberr_t		err;
 	ulint		col_type;
 	ulint		col_len;
 	ulint		nulls_allowed;
@@ -8097,13 +8128,13 @@ create_table_def(
 	DBUG_ENTER("create_table_def");
 	DBUG_PRINT("enter", ("table_name: %s", table_name));
 
-	DBUG_ASSERT(trx->mysql_thd != NULL);
+	DBUG_ASSERT(thd != NULL);
 
 	/* MySQL does the name length check. But we do additional check
 	on the name length here */
 	if (strlen(table_name) > MAX_FULL_NAME_LEN) {
 		push_warning_printf(
-			trx->mysql_thd, Sql_condition::WARN_LEVEL_WARN,
+			thd, Sql_condition::WARN_LEVEL_WARN,
 			ER_TABLE_NAME,
 			"InnoDB: Table Name or Database Name is too long");
 
@@ -8115,7 +8146,7 @@ create_table_def(
 	if (strcmp(strchr(table_name, '/') + 1,
 		   "innodb_table_monitor") == 0) {
 		push_warning(
-			trx->mysql_thd, Sql_condition::WARN_LEVEL_WARN,
+			thd, Sql_condition::WARN_LEVEL_WARN,
 			HA_ERR_WRONG_COMMAND,
 			DEPRECATED_MSG_INNODB_TABLE_MONITOR);
 	}
@@ -8129,7 +8160,7 @@ create_table_def(
 		if (doc_id_col == ULINT_UNDEFINED) {
 			trx_commit_for_mysql(trx);
 
-			error = DB_ERROR;
+			err = DB_ERROR;
 			goto error_ret;
 		} else {
 			has_doc_id_col = TRUE;
@@ -8158,8 +8189,14 @@ create_table_def(
 	}
 
 	if (flags2 & DICT_TF2_TEMPORARY) {
+		ut_a(strlen(temp_path));
 		table->dir_path_of_temp_table =
-			mem_heap_strdup(table->heap, path_of_temp_table);
+			mem_heap_strdup(table->heap, temp_path);
+	}
+
+	if (strlen(remote_path)) {
+		table->data_dir_path =
+			mem_heap_strdup(table->heap, remote_path);
 	}
 
 	heap = mem_heap_create(1000);
@@ -8172,8 +8209,7 @@ create_table_def(
 
 		if (!col_type) {
 			push_warning_printf(
-				trx->mysql_thd,
-				Sql_condition::WARN_LEVEL_WARN,
+				thd, Sql_condition::WARN_LEVEL_WARN,
 				ER_CANT_CREATE_TABLE,
 				"Error creating table '%s' with "
 				"column '%s'. Please check its "
@@ -8197,8 +8233,7 @@ create_table_def(
 				/* in data0type.h we assume that the
 				number fits in one byte in prtype */
 				push_warning_printf(
-					trx->mysql_thd,
-					Sql_condition::WARN_LEVEL_WARN,
+					thd, Sql_condition::WARN_LEVEL_WARN,
 					ER_CANT_CREATE_TABLE,
 					"In InnoDB, charset-collation codes"
 					" must be below 256."
@@ -8239,7 +8274,7 @@ err_col:
 			mem_heap_free(heap);
 			trx_commit_for_mysql(trx);
 
-			error = DB_ERROR;
+			err = DB_ERROR;
 			goto error_ret;
 		}
 
@@ -8259,18 +8294,25 @@ err_col:
 		fts_add_doc_id_column(table, heap);
 	}
 
-	error = row_create_table_for_mysql(table, trx);
+	err = row_create_table_for_mysql(table, trx);
 
 	mem_heap_free(heap);
 
-	if (error == DB_DUPLICATE_KEY) {
-		char buf[100];
+	if (err == DB_DUPLICATE_KEY || err == DB_TABLESPACE_EXISTS) {
+		ulint name_len = strlen(table_name);
+		char* display_name = static_cast<char*>(mem_alloc(name_len + 32));
 		char* buf_end = innobase_convert_identifier(
-			buf, sizeof buf - 1, table_name, strlen(table_name),
-			trx->mysql_thd, TRUE);
+			display_name, name_len + 31,
+			table_name, name_len,
+			thd, TRUE);
 
 		*buf_end = '\0';
-		my_error(ER_TABLE_EXISTS_ERROR, MYF(0), buf);
+
+		my_error(err == DB_DUPLICATE_KEY
+			 ? ER_TABLE_EXISTS_ERROR
+			 : ER_TABLESPACE_EXISTS, MYF(0), display_name);
+
+		mem_free(display_name);
 	}
 
 	if (flags2 & DICT_TF2_FTS) {
@@ -8278,7 +8320,7 @@ err_col:
 	}
 
 error_ret:
-	DBUG_RETURN(convert_error_code_to_mysql(error, flags, trx->mysql_thd));
+	DBUG_RETURN(convert_error_code_to_mysql(err, flags, thd));
 }
 
 /*****************************************************************//**
@@ -8529,7 +8571,7 @@ create_options_are_valid(
 	ut_ad(thd != NULL);
 
 	/* If innodb_strict_mode is not set don't do any validation. */
-	if (!(THDVAR(thd, strict_mode))) {
+	if (!thd_is_strict(thd)) {
 		return(TRUE);
 	}
 
@@ -8629,6 +8671,36 @@ create_options_are_valid(
 		break;
 	}
 
+	/* Use DATA DIRECTORY only with file-per-table. */
+	if (create_info->data_file_name && !use_tablespace) {
+		push_warning(
+			thd, Sql_condition::WARN_LEVEL_WARN,
+			ER_ILLEGAL_HA_CREATE_OPTION,
+			"InnoDB: DATA DIRECTORY requires"
+			" innodb_file_per_table.");
+		ret = FALSE;
+	}
+
+	/* Do not use DATA DIRECTORY with TEMPORARY TABLE. */
+	if (create_info->data_file_name
+	    && create_info->options & HA_LEX_CREATE_TMP_TABLE) {
+		push_warning(
+			thd, Sql_condition::WARN_LEVEL_WARN,
+			ER_ILLEGAL_HA_CREATE_OPTION,
+			"InnoDB: DATA DIRECTORY cannot be used"
+			" for TEMPORARY tables.");
+		ret = FALSE;
+	}
+
+	/* Do not allow INDEX_DIRECTORY */
+	if (create_info->index_file_name) {
+		push_warning_printf(
+			thd, Sql_condition::WARN_LEVEL_WARN,
+			ER_ILLEGAL_HA_CREATE_OPTION,
+			"InnoDB: INDEX DIRECTORY is not supported");
+		ret = FALSE;
+	}
+
 	return(ret);
 }
 
@@ -8644,6 +8716,34 @@ ha_innobase::update_create_info(
 		ha_innobase::info(HA_STATUS_AUTO);
 		create_info->auto_increment_value = stats.auto_increment_value;
 	}
+
+	/* Update the DATA DIRECTORY name from SYS_DATAFILES. */
+	if (DICT_TF_HAS_DATA_DIR(prebuilt->table->flags)) {
+		if (!prebuilt->table->data_dir_path) {
+			char* path;
+
+			if (prebuilt->table->tablespace_discarded) {
+				mutex_enter(&(dict_sys->mutex));
+				path = dict_get_first_path(
+					prebuilt->table->space,
+					prebuilt->table->name);
+				mutex_exit(&dict_sys->mutex);
+			} else {
+				path = fil_space_get_first_path(
+					prebuilt->table->space);
+			}
+
+			mutex_enter(&(dict_sys->mutex));
+
+			ut_a(path);
+			dict_save_data_dir_path(prebuilt->table, path);
+
+			mutex_exit(&dict_sys->mutex);
+			mem_free(path);
+		}
+
+		create_info->data_file_name = prebuilt->table->data_dir_path;
+	}
 }
 
 /*****************************************************************//**
@@ -8664,6 +8764,109 @@ innobase_fts_load_stopword(
 }
 
 /*****************************************************************//**
+Parses the table name into normal name and either temp path or remote path
+if needed.  The memory for these output strings is allocated here and the
+caller is responsible to free it.
+@return	0 if successful, otherwise, error number */
+UNIV_INTERN
+int
+ha_innobase::parse_table_name(
+/*==========================*/
+	const char*	name,		/*!< in/out: table name provided*/
+	HA_CREATE_INFO*	create_info,	/*!< in: more information of the
+					created table, contains also the
+					create statement string */
+	bool		use_tablespace,	/*!< in: srv_file_per_table */
+	char*		norm_name,	/*!< out: normalized table name */
+	char*		temp_path,	/*!< out: absolute path of table */
+	char*		remote_path)	/*!< out: remote path of table */
+{
+	THD*		thd = ha_thd();
+	DBUG_ENTER("ha_innobase::parse_table_name");
+
+#ifdef __WIN__
+	/* Names passed in from server are in two formats:
+	1. <database_name>/<table_name>: for normal table creation
+	2. full path: for temp table creation, or DATA DIRECTORY.
+
+	When srv_file_per_table is on and mysqld_embedded is off,
+	check for full path pattern, i.e.
+	X:\dir\...,		X is a driver letter, or
+	\\dir1\dir2\...,	UNC path
+	returns error if it is in full path format, but not creating a temp.
+	table. Currently InnoDB does not support symbolic link on Windows. */
+
+	if (use_tablespace
+	    && !mysqld_embedded
+	    && (!create_info->options & HA_LEX_CREATE_TMP_TABLE)) {
+
+		if ((name[1] == ':')
+		    || (name[0] == '\\' && name[1] == '\\')) {
+			sql_print_error("Cannot create table %s\n", name);
+			DBUG_RETURN(HA_ERR_GENERIC);
+		}
+	}
+#endif
+
+	normalize_table_name(norm_name, name);
+	temp_path[0] = '\0';
+	remote_path[0] = '\0';
+
+	/* A full path is used for TEMPORARY TABLE and DATA DIRECTORY.
+	In the case of;
+	  CREATE TEMPORARY TABLE ... DATA DIRECTORY={path} ... ;
+	We ignore the DATA DIRECTORY. */
+	if (create_info->options & HA_LEX_CREATE_TMP_TABLE) {
+		strncpy(temp_path, name, FN_REFLEN - 1);
+	}
+
+	if (create_info->data_file_name) {
+		ibool ignore = FALSE;
+
+		/* Use DATA DIRECTORY only with file-per-table. */
+		if (!use_tablespace) {
+			push_warning(
+				thd, Sql_condition::WARN_LEVEL_WARN,
+				ER_ILLEGAL_HA_CREATE_OPTION,
+				"InnoDB: DATA DIRECTORY requires"
+				" innodb_file_per_table.");
+			ignore = TRUE;
+		}
+
+		/* Do not use DATA DIRECTORY with TEMPORARY TABLE. */
+		if (create_info->options & HA_LEX_CREATE_TMP_TABLE) {
+			push_warning(
+				thd, Sql_condition::WARN_LEVEL_WARN,
+				ER_ILLEGAL_HA_CREATE_OPTION,
+				"InnoDB: DATA DIRECTORY cannot be"
+				" used for TEMPORARY tables.");
+			ignore = TRUE;
+		}
+
+		if (ignore) {
+			push_warning_printf(
+				thd, Sql_condition::WARN_LEVEL_WARN,
+				WARN_OPTION_IGNORED,
+				ER_DEFAULT(WARN_OPTION_IGNORED),
+				"DATA DIRECTORY");
+		} else {
+			strncpy(remote_path, create_info->data_file_name,
+				FN_REFLEN - 1);
+		}
+	}
+
+	if (create_info->index_file_name) {
+		push_warning_printf(
+			thd, Sql_condition::WARN_LEVEL_WARN,
+			WARN_OPTION_IGNORED,
+			ER_DEFAULT(WARN_OPTION_IGNORED),
+			"INDEX DIRECTORY");
+	}
+
+	DBUG_RETURN(0);
+}
+
+/*****************************************************************//**
 Determines InnoDB table flags.
 @retval true if successful, false if error */
 UNIV_INTERN
@@ -8686,6 +8889,8 @@ innobase_table_flags(
 	ulint		zip_ssize = 0;
 	enum row_type	row_format;
 	rec_format_t	innodb_row_format = REC_FORMAT_COMPACT;
+	bool		use_data_dir;
+
 	/* Cache the value of innodb_file_format, in case it is
 	modified by another thread while the table is being created. */
 	const ulint	file_format_allowed = srv_file_format;
@@ -8866,7 +9071,11 @@ innobase_table_flags(
 		zip_ssize = 0;
 	}
 
-	dict_tf_set(flags, innodb_row_format, zip_ssize);
+	use_data_dir =
+		((create_info->data_file_name != NULL)
+		&& !(create_info->options & HA_LEX_CREATE_TMP_TABLE));
+
+	dict_tf_set(flags, innodb_row_format, zip_ssize, use_data_dir);
 
 	if (create_info->options & HA_LEX_CREATE_TMP_TABLE) {
 		*flags2 |= DICT_TF2_TEMPORARY;
@@ -8893,13 +9102,14 @@ ha_innobase::create(
 					created table, contains also the
 					create statement string */
 {
-	int		err;
+	int		error;
 	trx_t*		parent_trx;
 	trx_t*		trx;
 	int		primary_key_no;
 	uint		i;
-	char		name2[FN_REFLEN];
-	char		norm_name[FN_REFLEN];
+	char		norm_name[FN_REFLEN];	/* {database}/{tablename} */
+	char		temp_path[FN_REFLEN];	/* absolute path of temp frm */
+	char		remote_path[FN_REFLEN];	/* absolute path of table */
 	THD*		thd = ha_thd();
 	ib_int64_t	auto_inc_value;
 
@@ -8924,30 +9134,6 @@ ha_innobase::create(
 	DBUG_ASSERT(thd != NULL);
 	DBUG_ASSERT(create_info != NULL);
 
-#ifdef __WIN__
-	/* Names passed in from server are in two formats:
-	1. <database_name>/<table_name>: for normal table creation
-	2. full path: for temp table creation, or sym link
-
-	When srv_file_per_table is on and mysqld_embedded is off,
-	check for full path pattern, i.e.
-	X:\dir\...,		X is a driver letter, or
-	\\dir1\dir2\...,	UNC path
-	returns error if it is in full path format, but not creating a temp.
-	table. Currently InnoDB does not support symbolic link on Windows. */
-
-	if (use_tablespace
-	    && !mysqld_embedded
-	    && (!create_info->options & HA_LEX_CREATE_TMP_TABLE)) {
-
-		if ((name[1] == ':')
-		    || (name[0] == '\\' && name[1] == '\\')) {
-			sql_print_error("Cannot create table %s\n", name);
-			DBUG_RETURN(HA_ERR_GENERIC);
-		}
-	}
-#endif
-
 	if (form->s->fields > 1000) {
 		/* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
 		but we play safe here */
@@ -8955,10 +9141,6 @@ ha_innobase::create(
 		DBUG_RETURN(HA_ERR_TO_BIG_ROW);
 	}
 
-	strcpy(name2, name);
-
-	normalize_table_name(norm_name, name2);
-
 	/* Create the table definition in InnoDB */
 
 	/* Validate create options if innodb_strict_mode is set. */
@@ -8973,6 +9155,12 @@ ha_innobase::create(
 		DBUG_RETURN(-1);
 	}
 
+	error = parse_table_name(name, create_info, use_tablespace,
+				 norm_name, temp_path, remote_path);
+	if (error) {
+		DBUG_RETURN(error);
+	}
+
 	/* Look for a primary key */
 	primary_key_no = (form->s->primary_key != MAX_KEY ?
 			  (int) form->s->primary_key :
@@ -9011,9 +9199,10 @@ ha_innobase::create(
 
 	row_mysql_lock_data_dictionary(trx);
 
-	err = create_table_def(trx, form, norm_name, name2, flags, flags2);
+	error = create_table_def(trx, form, norm_name, temp_path,
+				 remote_path, flags, flags2);
 
-	if (err) {
+	if (error) {
 		goto cleanup;
 	}
 
@@ -9024,9 +9213,9 @@ ha_innobase::create(
 		order the rows by their row id which is internally generated
 		by InnoDB */
 
-		err = create_clustered_index_when_no_primary(
+		error = create_clustered_index_when_no_primary(
 			trx, flags, norm_name);
-		if (err) {
+		if (error) {
 			goto cleanup;
 		}
 	}
@@ -9034,7 +9223,7 @@ ha_innobase::create(
 	if (primary_key_no != -1) {
 		/* In InnoDB the clustered index must always be created
 		first */
-		if ((err = create_index(trx, form, flags, norm_name,
+		if ((error = create_index(trx, form, flags, norm_name,
 					  (uint) primary_key_no))) {
 			goto cleanup;
 		}
@@ -9077,22 +9266,22 @@ ha_innobase::create(
 			dict_table_close(innobase_table, TRUE, FALSE);
 			my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
 				 FTS_DOC_ID_INDEX_NAME);
-			err = -1;
+			error = -1;
 			goto cleanup;
 		case FTS_EXIST_DOC_ID_INDEX:
 		case FTS_NOT_EXIST_DOC_ID_INDEX:
 			break;
 		}
 
-		dberr_t error = fts_create_common_tables(
+		dberr_t	err = fts_create_common_tables(
 			trx, innobase_table, norm_name,
 			(ret == FTS_EXIST_DOC_ID_INDEX));
 
-		err = convert_error_code_to_mysql(error, 0, NULL);
+		error = convert_error_code_to_mysql(err, 0, NULL);
 
 		dict_table_close(innobase_table, TRUE, FALSE);
 
-		if (err) {
+		if (error) {
 			goto cleanup;
 		}
 	}
@@ -9101,7 +9290,7 @@ ha_innobase::create(
 
 		if (i != static_cast<uint>(primary_key_no)) {
 
-			if ((err = create_index(trx, form, flags,
+			if ((error = create_index(trx, form, flags,
 						  norm_name, i))) {
 				goto cleanup;
 			}
@@ -9111,11 +9300,11 @@ ha_innobase::create(
 	stmt = innobase_get_stmt(thd, &stmt_len);
 
 	if (stmt) {
-		dberr_t error = row_table_add_foreign_constraints(
+		dberr_t	err = row_table_add_foreign_constraints(
 			trx, stmt, stmt_len, norm_name,
 			create_info->options & HA_LEX_CREATE_TMP_TABLE);
 
-		switch (error) {
+		switch (err) {
 
 		case DB_PARENT_NO_INDEX:
 			push_warning_printf(
@@ -9140,9 +9329,9 @@ ha_innobase::create(
 			break;
 		}
 
-		err = convert_error_code_to_mysql(error, flags, NULL);
+		error = convert_error_code_to_mysql(err, flags, NULL);
 
-		if (err) {
+		if (error) {
 			goto cleanup;
 		}
 	}
@@ -9191,8 +9380,8 @@ ha_innobase::create(
 		if (!innobase_fts_load_stopword(innobase_table, NULL, thd)) {
 			dict_table_close(innobase_table, FALSE, FALSE);
 			srv_active_wake_master_thread();
-			trx_free_for_mysql(trx);
-			DBUG_RETURN(-1);
+			error = -1;
+			goto cleanup;
 		}
 	}
 
@@ -9234,7 +9423,6 @@ ha_innobase::create(
 	srv_active_wake_master_thread();
 
 	trx_free_for_mysql(trx);
-
 	DBUG_RETURN(0);
 
 cleanup:
@@ -9244,7 +9432,7 @@ cleanup:
 
 	trx_free_for_mysql(trx);
 
-	DBUG_RETURN(err);
+	DBUG_RETURN(error);
 }
 
 /*****************************************************************//**
@@ -9320,11 +9508,11 @@ ha_innobase::delete_table(
 	const char*	name)	/*!< in: table name */
 {
 	ulint	name_len;
-	dberr_t	error;
+	dberr_t	err;
 	trx_t*	parent_trx;
 	trx_t*	trx;
 	THD	*thd = ha_thd();
-	char	norm_name[1000];
+	char	norm_name[FN_REFLEN];
 	char	errstr[1024];
 
 	DBUG_ENTER("ha_innobase::delete_table");
@@ -9350,9 +9538,9 @@ ha_innobase::delete_table(
 	persistent storage if it exists and if there are stats for this
 	table in there. This function creates its own trx and commits
 	it. */
-	error = dict_stats_delete_table_stats(norm_name,
-					      errstr, sizeof(errstr));
-	if (error != DB_SUCCESS) {
+	err = dict_stats_delete_table_stats(norm_name,
+					    errstr, sizeof(errstr));
+	if (err != DB_SUCCESS) {
 		push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
 			     ER_LOCK_WAIT_TIMEOUT, errstr);
 	}
@@ -9382,12 +9570,11 @@ ha_innobase::delete_table(
 	++trx->will_lock;
 
 	/* Drop the table in InnoDB */
-	error = row_drop_table_for_mysql(norm_name, trx,
-					 thd_sql_command(thd)
-					 == SQLCOM_DROP_DB);
+	err = row_drop_table_for_mysql(
+		norm_name, trx, thd_sql_command(thd) == SQLCOM_DROP_DB);
 
 
-	if (error == DB_TABLE_NOT_FOUND
+	if (err == DB_TABLE_NOT_FOUND
 	    && innobase_get_lower_case_table_names() == 1) {
 		char*	is_part = NULL;
 #ifdef __WIN__
@@ -9397,25 +9584,25 @@ ha_innobase::delete_table(
 #endif /* __WIN__ */
 
 		if (is_part) {
-			char	par_case_name[MAX_FULL_NAME_LEN + 1];
+			char	par_case_name[FN_REFLEN];
 
 #ifndef __WIN__
 			/* Check for the table using lower
 			case name, including the partition
 			separator "P" */
-			memcpy(par_case_name, norm_name, strlen(norm_name));
-			par_case_name[strlen(norm_name)] = 0;
+			strcpy(par_case_name, norm_name);
 			innobase_casedn_str(par_case_name);
 #else
 			/* On Windows platfrom, check
 			whether there exists table name in
 			system table whose name is
 			not being normalized to lower case */
-			normalize_table_name_low(par_case_name, name, FALSE);
+			normalize_table_name_low(
+				par_case_name, name, FALSE);
 #endif
-			error = row_drop_table_for_mysql(par_case_name, trx,
-							 thd_sql_command(thd)
-							 == SQLCOM_DROP_DB);
+			err = row_drop_table_for_mysql(
+				par_case_name, trx,
+				thd_sql_command(thd) == SQLCOM_DROP_DB);
 		}
 	}
 
@@ -9433,7 +9620,8 @@ ha_innobase::delete_table(
 	innobase_commit_low(trx);
 
 	trx_free_for_mysql(trx);
-	DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
+
+	DBUG_RETURN(convert_error_code_to_mysql(err, 0, NULL));
 }
 
 /*****************************************************************//**
@@ -9514,6 +9702,7 @@ innobase_drop_database(
 	innobase_commit_low(trx);
 	trx_free_for_mysql(trx);
 }
+
 /*********************************************************************//**
 Renames an InnoDB table.
 @return DB_SUCCESS or error code */
@@ -9526,16 +9715,12 @@ innobase_rename_table(
 	const char*	to)	/*!< in: new name of the table */
 {
 	dberr_t	error;
-	char*	norm_to;
-	char*	norm_from;
+	char	norm_to[FN_REFLEN];
+	char	norm_from[FN_REFLEN];
 
 	DBUG_ENTER("innobase_rename_table");
 	DBUG_ASSERT(trx_get_dict_operation(trx) == TRX_DICT_OP_INDEX);
 
-	// Magic number 64 arbitrary
-	norm_to = (char*) my_malloc(strlen(to) + 64, MYF(0));
-	norm_from = (char*) my_malloc(strlen(from) + 64, MYF(0));
-
 	normalize_table_name(norm_to, to);
 	normalize_table_name(norm_from, from);
 
@@ -9563,27 +9748,23 @@ innobase_rename_table(
 #endif /* __WIN__ */
 
 			if (is_part) {
-				char	par_case_name[MAX_FULL_NAME_LEN + 1];
-
+				char	par_case_name[FN_REFLEN];
 #ifndef __WIN__
 				/* Check for the table using lower
 				case name, including the partition
 				separator "P" */
-				memcpy(par_case_name, norm_from,
-				       strlen(norm_from));
-				par_case_name[strlen(norm_from)] = 0;
+				strcpy(par_case_name, norm_from);
 				innobase_casedn_str(par_case_name);
 #else
 				/* On Windows platfrom, check
 				whether there exists table name in
 				system table whose name is
 				not being normalized to lower case */
-				normalize_table_name_low(par_case_name,
-							 from, FALSE);
+				normalize_table_name_low(
+					par_case_name, from, FALSE);
 #endif
 				error = row_rename_table_for_mysql(
 					par_case_name, norm_to, trx, TRUE);
-
 			}
 		}
 
@@ -9623,9 +9804,6 @@ innobase_rename_table(
 
 	log_buffer_flush_to_disk();
 
-	my_free(norm_to);
-	my_free(norm_from);
-
 	DBUG_RETURN(error);
 }
 
@@ -10294,8 +10472,8 @@ ha_innobase::info(
 					"space for table %s but its "
 					"tablespace has been discarded or "
 					"the .ibd file is missing. Setting "
-                                        "the free space to zero. "
-                                        "(errno: %d - %s)",
+					"the free space to zero. "
+					"(errno: %d - %s)",
 					ib_table->name, errno,
 					my_strerror(errbuf, sizeof(errbuf),
 						    errno));
@@ -15159,7 +15337,9 @@ 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
+i_s_innodb_sys_foreign_cols,
+i_s_innodb_sys_tablespaces,
+i_s_innodb_sys_datafiles
 
 mysql_declare_plugin_end;
 

=== modified file 'storage/innobase/handler/ha_innodb.h'
--- a/storage/innobase/handler/ha_innodb.h	revid:andrei.elkin@stripped
+++ b/storage/innobase/handler/ha_innodb.h	revid:kevin.lewis@stripped
@@ -189,6 +189,12 @@ class ha_innobase: public handler
 	ha_rows estimate_rows_upper_bound();
 
 	void update_create_info(HA_CREATE_INFO* create_info);
+	int parse_table_name(const char*name,
+			     HA_CREATE_INFO*create_info,
+			     bool use_tablespace,
+			     char* norm_name,
+			     char* temp_path,
+			     char* remote_path);
 	int create(const char *name, register TABLE *form,
 					HA_CREATE_INFO *create_info);
 	int truncate();

=== modified file 'storage/innobase/handler/handler0alter.cc'
--- a/storage/innobase/handler/handler0alter.cc	revid:andrei.elkin@stripped
+++ b/storage/innobase/handler/handler0alter.cc	revid:kevin.lewis@stripped
@@ -124,7 +124,7 @@ my_error_innodb(
 #ifdef UNIV_DEBUG
 	case DB_SUCCESS:
 	case DB_DUPLICATE_KEY:
-	case DB_TABLESPACE_ALREADY_EXISTS:
+	case DB_TABLESPACE_EXISTS:
 	case DB_ONLINE_LOG_TOO_BIG:
 		/* These codes should not be passed here. */
 		ut_error;
@@ -906,7 +906,7 @@ innobase_fts_check_doc_id_index_in_def(
 		}
 
 		return(FTS_EXIST_DOC_ID_INDEX);
-        }
+	}
 
 	return(FTS_NOT_EXIST_DOC_ID_INDEX);
 }
@@ -1611,7 +1611,11 @@ col_fail:
 			holding dict_operation_lock X-latch. */
 			DBUG_ASSERT(indexed_table->n_ref_count == 1);
 			break;
-		case DB_TABLESPACE_ALREADY_EXISTS:
+		case DB_TABLESPACE_EXISTS:
+			innobase_convert_tablename(new_table_name);
+			my_error(ER_TABLESPACE_EXISTS, MYF(0),
+				 new_table_name);
+			goto new_clustered_failed;
 		case DB_DUPLICATE_KEY:
 			innobase_convert_tablename(new_table_name);
 			my_error(HA_ERR_TABLE_EXIST, MYF(0),
@@ -1785,8 +1789,8 @@ error_handling:
 			!exclusive && !new_clustered && !num_fts_index,
 			heap, trx, indexed_table);
 		DBUG_RETURN(false);
-	case DB_TABLESPACE_ALREADY_EXISTS:
-		my_error(ER_TABLE_EXISTS_ERROR, MYF(0), "(unknown)");
+	case DB_TABLESPACE_EXISTS:
+		my_error(ER_TABLESPACE_EXISTS, MYF(0), "(unknown)");
 		break;
 	case DB_DUPLICATE_KEY:
 		my_error(ER_DUP_KEY, MYF(0), "SYS_INDEXES");
@@ -2851,7 +2855,12 @@ ha_innobase::commit_inplace_alter_table(
 		case DB_SUCCESS:
 			err = 0;
 			break;
-		case DB_TABLESPACE_ALREADY_EXISTS:
+		case DB_TABLESPACE_EXISTS:
+			ut_a(ctx->indexed_table->n_ref_count == 1);
+			innobase_convert_tablename(tmp_name);
+			my_error(ER_TABLESPACE_EXISTS, MYF(0), tmp_name);
+			err = HA_ERR_TABLESPACE_EXISTS;
+			goto drop_new_clustered;
 		case DB_DUPLICATE_KEY:
 			ut_a(ctx->indexed_table->n_ref_count == 1);
 			innobase_convert_tablename(tmp_name);

=== modified file 'storage/innobase/handler/i_s.cc'
--- a/storage/innobase/handler/i_s.cc	revid:andrei.elkin@stripped
+++ b/storage/innobase/handler/i_s.cc	revid:kevin.lewis@stripped
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2007, 2012, Oracle and/or its affiliates. All Rights Reserved.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -5512,10 +5512,11 @@ i_s_common_deinit(
 	DBUG_RETURN(0);
 }
 
+/**  SYS_TABLES  ***************************************************/
 /* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLES */
 static ST_FIELD_INFO	innodb_sys_tables_fields_info[] =
 {
-#define SYS_TABLE_ID		0
+#define SYS_TABLES_ID			0
 	{STRUCT_FLD(field_name,		"TABLE_ID"),
 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
@@ -5524,7 +5525,7 @@ static ST_FIELD_INFO	innodb_sys_tables_f
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define SYS_TABLE_NAME		1
+#define SYS_TABLES_NAME			1
 	{STRUCT_FLD(field_name,		"NAME"),
 	 STRUCT_FLD(field_length,	MAX_FULL_NAME_LEN + 1),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
@@ -5533,7 +5534,7 @@ static ST_FIELD_INFO	innodb_sys_tables_f
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define SYS_TABLE_FLAG		2
+#define SYS_TABLES_FLAG			2
 	{STRUCT_FLD(field_name,		"FLAG"),
 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
@@ -5542,7 +5543,7 @@ static ST_FIELD_INFO	innodb_sys_tables_f
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define SYS_TABLE_NUM_COLUMN	3
+#define SYS_TABLES_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),
@@ -5551,7 +5552,7 @@ static ST_FIELD_INFO	innodb_sys_tables_f
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define SYS_TABLE_SPACE		4
+#define SYS_TABLES_SPACE		4
 	{STRUCT_FLD(field_name,		"SPACE"),
 	 STRUCT_FLD(field_length,	MY_INT32_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
@@ -5560,6 +5561,33 @@ static ST_FIELD_INFO	innodb_sys_tables_f
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
+#define SYS_TABLES_FILE_FORMAT		5
+	{STRUCT_FLD(field_name,		"FILE_FORMAT"),
+	 STRUCT_FLD(field_length,	10),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLES_ROW_FORMAT		6
+	{STRUCT_FLD(field_name,		"ROW_FORMAT"),
+	 STRUCT_FLD(field_length,	12),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLES_ZIP_PAGE_SIZE	7
+	{STRUCT_FLD(field_name,		"ZIP_PAGE_SIZE"),
+	 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
 };
 
@@ -5576,20 +5604,42 @@ i_s_dict_fill_sys_tables(
 	TABLE*		table_to_fill)	/*!< in/out: fill this table */
 {
 	Field**		fields;
+	ulint	compact		= DICT_TF_GET_COMPACT(table->flags);
+	ulint	atomic_blobs	= DICT_TF_HAS_ATOMIC_BLOBS(table->flags);
+	ulint	zip_size	= dict_tf_get_zip_size(table->flags);
+	const char* file_format;
+	const char* row_format;
+
+	file_format = trx_sys_file_format_id_to_name(atomic_blobs);
+	if (!compact) {
+		row_format = "Redundant";
+	} else if (!atomic_blobs) {
+		row_format = "Compact";
+	} else if DICT_TF_GET_ZIP_SSIZE(table->flags) {
+		row_format = "Compressed";
+	} else {
+		row_format = "Dynamic";
+	}
 
 	DBUG_ENTER("i_s_dict_fill_sys_tables");
 
 	fields = table_to_fill->field;
 
-	OK(fields[SYS_TABLE_ID]->store(longlong(table->id), TRUE));
+	OK(fields[SYS_TABLES_ID]->store(longlong(table->id), TRUE));
+
+	OK(field_store_string(fields[SYS_TABLES_NAME], table->name));
+
+	OK(fields[SYS_TABLES_FLAG]->store(table->flags));
+
+	OK(fields[SYS_TABLES_NUM_COLUMN]->store(table->n_cols));
 
-	OK(field_store_string(fields[SYS_TABLE_NAME], table->name));
+	OK(fields[SYS_TABLES_SPACE]->store(table->space));
 
-	OK(fields[SYS_TABLE_FLAG]->store(table->flags));
+	OK(field_store_string(fields[SYS_TABLES_FILE_FORMAT], file_format));
 
-	OK(fields[SYS_TABLE_NUM_COLUMN]->store(table->n_cols));
+	OK(field_store_string(fields[SYS_TABLES_ROW_FORMAT], row_format));
 
-	OK(fields[SYS_TABLE_SPACE]->store(table->space));
+	OK(fields[SYS_TABLES_ZIP_PAGE_SIZE]->store(zip_size));
 
 	OK(schema_table_store_record(thd, table_to_fill));
 
@@ -5742,6 +5792,7 @@ UNIV_INTERN struct st_mysql_plugin	i_s_i
 	STRUCT_FLD(flags, 0UL),
 };
 
+/**  SYS_TABLESTATS  ***********************************************/
 /* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLESTATS */
 static ST_FIELD_INFO	innodb_sys_tablestats_fields_info[] =
 {
@@ -6034,6 +6085,7 @@ UNIV_INTERN struct st_mysql_plugin	i_s_i
 	STRUCT_FLD(flags, 0UL),
 };
 
+/**  SYS_INDEXES  **************************************************/
 /* Fields of the dynamic table INFORMATION_SCHEMA.SYS_INDEXES */
 static ST_FIELD_INFO	innodb_sysindex_fields_info[] =
 {
@@ -6293,7 +6345,8 @@ UNIV_INTERN struct st_mysql_plugin	i_s_i
 	STRUCT_FLD(flags, 0UL),
 };
 
-/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_COLUMNS */
+/**  SYS_COLUMNS  **************************************************/
+/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_COLUMNS */
 static ST_FIELD_INFO	innodb_sys_columns_fields_info[] =
 {
 #define SYS_COLUMN_TABLE_ID		0
@@ -6531,7 +6584,9 @@ UNIV_INTERN struct st_mysql_plugin	i_s_i
 	/* unsigned long */
 	STRUCT_FLD(flags, 0UL),
 };
-/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_fields */
+
+/**  SYS_FIELDS  ***************************************************/
+/* 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
@@ -6743,7 +6798,8 @@ UNIV_INTERN struct st_mysql_plugin	i_s_i
 	STRUCT_FLD(flags, 0UL),
 };
 
-/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign */
+/**  SYS_FOREIGN        ********************************************/
+/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FOREIGN */
 static ST_FIELD_INFO	innodb_sys_foreign_fields_info[] =
 {
 #define SYS_FOREIGN_ID		0
@@ -6828,6 +6884,7 @@ i_s_dict_fill_sys_foreign(
 
 	DBUG_RETURN(0);
 }
+
 /*******************************************************************//**
 Function to populate INFORMATION_SCHEMA.innodb_sys_foreign table. Loop
 through each record in SYS_FOREIGN, and extract the foreign key
@@ -6894,6 +6951,7 @@ i_s_sys_foreign_fill_table(
 
 	DBUG_RETURN(0);
 }
+
 /*******************************************************************//**
 Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign
 @return 0 on success */
@@ -6967,7 +7025,9 @@ UNIV_INTERN struct st_mysql_plugin	i_s_i
 	/* unsigned long */
 	STRUCT_FLD(flags, 0UL),
 };
-/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign_cols */
+
+/**  SYS_FOREIGN_COLS   ********************************************/
+/* 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
@@ -7186,3 +7246,461 @@ UNIV_INTERN struct st_mysql_plugin	i_s_i
 	STRUCT_FLD(flags, 0UL),
 };
 
+/**  SYS_TABLESPACES    ********************************************/
+/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES */
+static ST_FIELD_INFO	innodb_sys_tablespaces_fields_info[] =
+{
+#define SYS_TABLESPACES_SPACE		0
+	{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,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESPACES_NAME		1
+	{STRUCT_FLD(field_name,		"NAME"),
+	 STRUCT_FLD(field_length,	MAX_FULL_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_TABLESPACES_FLAGS		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,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESPACES_FILE_FORMAT	3
+	{STRUCT_FLD(field_name,		"FILE_FORMAT"),
+	 STRUCT_FLD(field_length,	10),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESPACES_ROW_FORMAT	4
+	{STRUCT_FLD(field_name,		"ROW_FORMAT"),
+	 STRUCT_FLD(field_length,	22),
+	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
+	 STRUCT_FLD(value,		0),
+	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_TABLESPACES_PAGE_SIZE	5
+	{STRUCT_FLD(field_name,		"PAGE_SIZE"),
+	 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_TABLESPACES_ZIP_PAGE_SIZE	6
+	{STRUCT_FLD(field_name,		"ZIP_PAGE_SIZE"),
+	 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_TABLESPACES with information
+collected by scanning SYS_TABLESPACESS table.
+@return 0 on success */
+static
+int
+i_s_dict_fill_sys_tablespaces(
+/*==========================*/
+	THD*		thd,		/*!< in: thread */
+	ulint		space,		/*!< in: space ID */
+	const char*	name,		/*!< in: tablespace name */
+	ulint		flags,		/*!< in: tablespace flags */
+	TABLE*		table_to_fill)	/*!< in/out: fill this table */
+{
+	Field**	fields;
+	ulint	atomic_blobs	= FSP_FLAGS_HAS_ATOMIC_BLOBS(flags);
+	ulint	page_size	= fsp_flags_get_page_size(flags);;
+	ulint	zip_size	= fsp_flags_get_zip_size(flags);
+	const char* file_format;
+	const char* row_format;
+
+	DBUG_ENTER("i_s_dict_fill_sys_tablespaces");
+
+	file_format = trx_sys_file_format_id_to_name(atomic_blobs);
+	if (!atomic_blobs) {
+		row_format = "Compact or Redundant";
+	} else if DICT_TF_GET_ZIP_SSIZE(flags) {
+		row_format = "Compressed";
+	} else {
+		row_format = "Dynamic";
+	}
+
+	fields = table_to_fill->field;
+
+	OK(fields[SYS_TABLESPACES_SPACE]->store(space));
+
+	OK(field_store_string(fields[SYS_TABLESPACES_NAME], name));
+
+	OK(fields[SYS_TABLESPACES_FLAGS]->store(flags));
+
+	OK(field_store_string(fields[SYS_TABLESPACES_FILE_FORMAT],
+			      file_format));
+
+	OK(field_store_string(fields[SYS_TABLESPACES_ROW_FORMAT],
+			      row_format));
+
+	OK(fields[SYS_TABLESPACES_PAGE_SIZE]->store(page_size));
+
+	OK(fields[SYS_TABLESPACES_ZIP_PAGE_SIZE]->store(zip_size));
+
+	OK(schema_table_store_record(thd, table_to_fill));
+
+	DBUG_RETURN(0);
+}
+/*******************************************************************//**
+Function to populate INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES table.
+Loop through each record in SYS_TABLESPACES, and extract the column
+information and fill the INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES table.
+@return 0 on success */
+static
+int
+i_s_sys_tablespaces_fill_table(
+/*===========================*/
+	THD*		thd,	/*!< in: thread */
+	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
+	Item*		)	/*!< in: condition (not used) */
+{
+	btr_pcur_t	pcur;
+	const rec_t*	rec;
+	mem_heap_t*	heap;
+	mtr_t		mtr;
+
+	DBUG_ENTER("i_s_sys_tablespaces_fill_table");
+
+	/* deny access to user without PROCESS_ACL privilege */
+	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_TABLESPACES);
+
+	while (rec) {
+		const char*	err_msg;
+		ulint		space;
+		const char*	name;
+		ulint		flags;
+
+		/* Extract necessary information from a SYS_TABLESPACES row */
+		err_msg = dict_process_sys_tablespaces(
+			heap, rec, &space, &name, &flags);
+
+		mtr_commit(&mtr);
+		mutex_exit(&dict_sys->mutex);
+
+		if (!err_msg) {
+			i_s_dict_fill_sys_tablespaces(
+				thd, space, name, flags,
+				tables->table);
+		} else {
+			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+					    ER_CANT_FIND_SYSTEM_REC, "%s",
+					    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_TABLESPACES
+@return 0 on success */
+static
+int
+innodb_sys_tablespaces_init(
+/*========================*/
+	void*	p)	/*!< in/out: table schema object */
+{
+	ST_SCHEMA_TABLE*	schema;
+
+	DBUG_ENTER("innodb_sys_tablespaces_init");
+
+	schema = (ST_SCHEMA_TABLE*) p;
+
+	schema->fields_info = innodb_sys_tablespaces_fields_info;
+	schema->fill_table = i_s_sys_tablespaces_fill_table;
+
+	DBUG_RETURN(0);
+}
+
+UNIV_INTERN struct st_mysql_plugin	i_s_innodb_sys_tablespaces =
+{
+	/* 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_TABLESPACES"),
+
+	/* 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_TABLESPACES"),
+
+	/* 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_tablespaces_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),
+
+	/* Plugin flags */
+	/* unsigned long */
+	STRUCT_FLD(flags, 0UL),
+};
+
+/**  SYS_DATAFILES  ************************************************/
+/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_DATAFILES */
+static ST_FIELD_INFO	innodb_sys_datafiles_fields_info[] =
+{
+#define SYS_DATAFILES_SPACE		0
+	{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,	MY_I_S_UNSIGNED),
+	 STRUCT_FLD(old_name,		""),
+	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+
+#define SYS_DATAFILES_PATH		1
+	{STRUCT_FLD(field_name,		"PATH"),
+	 STRUCT_FLD(field_length,	OS_FILE_MAX_PATH),
+	 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)},
+
+	END_OF_ST_FIELD_INFO
+};
+
+/**********************************************************************//**
+Function to fill INFORMATION_SCHEMA.INNODB_SYS_DATAFILES with information
+collected by scanning SYS_DATAFILESS table.
+@return 0 on success */
+static
+int
+i_s_dict_fill_sys_datafiles(
+/*========================*/
+	THD*		thd,		/*!< in: thread */
+	ulint		space,		/*!< in: space ID */
+	const char*	path,		/*!< in: absolute path */
+	TABLE*		table_to_fill)	/*!< in/out: fill this table */
+{
+	Field**		fields;
+
+	DBUG_ENTER("i_s_dict_fill_sys_datafiles");
+
+	fields = table_to_fill->field;
+
+	OK(field_store_ulint(fields[SYS_DATAFILES_SPACE], space));
+
+	OK(field_store_string(fields[SYS_DATAFILES_PATH], path));
+
+	OK(schema_table_store_record(thd, table_to_fill));
+
+	DBUG_RETURN(0);
+}
+/*******************************************************************//**
+Function to populate INFORMATION_SCHEMA.INNODB_SYS_DATAFILES table.
+Loop through each record in SYS_DATAFILES, and extract the column
+information and fill the INFORMATION_SCHEMA.INNODB_SYS_DATAFILES table.
+@return 0 on success */
+static
+int
+i_s_sys_datafiles_fill_table(
+/*=========================*/
+	THD*		thd,	/*!< in: thread */
+	TABLE_LIST*	tables,	/*!< in/out: tables to fill */
+	Item*		)	/*!< in: condition (not used) */
+{
+	btr_pcur_t	pcur;
+	const rec_t*	rec;
+	mem_heap_t*	heap;
+	mtr_t		mtr;
+
+	DBUG_ENTER("i_s_sys_datafiles_fill_table");
+
+	/* deny access to user without PROCESS_ACL privilege */
+	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_DATAFILES);
+
+	while (rec) {
+		const char*	err_msg;
+		ulint		space;
+		const char*	path;
+
+		/* Extract necessary information from a SYS_DATAFILES row */
+		err_msg = dict_process_sys_datafiles(
+			heap, rec, &space, &path);
+
+		mtr_commit(&mtr);
+		mutex_exit(&dict_sys->mutex);
+
+		if (!err_msg) {
+			i_s_dict_fill_sys_datafiles(
+				thd, space, path, tables->table);
+		} else {
+			push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+					    ER_CANT_FIND_SYSTEM_REC, "%s",
+					    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_DATAFILES
+@return 0 on success */
+static
+int
+innodb_sys_datafiles_init(
+/*======================*/
+	void*	p)	/*!< in/out: table schema object */
+{
+	ST_SCHEMA_TABLE*	schema;
+
+	DBUG_ENTER("innodb_sys_datafiles_init");
+
+	schema = (ST_SCHEMA_TABLE*) p;
+
+	schema->fields_info = innodb_sys_datafiles_fields_info;
+	schema->fill_table = i_s_sys_datafiles_fill_table;
+
+	DBUG_RETURN(0);
+}
+
+UNIV_INTERN struct st_mysql_plugin	i_s_innodb_sys_datafiles =
+{
+	/* 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_DATAFILES"),
+
+	/* 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_DATAFILES"),
+
+	/* 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_datafiles_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),
+
+	/* Plugin flags */
+	/* unsigned long */
+	STRUCT_FLD(flags, 0UL),
+};

=== modified file 'storage/innobase/handler/i_s.h'
--- a/storage/innobase/handler/i_s.h	revid:andrei.elkin@stripped
+++ b/storage/innobase/handler/i_s.h	revid:kevin.lewis@stripped
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2007, 2012, Oracle and/or its affiliates. All Rights Reserved.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -53,5 +53,7 @@ extern struct st_mysql_plugin	i_s_innodb
 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;
+extern struct st_mysql_plugin	i_s_innodb_sys_tablespaces;
+extern struct st_mysql_plugin	i_s_innodb_sys_datafiles;
 
 #endif /* i_s_h */

=== modified file 'storage/innobase/include/db0err.h'
--- a/storage/innobase/include/db0err.h	revid:andrei.elkin@stripped
+++ b/storage/innobase/include/db0err.h	revid:kevin.lewis@stripped
@@ -68,7 +68,7 @@ enum dberr_t {
 					from a table failed */
 	DB_NO_SAVEPOINT,		/*!< no savepoint exists with the given
 					name */
-	DB_TABLESPACE_ALREADY_EXISTS,	/*!< we cannot create a new single-table
+	DB_TABLESPACE_EXISTS,		/*!< we cannot create a new single-table
 					tablespace because a file of the same
 					name already exists */
 	DB_TABLESPACE_DELETED,		/*!< tablespace does not exist or is

=== modified file 'storage/innobase/include/dict0boot.h'
--- a/storage/innobase/include/dict0boot.h	revid:andrei.elkin@stripped
+++ b/storage/innobase/include/dict0boot.h	revid:kevin.lewis@stripped
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1996, 2010, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -88,7 +88,7 @@ void
 dict_boot(void);
 /*===========*/
 /*****************************************************************//**
-Creates and initializes the data dictionary at the database creation. */
+Creates and initializes the data dictionary at the server bootstrap. */
 UNIV_INTERN
 void
 dict_create(void);
@@ -273,6 +273,41 @@ enum dict_fld_sys_foreign_cols_enum {
 	DICT_FLD__SYS_FOREIGN_COLS__REF_COL_NAME	= 5,
 	DICT_NUM_FIELDS__SYS_FOREIGN_COLS		= 6
 };
+/* The columns in SYS_TABLESPACES */
+enum dict_col_sys_tablespaces_enum {
+	DICT_COL__SYS_TABLESPACES__SPACE		= 0,
+	DICT_COL__SYS_TABLESPACES__NAME			= 1,
+	DICT_COL__SYS_TABLESPACES__FLAGS		= 2,
+	DICT_NUM_COLS__SYS_TABLESPACES			= 3
+};
+/* The field numbers in the SYS_TABLESPACES clustered index */
+enum dict_fld_sys_tablespaces_enum {
+	DICT_FLD__SYS_TABLESPACES__SPACE		= 0,
+	DICT_FLD__SYS_TABLESPACES__DB_TRX_ID		= 1,
+	DICT_FLD__SYS_TABLESPACES__DB_ROLL_PTR		= 2,
+	DICT_FLD__SYS_TABLESPACES__NAME			= 3,
+	DICT_FLD__SYS_TABLESPACES__FLAGS		= 4,
+	DICT_NUM_FIELDS__SYS_TABLESPACES		= 5
+};
+/* The columns in SYS_DATAFILES */
+enum dict_col_sys_datafiles_enum {
+	DICT_COL__SYS_DATAFILES__SPACE			= 0,
+	DICT_COL__SYS_DATAFILES__PATH			= 1,
+	DICT_NUM_COLS__SYS_DATAFILES			= 2
+};
+/* The field numbers in the SYS_DATAFILES clustered index */
+enum dict_fld_sys_datafiles_enum {
+	DICT_FLD__SYS_DATAFILES__SPACE			= 0,
+	DICT_FLD__SYS_DATAFILES__DB_TRX_ID		= 1,
+	DICT_FLD__SYS_DATAFILES__DB_ROLL_PTR		= 2,
+	DICT_FLD__SYS_DATAFILES__PATH			= 3,
+	DICT_NUM_FIELDS__SYS_DATAFILES			= 4
+};
+
+/* A number of the columns above occur in multiple tables.  These are the
+length of thos fields. */
+#define	DICT_FLD_LEN_SPACE	4
+#define	DICT_FLD_LEN_FLAGS	4
 
 /* When a row id which is zero modulo this number (which must be a power of
 two) is assigned, the field DICT_HDR_ROW_ID on the dictionary header page is

=== modified file 'storage/innobase/include/dict0crea.h'
--- a/storage/innobase/include/dict0crea.h	revid:andrei.elkin@stripped
+++ b/storage/innobase/include/dict0crea.h	revid:kevin.lewis@stripped
@@ -99,7 +99,7 @@ dict_drop_index_tree(
 	mtr_t*	mtr);	/*!< in: mtr having the latch on the record page */
 /****************************************************************//**
 Creates the foreign key constraints system tables inside InnoDB
-at database creation or database start if they are not found or are
+at server bootstrap or server start if they are not found or are
 not of the right form.
 @return	DB_SUCCESS or error code */
 UNIV_INTERN
@@ -129,9 +129,30 @@ dict_create_add_foreigns_to_dictionary(
 	dict_table_t*	table,	/*!< in: table */
 	trx_t*		trx)	/*!< in: transaction */
 	__attribute__((nonnull, warn_unused_result));
-
-/* Table create node structure */
-
+/****************************************************************//**
+Creates the tablespaces and datafiles system tables inside InnoDB
+at server bootstrap or server start if they are not found or are
+not of the right form.
+@return	DB_SUCCESS or error code */
+UNIV_INTERN
+dberr_t
+dict_create_or_check_sys_tablespace(void);
+/*=====================================*/
+/********************************************************************//**
+Add a single tablespace definition to the data dictionary tables in the
+database.
+@return	error code or DB_SUCCESS */
+UNIV_INTERN
+dberr_t
+dict_create_add_tablespace_to_dictionary(
+/*=====================================*/
+	ulint		space,		/*!< in: tablespace id */
+	const char*	name,		/*!< in: tablespace name */
+	ulint		flags,		/*!< in: tablespace flags */
+	const char*	path,		/*!< in: tablespace path */
+	trx_t*		trx);		/*!< in: transaction */
+/********************************************************************//**
+Table create node structure */
 struct tab_node_struct{
 	que_common_t	common;	/*!< node type: QUE_NODE_TABLE_CREATE */
 	dict_table_t*	table;	/*!< table to create, built as a memory data

=== modified file 'storage/innobase/include/dict0dict.h'
--- a/storage/innobase/include/dict0dict.h	revid:andrei.elkin@stripped
+++ b/storage/innobase/include/dict0dict.h	revid:kevin.lewis@stripped
@@ -326,7 +326,7 @@ dict_table_remove_from_cache(
 Renames a table object.
 @return	TRUE if success */
 UNIV_INTERN
-ibool
+dberr_t
 dict_table_rename_in_cache(
 /*=======================*/
 	dict_table_t*	table,		/*!< in/out: table */
@@ -823,7 +823,8 @@ dict_tf_set(
 /*========*/
 	ulint*		flags,		/*!< in/out: table */
 	rec_format_t	format,		/*!< in: file format */
-	ulint		zip_ssize)	/*!< in: zip shift size */
+	ulint		zip_ssize,	/*!< in: zip shift size */
+	bool		remote_path)	/*!< in: table uses DATA DIRECTORY */
 	__attribute__((nonnull));
 /********************************************************************//**
 Convert a 32 bit integer table flags to the 32 bit integer that is

=== modified file 'storage/innobase/include/dict0dict.ic'
--- a/storage/innobase/include/dict0dict.ic	revid:andrei.elkin@stripped
+++ b/storage/innobase/include/dict0dict.ic	revid:kevin.lewis@stripped
@@ -547,6 +547,9 @@ dict_tf_validate(
 		ut_a(zip_ssize <= PAGE_ZIP_SSIZE_MAX);
 	}
 
+	/* CREATE TABLE ... DATA DIRECTORY is supported for any row format,
+	so the DATA_DIR flag is compatible with all other table flags. */
+
 	/* Return the flags sent if we did not crash. */
 	return(flags);
 }
@@ -568,9 +571,7 @@ dict_sys_tables_type_validate(
 	ulint	atomic_blobs = DICT_TF_HAS_ATOMIC_BLOBS(type);
 	ulint	unused = DICT_TF_GET_UNUSED(type);
 
-	/* If the format is UNIV_FORMAT_A, table->flags == 0, but
-	SYS_TABLES.TYPE == 1, which is defined as SYS_TABLE_TYPE_ANTELOPE.
-	The low order bit of SYS_TABLES.TYPE is always set to 1.
+	/* The low order bit of SYS_TABLES.TYPE is always set to 1.
 	If the format is UNIV_FORMAT_B or higher, this field is the same
 	as dict_table_t::flags. Zero is not allowed here. */
 	if (!low_order_bit) {
@@ -578,12 +579,9 @@ dict_sys_tables_type_validate(
 	}
 
 	if (redundant) {
-		/* This is Redundant row format, only the first bit
-		should be set in SYS_TABLES.TYPE */
-		if (type != SYS_TABLE_TYPE_ANTELOPE) {
+		if (zip_ssize || atomic_blobs) {
 			return(ULINT_UNDEFINED);
 		}
-		return(DICT_TF_REDUNDANT);
 	}
 
 	/* Make sure there are no bits that we do not know about. */
@@ -620,6 +618,11 @@ dict_sys_tables_type_validate(
 		}
 	}
 
+	/* There is nothing to validate for the data_dir field.
+	CREATE TABLE ... DATA DIRECTORY is supported for any row
+	format, so the DATA_DIR flag is compatible with any other
+	table flags. However, it is not used with TEMPORARY tables.*/
+
 	/* Return the validated SYS_TABLES.TYPE. */
 	return(type);
 }
@@ -691,7 +694,8 @@ dict_tf_set(
 /*========*/
 	ulint*		flags,		/*!< in/out: table flags */
 	rec_format_t	format,		/*!< in: file format */
-	ulint		zip_ssize)	/*!< in: zip shift size */
+	ulint		zip_ssize,	/*!< in: zip shift size */
+	bool		use_data_dir)	/*!< in: table uses DATA DIRECTORY */
 {
 	switch (format) {
 	case REC_FORMAT_REDUNDANT:
@@ -713,6 +717,10 @@ dict_tf_set(
 		ut_ad(zip_ssize == 0);
 		break;
 	}
+
+	if (use_data_dir) {
+		*flags |= (1 << DICT_TF_POS_DATA_DIR);
+	}
 }
 
 /********************************************************************//**
@@ -730,18 +738,58 @@ UNIV_INLINE
 ulint
 dict_tf_to_fsp_flags(
 /*=================*/
-	ulint	flags)	/*!< in: dict_table_t::flags */
+	ulint	table_flags)	/*!< in: dict_table_t::flags */
 {
+	ulint fsp_flags;
+
 	/* Adjust bit zero. */
-	flags = (flags == DICT_TF_COMPACT) ? 0 : flags;
+	fsp_flags = DICT_TF_HAS_ATOMIC_BLOBS(table_flags) ? 1 : 0;
+
+	/* ZIP_SSIZE and ATOMIC_BLOBS are the same. */
+	fsp_flags |= table_flags & DICT_TF_MASK_ZIP_SSIZE;
+	fsp_flags |= table_flags & DICT_TF_MASK_ATOMIC_BLOBS;
 
 	/* In addition, tablespace flags also contain the page size. */
-	flags = fsp_flags_set_page_size(flags, UNIV_PAGE_SIZE);
+	fsp_flags |= fsp_flags_set_page_size(fsp_flags, UNIV_PAGE_SIZE);
 
-	return(fsp_flags_validate(flags));
+	/* Table flags contain the DATA_DIR flag but fsp_flags do not */
+
+	return(fsp_flags_validate(fsp_flags));
 }
 
 /********************************************************************//**
+Convert a 32 bit integer from SYS_TABLES.TYPE to dict_table_t::flags
+The following chart shows the translation of the low order bit.
+Other bits are the same.
+========================= Low order bit ==========================
+                    | REDUNDANT | COMPACT | COMPRESSED and DYNAMIC
+SYS_TABLES.TYPE     |     1     |    1    |     1
+dict_table_t::flags |     0     |    1    |     1
+==================================================================
+@return	ulint containing SYS_TABLES.TYPE */
+UNIV_INLINE
+ulint
+dict_sys_tables_type_to_tf(
+/*=======================*/
+	ulint	type,	/*!< in: SYS_TABLES.TYPE field */
+	ulint	n_cols)	/*!< in: SYS_TABLES.N_COLS field */
+{
+	ulint	flags;
+	ulint	redundant = !(n_cols & DICT_N_COLS_COMPACT);
+
+	/* Adjust bit zero. */
+	flags = redundant ? 0 : 1;
+
+	/* ZIP_SSIZE, ATOMIC_BLOBS & DATA_DIR are the same. */
+	flags |= type & (DICT_TF_MASK_ZIP_SSIZE
+			 | DICT_TF_MASK_ATOMIC_BLOBS
+			 | DICT_TF_MASK_DATA_DIR);
+
+	return(flags);
+}
+
+
+/********************************************************************//**
 Convert a 32 bit integer table flags to the 32bit integer that is written
 to a SYS_TABLES.TYPE field. The following chart shows the translation of
 the low order bit.  Other bits are the same.
@@ -757,13 +805,19 @@ dict_tf_to_sys_tables_type(
 /*=======================*/
 	ulint	flags)	/*!< in: dict_table_t::flags */
 {
-	if (!DICT_TF_HAS_ATOMIC_BLOBS(flags)) {
-		ut_a(flags == DICT_TF_REDUNDANT
-		     || flags == DICT_TF_COMPACT);
-		return(SYS_TABLE_TYPE_ANTELOPE);
-	}
+	ulint type;
+
+	dict_tf_validate(flags);
+
+	/* Adjust bit zero. It is always 1 in SYS_TABLES.TYPE */
+	type = 1;
 
-	return(dict_tf_validate(flags));
+	/* ZIP_SSIZE, ATOMIC_BLOBS & DATA_DIR are the same. */
+	type |= flags & (DICT_TF_MASK_ZIP_SSIZE
+			 | DICT_TF_MASK_ATOMIC_BLOBS
+			 | DICT_TF_MASK_DATA_DIR);
+
+	return(type);
 }
 
 /********************************************************************//**

=== modified file 'storage/innobase/include/dict0load.h'
--- a/storage/innobase/include/dict0load.h	revid:andrei.elkin@stripped
+++ b/storage/innobase/include/dict0load.h	revid:kevin.lewis@stripped
@@ -29,11 +29,12 @@ Created 4/24/1996 Heikki Tuuri
 
 #include "univ.i"
 #include "dict0types.h"
+#include "trx0types.h"
 #include "ut0byte.h"
 #include "mem0mem.h"
 #include "btr0types.h"
 
-/** enum that defines all 6 system table IDs */
+/** enum that defines all system table IDs. @see SYSTEM_TABLE_NAME[] */
 enum dict_system_table_id {
 	SYS_TABLES = 0,
 	SYS_INDEXES,
@@ -41,6 +42,8 @@ enum dict_system_table_id {
 	SYS_FIELDS,
 	SYS_FOREIGN,
 	SYS_FOREIGN_COLS,
+	SYS_TABLESPACES,
+	SYS_DATAFILES,
 
 	/* This must be last item. Defines the number of system tables. */
 	SYS_NUM_SYSTEM_TABLES
@@ -157,6 +160,17 @@ dict_load_field_low(
 					for temporary storage */
 	const rec_t*	rec);		/*!< in: SYS_FIELDS record */
 /********************************************************************//**
+Using the table->heap, copy the null-terminated filepath into
+table->data_dir_path and put a null byte before the extension.
+This allows SHOW CREATE TABLE to return the correct DATA DIRECTORY path.
+Make this data directory path only if it has not yet been saved. */
+UNIV_INTERN
+void
+dict_save_data_dir_path(
+/*====================*/
+	dict_table_t*	table,		/*!< in/out: table */
+	char*		filepath);	/*!< in: filepath of tablespace */
+/********************************************************************//**
 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
@@ -325,6 +339,75 @@ dict_process_sys_foreign_col_rec(
 	const char**	ref_col_name,	/*!< out: referenced column name
 					in referenced table */
 	ulint*		pos);		/*!< out: column position */
+/********************************************************************//**
+This function parses a SYS_TABLESPACES record, extracts necessary
+information from the record and returns to caller.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_tablespaces(
+/*=========================*/
+	mem_heap_t*	heap,		/*!< in/out: heap memory */
+	const rec_t*	rec,		/*!< in: current SYS_TABLESPACES rec */
+	ulint*		space,		/*!< out: pace id */
+	const char**	name,		/*!< out: tablespace name */
+	ulint*		flags);		/*!< out: tablespace flags */
+/********************************************************************//**
+This function parses a SYS_DATAFILES record, extracts necessary
+information from the record and returns to caller.
+@return error message, or NULL on success */
+UNIV_INTERN
+const char*
+dict_process_sys_datafiles(
+/*=======================*/
+	mem_heap_t*	heap,		/*!< in/out: heap memory */
+	const rec_t*	rec,		/*!< in: current SYS_DATAFILES rec */
+	ulint*		space,		/*!< out: pace id */
+	const char**	path);		/*!< out: datafile path */
+/********************************************************************//**
+Look up a tablename in SYS_TABLES and return the space ID.
+@return TRUE if tablename was found and space is set, FALSE if not */
+UNIV_INTERN
+bool
+dict_get_space_from_sys_tables(
+/*===========================*/
+	const char*	name,		/*!< in: table name */
+	ulint*		space);		/*!< out: space ID */
+/********************************************************************//**
+Get the filepath for a spaceid from SYS_DATAFILES. This function provides
+a temporary heap which is used for the table lookup, but not for the path.
+The caller must free the memory for the path returned. This function can
+return NULL if the space ID is not found in SYS_DATAFILES, then the caller
+will assume that the ibd file is in the normal datadir.
+@return	own: A copy of the first datafile found in SYS_DATAFILES.PATH for
+the given space ID. NULL if space ID is zero or not found. */
+UNIV_INTERN
+char*
+dict_get_first_path(
+/*================*/
+	ulint		space,	/*!< in: space id */
+	const char*	name);	/*!< in: tablespace name */
+/********************************************************************//**
+Update the record for space_id in SYS_TABLESPACES to this filepath.
+@return	DB_SUCCESS if OK, dberr_t if the insert failed */
+UNIV_INTERN
+dberr_t
+dict_update_filepath(
+/*===============*/
+	ulint		space_id,	/*!< in: space id */
+	const char*	filepath);	/*!< in: filepath */
+/********************************************************************//**
+Insert records into SYS_TABLESPACES and SYS_DATAFILES.
+@return	DB_SUCCESS if OK, dberr_t if the insert failed */
+UNIV_INTERN
+dberr_t
+dict_insert_tablespace_and_filepath(
+/*================================*/
+	ulint		space,		/*!< in: space id */
+	const char*	name,		/*!< in: talespace name */
+	const char*	filepath,	/*!< in: filepath */
+	ulint		fsp_flags);	/*!< in: tablespace flags */
+
 #ifndef UNIV_NONINL
 #include "dict0load.ic"
 #endif

=== modified file 'storage/innobase/include/dict0mem.h'
--- a/storage/innobase/include/dict0mem.h	revid:andrei.elkin@stripped
+++ b/storage/innobase/include/dict0mem.h	revid:kevin.lewis@stripped
@@ -94,12 +94,9 @@ and SYS_TABLES.TYPE.  Similar flags foun
 are described in fsp0fsp.h. */
 
 /* @{ */
-/** SYS_TABLES.TYPE can be equal to 1 which means that the Row format
-is one of two Antelope row formats, Redundant or Compact. */
-#define SYS_TABLE_TYPE_ANTELOPE		1
-/** dict_table_t::flags can be equal to 0 if the row format = Redundant */
+/** dict_table_t::flags bit 0 is equal to 0 if the row format = Redundant */
 #define DICT_TF_REDUNDANT		0	/*!< Redundant row format. */
-/** dict_table_t::flags can be equal to 1 if the row format = Compact */
+/** dict_table_t::flags bit 0 is equal to 1 if the row format = Compact */
 #define DICT_TF_COMPACT			1	/*!< Compact row format. */
 
 /** This bitmask is used in SYS_TABLES.N_COLS to set and test whether
@@ -116,10 +113,17 @@ Brracuda row formats store the whole blo
 Secondary indexes are created from this external data using row_ext_t
 to cache the BLOB prefixes. */
 #define DICT_TF_WIDTH_ATOMIC_BLOBS	1
+/** If a table is created with the MYSQL option DATA DIRECTORY and
+innodb-file-per-table, an older engine will not be able to find that table.
+This flag prevents older engines from attempting to open the table and
+allows InnoDB to update_create_info() accordingly. */
+#define DICT_TF_WIDTH_DATA_DIR		1
+
 /** Width of all the currently known table flags */
 #define DICT_TF_BITS	(DICT_TF_WIDTH_COMPACT		\
 			+ DICT_TF_WIDTH_ZIP_SSIZE	\
-			+ DICT_TF_WIDTH_ATOMIC_BLOBS)
+			+ DICT_TF_WIDTH_ATOMIC_BLOBS	\
+			+ DICT_TF_WIDTH_DATA_DIR)
 
 /** A mask of all the known/used bits in table flags */
 #define DICT_TF_BIT_MASK	(~(~0 << DICT_TF_BITS))
@@ -132,9 +136,12 @@ to cache the BLOB prefixes. */
 /** Zero relative shift position of the ATOMIC_BLOBS field */
 #define DICT_TF_POS_ATOMIC_BLOBS	(DICT_TF_POS_ZIP_SSIZE		\
 					+ DICT_TF_WIDTH_ZIP_SSIZE)
-/** Zero relative shift position of the start of the UNUSED bits */
-#define DICT_TF_POS_UNUSED		(DICT_TF_POS_ATOMIC_BLOBS	\
+/** Zero relative shift position of the DATA_DIR field */
+#define DICT_TF_POS_DATA_DIR		(DICT_TF_POS_ATOMIC_BLOBS	\
 					+ DICT_TF_WIDTH_ATOMIC_BLOBS)
+/** Zero relative shift position of the start of the UNUSED bits */
+#define DICT_TF_POS_UNUSED		(DICT_TF_POS_DATA_DIR		\
+					+ DICT_TF_WIDTH_DATA_DIR)
 
 /** Bit mask of the COMPACT field */
 #define DICT_TF_MASK_COMPACT				\
@@ -148,6 +155,10 @@ to cache the BLOB prefixes. */
 #define DICT_TF_MASK_ATOMIC_BLOBS			\
 		((~(~0 << DICT_TF_WIDTH_ATOMIC_BLOBS))	\
 		<< DICT_TF_POS_ATOMIC_BLOBS)
+/** Bit mask of the DATA_DIR field */
+#define DICT_TF_MASK_DATA_DIR				\
+		((~(~0 << DICT_TF_WIDTH_DATA_DIR))	\
+		<< DICT_TF_POS_DATA_DIR)
 
 /** Return the value of the COMPACT field */
 #define DICT_TF_GET_COMPACT(flags)			\
@@ -161,6 +172,10 @@ to cache the BLOB prefixes. */
 #define DICT_TF_HAS_ATOMIC_BLOBS(flags)			\
 		((flags & DICT_TF_MASK_ATOMIC_BLOBS)	\
 		>> DICT_TF_POS_ATOMIC_BLOBS)
+/** Return the value of the ATOMIC_BLOBS field */
+#define DICT_TF_HAS_DATA_DIR(flags)			\
+		((flags & DICT_TF_MASK_DATA_DIR)	\
+		>> DICT_TF_POS_DATA_DIR)
 /** Return the contents of the UNUSED bits */
 #define DICT_TF_GET_UNUSED(flags)			\
 		(flags >> DICT_TF_POS_UNUSED)
@@ -632,6 +647,8 @@ struct dict_table_struct{
 				innodb_file_per_table is defined in my.cnf;
 				in Unix this is usually /tmp/..., in Windows
 				temp\... */
+	char*		data_dir_path; /*!< NULL or the directory path
+				specified by DATA DIRECTORY */
 	unsigned	space:32;
 				/*!< space where the clustered index of the
 				table is placed */

=== modified file 'storage/innobase/include/fil0fil.h'
--- a/storage/innobase/include/fil0fil.h	revid:andrei.elkin@stripped
+++ b/storage/innobase/include/fil0fil.h	revid:kevin.lewis@stripped
@@ -248,6 +248,16 @@ fil_assign_new_space_id(
 /*====================*/
 	ulint*	space_id);	/*!< in/out: space id */
 /*******************************************************************//**
+Returns the path from the first fil_node_t found for the space ID sent.
+The caller is responsible for freeing the memory allocated here for the
+value returned.
+@return	a copy of fil_node_t::path, NULL if space is zero or not found. */
+UNIV_INTERN
+char*
+fil_space_get_first_path(
+/*=====================*/
+	ulint	id);	/*!< in: space id */
+/*******************************************************************//**
 Returns the size of the space in pages. The tablespace must be cached in the
 memory cache.
 @return	space size, 0 if space not found */
@@ -346,6 +356,7 @@ fil_read_first_page(
 						parameters below already
 						contain sensible data */
 	ulint*		flags,			/*!< out: tablespace flags */
+	ulint*		space_id,		/*!< out: tablespace ID */
 #ifdef UNIV_LOG_ARCHIVE
 	ulint*		min_arch_log_no,	/*!< out: min of archived
 						log numbers in data files */
@@ -435,16 +446,70 @@ UNIV_INTERN
 ibool
 fil_rename_tablespace(
 /*==================*/
-	const char*	old_name_in,	/*!< in: old table name in the standard
-					databasename/tablename format of
-					InnoDB, or NULL if we do the rename
-					based on the space id only */
+	const char*	old_name_in,	/*!< in: old table name in the
+					standard databasename/tablename
+					format of InnoDB, or NULL if we
+					do the rename based on the space
+					id only */
 	ulint		id,		/*!< in: space id */
-	const char*	new_name);	/*!< in: new table name in the standard
-					databasename/tablename format
-					of InnoDB */
+	const char*	new_name,	/*!< in: new table name in the
+					standard databasename/tablename
+					format of InnoDB */
+	const char*	new_path);	/*!< in: new full datafile path
+					if the tablespace is remotely
+					located, or NULL if it is located
+					in the normal data directory. */
 
 /*******************************************************************//**
+Allocates a file name for a single-table tablespace. The string must be freed
+by caller with mem_free().
+@return	own: file name */
+UNIV_INTERN
+char*
+fil_make_ibd_name(
+/*==============*/
+	const char*	name,		/*!< in: table name or a dir path */
+	ibool		is_full_path);	/*!< in: TRUE if it is a dir path */
+/*******************************************************************//**
+Allocates a file name for a tablespace ISL file (InnoDB Symbolic Link).
+The string must be freed by caller with mem_free().
+@return	own: file name */
+UNIV_INTERN
+char*
+fil_make_isl_name(
+/*==============*/
+	const char*	name);	/*!< in: table name */
+/*******************************************************************//**
+Creates a new InnoDB Symbolic Link (ISL) file.  It is always created
+under the 'datadir' of MySQL. The datadir is the directory of a
+running mysqld program. We can refer to it by simply using the path '.'.
+@return	DB_SUCCESS or error code */
+UNIV_INTERN
+dberr_t
+fil_create_link_file(
+/*=================*/
+	const char*	tablename,	/*!< in: tablename */
+	const char*	filepath);	/*!< in: pathname of tablespace */
+/*******************************************************************//**
+Deletes an InnoDB Symbolic Link (ISL) file. */
+UNIV_INTERN
+void
+fil_delete_link_file(
+/*==================*/
+	const char*	tablename);	/*!< in: name of table */
+/*******************************************************************//**
+Reads an InnoDB Symbolic Link (ISL) file.
+It is always created under the 'datadir' of MySQL.  The name is of the
+form {databasename}/{tablename}. and the isl file is expected to be in a
+'{databasename}' directory called '{tablename}.isl'. The caller must free
+the memory of the null-terminated path returned if it is not null.
+@return	own: filepath found in link file, NULL if not found. */
+UNIV_INTERN
+char*
+fil_read_link_file(
+/*===============*/
+	const char*	name);		/*!< in: tablespace name */
+/*******************************************************************//**
 Creates a new single-table tablespace to a database directory of MySQL.
 Database directories are under the 'datadir' of MySQL. The datadir is the
 directory of a running mysqld program. We can refer to it by simply the
@@ -458,10 +523,8 @@ fil_create_new_single_table_tablespace(
 	ulint		space_id,	/*!< in: space id */
 	const char*	tablename,	/*!< in: the table name in the usual
 					databasename/tablename format
-					of InnoDB, or a dir path to a temp
-					table */
-	ibool		is_temp,	/*!< in: TRUE if a table created with
-					CREATE TEMPORARY TABLE */
+					of InnoDB */
+	const char*	dir_path,	/*!< in: NULL or a dir path */
 	ulint		flags,		/*!< in: tablespace flags */
 	ulint		flags2,		/*!< in: table flags2 */
 	ulint		size)		/*!< in: the initial size of the
@@ -492,8 +555,9 @@ fil_open_single_table_tablespace(
 					accessing the first page of the file */
 	ulint		id,		/*!< in: space id */
 	ulint		flags,		/*!< in: tablespace flags */
-	const char*	name);		/*!< in: table name in the
+	const char*	tablename,	/*!< in: table name in the
 					databasename/tablename format */
+	const char*	filepath);	/*!< in: tablespace filepath */
 /********************************************************************//**
 It is possible, though very improbable, that the lsn's in the tablespace to be
 imported have risen above the current system lsn, if a lengthy purge, ibuf
@@ -508,8 +572,7 @@ UNIV_INTERN
 ibool
 fil_reset_too_high_lsns(
 /*====================*/
-	const char*	name,		/*!< in: table name in the
-					databasename/tablename format */
+	const char*	filepath,	/*!< in: filepath of tablespace */
 	lsn_t		current_lsn);	/*!< in: reset lsn's if the lsn stamped
 					to FIL_PAGE_FILE_FLUSH_LSN in the
 					first page is too high */

=== modified file 'storage/innobase/include/os0file.h'
--- a/storage/innobase/include/os0file.h	revid:andrei.elkin@stripped
+++ b/storage/innobase/include/os0file.h	revid:kevin.lewis@stripped
@@ -1,6 +1,6 @@
 /***********************************************************************
 
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
 Copyright (c) 2009, Percona Inc.
 
 Portions of this file contain modifications contributed and copyrighted
@@ -925,6 +925,59 @@ os_file_dirname(
 /*============*/
 	const char*	path);	/*!< in: pathname */
 /****************************************************************//**
+This function returns a new path name after replacing the basename
+in an old path with a new basename.  The old_path is a full path
+name including the extension.  The tablename is in the normal
+form "databasename/tablename".  The new base name is found after
+the forward slash.  Both input strings are null terminated.
+
+This function allocates memory to be returned.  It is the callers
+responsibility to free the return value after it is no longer needed.
+
+@return	own: new full pathname */
+UNIV_INTERN
+char*
+os_file_make_new_pathname(
+/*======================*/
+	const char*	old_path,	/*!< in: pathname */
+	const char*	new_name);	/*!< in: new file name */
+/****************************************************************//**
+This function returns a remote path name by combining a data directory
+path provided in a DATA DIRECTORY clause with the tablename which is
+in the form 'database/tablename'.  It strips the file basename (which
+is the tablename) found after the last directory in the path provided.
+The full filepath created will include the database name as a directory
+under the path provided.  The filename is the tablename with the '.ibd'
+extension. All input and output strings are null-terminated.
+
+This function allocates memory to be returned.  It is the callers
+responsibility to free the return value after it is no longer needed.
+
+@return	own: A full pathname; data_dir_path/databasename/tablename.ibd */
+UNIV_INTERN
+char*
+os_file_make_remote_pathname(
+/*=========================*/
+	const char*	data_dir_path,	/*!< in: pathname */
+	const char*	tablename);	/*!< in: tablename */
+/****************************************************************//**
+This function reduces a null-terminated full remote path name into
+the path that is sent by MySQL for DATA DIRECTORY clause.  It replaces
+the 'databasename/tablename.ibd' found at the end of the path with just
+'tablename'.
+
+Since the result is always smaller than the path sent in, no new memory
+is allocated. The caller should allocate memory for the path sent in.
+This function manipulates that path in place.
+
+If the path format is not as expected, just return.  The result is used
+to inform a SHOW CREATE TABLE command. */
+UNIV_INTERN
+void
+os_file_make_data_dir_path(
+/*========================*/
+	char*	data_dir_path);	/*!< in/out: full path/data_dir_path */
+/****************************************************************//**
 Creates all missing subdirectories along the given path.
 @return	TRUE if call succeeded FALSE otherwise */
 UNIV_INTERN

=== modified file 'storage/innobase/include/read0read.h'
--- a/storage/innobase/include/read0read.h	revid:andrei.elkin@stripped
+++ b/storage/innobase/include/read0read.h	revid:kevin.lewis@stripped
@@ -148,7 +148,7 @@ struct read_view_struct{
 	trx_id_t*	trx_ids;/*!< Additional trx ids which the read should
 				not see: typically, these are the read-write
 				active transactions at the time when the read
-			       	is serialized, except the reading transaction
+				is serialized, except the reading transaction
 				itself; the trx ids in this array are in a
 				descending order. These trx_ids should be
 				between the "low" and "high" water marks,

=== modified file 'storage/innobase/include/row0merge.h'
--- a/storage/innobase/include/row0merge.h	revid:andrei.elkin@stripped
+++ b/storage/innobase/include/row0merge.h	revid:kevin.lewis@stripped
@@ -199,6 +199,17 @@ row_merge_file_destroy_low(
 	int		fd);	/*!< in: merge file descriptor */
 
 /*********************************************************************//**
+Provide a new pathname for a table that is being renamed if it belongs to
+a file-per-table tablespace.  The caller is responsible for freeing the
+memory allocated for the return value.
+@return	new pathname of tablespace file, or NULL if space = 0 */
+UNIV_INTERN
+char*
+row_make_new_pathname(
+/*==================*/
+	dict_table_t*	table,		/*!< in: table to be renamed */
+	const char*	new_name);	/*!< in: new name */
+/*********************************************************************//**
 Rename the tables in the data dictionary.  The data dictionary must
 have been locked exclusively by the caller, because the transaction
 will not be committed.

=== modified file 'storage/innobase/include/trx0trx.h'
--- a/storage/innobase/include/trx0trx.h	revid:andrei.elkin@stripped
+++ b/storage/innobase/include/trx0trx.h	revid:kevin.lewis@stripped
@@ -368,8 +368,16 @@ ibool
 trx_is_strict(
 /*==========*/
 	trx_t*	trx);	/*!< in: transaction */
+/**********************************************************************//**
+returns the global setting for innodb_strict_mode.
+@return	TRUE if strict */
+UNIV_INTERN
+ibool
+global_mode_is_strict();
+
 #else /* !UNIV_HOTBACKUP */
 #define trx_is_interrupted(trx) FALSE
+#define global_mode_is_strict() FALSE
 #endif /* !UNIV_HOTBACKUP */
 
 /*******************************************************************//**

=== modified file 'storage/innobase/lock/lock0lock.cc'
--- a/storage/innobase/lock/lock0lock.cc	revid:andrei.elkin@stripped
+++ b/storage/innobase/lock/lock0lock.cc	revid:kevin.lewis@stripped
@@ -6244,7 +6244,8 @@ lock_clust_rec_read_check_and_lock(
 	ut_ad(mode != LOCK_S
 	      || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
 
-	err = lock_rec_lock(FALSE, mode | gap_mode, block, heap_no, index, thr);
+	err = lock_rec_lock(FALSE, mode | gap_mode,
+			    block, heap_no, index, thr);
 
 	MONITOR_INC(MONITOR_NUM_RECLOCK_REQ);
 

=== modified file 'storage/innobase/os/os0file.cc'
--- a/storage/innobase/os/os0file.cc	revid:andrei.elkin@stripped
+++ b/storage/innobase/os/os0file.cc	revid:kevin.lewis@stripped
@@ -497,7 +497,7 @@ os_file_get_last_error_low(
 		} else {
 			if (strerror(err) != NULL) {
 				fprintf(stderr,
-					"InnoDB: Error number %d"
+					"InnoDB: The error number %d"
 					" means '%s'.\n",
 					err, strerror(err));
 			}
@@ -643,7 +643,8 @@ os_file_handle_error_cond_exit(
 
 			ut_print_timestamp(stderr);
 			fprintf(stderr, "  InnoDB: File operation call: "
-				"'%s'.\n", operation);
+				"'%s' returned OS error " ULINTPF ".\n",
+				operation, err);
 		}
 
 		if (should_exit) {
@@ -1052,10 +1053,12 @@ next_file:
 }
 
 /*****************************************************************//**
-This function attempts to create a directory named pathname. The new directory
-gets default permissions. On Unix the permissions are (0770 & ~umask). If the
-directory exists already, nothing is done and the call succeeds, unless the
-fail_if_exists arguments is true.
+This function attempts to create a directory named pathname. The new
+directory gets default permissions. On Unix the permissions are
+(0770 & ~umask). If the directory exists already, nothing is done and
+the call succeeds, unless the fail_if_exists arguments is true.
+If another error occurs, such as a permission error, this does not crash,
+but reports the error and returns FALSE.
 @return	TRUE if call succeeds, FALSE on error */
 UNIV_INTERN
 ibool
@@ -1074,7 +1077,7 @@ os_file_create_directory(
 	      || (GetLastError() == ERROR_ALREADY_EXISTS
 		  && !fail_if_exists))) {
 		/* failure */
-		os_file_handle_error(pathname, "CreateDirectory");
+		os_file_handle_error_no_exit(pathname, "CreateDirectory", FALSE);
 
 		return(FALSE);
 	}
@@ -1087,7 +1090,7 @@ os_file_create_directory(
 
 	if (!(rcode == 0 || (errno == EEXIST && !fail_if_exists))) {
 		/* failure */
-		os_file_handle_error(pathname, "mkdir");
+		os_file_handle_error_no_exit(pathname, "mkdir", FALSE);
 
 		return(FALSE);
 	}
@@ -3002,6 +3005,146 @@ os_file_get_status(
 #endif
 
 /****************************************************************//**
+This function returns a new path name after replacing the basename
+in an old path with a new basename.  The old_path is a full path
+name including the extension.  The tablename is in the normal
+form "databasename/tablename".  The new base name is found after
+the forward slash.  Both input strings are null terminated.
+
+This function allocates memory to be returned.  It is the callers
+responsibility to free the return value after it is no longer needed.
+
+@return	own: new full pathname */
+UNIV_INTERN
+char*
+os_file_make_new_pathname(
+/*======================*/
+	const char*	old_path,	/*!< in: pathname */
+	const char*	tablename)	/*!< in: contains new base name */
+{
+	ulint		dir_len;
+	char*		last_slash;
+	char*		base_name;
+	char*		new_path;
+	ulint		new_path_len;
+
+	/* Get a pointer to the Separate the database name string from the base name in
+	the new tablename. */
+	last_slash = strrchr((char*) tablename, '/');
+	base_name = last_slash ? last_slash + 1 : (char*) tablename;
+
+	/* Find the offset of the last slash. We will strip off the
+	old basename.ibd which starts after that slash. */
+	last_slash = strrchr((char*) old_path, OS_FILE_PATH_SEPARATOR);
+	dir_len = last_slash ? last_slash - old_path : strlen(old_path);
+
+	/* allocate a new path and move the old directory path to it. */
+	new_path_len = dir_len + strlen(base_name) + sizeof "/.ibd";
+	new_path = static_cast<char*>(mem_alloc(new_path_len));
+	memcpy(new_path, old_path, dir_len);
+
+	ut_snprintf(new_path + dir_len,
+		    new_path_len - dir_len,
+		    "%c%s.ibd",
+		    OS_FILE_PATH_SEPARATOR,
+		    base_name);
+
+	return(new_path);
+}
+
+/****************************************************************//**
+This function returns a remote path name by combining a data directory
+path provided in a DATA DIRECTORY clause with the tablename which is
+in the form 'database/tablename'.  It strips the file basename (which
+is the tablename) found after the last directory in the path provided.
+The full filepath created will include the database name as a directory
+under the path provided.  The filename is the tablename with the '.ibd'
+extension. All input and output strings are null-terminated.
+
+This function allocates memory to be returned.  It is the callers
+responsibility to free the return value after it is no longer needed.
+
+@return	own: A full pathname; data_dir_path/databasename/tablename.ibd */
+UNIV_INTERN
+char*
+os_file_make_remote_pathname(
+/*=========================*/
+	const char*	data_dir_path,	/*!< in: pathname */
+	const char*	tablename)	/*!< in: tablename */
+{
+	ulint		data_dir_len;
+	char*		last_slash;
+	char*		new_path;
+	ulint		new_path_len;
+
+	/* Find the offset of the last slash. We will strip off the
+	old basename or tablename which starts after that slash. */
+	last_slash = strrchr((char*) data_dir_path, OS_FILE_PATH_SEPARATOR);
+	data_dir_len = last_slash ? last_slash - data_dir_path : strlen(data_dir_path);
+
+	/* allocate a new path and move the old directory path to it. */
+	new_path_len = data_dir_len + strlen(tablename) + sizeof "/.ibd";
+	new_path = static_cast<char*>(mem_alloc(new_path_len));
+	memcpy(new_path, data_dir_path, data_dir_len);
+	ut_snprintf(new_path + data_dir_len,
+		    new_path_len - data_dir_len,
+		    "%c%s.ibd",
+		    OS_FILE_PATH_SEPARATOR,
+		    tablename);
+
+	srv_normalize_path_for_win(new_path);
+
+	return(new_path);
+}
+
+/****************************************************************//**
+This function reduces a null-terminated full remote path name into
+the path that is sent by MySQL for DATA DIRECTORY clause.  It replaces
+the 'databasename/tablename.ibd' found at the end of the path with just
+'tablename'.
+
+Since the result is always smaller than the path sent in, no new memory
+is allocated. The caller should allocate memory for the path sent in.
+This function manipulates that path in place.
+
+If the path format is not as expected, just return.  The result is used
+to inform a SHOW CREATE TABLE command. */
+UNIV_INTERN
+void
+os_file_make_data_dir_path(
+/*========================*/
+	char*	data_dir_path)	/*!< in/out: full path/data_dir_path */
+{
+	char*	ptr;
+	char*	tablename;
+	ulint	tablename_len;
+
+	/* Replace the period before the extension with a null byte. */
+	ptr = strrchr((char*) data_dir_path, '.');
+	if (!ptr) {
+		return;
+	}
+	ptr[0] = '\0';
+
+	/* The tablename starts after the last slash. */
+	ptr = strrchr((char*) data_dir_path, OS_FILE_PATH_SEPARATOR);
+	if (!ptr) {
+		return;
+	}
+	ptr[0] = '\0';
+	tablename = ptr + 1;
+
+	/* The databasename starts after the next to last slash. */
+	ptr = strrchr((char*) data_dir_path, OS_FILE_PATH_SEPARATOR);
+	if (!ptr) {
+		return;
+	}
+	tablename_len = ut_strlen(tablename);
+
+	ut_memmove(++ptr, tablename, tablename_len);
+}
+
+/****************************************************************//**
 The function os_file_dirname returns a directory component of a
 null-terminated pathname string. In the usual case, dirname returns
 the string up to, but not including, the final '/', and basename

=== modified file 'storage/innobase/row/row0merge.cc'
--- a/storage/innobase/row/row0merge.cc	revid:andrei.elkin@stripped
+++ b/storage/innobase/row/row0merge.cc	revid:kevin.lewis@stripped
@@ -2913,6 +2913,33 @@ row_merge_rename_index_to_drop(
 }
 
 /*********************************************************************//**
+Provide a new pathname for a table that is being renamed if it belongs to
+a file-per-table tablespace.  The caller is responsible for freeing the
+memory allocated for the return value.
+@return	new pathname of tablespace file, or NULL if space = 0 */
+UNIV_INTERN
+char*
+row_make_new_pathname(
+/*==================*/
+	dict_table_t*	table,		/*!< in: table to be renamed */
+	const char*	new_name)	/*!< in: new name */
+{
+	char*	new_path;
+	char*	old_path;
+
+	ut_ad(table->space != 0);
+
+	old_path = fil_space_get_first_path(table->space);
+	ut_a(old_path);
+
+	new_path = os_file_make_new_pathname(old_path, new_name);
+
+	mem_free(old_path);
+
+	return(new_path);
+}
+
+/*********************************************************************//**
 Rename the tables in the data dictionary.  The data dictionary must
 have been locked exclusively by the caller, because the transaction
 will not be committed.
@@ -2969,6 +2996,60 @@ row_merge_rename_tables(
 			   " WHERE NAME = :new_name;\n"
 			   "END;\n", FALSE, trx);
 
+	/* Update SYS_TABLESPACES and SYS_DATAFILES if the old
+	table is in a non-system tablespace where space > 0. */
+	if (err == DB_SUCCESS && old_table->space) {
+		/* Make pathname to update SYS_DATAFILES. */
+		char* tmp_path = row_make_new_pathname(old_table, tmp_name);
+
+		info = pars_info_create();
+
+		pars_info_add_str_literal(info, "tmp_name", tmp_name);
+		pars_info_add_str_literal(info, "tmp_path", tmp_path);
+		pars_info_add_int4_literal(info, "old_space",
+					   (lint) old_table->space);
+
+		err = que_eval_sql(info,
+				   "PROCEDURE RENAME_OLD_SPACE () IS\n"
+				   "BEGIN\n"
+				   "UPDATE SYS_TABLESPACES"
+				   " SET NAME = :tmp_name\n"
+				   " WHERE SPACE = :old_space;\n"
+				   "UPDATE SYS_DATAFILES"
+				   " SET PATH = :tmp_path\n"
+				   " WHERE SPACE = :old_space;\n"
+				   "END;\n", FALSE, trx);
+
+		mem_free(tmp_path);
+	}
+
+	/* Update SYS_TABLESPACES and SYS_DATAFILES if the new
+	table is in a non-system tablespace where space > 0. */
+	if (err == DB_SUCCESS && new_table->space) {
+		/* Make pathname to update SYS_DATAFILES. */
+		char* old_path = row_make_new_pathname(new_table, old_name);
+
+		info = pars_info_create();
+
+		pars_info_add_str_literal(info, "old_name", old_name);
+		pars_info_add_str_literal(info, "old_path", old_path);
+		pars_info_add_int4_literal(info, "new_space",
+					   (lint) new_table->space);
+
+		err = que_eval_sql(info,
+				   "PROCEDURE RENAME_NEW_SPACE () IS\n"
+				   "BEGIN\n"
+				   "UPDATE SYS_TABLESPACES"
+				   " SET NAME = :old_name\n"
+				   " WHERE SPACE = :new_space;\n"
+				   "UPDATE SYS_DATAFILES"
+				   " SET PATH = :old_path\n"
+				   " WHERE SPACE = :new_space;\n"
+				   "END;\n", FALSE, trx);
+
+		mem_free(old_path);
+	}
+
 	if (err != DB_SUCCESS) {
 
 		goto err_exit;
@@ -2977,15 +3058,24 @@ row_merge_rename_tables(
 	/* The following calls will also rename the .ibd data files if
 	the tables are stored in a single-table tablespace */
 
-	if (!dict_table_rename_in_cache(old_table, tmp_name, FALSE)
-	    || !dict_table_rename_in_cache(new_table, old_name, FALSE)) {
+	err = dict_table_rename_in_cache(old_table, tmp_name, FALSE);
+	if (err != DB_SUCCESS) {
+		goto err_exit;
+	}
 
-		err = DB_ERROR;
+	err = dict_table_rename_in_cache(new_table, old_name, FALSE);
+	if (err != DB_SUCCESS) {
+		if (dict_table_rename_in_cache(old_table, old_name, FALSE)
+		    != DB_SUCCESS) {
+			ut_print_timestamp(stderr);
+			fprintf(stderr, " InnoDB: Error: Cannot undo "
+				" the rename in cache from %s to %s\n",
+				old_name, tmp_name);
+		}
 		goto err_exit;
 	}
 
 	err = dict_load_foreigns(old_name, FALSE, TRUE);
-
 	if (err != DB_SUCCESS) {
 err_exit:
 		trx->error_state = DB_SUCCESS;

=== modified file 'storage/innobase/row/row0mysql.cc'
--- a/storage/innobase/row/row0mysql.cc	revid:andrei.elkin@stripped
+++ b/storage/innobase/row/row0mysql.cc	revid:kevin.lewis@stripped
@@ -2200,6 +2200,29 @@ err_exit:
 
 	err = trx->error_state;
 
+	if (table->space) {
+		ut_a(table->flags2 & DICT_TF2_USE_TABLESPACE);
+
+		/* Update SYS_TABLESPACES and SYS_DATAFILES if a new
+		tablespace was created. */
+		if (err == DB_SUCCESS) {
+			char*	path;
+			path = fil_space_get_first_path(table->space);
+
+			err = dict_create_add_tablespace_to_dictionary(
+				table->space, table->name,
+				fil_space_get_flags(table->space),
+				path, trx);
+
+			mem_free(path);
+		}
+
+		if (err != DB_SUCCESS) {
+			/* We must delete the link file. */
+			fil_delete_link_file(table->name);
+		}
+	}
+
 	switch (err) {
 	case DB_SUCCESS:
 		break;
@@ -2245,10 +2268,8 @@ err_exit:
 		/* fall through */
 
 	case DB_DUPLICATE_KEY:
+	case DB_TABLESPACE_EXISTS:
 	default:
-		/* We may also get err == DB_ERROR if the .ibd file for the
-		table already exists */
-
 		trx->error_state = DB_SUCCESS;
 		trx_rollback_to_savepoint(trx, NULL);
 		dict_mem_table_free(table);
@@ -2781,25 +2802,24 @@ row_discard_tablespace_for_mysql(
 
 	pars_info_add_str_literal(info, "table_name", name);
 	pars_info_add_ull_literal(info, "new_id", new_id);
+	pars_info_add_ull_literal(info, "old_id", table->id);
 
 	err = que_eval_sql(info,
 			   "PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
-			   "old_id CHAR;\n"
 			   "BEGIN\n"
-			   "SELECT ID INTO old_id\n"
-			   "FROM SYS_TABLES\n"
-			   "WHERE NAME = :table_name\n"
+			   "SELECT ID FROM SYS_TABLES\n"
+			   " WHERE NAME = :table_name\n"
 			   "LOCK IN SHARE MODE;\n"
 			   "IF (SQL % NOTFOUND) THEN\n"
 			   "       COMMIT WORK;\n"
 			   "       RETURN;\n"
 			   "END IF;\n"
 			   "UPDATE SYS_TABLES SET ID = :new_id\n"
-			   " WHERE ID = old_id;\n"
+			   " WHERE ID = :old_id;\n"
 			   "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
-			   " WHERE TABLE_ID = old_id;\n"
+			   " WHERE TABLE_ID = :old_id;\n"
 			   "UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
-			   " WHERE TABLE_ID = old_id;\n"
+			   " WHERE TABLE_ID = :old_id;\n"
 			   "COMMIT WORK;\n"
 			   "END;\n"
 			   , FALSE, trx);
@@ -2853,7 +2873,9 @@ row_import_tablespace_for_mysql(
 	const char*	name,	/*!< in: table name */
 	trx_t*		trx)	/*!< in: transaction handle */
 {
-	dict_table_t*	table;
+	dict_table_t*	table = NULL;
+	ulint		space;
+	char*		filepath	= NULL;
 	ibool		success;
 	lsn_t		current_lsn;
 	dberr_t		err		= DB_SUCCESS;
@@ -2864,6 +2886,25 @@ row_import_tablespace_for_mysql(
 
 	current_lsn = log_get_lsn();
 
+	/* Serialize data dictionary operations with dictionary mutex:
+	no deadlocks can occur then in these operations */
+
+	row_mysql_lock_data_dictionary(trx);
+
+	/* If the table is stored in a remote tablespace, we need to
+	determine that filepath from the link file and system tables.
+	Find the space ID in SYS_TABLES since this is an ALTER TABLE. */
+	if (!dict_get_space_from_sys_tables(name, &space)) {
+		goto table_not_found;
+	}
+	if (space > 0) {
+		filepath = dict_get_first_path(space, name);
+	}
+	if (!filepath) {
+		filepath = fil_make_ibd_name(name, FALSE);
+	}
+	ut_a(filepath);
+
 	/* It is possible, though very improbable, that the lsn's in the
 	tablespace to be imported have risen above the current system lsn, if
 	a lengthy purge, ibuf merge, or rollback was performed on a backup
@@ -2876,7 +2917,7 @@ row_import_tablespace_for_mysql(
 	a new space id to each data page. That would allow us to import clean
 	.ibd files from another MySQL installation. */
 
-	success = fil_reset_too_high_lsns(name, current_lsn);
+	success = fil_reset_too_high_lsns(filepath, current_lsn);
 
 	if (!success) {
 		ut_print_timestamp(stderr);
@@ -2888,9 +2929,6 @@ row_import_tablespace_for_mysql(
 
 		err = DB_ERROR;
 
-		row_mysql_lock_data_dictionary(trx);
-		table = NULL;
-
 		goto funct_exit;
 	}
 
@@ -2903,6 +2941,7 @@ row_import_tablespace_for_mysql(
 					DICT_ERR_IGNORE_NONE);
 
 	if (!table) {
+table_not_found:
 		ut_print_timestamp(stderr);
 		fputs("  InnoDB: table ", stderr);
 		ut_print_name(stderr, trx, TRUE, name);
@@ -2951,7 +2990,7 @@ row_import_tablespace_for_mysql(
 	success = fil_open_single_table_tablespace(
 		TRUE, table->space,
 		dict_tf_to_fsp_flags(table->flags),
-		table->name);
+		table->name, filepath);
 	if (success) {
 		table->ibd_file_missing = FALSE;
 		table->tablespace_discarded = FALSE;
@@ -2972,6 +3011,9 @@ row_import_tablespace_for_mysql(
 
 funct_exit:
 
+	if (filepath) {
+		mem_free(filepath);
+	}
 	if (table != NULL) {
 		dict_table_close(table, TRUE, FALSE);
 	}
@@ -3008,6 +3050,7 @@ row_truncate_table_for_mysql(
 	ulint		recreate_space = 0;
 	pars_info_t*	info = NULL;
 	ibool		has_internal_doc_id;
+	ulint		old_space = table->space;
 
 	/* How do we prevent crashes caused by ongoing operations on
 	the table? Old operations could try to access non-existent
@@ -3140,11 +3183,32 @@ row_truncate_table_for_mysql(
 		ulint	space	= table->space;
 		ulint	flags	= fil_space_get_flags(space);
 
+		ut_a(!(table->flags2 & DICT_TF2_TEMPORARY));
+
 		if (flags != ULINT_UNDEFINED
 		    && fil_discard_tablespace(space)) {
 
 			dict_index_t*	index;
 
+			/* Refresh the table's data_dir_path. */
+			if (DICT_TF_HAS_DATA_DIR(table->flags)
+			    && !table->data_dir_path) {
+				char* path;
+				path = fil_space_get_first_path(space);
+				if (path == NULL) {
+					path = dict_get_first_path(
+						space, table->name);
+				}
+
+				dict_save_data_dir_path(table, path);
+				mem_free(path);
+			}
+
+			/* Delete the link file if used. */
+			if (DICT_TF_HAS_DATA_DIR(table->flags)) {
+				fil_delete_link_file(table->name);
+			}
+
 			dict_hdr_get_new_id(NULL, NULL, &space);
 
 			/* Lock all index trees for this table. We must
@@ -3154,9 +3218,11 @@ row_truncate_table_for_mysql(
 
 			if (space == ULINT_UNDEFINED
 			    || fil_create_new_single_table_tablespace(
-				    space, table->name, FALSE,
+				    space, table->name,
+				    table->data_dir_path,
 				    flags, table->flags2,
-				    FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
+				    FIL_IBD_FILE_INITIAL_SIZE)
+			    != DB_SUCCESS) {
 				dict_table_x_unlock_indexes(table);
 				ut_print_timestamp(stderr);
 				fprintf(stderr,
@@ -3322,25 +3388,42 @@ next_rec:
 
 	info = pars_info_create();
 
-	pars_info_add_int4_literal(info, "space", (lint) table->space);
+	pars_info_add_int4_literal(info, "new_space", (lint) table->space);
 	pars_info_add_ull_literal(info, "old_id", table->id);
 	pars_info_add_ull_literal(info, "new_id", new_id);
 
 	err = que_eval_sql(info,
-			   "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
+			   "PROCEDURE RENUMBER_TABLE_ID_PROC () IS\n"
 			   "BEGIN\n"
 			   "UPDATE SYS_TABLES"
-			   " SET ID = :new_id, SPACE = :space\n"
+			   " SET ID = :new_id, SPACE = :new_space\n"
 			   " WHERE ID = :old_id;\n"
 			   "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
 			   " WHERE TABLE_ID = :old_id;\n"
 			   "UPDATE SYS_INDEXES"
-			   " SET TABLE_ID = :new_id, SPACE = :space\n"
+			   " SET TABLE_ID = :new_id, SPACE = :new_space\n"
 			   " WHERE TABLE_ID = :old_id;\n"
-			   "COMMIT WORK;\n"
 			   "END;\n"
 			   , FALSE, trx);
 
+	if (err == DB_SUCCESS && old_space != table->space) {
+		info = pars_info_create();
+
+		pars_info_add_int4_literal(info, "old_space", (lint) old_space);
+		pars_info_add_int4_literal(info, "new_space", (lint) table->space);
+
+		err = que_eval_sql(info,
+				   "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
+				   "BEGIN\n"
+				   "UPDATE SYS_TABLESPACES"
+				   " SET SPACE = :new_space\n"
+				   " WHERE SPACE = :old_space;\n"
+				   "UPDATE SYS_DATAFILES"
+				   " SET SPACE = :new_space"
+				   " WHERE SPACE = :old_space;\n"
+				   "END;\n"
+				   , FALSE, trx);
+	}
 	if (err != DB_SUCCESS) {
 		trx->error_state = DB_SUCCESS;
 		trx_rollback_to_savepoint(trx, NULL);
@@ -3560,6 +3643,11 @@ retry:
 		}
 	}
 
+	/* Delete the link file if used. */
+	if (DICT_TF_HAS_DATA_DIR(table->flags)) {
+		fil_delete_link_file(name);
+	}
+
 	/* Move the table the the non-LRU list so that it isn't
 	considered for eviction. */
 
@@ -3748,6 +3836,7 @@ check_next_foreign:
 			   "table_id CHAR;\n"
 			   "index_id CHAR;\n"
 			   "foreign_id CHAR;\n"
+			   "space_id INT;\n"
 			   "found INT;\n"
 
 			   "DECLARE CURSOR cur_fk IS\n"
@@ -3770,6 +3859,12 @@ check_next_foreign:
 			   "IF (SQL % NOTFOUND) THEN\n"
 			   "       RETURN;\n"
 			   "END IF;\n"
+			   "SELECT SPACE INTO space_id\n"
+			   "FROM SYS_TABLES\n"
+			   "WHERE NAME = :table_name;\n"
+			   "IF (SQL % NOTFOUND) THEN\n"
+			   "       RETURN;\n"
+			   "END IF;\n"
 			   "found := 1;\n"
 			   "SELECT ID INTO sys_foreign_id\n"
 			   "FROM SYS_TABLES\n"
@@ -3812,6 +3907,10 @@ check_next_foreign:
 			   "       END IF;\n"
 			   "END LOOP;\n"
 			   "CLOSE cur_idx;\n"
+			   "DELETE FROM SYS_TABLESPACES\n"
+			   "WHERE SPACE = space_id;\n"
+			   "DELETE FROM SYS_DATAFILES\n"
+			   "WHERE SPACE = space_id;\n"
 			   "DELETE FROM SYS_COLUMNS\n"
 			   "WHERE TABLE_ID = table_id;\n"
 			   "DELETE FROM SYS_TABLES\n"
@@ -4386,21 +4485,48 @@ row_rename_table_for_mysql(
 	info = pars_info_create();
 
 	pars_info_add_str_literal(info, "new_table_name", new_name);
-
 	pars_info_add_str_literal(info, "old_table_name", old_name);
 
 	err = que_eval_sql(info,
 			   "PROCEDURE RENAME_TABLE () IS\n"
 			   "BEGIN\n"
-			   "UPDATE SYS_TABLES SET NAME = :new_table_name\n"
+			   "UPDATE SYS_TABLES"
+			   " SET NAME = :new_table_name\n"
 			   " WHERE NAME = :old_table_name;\n"
 			   "END;\n"
 			   , FALSE, trx);
 
-	if (err != DB_SUCCESS) {
+	/* SYS_TABLESPACES and SYS_DATAFILES track non-system tablespaces
+	which have space IDs > 0. */
+	if (err == DB_SUCCESS && table->space) {
+		/* Make a new pathname to update SYS_DATAFILES. */
+		char*	new_path = row_make_new_pathname(table, new_name);
+
+		info = pars_info_create();
+
+		pars_info_add_str_literal(info, "new_table_name", new_name);
+		pars_info_add_str_literal(info, "new_path_name", new_path);
+		pars_info_add_int4_literal(info, "space_id", table->space);
 
+		err = que_eval_sql(info,
+				   "PROCEDURE RENAME_SPACE () IS\n"
+				   "BEGIN\n"
+				   "UPDATE SYS_TABLESPACES"
+				   " SET NAME = :new_table_name\n"
+				   " WHERE SPACE = :space_id;\n"
+				   "UPDATE SYS_DATAFILES"
+				   " SET PATH = :new_path_name\n"
+				   " WHERE SPACE = :space_id;\n"
+				   "END;\n"
+				   , FALSE, trx);
+
+		mem_free(new_path);
+	}
+	if (err != DB_SUCCESS) {
 		goto end;
-	} else if (!new_is_tmp) {
+	}
+
+	if (!new_is_tmp) {
 		/* Rename all constraints. */
 
 		info = pars_info_create();
@@ -4537,12 +4663,12 @@ end:
 		/* The following call will also rename the .ibd data file if
 		the table is stored in a single-table tablespace */
 
-		if (!dict_table_rename_in_cache(table, new_name,
-						!new_is_tmp)) {
+		err = dict_table_rename_in_cache(
+			table, new_name, !new_is_tmp);
+		if (err != DB_SUCCESS) {
 			trx->error_state = DB_SUCCESS;
 			trx_rollback_to_savepoint(trx, NULL);
 			trx->error_state = DB_SUCCESS;
-			err = DB_ERROR;
 			goto funct_exit;
 		}
 
@@ -4578,8 +4704,8 @@ end:
 				      stderr);
 			}
 
-			ut_a(dict_table_rename_in_cache(table,
-							old_name, FALSE));
+			ut_a(DB_SUCCESS == dict_table_rename_in_cache(
+				table, old_name, FALSE));
 			trx->error_state = DB_SUCCESS;
 			trx_rollback_to_savepoint(trx, NULL);
 			trx->error_state = DB_SUCCESS;

=== modified file 'storage/innobase/srv/srv0start.cc'
--- a/storage/innobase/srv/srv0start.cc	revid:andrei.elkin@stripped
+++ b/storage/innobase/srv/srv0start.cc	revid:kevin.lewis@stripped
@@ -717,6 +717,7 @@ open_or_create_data_files(
 	ibool		one_created	= FALSE;
 	os_offset_t	size;
 	ulint		flags;
+	ulint		space;
 	ulint		rounded_size_pages;
 	char		name[10000];
 
@@ -898,12 +899,19 @@ open_or_create_data_files(
 			}
 skip_size_check:
 			fil_read_first_page(
-				files[i], one_opened, &flags,
+				files[i], one_opened, &flags, &space,
 #ifdef UNIV_LOG_ARCHIVE
 				min_arch_log_no, max_arch_log_no,
 #endif /* UNIV_LOG_ARCHIVE */
 				min_flushed_lsn, max_flushed_lsn);
 
+			/* The first file of the system tablespace must
+			have space ID = 0.  The FSP_SPACE_ID field in files
+			greater than ibdata1 are unreliable. */
+			ut_a(one_opened || space == 0);
+
+			/* Check the flags for the first system tablespace
+			file only. */
 			if (!one_opened
 			    && UNIV_PAGE_SIZE
 			       != fsp_flags_get_page_size(flags)) {
@@ -2119,6 +2127,7 @@ innobase_start_or_create_for_mysql(void)
 		are initialized in trx_sys_init_at_db_start(). */
 
 		recv_recovery_from_checkpoint_finish();
+
 		if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) {
 			/* The following call is necessary for the insert
 			buffer to work with multiple tablespaces. We must
@@ -2240,12 +2249,16 @@ innobase_start_or_create_for_mysql(void)
 		srv_monitor_thread,
 		NULL, thread_ids + 4 + SRV_MAX_N_IO_THREADS);
 
-	srv_is_being_started = FALSE;
-
 	/* Create the SYS_FOREIGN and SYS_FOREIGN_COLS system tables */
 	err = dict_create_or_check_foreign_constraint_tables();
 	if (err != DB_SUCCESS) {
-		return(DB_ERROR);
+		return(err);
+	}
+
+	/* Create the SYS_TABLESPACES system table */
+	err = dict_create_or_check_sys_tablespace();
+	if (err != DB_SUCCESS) {
+		return(err);
 	}
 
 	srv_is_being_started = FALSE;

=== modified file 'storage/innobase/sync/sync0sync.cc'
--- a/storage/innobase/sync/sync0sync.cc	revid:andrei.elkin@stripped
+++ b/storage/innobase/sync/sync0sync.cc	revid:kevin.lewis@stripped
@@ -1534,7 +1534,7 @@ sync_close(void)
 
 		mutex_free(mutex);
 
-	        mutex = UT_LIST_GET_FIRST(mutex_list);
+		mutex = UT_LIST_GET_FIRST(mutex_list);
 	}
 
 	mutex_free(&mutex_list_mutex);

=== modified file 'storage/innobase/ut/ut0ut.cc'
--- a/storage/innobase/ut/ut0ut.cc	revid:andrei.elkin@stripped
+++ b/storage/innobase/ut/ut0ut.cc	revid:kevin.lewis@stripped
@@ -747,7 +747,7 @@ ut_strerr(
 		return("Cannot drop constraint");
 	case DB_NO_SAVEPOINT:
 		return("No such savepoint");
-	case DB_TABLESPACE_ALREADY_EXISTS:
+	case DB_TABLESPACE_EXISTS:
 		return("Tablespace already exists");
 	case DB_TABLESPACE_DELETED:
 		return("No such tablespace");

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (kevin.lewis:3802 to 3803) kevin.lewis21 May