diff --git a/mysql-test/suite/parts/r/partition_special_innodb.result b/mysql-test/suite/parts/r/partition_special_innodb.result index 01c6e1f9e64..37191eae502 100644 --- a/mysql-test/suite/parts/r/partition_special_innodb.result +++ b/mysql-test/suite/parts/r/partition_special_innodb.result @@ -236,6 +236,7 @@ DROP TABLE t1; connect con1,localhost,root,,; CREATE TABLE t1 ( i INT NOT NULL AUTO_INCREMENT PRIMARY KEY, f INT ) ENGINE = InnoDB PARTITION BY HASH(i) PARTITIONS 2; +INSERT INTO t1 VALUES (2, 2), (3, 3), (4, 4), (5, 5); connect con2,localhost,root,,; SET lock_wait_timeout = 2; connection con1; @@ -249,6 +250,19 @@ ERROR HY000: Lock wait timeout exceeded; try restarting transaction # Second attempt: says that partition already exists ALTER TABLE t1 ADD PARTITION PARTITIONS 2; ERROR HY000: Lock wait timeout exceeded; try restarting transaction +# Check that we only can select, not insert/update/delete. +INSERT INTO t1 VALUES (NULL, 6), (NULL, 7), (10, 10), (11, 11); +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +UPDATE t1 SET i = 5 WHERE f = 2; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +DELETE FROM t1 WHERE i = 10; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +SELECT * FROM t1; +i f +2 2 +3 3 +4 4 +5 5 connection con1; # Connection 1 unlocks the table and locks it again: UNLOCK TABLES; @@ -335,3 +349,30 @@ PARTITION BY RANGE(f1) (PARTITION p1 VALUES LESS THAN(10), PARTITION p2 VALUES LESS THAN (100)); ALTER TABLE t1 convert to charset ascii collate ascii_bin, ALGORITHM=INSTANT; DROP TABLE t1; +# Test WRITE LOCK. +connect con1,localhost,root,,; +CREATE TABLE t1 ( i INT NOT NULL AUTO_INCREMENT PRIMARY KEY, f INT ) +ENGINE = InnoDB PARTITION BY HASH(i) PARTITIONS 2; +INSERT INTO t1 VALUES (3, 3), (4, 4); +connect con2,localhost,root,,; +SET lock_wait_timeout = 2; +connection con1; +#Connection 1 locks the table +LOCK TABLE t1 WRITE; +connection con2; +# Check that we still can SELECT, but not insert/update/delete. +# Check that we only can select, not insert/update/delete. +INSERT INTO t1 VALUES (NULL, 1), (NULL, 2), (10, 10), (11, 11); +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +UPDATE t1 SET i = 5 WHERE f = 2; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +DELETE FROM t1 WHERE i = 10; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +SELECT * FROM t1; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +connection con1; +UNLOCK TABLES; +connection con2; +DROP TABLE t1; +disconnect con1; +connection default; diff --git a/mysql-test/suite/parts/t/partition_special_innodb.test b/mysql-test/suite/parts/t/partition_special_innodb.test index ef7cf4bd4cf..a25feed08ef 100644 --- a/mysql-test/suite/parts/t/partition_special_innodb.test +++ b/mysql-test/suite/parts/t/partition_special_innodb.test @@ -83,6 +83,7 @@ DROP TABLE t1; --connect (con1,localhost,root,,) CREATE TABLE t1 ( i INT NOT NULL AUTO_INCREMENT PRIMARY KEY, f INT ) ENGINE = InnoDB PARTITION BY HASH(i) PARTITIONS 2; +INSERT INTO t1 VALUES (2, 2), (3, 3), (4, 4), (5, 5); --connect (con2,localhost,root,,) SET lock_wait_timeout = 2; @@ -99,6 +100,15 @@ ALTER TABLE t1 ADD PARTITION PARTITIONS 2; --echo # Second attempt: says that partition already exists --error ER_LOCK_WAIT_TIMEOUT ALTER TABLE t1 ADD PARTITION PARTITIONS 2; +--echo # Check that we only can select, not insert/update/delete. +--error ER_LOCK_WAIT_TIMEOUT +INSERT INTO t1 VALUES (NULL, 6), (NULL, 7), (10, 10), (11, 11); +--error ER_LOCK_WAIT_TIMEOUT +UPDATE t1 SET i = 5 WHERE f = 2; +--error ER_LOCK_WAIT_TIMEOUT +DELETE FROM t1 WHERE i = 10; +--sorted_result +SELECT * FROM t1; --connection con1 --echo # Connection 1 unlocks the table and locks it again: @@ -215,3 +225,37 @@ CREATE TABLE t1( PARTITION p2 VALUES LESS THAN (100)); ALTER TABLE t1 convert to charset ascii collate ascii_bin, ALGORITHM=INSTANT; DROP TABLE t1; + +--echo # Test WRITE LOCK. +--connect (con1,localhost,root,,) +CREATE TABLE t1 ( i INT NOT NULL AUTO_INCREMENT PRIMARY KEY, f INT ) + ENGINE = InnoDB PARTITION BY HASH(i) PARTITIONS 2; +INSERT INTO t1 VALUES (3, 3), (4, 4); + +--connect (con2,localhost,root,,) +SET lock_wait_timeout = 2; + +--connection con1 +--echo #Connection 1 locks the table +LOCK TABLE t1 WRITE; + +--connection con2 +--echo # Check that we still can SELECT, but not insert/update/delete. +--echo # Check that we only can select, not insert/update/delete. +--error ER_LOCK_WAIT_TIMEOUT +INSERT INTO t1 VALUES (NULL, 1), (NULL, 2), (10, 10), (11, 11); +--error ER_LOCK_WAIT_TIMEOUT +UPDATE t1 SET i = 5 WHERE f = 2; +--error ER_LOCK_WAIT_TIMEOUT +DELETE FROM t1 WHERE i = 10; +--error ER_LOCK_WAIT_TIMEOUT +SELECT * FROM t1; + +--connection con1 +UNLOCK TABLES; + +--connection con2 +DROP TABLE t1; + +--disconnect con1 +--connection default diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ef8ef5114a8..ff1ddd200d0 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -6808,41 +6808,30 @@ static int alter_close_table(ALTER_PARTITION_PARAM_TYPE *lpt) static void handle_alter_part_error(ALTER_PARTITION_PARAM_TYPE *lpt, bool action_completed, bool drop_partition, - bool frm_install, - bool close_table) + bool frm_install) { - partition_info *part_info= lpt->part_info; THD *thd= lpt->thd; + partition_info *part_info= lpt->part_info->get_clone(thd); TABLE *table= lpt->table; DBUG_ENTER("handle_alter_part_error"); DBUG_ASSERT(table->m_needs_reopen); - if (close_table) + /* + All instances of this table needs to be closed. + Better to do that here, than leave the cleaning up to others. + Acquire EXCLUSIVE mdl lock if not already acquired. + */ + if (!thd->mdl_context.is_lock_owner(MDL_key::TABLE, lpt->db.str, + lpt->table_name.str, + MDL_EXCLUSIVE) && + wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) { /* - All instances of this table needs to be closed. - Better to do that here, than leave the cleaning up to others. - Aquire EXCLUSIVE mdl lock if not already aquired. - */ - if (!thd->mdl_context.is_lock_owner(MDL_key::TABLE, lpt->db.str, - lpt->table_name.str, - MDL_EXCLUSIVE)) - { - if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) - { - /* At least remove this instance on failure */ - goto err_exclusive_lock; - } - } - /* Ensure the share is destroyed and reopened. */ - if (part_info) - part_info= part_info->get_clone(thd); - close_all_tables_for_name(thd, table->s, HA_EXTRA_NOT_USED, NULL); - } - else - { -err_exclusive_lock: - /* + Did not succeed in getting exclusive access to the table. + + Since we have altered a cached table object (and its part_info) we need + at least to remove this instance so it will not be reused. + Temporarily remove it from the locked table list, so that it will get reopened. */ @@ -6854,11 +6843,14 @@ err_exclusive_lock: the table cache. */ mysql_lock_remove(thd, thd->lock, table); - if (part_info) - part_info= part_info->get_clone(thd); close_thread_table(thd, &thd->open_tables); lpt->table_list->table= NULL; } + else + { + /* Ensure the share is destroyed and reopened. */ + close_all_tables_for_name(thd, table->s, HA_EXTRA_NOT_USED, NULL); + } if (part_info->first_log_entry && execute_ddl_log_entry(thd, part_info->first_log_entry->entry_pos)) @@ -6876,17 +6868,20 @@ err_exclusive_lock: /* Table is still ok, but we left a shadow frm file behind. */ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, 1, "%s %s", - "Operation was unsuccessful, table is still intact,", - "but it is possible that a shadow frm file was left behind"); + "Operation was unsuccessful, table is still " + "intact, but it is possible that a shadow frm " + "file was left behind"); } else { push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, 1, "%s %s %s %s", - "Operation was unsuccessful, table is still intact,", - "but it is possible that a shadow frm file was left behind.", - "It is also possible that temporary partitions are left behind,", - "these could be empty or more or less filled with records"); + "Operation was unsuccessful, table is still " + "intact, but it is possible that a shadow frm " + "file was left behind.", + "It is also possible that temporary partitions " + "are left behind, these could be empty or more " + "or less filled with records"); } } else @@ -6894,14 +6889,15 @@ err_exclusive_lock: if (frm_install) { /* - Failed during install of shadow frm file, table isn't intact - and dropped partitions are still there + Failed during install of shadow frm file, table isn't intact + and dropped partitions are still there */ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, 1, "%s %s %s", - "Failed during alter of partitions, table is no longer intact.", - "The frm file is in an unknown state, and a backup", - "is required."); + "Failed during alter of partitions, table is no " + "longer intact.", + "The frm file is in an unknown state, and a " + "backup is required."); } else if (drop_partition) { @@ -6913,8 +6909,9 @@ err_exclusive_lock: */ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, 1, "%s %s", - "Failed during drop of partitions, table is intact.", - "Manual drop of remaining partitions is required"); + "Failed during drop of partitions, table is " + "intact.", + "Manual drop of remaining partitions is required"); } else { @@ -6925,9 +6922,10 @@ err_exclusive_lock: */ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, 1, "%s %s %s", - "Failed during renaming of partitions. We are now in a position", - "where table is not reusable", - "Table is disabled by writing ancient frm file version into it"); + "Failed during renaming of partitions. We are now " + "in a position where table is not reusable", + "Table is disabled by writing ancient frm file " + "version into it"); } } } @@ -6953,8 +6951,8 @@ err_exclusive_lock: completed. */ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, 1,"%s %s", - "Operation was successfully completed by failure handling,", - "after failure of normal operation"); + "Operation was successfully completed by failure " + "handling, after failure of normal operation"); } } @@ -7032,7 +7030,6 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ALTER_PARTITION_PARAM_TYPE lpt_obj; ALTER_PARTITION_PARAM_TYPE *lpt= &lpt_obj; bool action_completed= FALSE; - bool close_table_on_failure= FALSE; bool frm_install= FALSE; MDL_ticket *mdl_ticket= table->mdl_ticket; DBUG_ENTER("fast_alter_partition_table"); @@ -7171,13 +7168,11 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) || ERROR_INJECT_CRASH("crash_drop_partition_3") || ERROR_INJECT_ERROR("fail_drop_partition_3") || - (close_table_on_failure= TRUE, FALSE) || write_log_drop_partition(lpt) || (action_completed= TRUE, FALSE) || ERROR_INJECT_CRASH("crash_drop_partition_4") || ERROR_INJECT_ERROR("fail_drop_partition_4") || alter_close_table(lpt) || - (close_table_on_failure= FALSE, FALSE) || ERROR_INJECT_CRASH("crash_drop_partition_5") || ERROR_INJECT_ERROR("fail_drop_partition_5") || ((!thd->lex->no_write_to_binlog) && @@ -7197,8 +7192,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_drop_partition_9") || ERROR_INJECT_ERROR("fail_drop_partition_9")) { - handle_alter_part_error(lpt, action_completed, TRUE, frm_install, - close_table_on_failure); + handle_alter_part_error(lpt, action_completed, TRUE, frm_install); goto err; } if (alter_partition_lock_handling(lpt)) @@ -7246,14 +7240,12 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) || ERROR_INJECT_CRASH("crash_add_partition_3") || ERROR_INJECT_ERROR("fail_add_partition_3") || - (close_table_on_failure= TRUE, FALSE) || write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_add_partition_4") || ERROR_INJECT_ERROR("fail_add_partition_4") || mysql_change_partitions(lpt) || ERROR_INJECT_CRASH("crash_add_partition_5") || ERROR_INJECT_ERROR("fail_add_partition_5") || - (close_table_on_failure= FALSE, FALSE) || alter_close_table(lpt) || ERROR_INJECT_CRASH("crash_add_partition_6") || ERROR_INJECT_ERROR("fail_add_partition_6") || @@ -7275,8 +7267,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_add_partition_10") || ERROR_INJECT_ERROR("fail_add_partition_10")) { - handle_alter_part_error(lpt, action_completed, FALSE, frm_install, - close_table_on_failure); + handle_alter_part_error(lpt, action_completed, FALSE, frm_install); goto err; } if (alter_partition_lock_handling(lpt)) @@ -7343,7 +7334,6 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, mysql_write_frm(lpt, WFRM_WRITE_SHADOW) || ERROR_INJECT_CRASH("crash_change_partition_2") || ERROR_INJECT_ERROR("fail_change_partition_2") || - (close_table_on_failure= TRUE, FALSE) || write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_3") || ERROR_INJECT_ERROR("fail_change_partition_3") || @@ -7354,7 +7344,6 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_5") || ERROR_INJECT_ERROR("fail_change_partition_5") || alter_close_table(lpt) || - (close_table_on_failure= FALSE, FALSE) || ERROR_INJECT_CRASH("crash_change_partition_6") || ERROR_INJECT_ERROR("fail_change_partition_6") || write_log_final_change_partition(lpt) || @@ -7381,8 +7370,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_12") || ERROR_INJECT_ERROR("fail_change_partition_12")) { - handle_alter_part_error(lpt, action_completed, FALSE, frm_install, - close_table_on_failure); + handle_alter_part_error(lpt, action_completed, FALSE, frm_install); goto err; } if (alter_partition_lock_handling(lpt))