List:Commits« Previous MessageNext Message »
From:kevin.lewis Date:April 6 2012 2:13pm
Subject:bzr push into mysql-trunk-wl5522 branch (kevin.lewis:3858 to 3859)
View as plain text  
 3859 kevin.lewis@stripped	2012-04-06 [merge]
      Commit worklog 5980 to the april labs release.

    added:
      mysql-test/r/partition_innodb_tablespace.result
      mysql-test/suite/innodb/r/innodb-tablespace.result
      mysql-test/suite/innodb/t/innodb-tablespace.test
      mysql-test/t/partition_innodb_tablespace.test
    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/handler.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/fsp0fsp.ic
      storage/innobase/include/mtr0mtr.h
      storage/innobase/include/os0file.h
      storage/innobase/include/row0merge.h
      storage/innobase/os/os0file.cc
      storage/innobase/row/row0import.cc
      storage/innobase/row/row0merge.cc
      storage/innobase/row/row0mysql.cc
      storage/innobase/srv/srv0start.cc
      storage/innobase/ut/ut0ut.cc
 3858 Vasil Dimov	2012-04-06
      Make sure stats are initialized in all cases in dict_stats_init().
      If the .ibd file was missing we would have left the stats non-initialized,
      causing an assert later in the code.
      
      Reported by:	Kevin (crash via ./mtr innodb-wl5522-debug)

    modified:
      storage/innobase/dict/dict0stats.cc
=== modified file 'include/my_base.h'
--- a/include/my_base.h	revid:vasil.dimov@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:vasil.dimov@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
 +--------------------+

