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.lewis | 10 Apr |