diff options
-rw-r--r-- | mysql-test/r/partition_innodb.result | 28 | ||||
-rw-r--r-- | mysql-test/t/partition_innodb.test | 21 | ||||
-rw-r--r-- | sql/sql_table.cc | 63 |
3 files changed, 112 insertions, 0 deletions
diff --git a/mysql-test/r/partition_innodb.result b/mysql-test/r/partition_innodb.result index 148504bcc8b..525cc439cd1 100644 --- a/mysql-test/r/partition_innodb.result +++ b/mysql-test/r/partition_innodb.result @@ -489,3 +489,31 @@ Warning 1265 Data truncated for column 'b' at row 1 Error 1067 Invalid default value for 'b' SET SESSION sql_mode = @old_mode; DROP TABLE t1; +# +# Bug#57985 "ONLINE/FAST ALTER PARTITION can fail and leave the +# table unusable". +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a bigint not null, b int not null, PRIMARY KEY (a)) +ENGINE = InnoDB PARTITION BY KEY(a) PARTITIONS 2; +INSERT INTO t1 values (0,1), (1,2); +# The below ALTER should fail. It should leave the +# table in its original, non-corrupted, usable state. +ALTER TABLE t1 ADD UNIQUE KEY (b); +ERROR HY000: A UNIQUE INDEX must include all columns in the table's partitioning function +# The below statements should succeed, as ALTER should +# have left table intact. +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(20) NOT NULL, + `b` int(11) NOT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY KEY (a) +PARTITIONS 2 */ +SELECT * FROM t1; +a b +1 2 +0 1 +DROP TABLE t1; diff --git a/mysql-test/t/partition_innodb.test b/mysql-test/t/partition_innodb.test index 3e9ac2ce2b5..ddc2812f617 100644 --- a/mysql-test/t/partition_innodb.test +++ b/mysql-test/t/partition_innodb.test @@ -569,3 +569,24 @@ SET SESSION sql_mode = 'NO_ZERO_DATE'; OPTIMIZE TABLE t1; SET SESSION sql_mode = @old_mode; DROP TABLE t1; + + +--echo # +--echo # Bug#57985 "ONLINE/FAST ALTER PARTITION can fail and leave the +--echo # table unusable". +--echo # +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TABLE t1 (a bigint not null, b int not null, PRIMARY KEY (a)) + ENGINE = InnoDB PARTITION BY KEY(a) PARTITIONS 2; +INSERT INTO t1 values (0,1), (1,2); +--echo # The below ALTER should fail. It should leave the +--echo # table in its original, non-corrupted, usable state. +--error ER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF +ALTER TABLE t1 ADD UNIQUE KEY (b); +--echo # The below statements should succeed, as ALTER should +--echo # have left table intact. +SHOW CREATE TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 6d5180c38d9..772496a10d5 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3815,6 +3815,46 @@ void sp_prepare_create_field(THD *thd, Create_field *sql_field) (void) prepare_blob_field(thd, sql_field); } + +/** + Auxiliary function which allows to check if freshly created .FRM + file for table can be opened. + + @retval FALSE - Success. + @retval TRUE - Failure. +*/ + +static bool check_if_created_table_can_be_opened(THD *thd, + const char *path, + const char *db, + const char *table_name, + HA_CREATE_INFO *create_info, + handler *file) +{ + TABLE table; + TABLE_SHARE share; + bool result; + + /* + It is impossible to open definition of partitioned table without .par file. + */ + if (file->ha_create_handler_files(path, NULL, CHF_CREATE_FLAG, create_info)) + return TRUE; + + init_tmp_table_share(thd, &share, db, 0, table_name, path); + + result= (open_table_def(thd, &share, 0) || + open_table_from_share(thd, &share, "", 0, (uint) READ_ALL, + 0, &table, TRUE)); + if (! result) + (void) closefrm(&table, 0); + + free_table_share(&share); + (void) file->ha_create_handler_files(path, NULL, CHF_DELETE_FLAG, create_info); + return result; +} + + /* Create a table @@ -4241,6 +4281,29 @@ bool mysql_create_table_no_lock(THD *thd, thd->thread_specific_used= TRUE; } +#ifdef WITH_PARTITION_STORAGE_ENGINE + else if (part_info && create_info->frm_only) + { + /* + For partitioned tables we can't find some problems with table + until table is opened. Therefore in order to disallow creation + of corrupted tables we have to try to open table as the part + of its creation process. + In cases when both .FRM and SE part of table are created table + is implicitly open in ha_create_table() call. + In cases when we create .FRM without SE part we have to open + table explicitly. + */ + if (check_if_created_table_can_be_opened(thd, path, db, table_name, + create_info, file)) + { + char frm_name[FN_REFLEN]; + strxmov(frm_name, path, reg_ext, NullS); + (void) mysql_file_delete(key_file_frm, frm_name, MYF(0)); + goto err; + } + } +#endif error= FALSE; err: |