=== added file 'mysql-test/r/partition_innodb_tablespace.result'
--- a/mysql-test/r/partition_innodb_tablespace.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/partition_innodb_tablespace.result	revid:kevin.lewis@stripped
@@ -0,0 +1,315 @@
+SET default_storage_engine=InnoDB;
+#
+# TABLESPACE related tests for the partition engine and InnoDB.
+#
+# The partition engine can send DATA DIRECTORY to InnoDB.
+# In strict mode, it is an error if innodb_file_per_table = OFF
+# or INDEX DIRECTORY is used.
+SET SESSION innodb_strict_mode = ON;
+SET GLOBAL innodb_file_per_table = OFF;
+CREATE TABLE t1 (a int KEY, b text) ENGINE = InnoDB PARTITION BY HASH (a)
+(PARTITION p0 engine=InnoDB DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data' INDEX DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data',
+PARTITION p1 engine=InnoDB DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data' INDEX DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data');
+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 './test/t1.par' (Errcode: 2 - No such file or directory)
+# Try again with innodb_file_per_table = ON and no INDEX DIRECTORY.
+SET GLOBAL innodb_file_per_table = ON;
+CREATE TABLE t1 (a int KEY, b text) ENGINE = InnoDB PARTITION BY HASH (a)
+(PARTITION p0 engine=InnoDB DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data',
+PARTITION p1 engine=InnoDB DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data2');
+SHOW WARNINGS;
+Level	Code	Message
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) NOT NULL,
+  `b` text,
+  PRIMARY KEY (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (a)
+(PARTITION p0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data' ENGINE = InnoDB,
+ PARTITION p1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data2' ENGINE = InnoDB) */
+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#p#p0	5	Antelope	Compact
+test/t1#p#p1	5	Antelope	Compact
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces;
+name	file_format	row_format
+test/t1#p#p0	Antelope	Compact or Redundant
+test/t1#p#p1	Antelope	Compact or Redundant
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQL_TMP_DIR/alternate_dir/data/test/t1#p#p0.ibd
+MYSQL_TMP_DIR/alternate_dir/data2/test/t1#p#p1.ibd
+# Verifying .frm, .par, .isl & .ibd files
+# Verifying that there are no MyISAM files
+# Test TRUNCATE TABLE with partitioned InnoDB tables
+INSERT INTO t1 VALUES (1, "red");
+INSERT INTO t1 VALUES (2, "green");
+INSERT INTO t1 VALUES (3, "blue");
+SELECT * FROM t1;
+a	b
+2	green
+1	red
+3	blue
+TRUNCATE TABLE t1;
+SELECT * FROM t1;
+a	b
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) NOT NULL,
+  `b` text,
+  PRIMARY KEY (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (a)
+(PARTITION p0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data' ENGINE = InnoDB,
+ PARTITION p1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data2' ENGINE = InnoDB) */
+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#p#p0	5	Antelope	Compact
+test/t1#p#p1	5	Antelope	Compact
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces;
+name	file_format	row_format
+test/t1#p#p0	Antelope	Compact or Redundant
+test/t1#p#p1	Antelope	Compact or Redundant
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQL_TMP_DIR/alternate_dir/data/test/t1#p#p0.ibd
+MYSQL_TMP_DIR/alternate_dir/data2/test/t1#p#p1.ibd
+# Verifying .frm, .par and MyISAM files (.MYD, MYI)
+# Test RENAME TABLE with partitioned InnoDB tables
+RENAME TABLE t1 TO t11;
+SHOW CREATE TABLE t11;
+Table	Create Table
+t11	CREATE TABLE `t11` (
+  `a` int(11) NOT NULL,
+  `b` text,
+  PRIMARY KEY (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (a)
+(PARTITION p0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data' ENGINE = InnoDB,
+ PARTITION p1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data2' ENGINE = InnoDB) */
+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/t11#p#p0	5	Antelope	Compact
+test/t11#p#p1	5	Antelope	Compact
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces;
+name	file_format	row_format
+test/t11#p#p0	Antelope	Compact or Redundant
+test/t11#p#p1	Antelope	Compact or Redundant
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQL_TMP_DIR/alternate_dir/data/test/t11#p#p0.ibd
+MYSQL_TMP_DIR/alternate_dir/data2/test/t11#p#p1.ibd
+# Verifying .frm, .par and MyISAM files (.MYD, MYI)
+DROP TABLE t11;
+# Test the previous DDL as a prepared statement.
+SET GLOBAL innodb_file_per_table = ON;
+PREPARE stmt1 FROM "CREATE TABLE t1 (a int KEY, b text)
+     ENGINE = InnoDB PARTITION BY HASH (a)
+     (PARTITION p0 engine=InnoDB DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data',
+      PARTITION p1 engine=InnoDB DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data2')";
+EXECUTE stmt1;
+SHOW WARNINGS;
+Level	Code	Message
+DEALLOCATE PREPARE stmt1;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) NOT NULL,
+  `b` text,
+  PRIMARY KEY (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY HASH (a)
+(PARTITION p0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data' ENGINE = InnoDB,
+ PARTITION p1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data2' ENGINE = InnoDB) */
+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#p#p0	5	Antelope	Compact
+test/t1#p#p1	5	Antelope	Compact
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces;
+name	file_format	row_format
+test/t1#p#p0	Antelope	Compact or Redundant
+test/t1#p#p1	Antelope	Compact or Redundant
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQL_TMP_DIR/alternate_dir/data/test/t1#p#p0.ibd
+MYSQL_TMP_DIR/alternate_dir/data2/test/t1#p#p1.ibd
+DROP TABLE t1;
+# Test DATA DIRECTORY with Sub-partitions.
+SET GLOBAL innodb_file_per_table = ON;
+CREATE TABLE t1 (id INT, purchased DATE) engine=InnoDB
+PARTITION BY RANGE( YEAR(purchased) )
+SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
+PARTITION p0 VALUES LESS THAN (1990) (
+SUBPARTITION s0 DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data',
+SUBPARTITION s1 DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data2'
+),
+PARTITION p1 VALUES LESS THAN (2000) (
+SUBPARTITION s2 DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data',
+SUBPARTITION s3 DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data2'
+),
+PARTITION p2 VALUES LESS THAN MAXVALUE (
+SUBPARTITION s4 DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data',
+SUBPARTITION s5 DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data2'
+)
+);
+SHOW WARNINGS;
+Level	Code	Message
+INSERT INTO t1 VALUES(1,'1980-05-31');
+INSERT INTO t1 VALUES(2,'2090-05-31');
+INSERT INTO t1 VALUES(3,'2012-05-31');
+INSERT INTO t1 VALUES(4,'1970-05-31');
+INSERT INTO t1 VALUES(5,'1985-05-31');
+INSERT INTO t1 VALUES(6,'2006-05-31');
+SELECT * FROM t1;
+id	purchased
+4	1970-05-31
+1	1980-05-31
+5	1985-05-31
+2	2090-05-31
+3	2012-05-31
+6	2006-05-31
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `id` int(11) DEFAULT NULL,
+  `purchased` date DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE ( YEAR(purchased))
+SUBPARTITION BY HASH ( TO_DAYS(purchased))
+(PARTITION p0 VALUES LESS THAN (1990)
+ (SUBPARTITION s0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data' ENGINE = InnoDB,
+  SUBPARTITION s1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data2' ENGINE = InnoDB),
+ PARTITION p1 VALUES LESS THAN (2000)
+ (SUBPARTITION s2 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data' ENGINE = InnoDB,
+  SUBPARTITION s3 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data2' ENGINE = InnoDB),
+ PARTITION p2 VALUES LESS THAN MAXVALUE
+ (SUBPARTITION s4 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data' ENGINE = InnoDB,
+  SUBPARTITION s5 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data2' ENGINE = InnoDB)) */
+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#p#p0#sp#s0	5	Antelope	Compact
+test/t1#p#p0#sp#s1	5	Antelope	Compact
+test/t1#p#p1#sp#s2	5	Antelope	Compact
+test/t1#p#p1#sp#s3	5	Antelope	Compact
+test/t1#p#p2#sp#s4	5	Antelope	Compact
+test/t1#p#p2#sp#s5	5	Antelope	Compact
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces;
+name	file_format	row_format
+test/t1#p#p0#sp#s0	Antelope	Compact or Redundant
+test/t1#p#p0#sp#s1	Antelope	Compact or Redundant
+test/t1#p#p1#sp#s2	Antelope	Compact or Redundant
+test/t1#p#p1#sp#s3	Antelope	Compact or Redundant
+test/t1#p#p2#sp#s4	Antelope	Compact or Redundant
+test/t1#p#p2#sp#s5	Antelope	Compact or Redundant
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQL_TMP_DIR/alternate_dir/data/test/t1#p#p0#sp#s0.ibd
+MYSQL_TMP_DIR/alternate_dir/data2/test/t1#p#p0#sp#s1.ibd
+MYSQL_TMP_DIR/alternate_dir/data/test/t1#p#p1#sp#s2.ibd
+MYSQL_TMP_DIR/alternate_dir/data2/test/t1#p#p1#sp#s3.ibd
+MYSQL_TMP_DIR/alternate_dir/data/test/t1#p#p2#sp#s4.ibd
+MYSQL_TMP_DIR/alternate_dir/data2/test/t1#p#p2#sp#s5.ibd
+# Verifying .frm, .par, .isl & .ibd files
+DROP TABLE t1;
+# Same as above except with ROW_FORMAT=Dyamic.
+SET GLOBAL innodb_file_format = Barracuda;
+SET GLOBAL innodb_file_per_table = ON;
+CREATE TABLE t1 (id INT, purchased DATE)
+engine = innodb row_format = dynamic
+PARTITION BY RANGE( YEAR(purchased) )
+SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
+PARTITION p0 VALUES LESS THAN (1990) (
+SUBPARTITION s0 DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data',
+SUBPARTITION s1 DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data2'
+),
+PARTITION p1 VALUES LESS THAN (2000) (
+SUBPARTITION s2 DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data',
+SUBPARTITION s3 DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data2'
+),
+PARTITION p2 VALUES LESS THAN MAXVALUE (
+SUBPARTITION s4 DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data',
+SUBPARTITION s5 DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/data2'
+)
+);
+SHOW WARNINGS;
+Level	Code	Message
+INSERT INTO t1 VALUES(1,'1980-05-31');
+INSERT INTO t1 VALUES(2,'2090-05-31');
+INSERT INTO t1 VALUES(3,'2012-05-31');
+INSERT INTO t1 VALUES(4,'1970-05-31');
+INSERT INTO t1 VALUES(5,'1985-05-31');
+INSERT INTO t1 VALUES(6,'2006-05-31');
+SELECT * FROM t1;
+id	purchased
+4	1970-05-31
+1	1980-05-31
+5	1985-05-31
+2	2090-05-31
+3	2012-05-31
+6	2006-05-31
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `id` int(11) DEFAULT NULL,
+  `purchased` date DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+/*!50100 PARTITION BY RANGE ( YEAR(purchased))
+SUBPARTITION BY HASH ( TO_DAYS(purchased))
+(PARTITION p0 VALUES LESS THAN (1990)
+ (SUBPARTITION s0 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data' ENGINE = InnoDB,
+  SUBPARTITION s1 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data2' ENGINE = InnoDB),
+ PARTITION p1 VALUES LESS THAN (2000)
+ (SUBPARTITION s2 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data' ENGINE = InnoDB,
+  SUBPARTITION s3 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data2' ENGINE = InnoDB),
+ PARTITION p2 VALUES LESS THAN MAXVALUE
+ (SUBPARTITION s4 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data' ENGINE = InnoDB,
+  SUBPARTITION s5 DATA DIRECTORY = 'MYSQL_TMP_DIR/alternate_dir/data2' ENGINE = InnoDB)) */
+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#p#p0#sp#s0	5	Barracuda	Dynamic
+test/t1#p#p0#sp#s1	5	Barracuda	Dynamic
+test/t1#p#p1#sp#s2	5	Barracuda	Dynamic
+test/t1#p#p1#sp#s3	5	Barracuda	Dynamic
+test/t1#p#p2#sp#s4	5	Barracuda	Dynamic
+test/t1#p#p2#sp#s5	5	Barracuda	Dynamic
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces;
+name	file_format	row_format
+test/t1#p#p0#sp#s0	Barracuda	Dynamic
+test/t1#p#p0#sp#s1	Barracuda	Dynamic
+test/t1#p#p1#sp#s2	Barracuda	Dynamic
+test/t1#p#p1#sp#s3	Barracuda	Dynamic
+test/t1#p#p2#sp#s4	Barracuda	Dynamic
+test/t1#p#p2#sp#s5	Barracuda	Dynamic
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQL_TMP_DIR/alternate_dir/data/test/t1#p#p0#sp#s0.ibd
+MYSQL_TMP_DIR/alternate_dir/data2/test/t1#p#p0#sp#s1.ibd
+MYSQL_TMP_DIR/alternate_dir/data/test/t1#p#p1#sp#s2.ibd
+MYSQL_TMP_DIR/alternate_dir/data2/test/t1#p#p1#sp#s3.ibd
+MYSQL_TMP_DIR/alternate_dir/data/test/t1#p#p2#sp#s4.ibd
+MYSQL_TMP_DIR/alternate_dir/data2/test/t1#p#p2#sp#s5.ibd
+# Verifying .frm, .par, .isl & .ibd files
+#
+# Cleanup
+#
+DROP TABLE t1;

=== modified file 'mysql-test/suite/innodb/r/innodb-restart.result'
--- a/mysql-test/suite/innodb/r/innodb-restart.result	revid:vasil.dimov@stripped
+++ b/mysql-test/suite/innodb/r/innodb-restart.result	revid:kevin.lewis@stripped
@@ -1,4 +1,8 @@
+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 TABLE t1(c1 DOUBLE AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
@@ -8,6 +12,19 @@ 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 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 +32,19 @@ 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 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 +52,19 @@ 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 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 +72,69 @@ 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;
+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
+#
+# Test that the DATA DIRECTORY is visible after restart.
+#
+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/alternate_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/alternate_dir/'
+SELECT count(*) FROM t5;
+count(*)
+16
+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
+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
+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
+MYSQL_TMP_DIR/alternate_dir/test/t5.ibd
 # Restart the server
+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 +175,197 @@ 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/alternate_dir/'
 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);
+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 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
+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
+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
+MYSQL_TMP_DIR/alternate_dir/test/t5.ibd
 DROP TABLE t1;
 DROP TABLE t2;
 DROP TABLE t3;
 DROP TABLE t4;
+#
+# Truncate the remote tablespace and restart.
+#
+TRUNCATE TABLE t5;
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQL_TMP_DIR/alternate_dir/test/t5.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);
+SELECT count(*) FROM t5;
+count(*)
+2
+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=1000000002 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/'
+# 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;
+path
+MYSQL_TMP_DIR/alternate_dir/test/t5.ibd
+INSERT INTO t5 (SELECT 0, c2, c3, c4, c5 FROM t5);
+SELECT count(*) FROM t5;
+count(*)
+4
+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=1000000005 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/'
+#
+# Rename file table and tablespace, then restart
+#
+RENAME TABLE t5 TO t55;
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQL_TMP_DIR/alternate_dir/test/t55.ibd
+INSERT INTO t55 (SELECT 0, c2, c3, c4, c5 FROM t55);
+SELECT count(*) FROM t55;
+count(*)
+8
+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=1000000012 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/'
+# 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;
+path
+MYSQL_TMP_DIR/alternate_dir/test/t55.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/alternate_dir/'
+# Restart the server
+#
+# Move the remote tablespace to a new location and change the ISL file
+#
+# Copying tablespace to new_dir
+# Restart the server
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQL_TMP_DIR/new_dir/test/t55.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/new_dir/'
+# Restart the server
+#
+# Move the remote tablespace back to the default datadir and delete the ISL file.
+#
+FLUSH TABLE t55 WITH READ LOCK;
+# Copying tablespace to default datadir
+UNLOCK TABLES;
+# Restart the server
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQLD_DATADIR/test/t55.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
+DROP TABLE t55;
+#
+# Cleanup
+#

=== modified file 'mysql-test/suite/innodb/r/innodb-system-table-view.result'
--- a/mysql-test/suite/innodb/r/innodb-system-table-view.result	revid:vasil.dimov@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

=== added file 'mysql-test/suite/innodb/r/innodb-tablespace.result'
--- a/mysql-test/suite/innodb/r/innodb-tablespace.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/r/innodb-tablespace.result	revid:kevin.lewis@stripped
@@ -0,0 +1,457 @@
+SET default_storage_engine=InnoDB;
+#
+# TABLESPACE related tests.
+#
+#
+# CREATE TABLE ... DATA DIRECTORY
+#
+# Innodb does not support INDEX DIRECTORY.
+SET SESSION innodb_strict_mode = ON;
+CREATE TABLE t1 (a int KEY, b text) INDEX DIRECTORY='MYSQL_TMP_DIR/alternate_dir';
+ERROR HY000: Can't create table 'test.t1' (errno: 1478)
+SHOW WARNINGS;
+Level	Code	Message
+Warning	1478	InnoDB: INDEX DIRECTORY is not supported
+Error	1005	Can't create table 'test.t1' (errno: 1478)
+# Without strict mode, INDEX DIRECTORY is just ignored
+SET SESSION innodb_strict_mode = OFF;
+CREATE TABLE t1 (a int KEY, b text) INDEX DIRECTORY='MYSQL_TMP_DIR/alternate_dir';
+Warnings:
+Warning	1618	<INDEX DIRECTORY> option ignored
+SHOW WARNINGS;
+Level	Code	Message
+Warning	1618	<INDEX DIRECTORY> option ignored
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) NOT NULL,
+  `b` text,
+  PRIMARY KEY (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+# Innodb does not support DATA DIRECTORY without innodb_file_per_table=ON.
+SET SESSION innodb_strict_mode = ON;
+SET GLOBAL innodb_file_per_table=OFF;
+CREATE TABLE t1 (a int KEY, b text) DATA DIRECTORY='MYSQL_TMP_DIR/alternate_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.
+Error	1005	Can't create table 'test.t1' (errno: 1478)
+# Without strict mode, DATA DIRECTORY without innodb_file_per_table=ON is just ignored.
+SET SESSION innodb_strict_mode = OFF;
+CREATE TABLE t1 (a int KEY, b text) DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir';
+Warnings:
+Warning	1478	InnoDB: DATA DIRECTORY requires innodb_file_per_table.
+Warning	1618	<DATA DIRECTORY> option ignored
+SHOW WARNINGS;
+Level	Code	Message
+Warning	1478	InnoDB: DATA DIRECTORY requires innodb_file_per_table.
+Warning	1618	<DATA DIRECTORY> option ignored
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) NOT NULL,
+  `b` text,
+  PRIMARY KEY (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+# Now set innodb_file_per_table so that DATA DIRECTORY can be tested.
+SET GLOBAL innodb_file_per_table=ON;
+# Create the tablespace in MYSQL_TMP_DIR/alternate_dir
+# InnoDB will create the sub-directories if needed.
+CREATE TABLE t1 (a int KEY, b text) DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir';
+SHOW WARNINGS;
+Level	Code	Message
+INSERT INTO t1 VALUES (1, "Create the tablespace");
+SELECT * FROM t1;
+a	b
+1	Create the tablespace
+# Check if tablespace file exists where we specified in DATA DIRECTORY
+# Check if link file exists  in MYSQLD_DATADIR
+# Check that DATA DIRECTORY shows up in the SHOW CREATE TABLE results.
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) NOT NULL,
+  `b` text,
+  PRIMARY KEY (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/'
+# Show that the new system tables have this table in them correctly
+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	5	Antelope	Compact
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces;
+name	file_format	row_format
+test/t1	Antelope	Compact or Redundant
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQL_TMP_DIR/alternate_dir/test/t1.ibd
+# Show that the system tables are updated on drop table
+DROP TABLE t1;
+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
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces;
+name	file_format	row_format
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+# Create the same table a second time in the same place
+CREATE TABLE t1 (a int KEY, b text) DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir';
+INSERT INTO t1 VALUES (2, "Create the same table a second time in the same place");
+SELECT * FROM t1;
+a	b
+2	Create the same table a second time in the same place
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) NOT NULL,
+  `b` text,
+  PRIMARY KEY (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/'
+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	5	Antelope	Compact
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces;
+name	file_format	row_format
+test/t1	Antelope	Compact or Redundant
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQL_TMP_DIR/alternate_dir/test/t1.ibd
+# Truncate the table, then insert and verify
+TRUNCATE TABLE t1;
+INSERT INTO t1 VALUES (3, "Truncate the table, then insert");
+SELECT * FROM t1;
+a	b
+3	Truncate the table, then insert
+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	5	Antelope	Compact
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces;
+name	file_format	row_format
+test/t1	Antelope	Compact or Redundant
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQL_TMP_DIR/alternate_dir/test/t1.ibd
+# Rename the table, then insert and verify
+RENAME TABLE t1 TO t2;
+INSERT INTO t2 VALUES (4, "Rename the table, then insert");
+SELECT * FROM t2;
+a	b
+3	Truncate the table, then insert
+4	Rename the table, then insert
+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/t2	5	Antelope	Compact
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces;
+name	file_format	row_format
+test/t2	Antelope	Compact or Redundant
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQL_TMP_DIR/alternate_dir/test/t2.ibd
+# CREATE TABLE LIKE does not retain DATA DIRECTORY automatically.
+CREATE TABLE t3 LIKE t2;
+INSERT INTO t3 VALUES (5, "CREATE TABLE LIKE");
+SELECT * FROM t3;
+a	b
+5	CREATE TABLE LIKE
+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/t2	5	Antelope	Compact
+test/t3	5	Antelope	Compact
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces;
+name	file_format	row_format
+test/t2	Antelope	Compact or Redundant
+test/t3	Antelope	Compact or Redundant
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQL_TMP_DIR/alternate_dir/test/t2.ibd
+MYSQLD_DATADIR/test/t3.ibd
+# Now make sure the tables can be fully dropped.
+DROP TABLE t2, t3;
+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
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces;
+name	file_format	row_format
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+# Be sure SQL MODE "NO_DIR_IN_CREATE" prevents the use of DATA DIRECTORY
+SET @org_mode=@@sql_mode;
+SET @@sql_mode='NO_DIR_IN_CREATE';
+SELECT @@sql_mode;
+@@sql_mode
+NO_DIR_IN_CREATE
+CREATE TABLE t1 (a int, b text) DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir';
+Warnings:
+Warning	1618	<DATA DIRECTORY> option ignored
+SHOW WARNINGS;
+Level	Code	Message
+Warning	1618	<DATA DIRECTORY> option ignored
+INSERT INTO t1 VALUES (6, "SQL MODE NO_DIR_IN_CREATE prevents DATA DIRECTORY");
+DROP TABLE t1;
+set @@sql_mode=@org_mode;
+# MySQL engine does not allow DATA DIRECTORY to be
+# within --datadir for any engine, including InnoDB
+CREATE TABLE t1 (a int KEY, b text) DATA DIRECTORY 'MYSQLD_DATADIR/test';
+ERROR HY000: Incorrect arguments to DATA DIRECTORY
+# TEMPORARY tables are incompatible with DATA DIRECTORY
+SET SESSION innodb_strict_mode = ON;
+CREATE TEMPORARY TABLE t1 (a int KEY, b text) engine=InnoDB DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir';
+ERROR HY000: Can't create table 'test.t1' (errno: 1478)
+SHOW WARNINGS;
+Level	Code	Message
+Warning	1478	InnoDB: DATA DIRECTORY cannot be used for TEMPORARY tables.
+Error	1005	Can't create table 'test.t1' (errno: 1478)
+SET SESSION innodb_strict_mode = OFF;
+CREATE TEMPORARY TABLE t1 (a int KEY, b text) engine=InnoDB DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir';
+Warnings:
+Warning	1478	InnoDB: DATA DIRECTORY cannot be used for TEMPORARY tables.
+Warning	1618	<DATA DIRECTORY> option ignored
+SHOW WARNINGS;
+Level	Code	Message
+Warning	1478	InnoDB: DATA DIRECTORY cannot be used for TEMPORARY tables.
+Warning	1618	<DATA DIRECTORY> option ignored
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TEMPORARY TABLE `t1` (
+  `a` int(11) NOT NULL,
+  `b` text,
+  PRIMARY KEY (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+# Create the remote table via static DDL statements in a stored procedure
+CREATE PROCEDURE static_proc() BEGIN CREATE TABLE t1 (a int KEY, b text) DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir'; END |
+CALL static_proc;
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQL_TMP_DIR/alternate_dir/test/t1.ibd
+INSERT INTO t1 VALUES (7, "Create the remote table via static DDL statements");
+SELECT * FROM t1;
+a	b
+7	Create the remote table via static DDL statements
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) NOT NULL,
+  `b` text,
+  PRIMARY KEY (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/'
+DROP PROCEDURE static_proc;
+DROP TABLE t1;
+# Create the remote table via dynamic DDL statements in a stored procedure
+CREATE PROCEDURE dynamic_proc() BEGIN PREPARE stmt1 FROM "CREATE TABLE t1 (a int KEY, b text) DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir'"; EXECUTE stmt1; END |
+CALL dynamic_proc;
+SELECT path FROM information_schema.innodb_sys_datafiles;
+path
+MYSQL_TMP_DIR/alternate_dir/test/t1.ibd
+INSERT INTO t1 VALUES (8, "Create the remote table via dynamic DDL statements");
+SELECT * FROM t1;
+a	b
+8	Create the remote table via dynamic DDL statements
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) NOT NULL,
+  `b` text,
+  PRIMARY KEY (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQL_TMP_DIR/alternate_dir/'
+DROP PROCEDURE dynamic_proc;
+DROP TABLE t1;
+#
+# CREATE, DROP, ADD and TRUNCATE PARTITION with DATA DIRECTORY
+#
+CREATE TABLE emp (
+id INT NOT NULL,
+store_name VARCHAR(30),
+parts VARCHAR(30),
+store_id INT
+)
+PARTITION BY LIST(store_id) (
+PARTITION east VALUES IN (10,20,30)
+DATA DIRECTORY = 'MYSQL_TMP_DIR/alt-dir-east',
+PARTITION north VALUES IN (40,50,60)
+DATA DIRECTORY = 'MYSQL_TMP_DIR/alt-dir-north',
+PARTITION west VALUES IN (70,80,100)
+DATA DIRECTORY = 'MYSQL_TMP_DIR/alt-dir-west'
+);
+INSERT INTO emp values(1,'Oracle','NUTT',10);
+INSERT INTO emp values(2,'HUAWEI','BOLT',40);
+INSERT INTO emp values(3,'IBM','NAIL',70);
+SHOW CREATE TABLE emp;
+Table	Create Table
+emp	CREATE TABLE `emp` (
+  `id` int(11) NOT NULL,
+  `store_name` varchar(30) DEFAULT NULL,
+  `parts` varchar(30) DEFAULT NULL,
+  `store_id` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (store_id)
+(PARTITION east VALUES IN (10,20,30) DATA DIRECTORY = 'MYSQL_TMP_DIR/alt-dir-east' ENGINE = InnoDB,
+ PARTITION north VALUES IN (40,50,60) DATA DIRECTORY = 'MYSQL_TMP_DIR/alt-dir-north' ENGINE = InnoDB,
+ PARTITION west VALUES IN (70,80,100) DATA DIRECTORY = 'MYSQL_TMP_DIR/alt-dir-west' ENGINE = InnoDB) */
+SELECT name,n_cols,file_format,row_format
+FROM information_schema.innodb_sys_tables
+WHERE name LIKE 'test%'
+       ORDER BY name;
+name	n_cols	file_format	row_format
+test/emp#p#east	7	Antelope	Compact
+test/emp#p#north	7	Antelope	Compact
+test/emp#p#west	7	Antelope	Compact
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces
+ORDER BY name;
+name	file_format	row_format
+test/emp#p#east	Antelope	Compact or Redundant
+test/emp#p#north	Antelope	Compact or Redundant
+test/emp#p#west	Antelope	Compact or Redundant
+SELECT path FROM information_schema.innodb_sys_datafiles
+ORDER BY path;
+path
+MYSQL_TMP_DIR/alt-dir-east/test/emp#p#east.ibd
+MYSQL_TMP_DIR/alt-dir-north/test/emp#p#north.ibd
+MYSQL_TMP_DIR/alt-dir-west/test/emp#p#west.ibd
+SELECT * FROM emp;
+id	store_name	parts	store_id
+1	Oracle	NUTT	10
+2	HUAWEI	BOLT	40
+3	IBM	NAIL	70
+# DROP one PARTITION.
+ALTER TABLE emp DROP PARTITION west;
+SHOW CREATE TABLE emp;
+Table	Create Table
+emp	CREATE TABLE `emp` (
+  `id` int(11) NOT NULL,
+  `store_name` varchar(30) DEFAULT NULL,
+  `parts` varchar(30) DEFAULT NULL,
+  `store_id` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (store_id)
+(PARTITION east VALUES IN (10,20,30) DATA DIRECTORY = 'MYSQL_TMP_DIR/alt-dir-east' ENGINE = InnoDB,
+ PARTITION north VALUES IN (40,50,60) DATA DIRECTORY = 'MYSQL_TMP_DIR/alt-dir-north' ENGINE = InnoDB) */
+SELECT name,n_cols,file_format,row_format
+FROM information_schema.innodb_sys_tables
+WHERE name LIKE 'test%'
+       ORDER BY name;
+name	n_cols	file_format	row_format
+test/emp#p#east	7	Antelope	Compact
+test/emp#p#north	7	Antelope	Compact
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces
+ORDER BY name;
+name	file_format	row_format
+test/emp#p#east	Antelope	Compact or Redundant
+test/emp#p#north	Antelope	Compact or Redundant
+SELECT path FROM information_schema.innodb_sys_datafiles
+ORDER BY path;
+path
+MYSQL_TMP_DIR/alt-dir-east/test/emp#p#east.ibd
+MYSQL_TMP_DIR/alt-dir-north/test/emp#p#north.ibd
+SELECT * FROM emp;
+id	store_name	parts	store_id
+1	Oracle	NUTT	10
+2	HUAWEI	BOLT	40
+# ADD the PARTITION back.
+ALTER TABLE emp ADD PARTITION (
+PARTITION west VALUES IN (70,80,100)
+DATA DIRECTORY = 'MYSQL_TMP_DIR/alt-dir-west');
+SHOW CREATE TABLE emp;
+Table	Create Table
+emp	CREATE TABLE `emp` (
+  `id` int(11) NOT NULL,
+  `store_name` varchar(30) DEFAULT NULL,
+  `parts` varchar(30) DEFAULT NULL,
+  `store_id` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (store_id)
+(PARTITION east VALUES IN (10,20,30) DATA DIRECTORY = 'MYSQL_TMP_DIR/alt-dir-east' ENGINE = InnoDB,
+ PARTITION north VALUES IN (40,50,60) DATA DIRECTORY = 'MYSQL_TMP_DIR/alt-dir-north' ENGINE = InnoDB,
+ PARTITION west VALUES IN (70,80,100) DATA DIRECTORY = 'MYSQL_TMP_DIR/alt-dir-west' ENGINE = InnoDB) */
+SELECT name,n_cols,file_format,row_format
+FROM information_schema.innodb_sys_tables
+WHERE name LIKE 'test%'
+       ORDER BY name;
+name	n_cols	file_format	row_format
+test/emp#p#east	7	Antelope	Compact
+test/emp#p#north	7	Antelope	Compact
+test/emp#p#west	7	Antelope	Compact
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces
+ORDER BY name;
+name	file_format	row_format
+test/emp#p#east	Antelope	Compact or Redundant
+test/emp#p#north	Antelope	Compact or Redundant
+test/emp#p#west	Antelope	Compact or Redundant
+SELECT path FROM information_schema.innodb_sys_datafiles
+ORDER BY path;
+path
+MYSQL_TMP_DIR/alt-dir-east/test/emp#p#east.ibd
+MYSQL_TMP_DIR/alt-dir-north/test/emp#p#north.ibd
+MYSQL_TMP_DIR/alt-dir-west/test/emp#p#west.ibd
+INSERT INTO emp VALUES(3,'IBM','NAIL',70);
+SELECT * FROM emp;
+id	store_name	parts	store_id
+1	Oracle	NUTT	10
+2	HUAWEI	BOLT	40
+3	IBM	NAIL	70
+# TRUNCATE one PARTITION.
+ALTER TABLE emp TRUNCATE PARTITION west;
+SHOW CREATE TABLE emp;
+Table	Create Table
+emp	CREATE TABLE `emp` (
+  `id` int(11) NOT NULL,
+  `store_name` varchar(30) DEFAULT NULL,
+  `parts` varchar(30) DEFAULT NULL,
+  `store_id` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (store_id)
+(PARTITION east VALUES IN (10,20,30) DATA DIRECTORY = 'MYSQL_TMP_DIR/alt-dir-east' ENGINE = InnoDB,
+ PARTITION north VALUES IN (40,50,60) DATA DIRECTORY = 'MYSQL_TMP_DIR/alt-dir-north' ENGINE = InnoDB,
+ PARTITION west VALUES IN (70,80,100) DATA DIRECTORY = 'MYSQL_TMP_DIR/alt-dir-west' ENGINE = InnoDB) */
+SELECT name,n_cols,file_format,row_format
+FROM information_schema.innodb_sys_tables
+WHERE name LIKE 'test%'
+       ORDER BY name;
+name	n_cols	file_format	row_format
+test/emp#p#east	7	Antelope	Compact
+test/emp#p#north	7	Antelope	Compact
+test/emp#p#west	7	Antelope	Compact
+SELECT name,file_format,row_format
+FROM information_schema.innodb_sys_tablespaces
+ORDER BY name;
+name	file_format	row_format
+test/emp#p#east	Antelope	Compact or Redundant
+test/emp#p#north	Antelope	Compact or Redundant
+test/emp#p#west	Antelope	Compact or Redundant
+SELECT path FROM information_schema.innodb_sys_datafiles
+ORDER BY path;
+path
+MYSQL_TMP_DIR/alt-dir-east/test/emp#p#east.ibd
+MYSQL_TMP_DIR/alt-dir-north/test/emp#p#north.ibd
+MYSQL_TMP_DIR/alt-dir-west/test/emp#p#west.ibd
+SELECT * FROM emp;
+id	store_name	parts	store_id
+1	Oracle	NUTT	10
+2	HUAWEI	BOLT	40
+INSERT INTO emp VALUES(3,'IBM','NAIL',70);
+SELECT * FROM emp;
+id	store_name	parts	store_id
+1	Oracle	NUTT	10
+2	HUAWEI	BOLT	40
+3	IBM	NAIL	70
+DROP TABLE emp;
+#
+# Cleanup
+#

=== modified file 'mysql-test/suite/innodb/r/innodb_16k.result'
--- a/mysql-test/suite/innodb/r/innodb_16k.result	revid:vasil.dimov@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:vasil.dimov@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:vasil.dimov@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:vasil.dimov@stripped
+++ b/mysql-test/suite/innodb/t/innodb-restart.test	revid:kevin.lewis@stripped
@@ -2,20 +2,26 @@
 # 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/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/alternate_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';
@@ -27,6 +33,8 @@ 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;
 
 CREATE TABLE t2(c1 DOUBLE AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
 	ROW_FORMAT=COMPACT  ENGINE=InnoDB;
@@ -35,7 +43,8 @@ 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;
 
 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;
@@ -44,6 +53,8 @@ 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;
 
 CREATE TABLE t4(c1 DOUBLE AUTO_INCREMENT KEY, c2 CHAR(10), c3 VARCHAR(100), c4 DATE, c5 TEXT)
 	ROW_FORMAT=DYNAMIC  ENGINE=InnoDB;
@@ -52,24 +63,193 @@ 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 #
+--echo # Test that the DATA DIRECTORY is visible after restart.
+--echo #
+--mkdir $MYSQL_TMP_DIR/alternate_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;
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name like 'test%';
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+--replace_result ./ MYSQLD_DATADIR/  $MYSQLD_DATADIR MYSQLD_DATADIR  $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+
+
+--echo # Restart the server
+--source include/restart_mysqld.inc
+SHOW VARIABLES LIKE 'innodb_file_per_table';
 
--- echo # Restart the server
--- source include/restart_mysqld.inc
 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;
 
 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);
+
+SELECT count(*) FROM t1;
+SELECT count(*) FROM t2;
+SELECT count(*) FROM t3;
+SELECT count(*) FROM t4;
+SELECT count(*) FROM t5;
+
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name like 'test%';
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+--replace_result ./ MYSQLD_DATADIR/  $MYSQLD_DATADIR MYSQLD_DATADIR  $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
 
 DROP TABLE t1;
 DROP TABLE t2;
 DROP TABLE t3;
 DROP TABLE t4;
 
+--echo #
+--echo # Truncate the remote tablespace and restart.
+--echo #
+TRUNCATE TABLE t5;
+
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+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);
+SELECT count(*) FROM t5;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t5;
+--file_exists $MYSQLD_DATADIR/test/t5.frm
+--file_exists $MYSQLD_DATADIR/test/t5.isl
+--file_exists $MYSQL_TMP_DIR/alternate_dir/test/t5.ibd
+
+--echo # Restart the server
+--source include/restart_mysqld.inc
+SHOW VARIABLES LIKE 'innodb_file_per_table';
+
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+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;
+--file_exists $MYSQLD_DATADIR/test/t5.frm
+--file_exists $MYSQLD_DATADIR/test/t5.isl
+--file_exists $MYSQL_TMP_DIR/alternate_dir/test/t5.ibd
+
+--echo #
+--echo # Rename file table and tablespace, then restart
+--echo #
+RENAME TABLE t5 TO t55;
+
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+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;
+--file_exists $MYSQLD_DATADIR/test/t55.frm
+--file_exists $MYSQLD_DATADIR/test/t55.isl
+--file_exists $MYSQL_TMP_DIR/alternate_dir/test/t55.ibd
+
+--echo # Restart the server
+--source include/restart_mysqld.inc
+SHOW VARIABLES LIKE 'innodb_file_per_table';
+
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+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;
+--file_exists $MYSQLD_DATADIR/test/t55.frm
+--file_exists $MYSQLD_DATADIR/test/t55.isl
+--file_exists $MYSQL_TMP_DIR/alternate_dir/test/t55.ibd
+--echo # Restart the server
+--source include/restart_mysqld.inc
+
+--echo #
+--echo # Move the remote tablespace to a new location and change the ISL file
+--echo #
+--mkdir $MYSQL_TMP_DIR/new_dir
+--mkdir $MYSQL_TMP_DIR/new_dir/test
+--echo # Copying tablespace to new_dir
+--copy_file $MYSQL_TMP_DIR/alternate_dir/test/t55.ibd $MYSQL_TMP_DIR/new_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 # Restart the server
+--source include/restart_mysqld.inc
+
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+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;
+--file_exists $MYSQLD_DATADIR/test/t55.frm
+--file_exists $MYSQLD_DATADIR/test/t55.isl
+--file_exists $MYSQL_TMP_DIR/new_dir/test/t55.ibd
+--file_exists $MYSQL_TMP_DIR/alternate_dir/test/t55.ibd
+--remove_file $MYSQL_TMP_DIR/alternate_dir/test/t55.ibd
+--error 1
+--file_exists $MYSQL_TMP_DIR/alternate_dir/test/t55.ibd
+--echo # Restart the server
+--source include/restart_mysqld.inc
+
+--echo #
+--echo # Move the remote tablespace back to the default datadir and delete the ISL file.
+--echo #
+FLUSH TABLE t55 WITH READ LOCK;
+--echo # Copying tablespace to default datadir
+--copy_file $MYSQL_TMP_DIR/new_dir/test/t55.ibd $MYSQLD_DATADIR/test/t55.ibd
+UNLOCK TABLES;
+--remove_file $MYSQLD_DATADIR/test/t55.isl
+--file_exists $MYSQL_TMP_DIR/new_dir/test/t55.ibd
+--file_exists $MYSQLD_DATADIR/test/t55.ibd
+
+-- echo # Restart the server
+-- source include/restart_mysqld.inc
+
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR ./ MYSQLD_DATADIR/
+SELECT path FROM information_schema.innodb_sys_datafiles;
+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;
+--file_exists $MYSQLD_DATADIR/test/t55.frm
+--file_exists $MYSQLD_DATADIR/test/t55.ibd
+--error 1
+--file_exists $MYSQLD_DATADIR/test/t55.isl
+
+DROP TABLE t55;
+
+--echo #
+--echo # Cleanup
+--echo #
+
+--file_exists $MYSQL_TMP_DIR/new_dir/test/t55.ibd
+--remove_file $MYSQL_TMP_DIR/new_dir/test/t55.ibd
+--rmdir $MYSQL_TMP_DIR/alternate_dir/test
+--rmdir $MYSQL_TMP_DIR/alternate_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:vasil.dimov@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
+

=== added file 'mysql-test/suite/innodb/t/innodb-tablespace.test'
--- a/mysql-test/suite/innodb/t/innodb-tablespace.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/t/innodb-tablespace.test	revid:kevin.lewis@stripped
@@ -0,0 +1,414 @@
+#
+# A series of tests to show the correct tablespace behavior.
+# See also; parts.partition_basic_symlink_innodb.test for
+# partition related tests with remote tablespaces.
+# See innodb.innodb-restart for tablespace migration tests.
+#
+--source include/have_innodb.inc
+SET default_storage_engine=InnoDB;
+
+--echo #
+--echo # TABLESPACE related tests.
+--echo #
+
+# Set up some variables
+LET $MYSQLD_DATADIR = `select @@datadir`;
+LET $data_directory_clause = DATA DIRECTORY='$MYSQL_TMP_DIR/alternate_dir';
+LET $index_directory_clause = INDEX DIRECTORY='$MYSQL_TMP_DIR/alternate_dir';
+
+# 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`;
+LET $innodb_strict_mode_orig=`select @@session.innodb_strict_mode`;
+
+--echo #
+--echo # CREATE TABLE ... DATA DIRECTORY
+--echo #
+
+--echo # Innodb does not support INDEX DIRECTORY.
+SET SESSION innodb_strict_mode = ON;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+--error ER_CANT_CREATE_TABLE
+eval CREATE TABLE t1 (a int KEY, b text) $index_directory_clause;
+SHOW WARNINGS;
+
+--echo # Without strict mode, INDEX DIRECTORY is just ignored
+SET SESSION innodb_strict_mode = OFF;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval CREATE TABLE t1 (a int KEY, b text) $index_directory_clause;
+SHOW WARNINGS;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+--echo # Innodb does not support DATA DIRECTORY without innodb_file_per_table=ON.
+SET SESSION innodb_strict_mode = ON;
+SET GLOBAL innodb_file_per_table=OFF;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+--error ER_CANT_CREATE_TABLE
+eval CREATE TABLE t1 (a int KEY, b text) $data_directory_clause;
+SHOW WARNINGS;
+
+--echo # Without strict mode, DATA DIRECTORY without innodb_file_per_table=ON is just ignored.
+SET SESSION innodb_strict_mode = OFF;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval CREATE TABLE t1 (a int KEY, b text) $data_directory_clause;
+SHOW WARNINGS;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+--echo # Now set innodb_file_per_table so that DATA DIRECTORY can be tested.
+SET GLOBAL innodb_file_per_table=ON;
+
+--echo # Create the tablespace in MYSQL_TMP_DIR/alternate_dir
+--echo # InnoDB will create the sub-directories if needed.
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval CREATE TABLE t1 (a int KEY, b text) $data_directory_clause;
+SHOW WARNINGS;
+INSERT INTO t1 VALUES (1, "Create the tablespace");
+SELECT * FROM t1;
+
+--echo # Check if tablespace file exists where we specified in DATA DIRECTORY
+--file_exists $MYSQL_TMP_DIR/alternate_dir/test/t1.ibd
+
+--echo # Check if link file exists  in MYSQLD_DATADIR
+--file_exists $MYSQLD_DATADIR/test/t1.isl
+
+--echo # Check that DATA DIRECTORY shows up in the SHOW CREATE TABLE results.
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t1;
+
+--echo # Show that the new system tables have this table in them correctly
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name LIKE 'test%';
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+--replace_regex /emp#P#/emp#p#/
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+
+--echo # Show that the system tables are updated on drop table
+DROP TABLE t1;
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name LIKE 'test%';
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+SELECT path FROM information_schema.innodb_sys_datafiles;
+
+--echo # Create the same table a second time in the same place
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval CREATE TABLE t1 (a int KEY, b text) $data_directory_clause;
+
+INSERT INTO t1 VALUES (2, "Create the same table a second time in the same place");
+SELECT * FROM t1;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t1;
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name LIKE 'test%';
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+--file_exists $MYSQL_TMP_DIR/alternate_dir/test/t1.ibd
+--file_exists $MYSQLD_DATADIR/test/t1.isl
+--error 1
+--file_exists $MYSQLD_DATADIR/test/t1.ibd
+
+--echo # Truncate the table, then insert and verify
+TRUNCATE TABLE t1;
+INSERT INTO t1 VALUES (3, "Truncate the table, then insert");
+SELECT * FROM t1;
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name LIKE 'test%';
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+--file_exists $MYSQL_TMP_DIR/alternate_dir/test/t1.ibd
+--file_exists $MYSQLD_DATADIR/test/t1.isl
+
+--echo # Rename the table, then insert and verify
+RENAME TABLE t1 TO t2;
+INSERT INTO t2 VALUES (4, "Rename the table, then insert");
+SELECT * FROM t2;
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name LIKE 'test%';
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+--file_exists $MYSQL_TMP_DIR/alternate_dir/test/t2.ibd
+--file_exists $MYSQLD_DATADIR/test/t2.isl
+--error 1
+--file_exists $MYSQLD_DATADIR/test/t2.ibd
+
+--echo # CREATE TABLE LIKE does not retain DATA DIRECTORY automatically.
+CREATE TABLE t3 LIKE t2;
+INSERT INTO t3 VALUES (5, "CREATE TABLE LIKE");
+SELECT * FROM t3;
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name LIKE 'test%';
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+--replace_result ./ MYSQLD_DATADIR/ $MYSQLD_DATADIR MYSQLD_DATADIR  $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+--file_exists $MYSQLD_DATADIR/test/t3.ibd
+--error 1
+--file_exists $MYSQLD_DATADIR/test/t3.isl
+
+--echo # Now make sure the tables can be fully dropped.
+DROP TABLE t2, t3;
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name LIKE 'test%';
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+SELECT path FROM information_schema.innodb_sys_datafiles;
+--error 1
+--file_exists $MYSQLD_DATADIR/test/t2.frm
+--error 1
+--file_exists $MYSQLD_DATADIR/test/t2.isl
+--error 1
+--file_exists $MYSQL_TMP_DIR/alternate_dir/test/t2.ibd
+--error 1
+--file_exists $MYSQLD_DATADIR/test/t3.frm
+--error 1
+--file_exists $MYSQLD_DATADIR/test/t3.ibd
+
+--echo # Be sure SQL MODE "NO_DIR_IN_CREATE" prevents the use of DATA DIRECTORY
+SET @org_mode=@@sql_mode;
+SET @@sql_mode='NO_DIR_IN_CREATE';
+SELECT @@sql_mode;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval CREATE TABLE t1 (a int, b text) $data_directory_clause;
+SHOW WARNINGS;
+INSERT INTO t1 VALUES (6, "SQL MODE NO_DIR_IN_CREATE prevents DATA DIRECTORY");
+# Checking if tablespace exists in --datadir since DATA DIRECTORY was ignored.
+--file_exists $MYSQLD_DATADIR/test/t1.ibd
+DROP TABLE t1;
+set @@sql_mode=@org_mode;
+
+--echo # MySQL engine does not allow DATA DIRECTORY to be
+--echo # within --datadir for any engine, including InnoDB
+--replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
+--error ER_WRONG_ARGUMENTS
+eval CREATE TABLE t1 (a int KEY, b text) DATA DIRECTORY '$MYSQLD_DATADIR/test';
+
+--echo # TEMPORARY tables are incompatible with DATA DIRECTORY
+SET SESSION innodb_strict_mode = ON;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+--error ER_CANT_CREATE_TABLE
+eval CREATE TEMPORARY TABLE t1 (a int KEY, b text) engine=InnoDB $data_directory_clause;
+SHOW WARNINGS;
+SET SESSION innodb_strict_mode = OFF;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval CREATE TEMPORARY TABLE t1 (a int KEY, b text) engine=InnoDB $data_directory_clause;
+SHOW WARNINGS;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+--error 1
+--file_exists $MYSQLD_DATADIR/test/t1.frm
+--error 1
+--file_exists $MYSQLD_DATADIR/test/t1.isl
+--error 1
+--file_exists $MYSQL_TMP_DIR/alternate_dir/test/t1.ibd
+--error 1
+--file_exists $MYSQLD_DATADIR/test/t1.ibd
+
+
+--echo # Create the remote table via static DDL statements in a stored procedure
+DELIMITER |;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval CREATE PROCEDURE static_proc() BEGIN CREATE TABLE t1 (a int KEY, b text) $data_directory_clause; END |
+DELIMITER ;|
+CALL static_proc;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+INSERT INTO t1 VALUES (7, "Create the remote table via static DDL statements");
+SELECT * FROM t1;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t1;
+--file_exists $MYSQLD_DATADIR/test/t1.frm
+--file_exists $MYSQLD_DATADIR/test/t1.isl
+--file_exists $MYSQL_TMP_DIR/alternate_dir/test/t1.ibd
+DROP PROCEDURE static_proc;
+DROP TABLE t1;
+
+--echo # Create the remote table via dynamic DDL statements in a stored procedure
+DELIMITER |;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval CREATE PROCEDURE dynamic_proc() BEGIN PREPARE stmt1 FROM "CREATE TABLE t1 (a int KEY, b text) $data_directory_clause"; EXECUTE stmt1; END |
+DELIMITER ;|
+CALL dynamic_proc;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+INSERT INTO t1 VALUES (8, "Create the remote table via dynamic DDL statements");
+SELECT * FROM t1;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t1;
+--file_exists $MYSQLD_DATADIR/test/t1.frm
+--file_exists $MYSQLD_DATADIR/test/t1.isl
+--file_exists $MYSQL_TMP_DIR/alternate_dir/test/t1.ibd
+DROP PROCEDURE dynamic_proc;
+DROP TABLE t1;
+
+--echo #
+--echo # CREATE, DROP, ADD and TRUNCATE PARTITION with DATA DIRECTORY
+--echo #
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval CREATE TABLE emp (
+    id INT NOT NULL,
+    store_name VARCHAR(30),
+    parts VARCHAR(30),
+    store_id INT
+)
+PARTITION BY LIST(store_id) (
+  PARTITION east VALUES IN (10,20,30)
+    DATA DIRECTORY = '$MYSQL_TMP_DIR/alt-dir-east',
+  PARTITION north VALUES IN (40,50,60)
+    DATA DIRECTORY = '$MYSQL_TMP_DIR/alt-dir-north',
+  PARTITION west VALUES IN (70,80,100)
+    DATA DIRECTORY = '$MYSQL_TMP_DIR/alt-dir-west'
+);
+
+INSERT INTO emp values(1,'Oracle','NUTT',10);
+INSERT INTO emp values(2,'HUAWEI','BOLT',40);
+INSERT INTO emp values(3,'IBM','NAIL',70);
+
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE emp;
+# InnoDB always converts table names to lower case on Windows
+--replace_regex /emp#P#/emp#p#/
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables
+       WHERE name LIKE 'test%'
+       ORDER BY name;
+--replace_regex /emp#P#/emp#p#/
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces
+       ORDER BY name;
+--replace_regex /emp#P#/emp#p#/
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles
+       ORDER BY path;
+SELECT * FROM emp;
+--file_exists $MYSQLD_DATADIR/test/emp.frm
+--file_exists $MYSQLD_DATADIR/test/emp.par
+--file_exists $MYSQLD_DATADIR/test/emp#P#east.isl
+--file_exists $MYSQLD_DATADIR/test/emp#P#north.isl
+--file_exists $MYSQLD_DATADIR/test/emp#P#west.isl
+--file_exists $MYSQL_TMP_DIR/alt-dir-east/test/emp#P#east.ibd
+--file_exists $MYSQL_TMP_DIR/alt-dir-north/test/emp#P#north.ibd
+--file_exists $MYSQL_TMP_DIR/alt-dir-west/test/emp#P#west.ibd
+
+
+--echo # DROP one PARTITION.
+ALTER TABLE emp DROP PARTITION west;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE emp;
+--replace_regex /emp#P#/emp#p#/
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables
+       WHERE name LIKE 'test%'
+       ORDER BY name;
+--replace_regex /emp#P#/emp#p#/
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces
+       ORDER BY name;
+--replace_regex /emp#P#/emp#p#/
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles
+       ORDER BY path;
+SELECT * FROM emp;
+--file_exists $MYSQLD_DATADIR/test/emp.frm
+--file_exists $MYSQLD_DATADIR/test/emp.par
+--file_exists $MYSQLD_DATADIR/test/emp#P#east.isl
+--file_exists $MYSQLD_DATADIR/test/emp#P#north.isl
+--error 1
+--file_exists $MYSQLD_DATADIR/test/emp#P#west.isl
+--file_exists $MYSQL_TMP_DIR/alt-dir-east/test/emp#P#east.ibd
+--file_exists $MYSQL_TMP_DIR/alt-dir-north/test/emp#P#north.ibd
+--error 1
+--file_exists $MYSQL_TMP_DIR/alt-dir-west/test/emp#P#west.ibd
+
+
+--echo # ADD the PARTITION back.
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval ALTER TABLE emp ADD PARTITION (
+  PARTITION west VALUES IN (70,80,100)
+    DATA DIRECTORY = '$MYSQL_TMP_DIR/alt-dir-west');
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE emp;
+--replace_regex /emp#P#/emp#p#/
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables
+       WHERE name LIKE 'test%'
+       ORDER BY name;
+--replace_regex /emp#P#/emp#p#/
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces
+       ORDER BY name;
+--replace_regex /emp#P#/emp#p#/
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles
+       ORDER BY path;
+INSERT INTO emp VALUES(3,'IBM','NAIL',70);
+SELECT * FROM emp;
+--file_exists $MYSQLD_DATADIR/test/emp.frm
+--file_exists $MYSQLD_DATADIR/test/emp.par
+--file_exists $MYSQLD_DATADIR/test/emp#P#east.isl
+--file_exists $MYSQLD_DATADIR/test/emp#P#north.isl
+--file_exists $MYSQLD_DATADIR/test/emp#P#west.isl
+--file_exists $MYSQL_TMP_DIR/alt-dir-east/test/emp#P#east.ibd
+--file_exists $MYSQL_TMP_DIR/alt-dir-north/test/emp#P#north.ibd
+--file_exists $MYSQL_TMP_DIR/alt-dir-west/test/emp#P#west.ibd
+
+--echo # TRUNCATE one PARTITION.
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+ALTER TABLE emp TRUNCATE PARTITION west;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE emp;
+--replace_regex /emp#P#/emp#p#/
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables
+       WHERE name LIKE 'test%'
+       ORDER BY name;
+--replace_regex /emp#P#/emp#p#/
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces
+       ORDER BY name;
+--replace_regex /emp#P#/emp#p#/
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles
+       ORDER BY path;
+SELECT * FROM emp;
+INSERT INTO emp VALUES(3,'IBM','NAIL',70);
+SELECT * FROM emp;
+--file_exists $MYSQLD_DATADIR/test/emp.frm
+--file_exists $MYSQLD_DATADIR/test/emp.par
+--file_exists $MYSQLD_DATADIR/test/emp#P#east.isl
+--file_exists $MYSQLD_DATADIR/test/emp#P#north.isl
+--file_exists $MYSQLD_DATADIR/test/emp#P#west.isl
+--file_exists $MYSQL_TMP_DIR/alt-dir-east/test/emp#P#east.ibd
+--file_exists $MYSQL_TMP_DIR/alt-dir-north/test/emp#P#north.ibd
+--file_exists $MYSQL_TMP_DIR/alt-dir-west/test/emp#P#west.ibd
+
+DROP TABLE emp;
+
+--echo #
+--echo # Cleanup
+--echo #
+
+--rmdir $MYSQL_TMP_DIR/alternate_dir/test
+--rmdir $MYSQL_TMP_DIR/alternate_dir
+--rmdir $MYSQL_TMP_DIR/alt-dir-east/test
+--rmdir $MYSQL_TMP_DIR/alt-dir-east
+--rmdir $MYSQL_TMP_DIR/alt-dir-north/test
+--rmdir $MYSQL_TMP_DIR/alt-dir-north
+--rmdir $MYSQL_TMP_DIR/alt-dir-west/test
+--rmdir $MYSQL_TMP_DIR/alt-dir-west
+
+--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;
+EVAL SET SESSION innodb_strict_mode=$innodb_strict_mode_orig;
+--enable_query_log
+

=== modified file 'mysql-test/suite/innodb/t/innodb_16k.test'
--- a/mysql-test/suite/innodb/t/innodb_16k.test	revid:vasil.dimov@stripped
+++ b/mysql-test/suite/innodb/t/innodb_16k.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: 8123, Compact: 8126.

=== modified file 'mysql-test/suite/innodb/t/innodb_4k.test'
--- a/mysql-test/suite/innodb/t/innodb_4k.test	revid:vasil.dimov@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:vasil.dimov@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:vasil.dimov@stripped
+++ b/mysql-test/suite/parts/r/partition_basic_symlink_innodb.result	revid:kevin.lewis@stripped
@@ -1,10 +1,38 @@
-# 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.
+#
+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,7 +41,14 @@ PARTITION p1
 DATA DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-data-dir'
  INDEX DIRECTORY = 'MYSQLTEST_VARDIR/mysql-test-idx-dir'
 );
-# Verifying .frm and .par 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
 # Verifying that there are no MyISAM files
 FLUSH TABLES;
 SHOW CREATE TABLE t1;
@@ -24,9 +59,11 @@ t1	CREATE TABLE `t1` (
 /*!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;
+#
+# 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` (
@@ -35,4 +72,36 @@ t1	CREATE TABLE `t1` (
 /*!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) */
+# Verifying .frm, .par and MyISAM files (.MYD, MYI)
+#
+# Now verify that the DATA DIRECTORY is used again if we
+# ALTER TABLE back to InnoDB.  First try stict mode which
+# will fail since INDEX DIRECTORY is part of the definition.
+#
+SET SESSION innodb_strict_mode = ON;
+ALTER TABLE t1 engine=InnoDB;
+ERROR HY000: Can't create table 'test.#sql-temporary' (errno: 1478)
+SHOW WARNINGS;
+Level	Code	Message
+Warning	1478	InnoDB: INDEX DIRECTORY is not supported
+Error	1005	Can't create table 'test.#sql-temporary' (errno: 1478)
+Error	6	Error on delete of 'MYSQLD_DATADIR/test/#sql-temporary.par' (Errcode: 2 - No such file or directory)
+# Now use non-stict mode so that the INDEX DIRECTORY is ignored.
+SET SESSION innodb_strict_mode = OFF;
+ALTER TABLE t1 engine=InnoDB;
+Warnings:
+Warning	1618	<INDEX DIRECTORY> option ignored
+Warning	1618	<INDEX DIRECTORY> option ignored
+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' 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) */
+# Verifying .frm, .par, .isl and InnoDB .ibd  files
 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:vasil.dimov@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,52 @@
 # 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
-eval CREATE TABLE t1 (c1 INT)
-ENGINE = InnoDB
+--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 #
+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
 PARTITION BY HASH (c1)
 (PARTITION p0
  DATA DIRECTORY = '$MYSQLTEST_VARDIR/mysql-test-data-dir'
@@ -54,9 +93,16 @@ 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
+SHOW WARNINGS;
+
+--echo # Verifying .frm, .par, .isl & .ibd files
 --file_exists $MYSQLD_DATADIR/test/t1.frm
 --file_exists $MYSQLD_DATADIR/test/t1.par
+--file_exists $MYSQLD_DATADIR/test/t1#P#p0.isl
+--file_exists $MYSQLD_DATADIR/test/t1#P#p1.isl
+--file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/test/t1#P#p0.ibd
+--file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/test/t1#P#p1.ibd
+
 --echo # Verifying that there are no MyISAM files
 --error 1
 --file_exists $MYSQLD_DATADIR/test/t1#P#p0.MYD
@@ -74,96 +120,104 @@ PARTITION BY HASH (c1)
 --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
+# The ibd tablespaces should not be directly under the DATA DIRECTORY
+--error 1
+--file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/t1#P#p0.ibd
+--error 1
+--file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/t1#P#p1.ibd
 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;
---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
+--file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/t1#p#p0.myd
+--file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/t1#p#p1.myd
+--file_exists $MYSQLTEST_VARDIR/mysql-test-idx-dir/t1#p#p0.myi
+--file_exists $MYSQLTEST_VARDIR/mysql-test-idx-dir/t1#p#p1.myi
 
-#
-# 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
+--error 1
+--file_exists $MYSQLD_DATADIR/test/t1#P#p0.isl
+--error 1
+--file_exists $MYSQLD_DATADIR/test/t1#P#p1.isl
+--error 1
+--file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/t1#P#p0.ibd
+--error 1
+--file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/t1#P#p1.ibd
+--error 1
+--file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/test/t1#P#p0.ibd
+--error 1
+--file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/test/t1#P#p1.ibd
 
-#------------------------------------------------------------------------------#
-# Engine specific settings and requirements
+--echo #
+--echo # Now verify that the DATA DIRECTORY is used again if we
+--echo # ALTER TABLE back to InnoDB.  First try stict mode which
+--echo # will fail since INDEX DIRECTORY is part of the definition.
+--echo #
+SET SESSION innodb_strict_mode = ON;
+--replace_regex /#sql-[0-9a-f_]*/#sql-temporary/
+--error ER_CANT_CREATE_TABLE
+ALTER TABLE t1 engine=InnoDB;
+--replace_result ./ MYSQLD_DATADIR/  $MYSQLD_DATADIR MYSQLD_DATADIR
+--replace_regex /#sql-[0-9a-f_]*/#sql-temporary/
+SHOW WARNINGS;
 
-##### Storage engine to be tested
---source include/have_innodb.inc
-let $engine= 'InnoDB';
+--echo # Now use non-stict mode so that the INDEX DIRECTORY is ignored.
+SET SESSION innodb_strict_mode = OFF;
+ALTER TABLE t1 engine=InnoDB;
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+SHOW CREATE TABLE t1;
+--echo # Verifying .frm, .par, .isl and InnoDB .ibd  files
+--file_exists $MYSQLD_DATADIR/test/t1.frm
+--file_exists $MYSQLD_DATADIR/test/t1.par
+--file_exists $MYSQLD_DATADIR/test/t1#P#p0.isl
+--file_exists $MYSQLD_DATADIR/test/t1#P#p1.isl
+--file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/test/t1#P#p0.ibd
+--file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/test/t1#P#p1.ibd
 
-##### Execute the test of "table" files
-# InnoDB has no files per PK, UI, ...
-let $do_file_tests= 0;
+--error 1
+--file_exists $MYSQLD_DATADIR/test/t1#P#p0.myd
+--error 1
+--file_exists $MYSQLD_DATADIR/test/t1#P#p1.myd
+--error 1
+--file_exists $MYSQLD_DATADIR/test/t1#P#p0.myi
+--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-data-dir/t1#P#p1.myd
+--error 1
+--file_exists $MYSQLTEST_VARDIR/mysql-test-idx-dir/t1#P#p0.myi
+--error 1
+--file_exists $MYSQLTEST_VARDIR/mysql-test-idx-dir/t1#P#p1.myi
+--error 1
+--file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/t1#P#p0.ibd
+--error 1
+--file_exists $MYSQLTEST_VARDIR/mysql-test-data-dir/t1#P#p1.ibd
 
-##### 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

=== added file 'mysql-test/t/partition_innodb_tablespace.test'
--- a/mysql-test/t/partition_innodb_tablespace.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/partition_innodb_tablespace.test	revid:kevin.lewis@stripped
@@ -0,0 +1,290 @@
+#
+# A series of tests to show the correct tablespace behavior when the
+# partition engine uses InnoDB.
+#
+--source include/not_embedded.inc
+--source include/have_partition.inc
+--source include/have_innodb.inc
+SET default_storage_engine=InnoDB;
+
+--echo #
+--echo # TABLESPACE related tests for the partition engine and InnoDB.
+--echo #
+
+# Set up some variables
+LET $MYSQLD_DATADIR = `select @@datadir`;
+LET $data_directory = DATA DIRECTORY='$MYSQL_TMP_DIR/alternate_dir/data';
+LET $data_directory2 = DATA DIRECTORY='$MYSQL_TMP_DIR/alternate_dir/data2';
+LET $index_directory = INDEX DIRECTORY='$MYSQL_TMP_DIR/alternate_dir/data';
+
+# 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`;
+LET $innodb_strict_mode_orig=`select @@session.innodb_strict_mode`;
+
+--echo # The partition engine can send DATA DIRECTORY to InnoDB.
+--echo # In strict mode, it is an error if innodb_file_per_table = OFF
+--echo # or INDEX DIRECTORY is used.
+SET SESSION innodb_strict_mode = ON;
+SET GLOBAL innodb_file_per_table = OFF;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+--error ER_CANT_CREATE_TABLE
+eval CREATE TABLE t1 (a int KEY, b text) ENGINE = InnoDB PARTITION BY HASH (a)
+     (PARTITION p0 engine=InnoDB $data_directory $index_directory,
+      PARTITION p1 engine=InnoDB $data_directory $index_directory);
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW WARNINGS;
+
+--echo # Try again with innodb_file_per_table = ON and no INDEX DIRECTORY.
+SET GLOBAL innodb_file_per_table = ON;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval CREATE TABLE t1 (a int KEY, b text) ENGINE = InnoDB PARTITION BY HASH (a)
+     (PARTITION p0 engine=InnoDB $data_directory,
+      PARTITION p1 engine=InnoDB $data_directory2);
+SHOW WARNINGS;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t1;
+# replace_result 't1#P' with 't1#p' because on Linux, InnoDB is always
+# case sensitive with table names and on Windows, it is always lower case.
+# This is independent of the value of lower_case_table_names.  This cannot
+# be changes without breaking backward compatibility.
+--replace_result t1#P t1#p
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name LIKE 'test%';
+--replace_result t1#P t1#p
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+--replace_result t1#P t1#p  $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+
+--echo # Verifying .frm, .par, .isl & .ibd files
+--file_exists $MYSQLD_DATADIR/test/t1.frm
+--file_exists $MYSQLD_DATADIR/test/t1.par
+--file_exists $MYSQLD_DATADIR/test/t1#P#p0.isl
+--file_exists $MYSQLD_DATADIR/test/t1#P#p1.isl
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data/test/t1#P#p0.ibd
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data2/test/t1#P#p1.ibd
+
+--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 $MYSQL_TMP_DIR/alternate_dir/data/t1#P#p0.myd
+--error 1
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data/t1#P#p0.myi
+--error 1
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data2/t1#P#p1.myd
+--error 1
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data2/t1#P#p1.myi
+# The ibd tablespaces should not be directly under the DATA DIRECTORY
+--error 1
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data/t1#P#p0.ibd
+--error 1
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data2/t1#P#p1.ibd
+
+--echo # Test TRUNCATE TABLE with partitioned InnoDB tables
+INSERT INTO t1 VALUES (1, "red");
+INSERT INTO t1 VALUES (2, "green");
+INSERT INTO t1 VALUES (3, "blue");
+SELECT * FROM t1;
+TRUNCATE TABLE t1;
+SELECT * FROM t1;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t1;
+--replace_result t1#P t1#p
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name LIKE 'test%';
+--replace_result t1#P t1#p
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+--replace_result t1#P t1#p  $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+--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.isl
+--file_exists $MYSQLD_DATADIR/test/t1#P#p1.isl
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data/test/t1#P#p0.ibd
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data2/test/t1#P#p1.ibd
+
+--echo # Test RENAME TABLE with partitioned InnoDB tables
+RENAME TABLE t1 TO t11;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t11;
+--replace_result t11#P t11#p
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name LIKE 'test%';
+--replace_result t11#P t11#p
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+--replace_result t11#P t11#p  $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+--echo # Verifying .frm, .par and MyISAM files (.MYD, MYI)
+--file_exists $MYSQLD_DATADIR/test/t11.frm
+--file_exists $MYSQLD_DATADIR/test/t11.par
+--file_exists $MYSQLD_DATADIR/test/t11#P#p0.isl
+--file_exists $MYSQLD_DATADIR/test/t11#P#p1.isl
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data/test/t11#P#p0.ibd
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data2/test/t11#P#p1.ibd
+
+DROP TABLE t11;
+
+--echo # Test the previous DDL as a prepared statement.
+SET GLOBAL innodb_file_per_table = ON;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval PREPARE stmt1 FROM "CREATE TABLE t1 (a int KEY, b text)
+     ENGINE = InnoDB PARTITION BY HASH (a)
+     (PARTITION p0 engine=InnoDB $data_directory,
+      PARTITION p1 engine=InnoDB $data_directory2)";
+EXECUTE stmt1;
+SHOW WARNINGS;
+DEALLOCATE PREPARE stmt1;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t1;
+--replace_result t1#P t1#p
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name LIKE 'test%';
+--replace_result t1#P t1#p
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+--replace_result t1#P t1#p  $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+DROP TABLE t1;
+
+
+--echo # Test DATA DIRECTORY with Sub-partitions.
+SET GLOBAL innodb_file_per_table = ON;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval CREATE TABLE t1 (id INT, purchased DATE) engine=InnoDB
+    PARTITION BY RANGE( YEAR(purchased) )
+    SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
+        PARTITION p0 VALUES LESS THAN (1990) (
+            SUBPARTITION s0 $data_directory,
+            SUBPARTITION s1 $data_directory2
+        ),
+        PARTITION p1 VALUES LESS THAN (2000) (
+            SUBPARTITION s2 $data_directory,
+            SUBPARTITION s3 $data_directory2
+        ),
+        PARTITION p2 VALUES LESS THAN MAXVALUE (
+            SUBPARTITION s4 $data_directory,
+            SUBPARTITION s5 $data_directory2
+        )
+    );
+SHOW WARNINGS;
+INSERT INTO t1 VALUES(1,'1980-05-31');
+INSERT INTO t1 VALUES(2,'2090-05-31');
+INSERT INTO t1 VALUES(3,'2012-05-31');
+INSERT INTO t1 VALUES(4,'1970-05-31');
+INSERT INTO t1 VALUES(5,'1985-05-31');
+INSERT INTO t1 VALUES(6,'2006-05-31');
+SELECT * FROM t1;
+
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t1;
+--replace_result #P# #p#  #SP# #sp#
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name LIKE 'test%';
+--replace_result #P# #p#  #SP# #sp#
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+--replace_result #P# #p#  #SP# #sp#  $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+
+--echo # Verifying .frm, .par, .isl & .ibd files
+--file_exists $MYSQLD_DATADIR/test/t1.frm
+--file_exists $MYSQLD_DATADIR/test/t1.par
+--file_exists $MYSQLD_DATADIR/test/t1#P#p0#SP#s0.isl
+--file_exists $MYSQLD_DATADIR/test/t1#P#p0#SP#s1.isl
+--file_exists $MYSQLD_DATADIR/test/t1#P#p1#SP#s2.isl
+--file_exists $MYSQLD_DATADIR/test/t1#P#p1#SP#s3.isl
+--file_exists $MYSQLD_DATADIR/test/t1#P#p2#SP#s4.isl
+--file_exists $MYSQLD_DATADIR/test/t1#P#p2#SP#s5.isl
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data/test/t1#P#p0#SP#s0.ibd
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data2/test/t1#P#p0#SP#s1.ibd
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data/test/t1#P#p1#SP#s2.ibd
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data2/test/t1#P#p1#SP#s3.ibd
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data/test/t1#P#p2#SP#s4.ibd
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data2/test/t1#P#p2#SP#s5.ibd
+DROP TABLE t1;
+
+--echo # Same as above except with ROW_FORMAT=Dyamic.
+SET GLOBAL innodb_file_format = Barracuda;
+SET GLOBAL innodb_file_per_table = ON;
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+eval CREATE TABLE t1 (id INT, purchased DATE)
+    engine = innodb row_format = dynamic
+    PARTITION BY RANGE( YEAR(purchased) )
+    SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
+        PARTITION p0 VALUES LESS THAN (1990) (
+            SUBPARTITION s0 $data_directory,
+            SUBPARTITION s1 $data_directory2
+        ),
+        PARTITION p1 VALUES LESS THAN (2000) (
+            SUBPARTITION s2 $data_directory,
+            SUBPARTITION s3 $data_directory2
+        ),
+        PARTITION p2 VALUES LESS THAN MAXVALUE (
+            SUBPARTITION s4 $data_directory,
+            SUBPARTITION s5 $data_directory2
+        )
+    );
+SHOW WARNINGS;
+INSERT INTO t1 VALUES(1,'1980-05-31');
+INSERT INTO t1 VALUES(2,'2090-05-31');
+INSERT INTO t1 VALUES(3,'2012-05-31');
+INSERT INTO t1 VALUES(4,'1970-05-31');
+INSERT INTO t1 VALUES(5,'1985-05-31');
+INSERT INTO t1 VALUES(6,'2006-05-31');
+SELECT * FROM t1;
+
+--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SHOW CREATE TABLE t1;
+--replace_result #P# #p#  #SP# #sp#
+SELECT name,n_cols,file_format,row_format
+       FROM information_schema.innodb_sys_tables WHERE name LIKE 'test%';
+--replace_result #P# #p#  #SP# #sp#
+SELECT name,file_format,row_format
+       FROM information_schema.innodb_sys_tablespaces;
+--replace_result #P# #p#  #SP# #sp#  $MYSQL_TMP_DIR MYSQL_TMP_DIR
+SELECT path FROM information_schema.innodb_sys_datafiles;
+
+--echo # Verifying .frm, .par, .isl & .ibd files
+--file_exists $MYSQLD_DATADIR/test/t1.frm
+--file_exists $MYSQLD_DATADIR/test/t1.par
+--file_exists $MYSQLD_DATADIR/test/t1#P#p0#SP#s0.isl
+--file_exists $MYSQLD_DATADIR/test/t1#P#p0#SP#s1.isl
+--file_exists $MYSQLD_DATADIR/test/t1#P#p1#SP#s2.isl
+--file_exists $MYSQLD_DATADIR/test/t1#P#p1#SP#s3.isl
+--file_exists $MYSQLD_DATADIR/test/t1#P#p2#SP#s4.isl
+--file_exists $MYSQLD_DATADIR/test/t1#P#p2#SP#s5.isl
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data/test/t1#P#p0#SP#s0.ibd
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data2/test/t1#P#p0#SP#s1.ibd
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data/test/t1#P#p1#SP#s2.ibd
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data2/test/t1#P#p1#SP#s3.ibd
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data/test/t1#P#p2#SP#s4.ibd
+--file_exists $MYSQL_TMP_DIR/alternate_dir/data2/test/t1#P#p2#SP#s5.ibd
+
+--echo #
+--echo # Cleanup
+--echo #
+
+DROP TABLE t1;
+--rmdir $MYSQL_TMP_DIR/alternate_dir/data/test
+--rmdir $MYSQL_TMP_DIR/alternate_dir/data
+--rmdir $MYSQL_TMP_DIR/alternate_dir/data2/test
+--rmdir $MYSQL_TMP_DIR/alternate_dir/data2
+--rmdir $MYSQL_TMP_DIR/alternate_dir
+
+--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;
+EVAL SET SESSION innodb_strict_mode=$innodb_strict_mode_orig;
+--enable_query_log
+

=== modified file 'mysys/my_handler_errors.h'
--- a/mysys/my_handler_errors.h	revid:vasil.dimov@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/handler.cc'
--- a/sql/handler.cc	revid:vasil.dimov@stripped
+++ b/sql/handler.cc	revid:kevin.lewis@stripped
@@ -403,9 +403,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 'storage/innobase/dict/dict0boot.cc'
--- a/storage/innobase/dict/dict0boot.cc	revid:vasil.dimov@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:vasil.dimov@stripped
+++ b/storage/innobase/dict/dict0crea.cc	revid:kevin.lewis@stripped
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1996, 2011, 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
@@ -254,8 +254,7 @@ dict_build_table_def_step(
 	dict_table_t*	table;
 	dtuple_t*	row;
 	ulint		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);
@@ -1229,38 +1220,36 @@ 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.
 @return TRUE if they exist. */
 static
-ibool
-dict_check_sys_foreign_tables_exist(void)
-/*=====================================*/
+bool
+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;
+	bool		exists = false;
 
 	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
+	    && sys_table->n_cols == num_fields
+	    && UT_LIST_GET_LEN(sys_table->indexes) == num_indexes) {
 
-	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.  */
+		/* 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;
+		exists = true;
 	}
 
 	mutex_exit(&dict_sys->mutex);
@@ -1270,7 +1259,7 @@ dict_check_sys_foreign_tables_exist(void
 
 /****************************************************************//**
 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
@@ -1280,14 +1269,20 @@ dict_create_or_check_foreign_constraint_
 {
 	trx_t*		trx;
 	ulint		error;
-	ibool		success;
-	ibool		srv_file_per_table_backup;
+	my_bool		srv_file_per_table_backup;
+	bool		sys_foreign_ok;
+	bool		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 && sys_foreign_cols_ok) {
 		return(DB_SUCCESS);
 	}
 
@@ -1299,14 +1294,14 @@ 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) {
 		fprintf(stderr,
 			"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) {
 		fprintf(stderr,
 			"InnoDB: dropping incompletely created"
 			" SYS_FOREIGN_COLS table\n");
@@ -1327,7 +1322,7 @@ 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. */
@@ -1388,10 +1383,14 @@ 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);
+	ut_a(dict_check_if_system_table_exists(
+			"SYS_FOREIGN",
+			DICT_NUM_FIELDS__SYS_FOREIGN + 1, 3)
+	     && dict_check_if_system_table_exists(
+			"SYS_FOREIGN_COLS",
+			DICT_NUM_FIELDS__SYS_FOREIGN_COLS + 1, 1));
 
-	srv_file_per_table = (my_bool) srv_file_per_table_backup;
+	srv_file_per_table = srv_file_per_table_backup;
 
 	return(error);
 }
@@ -1621,3 +1620,206 @@ 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
+db_err
+dict_create_or_check_sys_tablespace(void)
+/*=====================================*/
+{
+	trx_t*		trx;
+	db_err		error;
+	my_bool		srv_file_per_table_backup;
+	bool		sys_tablespaces_ok;
+	bool		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 && sys_datafiles_ok) {
+		return(DB_SUCCESS);
+	}
+
+	trx = trx_allocate_for_mysql();
+
+	trx->op_info = "creating tablepace and datafile system tables";
+
+	row_mysql_lock_data_dictionary(trx);
+
+	/* Check which incomplete table definition to drop. */
+
+	if (!sys_tablespaces_ok) {
+		fprintf(stderr,
+			"InnoDB: dropping incompletely created"
+			" SYS_TABLESPACES table\n");
+		row_drop_table_for_mysql("SYS_TABLESPACES", trx, TRUE);
+	}
+
+	if (!sys_datafiles_ok) {
+		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\n"
+			"InnoDB: tablespace is full\n"
+			"InnoDB: dropping incompletely created"
+			" SYS_TABLESPACE 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);
+
+	if (error == DB_SUCCESS) {
+		fprintf(stderr,
+			"InnoDB: Tablespace and Datafile system tables"
+			" 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. */
+
+	ut_a(dict_check_if_system_table_exists(
+			"SYS_TABLESPACES",
+			DICT_NUM_FIELDS__SYS_TABLESPACES + 1, 1)
+	     && dict_check_if_system_table_exists(
+			"SYS_DATAFILES",
+			DICT_NUM_FIELDS__SYS_DATAFILES + 1, 1));
+
+	srv_file_per_table = srv_file_per_table_backup;
+
+	return(error);
+}
+
+/********************************************************************//**
+Add a single tablespace definition to the data dictionary tables in the
+database.
+@return	error code or DB_SUCCESS */
+UNIV_INTERN
+db_err
+dict_create_add_tablespace_to_dictionary(
+/*=====================================*/
+	ulint		space,		/*!< in: tablespace id */
+	const char*	name,		/*!< in: tablespace name */
+	ulint		flags,		/*!< in: tablespace flags */
+	trx_t*		trx)		/*!< in: transaction */
+{
+	db_err		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);
+
+	error = que_eval_sql(info,
+			     "PROCEDURE P () IS\n"
+			     "BEGIN\n"
+			     "INSERT INTO SYS_TABLESPACES VALUES"
+			     "(:space, :name, :flags);\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);
+}
+
+/********************************************************************//**
+Add a single datafile definition to the data dictionary tables in the
+database. Note; the caller must commit the transaction.
+@return	error code or DB_SUCCESS */
+UNIV_INTERN
+db_err
+dict_create_add_datafile_to_dictionary(
+/*===================================*/
+	ulint		space,		/*!< in: tablespace id */
+	const char*	path,		/*!< in: tablespace path */
+	trx_t*		trx)		/*!< in: transaction */
+{
+	db_err		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, "path", path);
+
+	error = que_eval_sql(info,
+			     "PROCEDURE P () IS\n"
+			     "BEGIN\n"
+			     "INSERT INTO SYS_DATAFILES VALUES"
+			     "(:space, :path);\n"
+			     "END;\n",
+			     FALSE, trx);
+
+	if (error != DB_SUCCESS) {
+		return(error);
+	}
+
+	return(error);
+}

=== modified file 'storage/innobase/dict/dict0dict.cc'
--- a/storage/innobase/dict/dict0dict.cc	revid:vasil.dimov@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"
@@ -1423,9 +1424,13 @@ dict_table_rename_in_cache(
 	}
 
 	/* If the table is stored in a single-table tablespace, rename the
-	.ibd file */
+	.ibd file and rebuild the .isl file if needed. */
 
 	if (!dict_table_is_discarded(table) && table->space != TRX_SYS_SPACE) {
+		ibool	success;
+		char*	new_path = NULL;
+		char*	link_filepath = NULL;
+
 		if (table->dir_path_of_temp_table != NULL) {
 			ut_print_timestamp(stderr);
 			fputs("  InnoDB: Error: trying to rename a"
@@ -1436,8 +1441,38 @@ dict_table_rename_in_cache(
 					  table->dir_path_of_temp_table);
 			fputs(" )\n", stderr);
 			return(FALSE);
-		} else if (!fil_rename_tablespace(old_name, table->space,
-						  new_name)) {
+		}
+
+		if (DICT_TF_HAS_DATA_DIR(table->flags)) {
+			ulint err;
+			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);
+
+			link_filepath = fil_make_isl_name(new_name);
+
+			err = fil_create_link_file(link_filepath, new_path);
+
+			mem_free(link_filepath);
+			if (err != DB_SUCCESS) {
+				mem_free(new_path);
+				return(FALSE);
+			}
+		}
+
+		success = fil_rename_tablespace(
+			old_name, table->space, new_name, new_path);
+
+		if (new_path) {
+			fil_delete_link_file(old_name);
+			mem_free(new_path);
+		}
+
+		if (!success) {
 			return(FALSE);
 		}
 	}

=== modified file 'storage/innobase/dict/dict0load.cc'
--- a/storage/innobase/dict/dict0load.cc	revid:vasil.dimov@stripped
+++ b/storage/innobase/dict/dict0load.cc	revid:kevin.lewis@stripped
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1996, 2011, 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
@@ -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,234 @@ 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;
+	char*		remote_filepath = NULL;
+	mem_heap_t*	heap = mem_heap_create(1024);
+	trx_t*		trx;
+
+	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);
+
+	/* Compare this path with the path found in a link file if it
+	exists. The .isl file is in the 'normal' tablespace location. */
+	remote_filepath = fil_read_link_file(name);
+	if (!remote_filepath) {
+		/* Since this function is only called for tablespaces
+		that should have a link file, we assume that the link
+		file no longer exists.  So the only place the file can
+		now exist is the default datadir. */
+		remote_filepath = fil_make_ibd_name(name, FALSE);
+	}
+
+	/* A link file existed, make sure it is the same file we found
+	in SYS_DATAFILES. */
+	if (strcmp(dict_filepath, remote_filepath) == 0) {
+		mem_free(remote_filepath);
+		return (dict_filepath);
+	}
+
+	/* The two filepaths are different. Since the link file may be
+	updated in order to migrate tablespaces, always use the
+	linked_filepath. Write the linked_filepath into the system tables. */
+	trx = trx_allocate_for_background();
+	trx_start_if_not_started(trx);
+
+	if (dict_filepath) {
+		db_err		error;
+		pars_info_t*	info = pars_info_create();
+
+		pars_info_add_int4_literal(info, "space", space);
+		pars_info_add_str_literal(info, "remote_path",
+					  remote_filepath);
+
+		error = que_eval_sql(info,
+				   "PROCEDURE UPDATE_FILEPATH () IS\n"
+				   "BEGIN\n"
+				   "UPDATE SYS_DATAFILES"
+				   " SET PATH = :remote_path\n"
+				   " WHERE SPACE = :space;\n"
+				   "END;\n", FALSE, trx);
+		mem_free(dict_filepath);
+	} else {
+		/* 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.
+		Note, we do not know the value of flags. */
+		dict_create_add_tablespace_to_dictionary(
+			space, name, 0, trx);
+
+		dict_create_add_datafile_to_dictionary(
+			space, remote_filepath, trx);
+	}
+	trx_commit_for_mysql(trx);
+	trx_free_for_background(trx);
+
+	/* We just updated SYS_DATAFILES due to the contents in a link
+	file.  Make a note that we did this. */
+	ut_print_timestamp(stderr);
+	fputs("  InnoDB: Note: The InnoDB data dictionary for table ",
+	      stderr);
+	ut_print_filename(stderr, name);
+	fprintf(stderr, "\n  InnoDB: was updated to use tablespace %s.\n",
+		remote_filepath);
+
+	return remote_filepath;
+}
+
+/********************************************************************//**
+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().
@@ -799,12 +1142,26 @@ loop:
 
 		} else if (!discarded) {
 
-			/* 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 needed. */
+			char*	filepath = NULL;
+			if (DICT_TF_HAS_DATA_DIR(flags)) {
+				filepath = dict_get_first_path(
+					space_id, name);
+			}
 
 			db_err	err = fil_open_single_table_tablespace(
 				NULL, space_id,
-				dict_tf_to_fsp_flags(flags), name);
+				dict_tf_to_fsp_flags(flags),
+				name, filepath);
+
+			if (filepath) {
+				mem_free(filepath);
+			}
 
 			if (err != DB_SUCCESS) {
 				ib_logf(IB_LOG_LEVEL_ERROR,
@@ -1784,6 +2141,40 @@ 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) {
+		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)  == 0) {
+		return;
+	}
+
+	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);
+}
+
+/********************************************************************//**
 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
@@ -1814,6 +2205,7 @@ dict_load_table(
 	const rec_t*	rec;
 	const byte*	field;
 	ulint		len;
+	char*		filepath = NULL;
 	const char*	err_msg;
 	mtr_t		mtr;
 
@@ -1899,10 +2291,21 @@ err_exit:
 				"tablespace with space id %lu.",
 				name, (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);
+				if (filepath) {
+					dict_save_data_dir_path(
+						table, filepath);
+				}
+			}
+
 			/* Try to open the tablespace */
 			err = fil_open_single_table_tablespace(
 				table, table->space,
-				dict_tf_to_fsp_flags(table->flags), name);
+				dict_tf_to_fsp_flags(table->flags),
+				name, filepath);
 
 			if (err != DB_SUCCESS) {
 				/* We failed to find a sensible
@@ -1910,6 +2313,9 @@ err_exit:
 
 				table->ibd_file_missing = TRUE;
 			}
+			if (filepath) {
+				mem_free(filepath);
+			}
 		}
 	}
 

=== modified file 'storage/innobase/fil/fil0fil.cc'
--- a/storage/innobase/fil/fil0fil.cc	revid:vasil.dimov@stripped
+++ b/storage/innobase/fil/fil0fil.cc	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.
 
 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
@@ -212,7 +212,7 @@ struct fil_space_struct {
 				last incomplete megabytes in data files may be
 				ignored if space == 0 */
 	ulint		flags;	/*!< tablespace flags; see
-				fsp_flags_validate(),
+				fsp_flags_is_valid(),
 				fsp_flags_get_zip_size() */
 	ulint		n_reserved_extents;
 				/*!< number of reserved free extents for
@@ -1442,29 +1442,23 @@ 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) {
@@ -1482,7 +1476,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);
 
@@ -1499,19 +1558,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);
@@ -1519,21 +1577,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);
@@ -1836,6 +1879,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 */
@@ -1861,6 +1905,8 @@ fil_read_first_page(
 
 	*flags = fsp_header_get_flags(page);
 
+	*space_id = fsp_header_get_space_id(page);
+
 	flushed_lsn = mach_read_from_8(page+ FIL_PAGE_FILE_FLUSH_LSN);
 
 	ut_free(buf);
@@ -2184,10 +2230,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;
 				}
 			}
@@ -2205,12 +2252,19 @@ fil_op_log_parse_or_replay(
 		} else if (log_flags & MLOG_FILE_FLAG_TEMP) {
 			/* Temporary table, do nothing */
 		} else {
+			const char*	path = NULL;
+
+			if (log_flags & MLOG_FILE_FLAG_TEMP) {
+				path = name;
+				/* TODO: name is not available. */
+			}
+
 			/* 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;
@@ -2748,26 +2802,23 @@ 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 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);
@@ -2776,6 +2827,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 */
@@ -2783,14 +2859,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;
@@ -2883,17 +2964,15 @@ 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);
 
@@ -2934,11 +3013,198 @@ 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
+ulint
+fil_create_link_file(
+/*=================*/
+	const char*	link_filepath,	/*!< in: pathname of link file */
+	const char*	filepath)	/*!< in: pathname of tablespace */
+{
+	os_file_t	file;
+	ibool		ret;
+	ulint		err = DB_SUCCESS;
+
+	file = os_file_create_simple_no_error_handling(
+		innodb_file_data_key, link_filepath,
+		OS_FILE_CREATE, OS_FILE_READ_WRITE, &ret);
+
+	if (ret == FALSE) {
+		ut_print_timestamp(stderr);
+		fputs("  InnoDB: Error creating file ", stderr);
+		ut_print_filename(stderr, link_filepath);
+		fputs(".\n", stderr);
+
+		/* The following call will print an error message */
+
+		err = os_file_get_last_error(TRUE);
+
+		if (err == OS_FILE_ALREADY_EXISTS) {
+			fputs("InnoDB: The file already exists though"
+			      " the corresponding tablespace did not.\n"
+			      "InnoDB: This file is needed during crash\n"
+			      " recovery in order find\n"
+			      "InnoDB: ", stderr);
+			ut_print_filename(stderr, filepath);
+
+			err = DB_TABLESPACE_EXISTS;
+
+		} else if (err == OS_FILE_DISK_FULL) {
+			err = DB_OUT_OF_FILE_SPACE;
+
+		} else {
+			err = DB_ERROR;
+		}
+
+		/* file is not open, no need to close it. */
+		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);
+
+	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 (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("\n", stderr);
+
+		ut_print_timestamp(stderr);
+		fputs("  InnoDB: 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
 ulint
@@ -2947,10 +3213,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
@@ -2964,13 +3228,38 @@ fil_create_new_single_table_tablespace(
 	byte*		page;
 	char*		path;
 	ibool		success;
+	char*		link_filepath = NULL;
+	/* 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);
 	ut_a(fsp_flags_is_valid(flags));
 
-	path = fil_make_ibd_name(tablename, is_temp);
+	if (dir_path) {
+		/* Create a link file if needed. */
+		if (has_data_dir) {
+			link_filepath = fil_make_isl_name(tablename);
+
+			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,
@@ -3003,35 +3292,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);
+			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) {
 		err = DB_OUT_OF_FILE_SPACE;
-error_exit:
-		os_file_close(file);
-error_exit2:
-		os_file_delete(path);
-
-		mem_free(path);
-		return(err);
+		goto error_exit_2;
 	}
 
 	/* printf("Creating tablespace %s id %lu\n", path, space_id); */
@@ -3085,7 +3367,7 @@ error_exit2:
 		ut_print_filename(stderr, path);
 		putc('\n', stderr);
 		err = DB_ERROR;
-		goto error_exit;
+		goto error_exit_2;
 	}
 
 	ret = os_file_flush(file);
@@ -3095,16 +3377,22 @@ error_exit2:
 		ut_print_filename(stderr, path);
 		fputs(" failed\n", stderr);
 		err = DB_ERROR;
-		goto error_exit;
+		goto error_exit_2;
 	}
 
-	os_file_close(file);
+	if (has_data_dir && link_filepath) {
+		/* Now that the IBD file is created, make the ISL file. */
+		err = fil_create_link_file(link_filepath, path);
+		if (err != DB_SUCCESS) {
+			goto error_exit_2;
+		}
+	}
 
 	success = fil_space_create(tablename, space_id, flags, FIL_TABLESPACE);
 
 	if (!success) {
 		err = DB_ERROR;
-		goto error_exit2;
+		goto error_exit_1;
 	}
 
 	fil_node_create(path, size, space_id, FALSE);
@@ -3112,22 +3400,44 @@ 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);
+	if (link_filepath) {
+		mem_free(link_filepath);
+	}
+
+	return(err);
 }
 
 #ifndef UNIV_HOTBACKUP
@@ -3271,6 +3581,7 @@ fil_reset_space_and_lsn(
 /*====================*/
 	dict_table_t*	table,		/*!< in/out: table
 					(in: name, space_id, out: flags) */
+	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 */
@@ -3282,14 +3593,11 @@ fil_reset_space_and_lsn(
 	ibool		success;
 	page_zip_des_t	page_zip;
 	ulint		zip_size;
-	char*		filepath;
 	byte*		buf2 = 0;
 	lsn_t		flush_lsn;
 	os_offset_t	file_size;
 	ulint		fil_space_id;
 
-	filepath = fil_make_ibd_name(table->name, FALSE);
-
 	file = os_file_create_simple_no_error_handling(
 		innodb_file_data_key, filepath,
 		OS_FILE_OPEN, OS_FILE_READ_WRITE, &success);
@@ -3302,7 +3610,6 @@ fil_reset_space_and_lsn(
 			"Trying to import a table, but could not "
 			"open the tablespace file %s ", filepath);
 
-		mem_free(filepath);
 
 		return(DB_TABLESPACE_NOT_FOUND);
 
@@ -3469,12 +3776,37 @@ func_exit:
 		ut_free(buf2);
 	}
 
-	mem_free(filepath);
-
 	return(err);
 }
 
 /********************************************************************//**
+Report information about a bad tablespace.
+@return	TRUE if success */
+static
+void
+fil_report_bad_tablespace(
+/*======================*/
+	const char*	name,		/*!< in: databasename/tablename */
+	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);
+
+	ib_logf(IB_LOG_LEVEL_ERROR,
+		"Tablespace id and flags in file %s "
+		"are %lu and %lu, but in the InnoDB "
+		"data dictionary they are %lu and %lu "
+		"for table '%s'. See " REFMAN 
+		"innodb-troubleshooting-datadict.html "
+		"for how to resolve the issue.\n",
+		filepath, (ulong) found_id, (ulong) found_flags,
+		(ulong) expected_id, (ulong) expected_flags, name);
+}
+
+/********************************************************************//**
 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
 function is used to open a tablespace when we start up mysqld, and also in
@@ -3497,45 +3829,60 @@ fil_open_single_table_tablespace(
 					accessing the file */
 	ulint			id,	/*!< in: space id */
 	ulint			flags,	/*!< in: tablespace flags */
-	const char*		name)	/*!< in: table name in the
+	const char*		name,	/*!< in: table name in the
 					databasename/tablename format */
+	const char*		path_in)/*!< in: tablespace filepath */
 {
+	db_err		err = DB_SUCCESS;
 	os_file_t	file;
 	char*		filepath;
 	ibool		success;
-	ulint		space_flags;
-	db_err		err = DB_SUCCESS;
+	lsn_t		space_lsn;
 	ulint		space_id = ULINT_UNDEFINED;
-
-	filepath = fil_make_ibd_name(name, FALSE);
+	ulint		space_flags;
+	os_file_t	remote_file;
+	char*		remote_filepath;
+	ibool		remote_success = FALSE;
+	lsn_t		remote_lsn;
+	ulint		remote_id;
+	ulint		remote_flags;
+#ifdef UNIV_LOG_ARCHIVE
+	ulint		space_arch_log_no;
+	ulint		remote_arch_log_no;
+#endif /* UNIV_LOG_ARCHIVE */
 
 	if (!fsp_flags_is_valid(flags)) {
 		return(DB_CORRUPTION);
-	} else if (table != 0) {
-		space_flags = dict_tf_to_fsp_flags(table->flags);
+	}
+
+	/* Use the filepath given or create a default filepath. */
+	if (path_in) {
+		filepath = mem_strdup(path_in);
+	} else {
+		filepath = fil_make_ibd_name(name, FALSE);
+	}
 
+	/* When the table pointer is used, we need to validate the
+	contents of the tablespace we open is consistent with what
+	was cached. If the dict_table_t* is not available, we just
+	tablespace at the default/given filepath and we do not
+	validate the file. */
+	if (table != 0) {
 		ut_ad(table->name == name || !strcmp(table->name, name));
 
-		switch (space_flags) {
-		case 0:
-		case DICT_TF_COMPACT:
-			if (flags != 0) {
-				return(DB_CORRUPTION);
-			}
-			break;
-		default:
-			if (flags != space_flags) {
-				return(DB_CORRUPTION);
-			}
-			break;
-		}
+		/* Look first for a link file and a remote tablespace.
+		If the filepath is the same as the remote_filepath in
+		the link file, then this call returns false. */
+		remote_success = fil_open_linked_file(
+			name, filepath, &remote_filepath, &remote_file);
 	}
 
+	/* Attempt to open the tablespace at the default/givrn filepath. */
 	file = os_file_create_simple_no_error_handling(
 		innodb_file_data_key, filepath, OS_FILE_OPEN,
 		OS_FILE_READ_ONLY, &success);
 
-	if (!success) {
+	if (!success && !remote_success) {
 		/* The following call prints an error message */
 		os_file_get_last_error(TRUE);
 
@@ -3561,63 +3908,92 @@ fil_open_single_table_tablespace(
 		mem_free(filepath);
 
 		return(DB_TABLESPACE_NOT_FOUND);
-	} else if (table != 0) {
-		/* Skip header check */
-		space_id = id;
-	} else {
-		byte*	buf2;
-		byte*	page;
-
-		/* 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));
+	}
 
-		if (!os_file_read(file, page, 0, UNIV_PAGE_SIZE)) {
-			err = DB_IO_ERROR;
-		} else {
-			/* We have to read the tablespace id and flags
-			from the file. */
+	if (table) {
+		/* Read the first page of the datadir tablespace. */
+		if (success) {
+			fil_read_first_page(
+				file, FALSE, &space_flags, &space_id,
+#ifdef UNIV_LOG_ARCHIVE
+				&space_arch_log_no, &space_arch_log_no,
+#endif /* UNIV_LOG_ARCHIVE */
+				&space_lsn, &space_lsn);
 
-			space_id = fsp_header_get_space_id(page);
-			space_flags = fsp_header_get_flags(page);
+			/* Validate this single-table-tablespace with SYS_TABLES */
+			if (space_id != id || space_flags != flags) {
+				/* Do not use this tablespace. */
+				fil_report_bad_tablespace(
+					name, filepath, space_id,
+					space_flags, id, flags);
+				success = FALSE;
+				os_file_close(file);
+				mem_free(filepath);
+				err = DB_CORRUPTION;
+			}
 		}
 
-		ut_free(buf2);
-
-		if (err == DB_SUCCESS
-		    && (space_id != id || space_flags != flags)) {
-
-			ib_logf(IB_LOG_LEVEL_ERROR,
-				"Tablespace id and flags in the file "
-				"are %lu and %lu, but in the InnoDB "
-				"data dictionary they are %lu and %lu "
-				"for table '%s'. See "
-				REFMAN "innodb-troubleshooting-datadict.html "
-				"for how to resolve the issue.\n",
-				(ulong) space_id, (ulong) space_flags,
-				(ulong) id, (ulong) flags, table->name);
+		/* 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);
 
-			err = DB_CORRUPTION;
+			/* 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(
+					name, remote_filepath, remote_id,
+					remote_flags, id, flags);
+				remote_success = FALSE;
+				os_file_close(remote_file);
+				mem_free(remote_filepath);
+				if (!success) {
+					err = DB_CORRUPTION;
+				}
+			} else if (success) {
+				/* Figure out which tablespace is newer. */
+				if (space_lsn > remote_lsn) {
+					/* Skip the remote tablespace */
+					remote_success = FALSE;
+					os_file_close(remote_file);
+					mem_free(remote_filepath);
+				} else {
+					/* Use the remote tablespace instead. */
+					success = FALSE;
+					os_file_close(file);
+					mem_free(filepath);
+				}
+			}
 		}
 	}
 
+	/* At this point, there should be only one filepath. */
+	ut_a(success != remote_success);
+
 	if (err != DB_SUCCESS) {
 		; // Don't load the tablespace into the cache
-	} else if (!fil_space_create(name, space_id, flags, FIL_TABLESPACE)) {
+	} else if (!fil_space_create(name, id, flags, FIL_TABLESPACE)) {
 		err = DB_ERROR;
 	} else {
 		/* 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);
+		fil_node_create(filepath, 0, id, FALSE);
 	}
 
-	os_file_close(file);
-	mem_free(filepath);
+	if (success) {
+		os_file_close(file);
+		mem_free(filepath);
+	}
+	if (remote_success) {
+		os_file_close(remote_file);
+		mem_free(remote_filepath);
+	}
 
 	return(err);
 }
@@ -3656,34 +4032,63 @@ 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;
+	os_file_t	remote_file;
 	char*		filepath;
+	char*		remote_filepath;
 	char*		tablename;
+	ulint		tablename_len;
+	ulint		dbname_len = strlen(dbname);
+	ulint		filename_len = strlen(filename);
 	ibool		success;
+	ibool		remote_success;
 	byte*		buf2;
 	byte*		page;
-	ulint		space_id;
 	ulint		flags;
 	os_offset_t	size;
+	lsn_t		space_lsn;
+	lsn_t		remote_lsn;
+	ulint		space_id;
+	ulint		remote_id;
+	ulint		space_flags;
+	ulint		remote_flags;
+#ifdef UNIV_LOG_ARCHIVE
+	ulint		space_arch_log_no;
+	ulint		remote_arch_log_no;
+#endif /* UNIV_LOG_ARCHIVE */
 #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';
+
+	/* 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 */
+	filepath = static_cast<char*>(
+		mem_alloc(strlen(fil_path_to_mysql_datadir)
+			  + tablename_len + sizeof "/.ibd"));
+	sprintf(filepath, "%s/%s.ibd",
+		fil_path_to_mysql_datadir, tablename);
+	srv_normalize_path_for_win(filepath);
 
 #ifdef __WIN__
 # ifndef UNIV_HOTBACKUP
@@ -3696,28 +4101,35 @@ fil_load_single_table_tablespace(
 	dict_casedn_str(filepath);
 # endif /* !UNIV_HOTBACKUP */
 #endif
+
+	/* Check for a link file which locates a remote tablespace. */
+	remote_success = fil_open_linked_file(
+		tablename, filepath, &remote_filepath, &remote_file);
+
+	/* Try to open the tablespace in the datadir. */
 	file = os_file_create_simple_no_error_handling(
 		innodb_file_data_key, filepath, OS_FILE_OPEN,
 		OS_FILE_READ_ONLY, &success);
-	if (!success) {
+
+	if (!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: Error: could not open single-table"
+			" tablespace file\n"
 			"InnoDB: %s!\n"
 			"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"
@@ -3744,9 +4156,56 @@ fil_load_single_table_tablespace(
 		exit(1);
 	}
 
+	/* Read the first page of the datadir tablespace */
+	if (success) {
+		fil_read_first_page(
+			file, FALSE, &space_flags, &space_id,
+#ifdef UNIV_LOG_ARCHIVE
+			&space_arch_log_no, &space_arch_log_no,
+#endif /* UNIV_LOG_ARCHIVE */
+			&space_lsn, &space_lsn);
+	}
+
+	/* 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);
+	}
+
+	if (success && remote_success) {
+		/* Figure out which tablespace is newer. */
+		if (space_lsn > remote_lsn) {
+			/* Skip the remote file */
+			remote_success = FALSE;
+			os_file_close(remote_file);
+			mem_free(remote_filepath);
+		} else {
+			/* Use the remote file instead. */
+			success = FALSE;
+			os_file_close(file);
+			mem_free(filepath);
+		}
+	}
+
+	/* At this point, only one tablespace is still open */
+	ut_a((success && !remote_success) || (!success && remote_success));
+	if (remote_success) {
+		success = TRUE;
+		remote_success = FALSE;
+		file = remote_file;
+		filepath = remote_filepath;
+	}
+	/* TODO: What to do in other cases where we cannot access an .ibd
+	file during a crash recovery? */
+
+	/* 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);
 
@@ -3792,9 +4251,6 @@ fil_load_single_table_tablespace(
 		exit(1);
 	}
 
-	/* 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. */
 
@@ -3930,6 +4386,7 @@ 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);
@@ -4064,11 +4521,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:vasil.dimov@stripped
+++ b/storage/innobase/handler/ha_innodb.cc	revid:kevin.lewis@stripped
@@ -54,7 +54,6 @@ this program; if not, write to the Free 
 #include "srv0srv.h"
 #include "trx0roll.h"
 #include "trx0trx.h"
-
 #include "trx0sys.h"
 #include "mtr0mtr.h"
 #include "row0ins.h"
@@ -1412,6 +1411,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);
 	}
 }
 
@@ -2358,7 +2359,7 @@ innobase_invalidate_query_cache(
 
 	/* Argument TRUE below means we are using transactions */
 #ifdef HAVE_QUERY_CACHE
-	mysql_query_cache_invalidate4((THD*) trx->mysql_thd,
+	mysql_query_cache_invalidate4(static_cast<THD*>(trx->mysql_thd),
 				      full_name,
 				      (uint32) full_name_len,
 				      TRUE);
@@ -2542,7 +2543,8 @@ trx_is_interrupted(
 /*===============*/
 	const trx_t*	trx)	/*!< in: transaction */
 {
-	return(trx && trx->mysql_thd && thd_killed((THD*) trx->mysql_thd));
+	return(trx && trx->mysql_thd
+	       && thd_killed(static_cast<THD*>(trx->mysql_thd)));
 }
 
 /**********************************************************************//**
@@ -2555,7 +2557,7 @@ trx_is_strict(
 	trx_t*	trx)	/*!< in: transaction */
 {
 	return(trx && trx->mysql_thd
-	       && THDVAR((THD*) trx->mysql_thd, strict_mode));
+	       && THDVAR(static_cast<THD*>(trx->mysql_thd), strict_mode));
 }
 
 /**************************************************************//**
@@ -3840,32 +3842,35 @@ ha_innobase::primary_key_is_clustered()
 
 /** Always normalize table name to lower case on Windows */
 #ifdef __WIN__
-#define normalize_table_name(norm_name, name)		\
-	normalize_table_name_low(norm_name, name, TRUE)
+#define normalize_table_name(name)		\
+	normalize_table_name_low(name, TRUE)
 #else
-#define normalize_table_name(norm_name, name)           \
-	normalize_table_name_low(norm_name, name, FALSE)
+#define normalize_table_name(name)           \
+	normalize_table_name_low(name, FALSE)
 #endif /* __WIN__ */
 
 /*****************************************************************//**
 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
-					null-terminated string */
 	const char*	name,		/*!< in: table name string */
 	ibool		set_lower_case)	/*!< in: TRUE if we want to set name
 					to lower case */
 {
+	char*	norm_name;
 	char*	name_ptr;
+	ulint	name_len;
 	char*	db_ptr;
 	ulint	db_len;
 	char*	ptr;
+	ulint	norm_len;
 
 	/* Scan name from the end */
 
@@ -3877,6 +3882,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 == '/')) {
@@ -3895,15 +3901,21 @@ normalize_table_name_low(
 
 	db_ptr = ptr + 1;
 
+	norm_len = db_len + name_len + sizeof "/";
+	norm_name = static_cast<char*>(mem_alloc(norm_len));
+
 	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)
@@ -3914,7 +3926,7 @@ void
 test_normalize_table_name_low()
 /*===========================*/
 {
-	char		norm_name[128];
+	char*		norm_name;
 	const char*	test_data[][2] = {
 		/* input, expected result */
 		{"./mysqltest/t1", "mysqltest/t1"},
@@ -3960,7 +3972,7 @@ test_normalize_table_name_low()
 		       "testing \"%s\", expected \"%s\"... ",
 		       test_data[i][0], test_data[i][1]);
 
-		normalize_table_name_low(norm_name, test_data[i][0], FALSE);
+		norm_name = normalize_table_name_low(test_data[i][0], FALSE);
 
 		if (strcmp(norm_name, test_data[i][1]) == 0) {
 			printf("ok\n");
@@ -3968,6 +3980,8 @@ test_normalize_table_name_low()
 			printf("got \"%s\"\n", norm_name);
 			ut_error;
 		}
+
+		mem_free(norm_name);
 	}
 }
 
@@ -4441,12 +4455,11 @@ ha_innobase::open(
 	uint		test_if_locked)	/*!< in: not used */
 {
 	dict_table_t*	ib_table;
-	char		norm_name[1000];
+	char*		norm_name;
 	THD*		thd;
 	ulint		retries = 0;
 	char*		is_part = NULL;
-	ibool		par_case_name_set = FALSE;
-	char		par_case_name[MAX_FULL_NAME_LEN + 1];
+	char*		par_case_name = NULL;
 
 	DBUG_ENTER("ha_innobase::open");
 
@@ -4462,8 +4475,6 @@ ha_innobase::open(
 		innobase_release_temporary_latches(ht, thd);
 	}
 
-	normalize_table_name(norm_name, name);
-
 	user_thd = NULL;
 
 	if (!(share=get_share())) {
@@ -4471,6 +4482,8 @@ ha_innobase::open(
 		DBUG_RETURN(1);
 	}
 
+	norm_name = normalize_table_name(name);
+
 	/* Will be allocated if it is needed in ::update_row() */
 	upd_buf = NULL;
 	upd_buf_size = 0;
@@ -4512,24 +4525,22 @@ retry:
 			case them in the system table. */
 			if (innobase_get_lower_case_table_names() == 1) {
 
-				if (!par_case_name_set) {
+				if (par_case_name == NULL) {
 #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;
+					par_case_name = mem_strdup(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);
+					par_case_name =
+						normalize_table_name_low(
+							name, FALSE);
 #endif
-					par_case_name_set = TRUE;
 				}
 
 				ib_table = dict_table_open_on_name(
@@ -4580,12 +4591,20 @@ retry:
 			"you can resolve the problem.", norm_name);
 
 		my_errno = ENOENT;
+		mem_free(norm_name);
+		if (par_case_name) {
+			mem_free(par_case_name);
+		}
 
 		DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
 	}
 
 table_opened:
 
+	if (par_case_name) {
+		mem_free(par_case_name);
+	}
+
 	dict_stats_init(
 		ib_table,
 		table->s->db_create_options & HA_OPTION_PERSISTENT_STATS,
@@ -4632,6 +4651,8 @@ table_opened:
 		my_errno = ENOENT;
 
 		dict_table_close(ib_table, FALSE, FALSE);
+		mem_free(norm_name);
+
 		DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
 	}
 
@@ -4798,6 +4819,8 @@ table_opened:
 
 	info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
 
+	mem_free(norm_name);
+
 	DBUG_RETURN(0);
 }
 
@@ -8071,7 +8094,7 @@ create_table_check_doc_id_col(
 				*doc_id_col = i;
 			} else {
 				push_warning_printf(
-					(THD*) 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 "
@@ -8099,17 +8122,19 @@ 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;
 	int		error;
@@ -8128,13 +8153,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(
-			(THD*) 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");
 
@@ -8146,7 +8171,7 @@ create_table_def(
 	if (strcmp(strchr(table_name, '/') + 1,
 		   "innodb_table_monitor") == 0) {
 		push_warning(
-			(THD*) trx->mysql_thd, Sql_condition::WARN_LEVEL_WARN,
+			thd, Sql_condition::WARN_LEVEL_WARN,
 			HA_ERR_WRONG_COMMAND,
 			DEPRECATED_MSG_INNODB_TABLE_MONITOR);
 	}
@@ -8188,9 +8213,14 @@ create_table_def(
 					      flags, flags2);
 	}
 
-	if (flags2 & DICT_TF2_TEMPORARY) {
+	if (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 (remote_path) {
+		table->data_dir_path =
+			mem_heap_strdup(table->heap, remote_path);
 	}
 
 	heap = mem_heap_create(1000);
@@ -8203,8 +8233,7 @@ create_table_def(
 
 		if (!col_type) {
 			push_warning_printf(
-				(THD*) 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 "
@@ -8228,8 +8257,7 @@ create_table_def(
 				/* in data0type.h we assume that the
 				number fits in one byte in prtype */
 				push_warning_printf(
-					(THD*) 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."
@@ -8294,18 +8322,29 @@ err_col:
 
 	mem_heap_free(heap);
 
-	if (error == DB_DUPLICATE_KEY) {
-		char buf[100];
+	switch (error) {
+	case DB_DUPLICATE_KEY:
+	case 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(error == DB_DUPLICATE_KEY
+			 ? ER_TABLE_EXISTS_ERROR
+			 : ER_TABLESPACE_EXISTS, MYF(0), display_name);
+
+		mem_free(display_name);
+		}
 	}
 
 error_ret:
-	error = convert_error_code_to_mysql(error, flags, NULL);
+	error = convert_error_code_to_mysql(error, flags, thd);
 
 	DBUG_RETURN(error);
 }
@@ -8660,6 +8699,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);
 }
 
@@ -8675,6 +8744,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 (dict_table_is_discarded(prebuilt->table)) {
+				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;
+	}
 }
 
 /*****************************************************************//**
@@ -8695,6 +8792,108 @@ 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
+
+	*norm_name = normalize_table_name(name);
+	*temp_path = NULL;
+	*remote_path = NULL;
+
+	/* 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) {
+		*temp_path = mem_strdup(name);
+	}
+
+	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 {
+			*remote_path = mem_strdup(create_info->data_file_name);
+		}
+	}
+
+	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
@@ -8717,6 +8916,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;
@@ -8897,7 +9098,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;
@@ -8929,8 +9134,9 @@ ha_innobase::create(
 	trx_t*		trx;
 	int		primary_key_no;
 	uint		i;
-	char		name2[FN_REFLEN];
-	char		norm_name[FN_REFLEN];
+	char*		remote_path = NULL;	/* absolute path of table */
+	char*		temp_path = NULL;	/* absolute path of temp frm */
+	char*		norm_name = NULL;	/* {database}/{tablename} */
 	THD*		thd = ha_thd();
 	ib_int64_t	auto_inc_value;
 
@@ -8955,30 +9161,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 */
@@ -8986,10 +9168,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. */
@@ -9004,6 +9182,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 :
@@ -9017,11 +9201,13 @@ ha_innobase::create(
 	any user indices to be created. */
 	if (innobase_index_name_is_reserved(thd, form->key_info,
 					    form->s->keys)) {
-		DBUG_RETURN(-1);
+		error = -1;
+		goto cleanup3;
 	}
 
 	if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) {
-		DBUG_RETURN(HA_ERR_GENERIC);
+		error = HA_ERR_GENERIC;
+		goto cleanup3;
 	}
 
 	/* Get the transaction associated with the current thd, or create one
@@ -9042,7 +9228,8 @@ ha_innobase::create(
 
 	row_mysql_lock_data_dictionary(trx);
 
-	error = 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 (error) {
 		goto cleanup;
@@ -9216,8 +9403,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 cleanup2;
 		}
 	}
 
@@ -9258,17 +9445,27 @@ ha_innobase::create(
 
 	srv_active_wake_master_thread();
 
-	trx_free_for_mysql(trx);
-
-	DBUG_RETURN(0);
+	error = 0;
+	goto cleanup2;
 
 cleanup:
 	innobase_commit_low(trx);
 
 	row_mysql_unlock_data_dictionary(trx);
 
+cleanup2:
 	trx_free_for_mysql(trx);
 
+	if (remote_path) {
+		mem_free(remote_path);
+	}
+	if (temp_path) {
+		mem_free(temp_path);
+	}
+
+cleanup3:
+	mem_free(norm_name);
+
 	DBUG_RETURN(error);
 }
 
@@ -9414,7 +9611,7 @@ ha_innobase::delete_table(
 	trx_t*	parent_trx;
 	trx_t*	trx;
 	THD	*thd = ha_thd();
-	char	norm_name[1000];
+	char*	norm_name = NULL;
 	char	errstr[1024];
 
 	DBUG_ENTER("ha_innobase::delete_table");
@@ -9430,9 +9627,10 @@ ha_innobase::delete_table(
 
 	/* Strangely, MySQL passes the table name without the '.frm'
 	extension, in contrast to ::create */
-	normalize_table_name(norm_name, name);
+	norm_name = normalize_table_name(name);
 
 	if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) {
+		mem_free(norm_name);
 		DBUG_RETURN(HA_ERR_GENERIC);
 	}
 
@@ -9484,25 +9682,26 @@ ha_innobase::delete_table(
 #endif /* __WIN__ */
 
 		if (is_part) {
-			char	par_case_name[MAX_FULL_NAME_LEN + 1];
+			char*	par_case_name;
 
 #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;
+			par_case_name = mem_strdup(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);
+			par_case_name = normalize_table_name_low(
+				name, FALSE);
 #endif
-			error = row_drop_table_for_mysql(par_case_name, trx,
-							 thd_sql_command(thd)
-							 == SQLCOM_DROP_DB);
+			error = row_drop_table_for_mysql(
+				par_case_name, trx,
+				thd_sql_command(thd) == SQLCOM_DROP_DB);
+			mem_free(par_case_name);
 		}
 	}
 
@@ -9523,6 +9722,7 @@ ha_innobase::delete_table(
 
 	error = convert_error_code_to_mysql(error, 0, NULL);
 
+	mem_free(norm_name);
 	DBUG_RETURN(error);
 }
 
@@ -9622,12 +9822,8 @@ innobase_rename_table(
 	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);
+	norm_to = normalize_table_name(to);
+	norm_from = normalize_table_name(from);
 
 	/* Serialize data dictionary operations with dictionary mutex:
 	no deadlocks can occur then in these operations */
@@ -9653,27 +9849,26 @@ innobase_rename_table(
 #endif /* __WIN__ */
 
 			if (is_part) {
-				char	par_case_name[MAX_FULL_NAME_LEN + 1];
+				char*	par_case_name;
 
 #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;
+				par_case_name = mem_strdup(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);
+				par_case_name = normalize_table_name_low(
+					from, FALSE);
 #endif
 				error = (db_err) row_rename_table_for_mysql(
 					par_case_name, norm_to, trx, TRUE);
 
+				mem_free(par_case_name);
 			}
 		}
 
@@ -9713,8 +9908,8 @@ innobase_rename_table(
 
 	log_buffer_flush_to_disk();
 
-	my_free(norm_to);
-	my_free(norm_from);
+	mem_free(norm_to);
+	mem_free(norm_from);
 
 	DBUG_RETURN(error);
 }
@@ -10393,8 +10588,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));
@@ -15340,7 +15535,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;
 
@@ -15691,7 +15888,7 @@ ib_logf(
 	...)				/*!< Args */
 {
 	char*		str;
-	va_list         args;
+	va_list		args;
 
 	va_start(args, format);
 

=== modified file 'storage/innobase/handler/ha_innodb.h'
--- a/storage/innobase/handler/ha_innodb.h	revid:vasil.dimov@stripped
+++ b/storage/innobase/handler/ha_innodb.h	revid:kevin.lewis@stripped
@@ -190,6 +190,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:vasil.dimov@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;
@@ -869,7 +869,7 @@ innobase_fts_check_doc_id_index_in_def(
 		}
 
 		return(FTS_EXIST_DOC_ID_INDEX);
-        }
+	}
 
 	return(FTS_NOT_EXIST_DOC_ID_INDEX);
 }
@@ -1595,7 +1595,12 @@ 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);
+			error = HA_ERR_TABLESPACE_EXISTS;
+			goto new_clustered_failed;
 		case DB_DUPLICATE_KEY:
 			innobase_convert_tablename(new_table_name);
 			my_error(HA_ERR_TABLE_EXIST, MYF(0),
@@ -1770,8 +1775,8 @@ error_handling:
 			!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");
@@ -2775,7 +2780,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 == 0);
+			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 == 0);
 			innobase_convert_tablename(tmp_name);

=== modified file 'storage/innobase/handler/i_s.cc'
--- a/storage/innobase/handler/i_s.cc	revid:vasil.dimov@stripped
+++ b/storage/innobase/handler/i_s.cc	revid: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:vasil.dimov@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:vasil.dimov@stripped
+++ b/storage/innobase/include/db0err.h	revid:kevin.lewis@stripped
@@ -68,7 +68,7 @@ enum db_err {
 					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 was deleted or is

=== modified file 'storage/innobase/include/dict0boot.h'
--- a/storage/innobase/include/dict0boot.h	revid:vasil.dimov@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
@@ -95,7 +95,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);
@@ -280,6 +280,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:vasil.dimov@stripped
+++ b/storage/innobase/include/dict0crea.h	revid:kevin.lewis@stripped
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1996, 2009, 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
@@ -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
@@ -128,9 +128,41 @@ dict_create_add_foreigns_to_dictionary(
 				was generated here */
 	dict_table_t*	table,	/*!< in: table */
 	trx_t*		trx);	/*!< in: transaction */
+/****************************************************************//**
+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
+db_err
+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
+db_err
+dict_create_add_tablespace_to_dictionary(
+/*=====================================*/
+	ulint		space,		/*!< in: tablespace id */
+	const char*	name,		/*!< in: tablespace name */
+	ulint		flags,		/*!< in: tablespace flags */
+	trx_t*		trx);		/*!< in: transaction */
+/********************************************************************//**
+Add a single datafile definition to the data dictionary tables in the
+database. Note; the caller must commit the transaction.
+@return	error code or DB_SUCCESS */
+UNIV_INTERN
+db_err
+dict_create_add_datafile_to_dictionary(
+/*===================================*/
+	ulint		space,		/*!< in: tablespace id */
+	const char*	path,		/*!< in: tablespace path */
+	trx_t*		trx);		/*!< in: transaction */
 
-/* Table create node structure */
-
+/********************************************************************//**
+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:vasil.dimov@stripped
+++ b/storage/innobase/include/dict0dict.h	revid:kevin.lewis@stripped
@@ -836,7 +836,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:vasil.dimov@stripped
+++ b/storage/innobase/include/dict0dict.ic	revid:kevin.lewis@stripped
@@ -560,6 +560,10 @@ dict_tf_is_valid(
 		}
 	}
 
+	/* 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(true);
 }
 
@@ -580,9 +584,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) {
@@ -590,12 +592,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. */
@@ -632,6 +631,14 @@ dict_sys_tables_type_validate(
 		}
 	}
 
+	/* if (data_dir) {
+		ulint	data_dir = DICT_TF_HAS_DATA_DIR(type);
+
+		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);
 }
@@ -703,7 +710,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:
@@ -725,6 +733,10 @@ dict_tf_set(
 		ut_ad(zip_ssize == 0);
 		break;
 	}
+
+	if (use_data_dir) {
+		*flags |= (1 << DICT_TF_POS_DATA_DIR);
+	}
 }
 
 /********************************************************************//**
@@ -742,15 +754,54 @@ 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);
+
+	/* Table flags contain the DATA_DIR flag but fsp_flags do not */
+
+	ut_a(fsp_flags_is_valid(fsp_flags));
+
+	return(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);
 
-	ut_a(fsp_flags_is_valid(flags));
+	/* 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);
 }
@@ -771,14 +822,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;
 
 	ut_a(dict_tf_is_valid(flags));
-	return(flags);
+
+	/* Adjust bit zero. It is always 1 in SYS_TABLES.TYPE */
+	type = 1;
+
+	/* 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:vasil.dimov@stripped
+++ b/storage/innobase/include/dict0load.h	revid:kevin.lewis@stripped
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1996, 2009, 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
@@ -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
@@ -324,6 +338,55 @@ 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 */
+
 #ifndef UNIV_NONINL
 #include "dict0load.ic"
 #endif

=== modified file 'storage/innobase/include/dict0mem.h'
--- a/storage/innobase/include/dict0mem.h	revid:vasil.dimov@stripped
+++ b/storage/innobase/include/dict0mem.h	revid: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)
@@ -625,6 +640,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:vasil.dimov@stripped
+++ b/storage/innobase/include/fil0fil.h	revid:kevin.lewis@stripped
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2010, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 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
@@ -251,6 +251,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 */
@@ -349,6 +359,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 */
@@ -454,16 +465,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
+ulint
+fil_create_link_file(
+/*=================*/
+	const char*	link_filepath,	/*!< in: pathname of link file */
+	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
@@ -477,10 +542,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
@@ -507,11 +570,12 @@ fil_open_single_table_tablespace(
 					if no check is made, since accessing
 					the file inode probably is much
 					faster (the OS caches them) than
-					accessing the file */
-	ulint			id,	/*!< in: space id */
-	ulint			flags,	/*!< in: tablespace flags */
-	const char*		name)	/*!< in: table name in the
+					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
 					databasename/tablename format */
+	const char*	filepath)	/*!< in: tablespace filepath */
 	__attribute__((nonnull(4), warn_unused_result));
 /********************************************************************//**
 It is possible, though very improbable, that the lsn's in the tablespace to be
@@ -529,6 +593,7 @@ fil_reset_space_and_lsn(
 /*====================*/
 	dict_table_t*	table,		/*!< in/out: table
 					(in: name, space_id, out: flags) */
+	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/fsp0fsp.ic'
--- a/storage/innobase/include/fsp0fsp.ic	revid:vasil.dimov@stripped
+++ b/storage/innobase/include/fsp0fsp.ic	revid:kevin.lewis@stripped
@@ -50,7 +50,7 @@ Validate and return the tablespace flags
 tablespace header at offset FSP_SPACE_FLAGS.  They should be 0 for
 ROW_FORMAT=COMPACT and ROW_FORMAT=REDUNDANT. The newer row formats,
 COMPRESSED and DYNAMIC, use a file format > Antelope so they should
-have a file format number plus the DICT_TF_COMPACT bit set.
+have a file format number plus the POST_ANTELOPE bit set.
 @return	true if check ok */
 UNIV_INLINE
 bool

=== modified file 'storage/innobase/include/mtr0mtr.h'
--- a/storage/innobase/include/mtr0mtr.h	revid:vasil.dimov@stripped
+++ b/storage/innobase/include/mtr0mtr.h	revid:kevin.lewis@stripped
@@ -189,7 +189,7 @@ For 1 - 8 bytes, the flag value must giv
 (stored in the page number parameter, called log_flags in the
 functions).  The page number parameter was originally written as 0. @{ */
 #define MLOG_FILE_FLAG_TEMP	1	/*!< identifies TEMPORARY TABLE in
-					MLOG_FILE_CREATE, MLOG_FILE_CREATE2 */
+					MLOG_FILE_CREATE,MLOG_FILE_CREATE2*/
 /* @} */
 
 /* included here because it needs MLOG_LSN defined */

=== modified file 'storage/innobase/include/os0file.h'
--- a/storage/innobase/include/os0file.h	revid:vasil.dimov@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/row0merge.h'
--- a/storage/innobase/include/row0merge.h	revid:vasil.dimov@stripped
+++ b/storage/innobase/include/row0merge.h	revid:kevin.lewis@stripped
@@ -198,6 +198,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/os/os0file.cc'
--- a/storage/innobase/os/os0file.cc	revid:vasil.dimov@stripped
+++ b/storage/innobase/os/os0file.cc	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
@@ -645,7 +645,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) {
@@ -1054,10 +1055,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
@@ -1076,7 +1079,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);
 	}
@@ -1089,7 +1092,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);
 	}
@@ -3004,6 +3007,143 @@ 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;
+
+	/* 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;
+	}
+	ut_strcpy(++ptr, tablename);
+}
+
+/****************************************************************//**
 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/row0import.cc'
--- a/storage/innobase/row/row0import.cc	revid:vasil.dimov@stripped
+++ b/storage/innobase/row/row0import.cc	revid:kevin.lewis@stripped
@@ -2032,16 +2032,26 @@ row_import_for_mysql(
 	ib_uint64_t	autoinc = 0;
 	ulint		n_rows_in_table;
 	char		table_name[MAX_FULL_NAME_LEN + 1];
-
-	innobase_format_name(
-		table_name, sizeof(table_name), table->name, FALSE);
+	char*		filepath;
 
 	ut_a(table->space);
 	ut_ad(prebuilt->trx);
 	ut_a(table->ibd_file_missing);
 
+	innobase_format_name(
+		table_name, sizeof(table_name), table->name, FALSE);
+
 	trx_start_if_not_started(prebuilt->trx);
 
+	row_mysql_lock_data_dictionary(prebuilt->trx);
+	filepath = dict_get_first_path(table->space, table->name);
+	row_mysql_unlock_data_dictionary(prebuilt->trx);
+
+	if (!filepath) {
+		filepath = fil_make_ibd_name(table->name, FALSE);
+	}
+	ut_a(filepath);
+
 	trx = trx_allocate_for_mysql();
 
 	/* So that the table is not DROPped during recovery. */
@@ -2134,7 +2144,7 @@ row_import_for_mysql(
 
 	lsn_t	current_lsn = log_get_lsn();
 
-	err = fil_reset_space_and_lsn(table, current_lsn);
+	err = fil_reset_space_and_lsn(table, filepath, current_lsn);
 
 	DBUG_EXECUTE_IF("ib_import_reset_space_and_lsn_failure",
 			err = DB_TOO_MANY_CONCURRENT_TRXS;);
@@ -2153,7 +2163,11 @@ row_import_for_mysql(
 	err = fil_open_single_table_tablespace(
 		    table, table->space,
 		    dict_tf_to_fsp_flags(table->flags),
-		    table->name);
+		    table->name, filepath);
+
+	if (filepath) {
+		mem_free(filepath);
+	}
 
 	DBUG_EXECUTE_IF("ib_import_open_tablespace_failure",
 			err = DB_TABLESPACE_NOT_FOUND;);

=== modified file 'storage/innobase/row/row0merge.cc'
--- a/storage/innobase/row/row0merge.cc	revid:vasil.dimov@stripped
+++ b/storage/innobase/row/row0merge.cc	revid:kevin.lewis@stripped
@@ -2943,6 +2943,35 @@ 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;
+
+	if (table->space == 0) {
+		return NULL;
+	}
+
+	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.
@@ -2999,6 +3028,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;

=== modified file 'storage/innobase/row/row0mysql.cc'
--- a/storage/innobase/row/row0mysql.cc	revid:vasil.dimov@stripped
+++ b/storage/innobase/row/row0mysql.cc	revid:kevin.lewis@stripped
@@ -2084,7 +2084,7 @@ row_create_table_for_mysql(
 	que_thr_t*	thr;
 	const char*	table_name;
 	ulint		table_name_len;
-	enum db_err	err;
+	db_err		err;
 
 #ifdef UNIV_SYNC_DEBUG
 	ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
@@ -2198,6 +2198,33 @@ 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) {
+			err = dict_create_add_tablespace_to_dictionary(
+				table->space, table->name,
+				fil_space_get_flags(table->space), trx);
+		}
+
+		if (err == DB_SUCCESS) {
+			char*	path;
+			path = fil_space_get_first_path(table->space);
+
+			err = dict_create_add_datafile_to_dictionary(
+				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 +2272,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);
@@ -3050,6 +3075,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
@@ -3199,11 +3225,18 @@ 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, FALSE) == DB_SUCCESS) {
 
 			dict_index_t*	index;
 
+			/* 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
@@ -3213,9 +3246,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,
@@ -3380,25 +3415,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);
@@ -3622,6 +3674,11 @@ retry:
 
 	ut_a(table->n_foreign_key_checks_running == 0);
 
+	/* 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. */
 
@@ -3810,6 +3867,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"
@@ -3832,6 +3890,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"
@@ -3874,6 +3938,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"
@@ -4460,21 +4528,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();

=== modified file 'storage/innobase/srv/srv0start.cc'
--- a/storage/innobase/srv/srv0start.cc	revid:vasil.dimov@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)) {
@@ -1625,8 +1633,7 @@ innobase_start_or_create_for_mysql(void)
 	err = srv_boot();
 
 	if (err != DB_SUCCESS) {
-
-		return((int) err);
+		return(err);
 	}
 
 	mutex_create(srv_monitor_file_mutex_key,
@@ -1871,7 +1878,7 @@ innobase_start_or_create_for_mysql(void)
 			" InnoDB: remove old data files"
 			" which contain your precious data!\n");
 
-		return((int) err);
+		return(err);
 	}
 
 #ifdef UNIV_LOG_ARCHIVE
@@ -1884,7 +1891,7 @@ innobase_start_or_create_for_mysql(void)
 					      log_opened, 0, i);
 		if (err != DB_SUCCESS) {
 
-			return((int) err);
+			return(err);
 		}
 
 		if (log_file_created) {
@@ -1935,7 +1942,7 @@ innobase_start_or_create_for_mysql(void)
 	if (err != DB_SUCCESS
 	    && srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) {
 
-		return((int) err);
+		return(err);
 	}
 
 	if (log_created && !create_new_db
@@ -2116,6 +2123,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
@@ -2237,12 +2245,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((int)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;
@@ -2433,7 +2445,7 @@ innobase_start_or_create_for_mysql(void)
 	in a separate background thread. */
 	fts_optimize_init();
 
-	return((int) DB_SUCCESS);
+	return(DB_SUCCESS);
 }
 
 #if 0

=== modified file 'storage/innobase/ut/ut0ut.cc'
--- a/storage/innobase/ut/ut0ut.cc	revid:vasil.dimov@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("Tablespace deleted or being deleted");

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk-wl5522 branch (kevin.lewis:3858 to 3859) kevin.lewis10 Apr