summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/suite/maria/lock.result19
-rw-r--r--mysql-test/suite/maria/lock.test23
-rw-r--r--sql/sql_admin.cc38
-rw-r--r--sql/sql_base.cc32
-rw-r--r--sql/sql_partition.cc10
-rw-r--r--sql/sql_reload.cc6
-rw-r--r--sql/sql_table.cc2
-rw-r--r--sql/sql_trigger.cc2
-rw-r--r--sql/sql_truncate.cc4
9 files changed, 98 insertions, 38 deletions
diff --git a/mysql-test/suite/maria/lock.result b/mysql-test/suite/maria/lock.result
index 606cb5fed4d..101347c7d4c 100644
--- a/mysql-test/suite/maria/lock.result
+++ b/mysql-test/suite/maria/lock.result
@@ -8,3 +8,22 @@ LOCK TABLE t1 WRITE, t2 WRITE;
DROP TABLE t1;
UNLOCK TABLES;
DROP TABLE t2;
+CREATE TABLE t1 (i INT) ENGINE=Aria;
+CREATE TABLE t2 (i INT) ENGINE=Aria;
+LOCK TABLE t1 WRITE, t2 WRITE;
+FLUSH TABLE t1;
+select * from t1;
+i
+unlock tables;
+drop table t1,t2;
+CREATE TABLE t1 (i INT) ENGINE=Aria;
+CREATE TABLE t2 (i INT) ENGINE=Aria;
+LOCK TABLE t1 WRITE, t2 WRITE;
+repair table t1 use_frm;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+select * from t1;
+i
+drop table t2;
+unlock tables;
+drop table t1;
diff --git a/mysql-test/suite/maria/lock.test b/mysql-test/suite/maria/lock.test
index 564cf965d17..6116f0b5f08 100644
--- a/mysql-test/suite/maria/lock.test
+++ b/mysql-test/suite/maria/lock.test
@@ -12,6 +12,8 @@ drop table if exists t1,t2;
# under LOCK
#
+# Test DROP TABLE
+
CREATE TABLE t1 (i INT) ENGINE=Aria;
CREATE TABLE t2 (i INT) ENGINE=Aria;
LOCK TABLE t1 WRITE, t2 WRITE;
@@ -19,3 +21,24 @@ LOCK TABLE t1 WRITE, t2 WRITE;
DROP TABLE t1;
UNLOCK TABLES;
DROP TABLE t2;
+
+#Test FLUSH TABLE
+
+CREATE TABLE t1 (i INT) ENGINE=Aria;
+CREATE TABLE t2 (i INT) ENGINE=Aria;
+LOCK TABLE t1 WRITE, t2 WRITE;
+FLUSH TABLE t1;
+select * from t1;
+unlock tables;
+drop table t1,t2;
+
+# Test REPAIR ... USE_FRM and unlock tables last
+
+CREATE TABLE t1 (i INT) ENGINE=Aria;
+CREATE TABLE t2 (i INT) ENGINE=Aria;
+LOCK TABLE t1 WRITE, t2 WRITE;
+repair table t1 use_frm;
+select * from t1;
+drop table t2;
+unlock tables;
+drop table t1;
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index 7d5012f8cdf..8d0f2e5634f 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -80,6 +80,7 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
{
int error= 0;
TABLE tmp_table, *table;
+ TABLE_LIST *pos_in_locked_tables= 0;
TABLE_SHARE *share;
bool has_mdl_lock= FALSE;
char from[FN_REFLEN],tmp[FN_REFLEN+32];
@@ -194,9 +195,13 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
Table was successfully open in mysql_admin_table(). Now we need
to close it, but leave it protected by exclusive metadata lock.
*/
- if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
+ pos_in_locked_tables= table->pos_in_locked_tables;
+ if (wait_while_table_is_used(thd, table,
+ HA_EXTRA_PREPARE_FOR_FORCED_CLOSE))
goto end;
- close_all_tables_for_name(thd, table_list->table->s, HA_EXTRA_NORMAL);
+ /* Close table but don't remove from locked list */
+ close_all_tables_for_name(thd, table_list->table->s,
+ HA_EXTRA_NOT_USED);
table_list->table= 0;
}
/*
@@ -230,18 +235,25 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
goto end;
}
- if (thd->locked_tables_list.reopen_tables(thd))
- goto end;
-
- /*
- Now we should be able to open the partially repaired table
- to finish the repair in the handler later on.
- */
- if (open_table(thd, table_list, thd->mem_root, &ot_ctx))
+ if (thd->locked_tables_list.locked_tables())
{
- error= send_check_errmsg(thd, table_list, "repair",
- "Failed to open partially repaired table");
- goto end;
+ if (thd->locked_tables_list.reopen_tables(thd))
+ goto end;
+ /* Restore the table in the table list with the new opened table */
+ table_list->table= pos_in_locked_tables->table;
+ }
+ else
+ {
+ /*
+ Now we should be able to open the partially repaired table
+ to finish the repair in the handler later on.
+ */
+ if (open_table(thd, table_list, thd->mem_root, &ot_ctx))
+ {
+ error= send_check_errmsg(thd, table_list, "repair",
+ "Failed to open partially repaired table");
+ goto end;
+ }
}
end:
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 88f7484b52f..c5d11aa71f6 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1097,7 +1097,7 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables,
TABLE_LIST *tables_to_reopen= (tables ? tables :
thd->locked_tables_list.locked_tables());
- /* Close open HANLER instances to avoid self-deadlock. */
+ /* Close open HANDLER instances to avoid self-deadlock. */
mysql_ha_flush_tables(thd, tables_to_reopen);
for (TABLE_LIST *table_list= tables_to_reopen; table_list;
@@ -1111,12 +1111,13 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables,
if (! table)
continue;
- if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
+ if (wait_while_table_is_used(thd, table,
+ HA_EXTRA_PREPARE_FOR_FORCED_CLOSE))
{
result= TRUE;
goto err_with_reopen;
}
- close_all_tables_for_name(thd, table->s, HA_EXTRA_NORMAL);
+ close_all_tables_for_name(thd, table->s, HA_EXTRA_NOT_USED);
}
}
@@ -1382,9 +1383,11 @@ static void close_open_tables(THD *thd)
@param[in] share table share, but is just a handy way to
access the table cache key
- @param[in] remove_from_locked_tables
- TRUE if the table is being dropped or renamed.
- In that case the documented behaviour is to
+ @param[in] extra
+ HA_EXTRA_PREPRE_FOR_DROP if the table is being dropped
+ HA_EXTRA_PREPARE_FOR_REANME if the table is being renamed
+ HA_EXTRA_NOT_USED no drop/rename
+ In case of drop/reanme the documented behaviour is to
implicitly remove the table from LOCK TABLES
list.
@@ -1412,10 +1415,13 @@ close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
{
thd->locked_tables_list.unlink_from_list(thd,
table->pos_in_locked_tables,
- extra != HA_EXTRA_NORMAL);
- /* Inform handler that there is a drop table or rename going on */
- if (extra != HA_EXTRA_NORMAL && table->db_stat)
+ extra != HA_EXTRA_NOT_USED);
+ /* Inform handler that there is a drop table or a rename going on */
+ if (extra != HA_EXTRA_NOT_USED && table->db_stat)
+ {
table->file->extra(extra);
+ extra= HA_EXTRA_NOT_USED; // Call extra once!
+ }
/*
Does nothing if the table is not locked.
@@ -2312,7 +2318,7 @@ bool rename_temporary_table(THD* thd, TABLE *table, const char *db,
@param function HA_EXTRA_PREPARE_FOR_DROP if table is to be deleted
HA_EXTRA_FORCE_REOPEN if table is not be used
HA_EXTRA_PREPARE_FOR_RENAME if table is to be renamed
- HA_EXTRA_NORMAL Don't call extra()
+ HA_EXTRA_NOT_USED Don't call extra()
@note When returning, the table will be unusable for other threads
until metadata lock is downgraded.
@@ -2337,7 +2343,7 @@ bool wait_while_table_is_used(THD *thd, TABLE *table,
table->s->db.str, table->s->table_name.str,
FALSE);
/* extra() call must come only after all instances above are closed */
- if (function != HA_EXTRA_NORMAL)
+ if (function != HA_EXTRA_NOT_USED)
(void) table->file->extra(function);
DBUG_RETURN(FALSE);
}
@@ -3386,7 +3392,6 @@ Locked_tables_list::init_locked_tables(THD *thd)
void
Locked_tables_list::unlock_locked_tables(THD *thd)
-
{
if (thd)
{
@@ -3408,7 +3413,8 @@ Locked_tables_list::unlock_locked_tables(THD *thd)
Clear the position in the list, the TABLE object will be
returned to the table cache.
*/
- table_list->table->pos_in_locked_tables= NULL;
+ if (table_list->table) // If not closed
+ table_list->table->pos_in_locked_tables= NULL;
}
thd->leave_locked_tables_mode();
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 00fba5f331a..a9c79589faa 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -6270,7 +6270,7 @@ static void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt)
THD *thd= lpt->thd;
if (lpt->old_table)
- close_all_tables_for_name(thd, lpt->old_table->s, HA_EXTRA_NORMAL);
+ close_all_tables_for_name(thd, lpt->old_table->s, HA_EXTRA_NOT_USED);
if (lpt->table)
{
/*
@@ -6307,7 +6307,7 @@ static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt, bool close_old)
}
if (close_old && lpt->old_table)
{
- close_all_tables_for_name(lpt->thd, lpt->old_table->s, HA_EXTRA_NORMAL);
+ close_all_tables_for_name(lpt->thd, lpt->old_table->s, HA_EXTRA_NOT_USED);
lpt->old_table= 0;
}
DBUG_RETURN(0);
@@ -6640,7 +6640,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
ERROR_INJECT_CRASH("crash_drop_partition_2") ||
ERROR_INJECT_ERROR("fail_drop_partition_2") ||
- wait_while_table_is_used(thd, table, HA_EXTRA_NORMAL) ||
+ 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) ||
@@ -6714,7 +6714,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
mysql_write_frm(lpt, WFRM_WRITE_SHADOW) ||
ERROR_INJECT_CRASH("crash_add_partition_2") ||
ERROR_INJECT_ERROR("fail_add_partition_2") ||
- wait_while_table_is_used(thd, table, HA_EXTRA_NORMAL) ||
+ 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) ||
@@ -6820,7 +6820,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
mysql_change_partitions(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_4") ||
ERROR_INJECT_ERROR("fail_change_partition_4") ||
- wait_while_table_is_used(thd, table, HA_EXTRA_NORMAL) ||
+ wait_while_table_is_used(thd, table, HA_EXTRA_NOT_USED) ||
ERROR_INJECT_CRASH("crash_change_partition_5") ||
ERROR_INJECT_ERROR("fail_change_partition_5") ||
write_log_final_change_partition(lpt) ||
diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc
index d2f118b62c9..1f3b1effff3 100644
--- a/sql/sql_reload.cc
+++ b/sql/sql_reload.cc
@@ -243,9 +243,9 @@ bool reload_acl_and_cache(THD *thd, unsigned long options,
{
/*
It is not safe to upgrade the metadata lock without GLOBAL IX lock.
- This can happen with FLUSH TABLES <list> WITH READ LOCK as we in these
- cases don't take a GLOBAL IX lock in order to be compatible with
- global read lock.
+ This can happen with FLUSH TABLES <list> WITH READ LOCK as we in
+ these cases don't take a GLOBAL IX lock in order to be compatible
+ with global read lock.
*/
if (thd->open_tables &&
!thd->mdl_context.is_lock_owner(MDL_key::GLOBAL, "", "",
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 51d1eab14f1..6e9d1709c8a 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -6894,7 +6894,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
close_all_tables_for_name(thd, table->s,
new_name != table_name || new_db != db ?
HA_EXTRA_PREPARE_FOR_RENAME :
- HA_EXTRA_NORMAL);
+ HA_EXTRA_NOT_USED);
error=0;
table_list->table= table= 0; /* Safety */
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 2eefe7d2c74..1b942ecc93b 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -561,7 +561,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
if (result)
goto end;
- close_all_tables_for_name(thd, table->s, HA_EXTRA_NORMAL);
+ close_all_tables_for_name(thd, table->s, HA_EXTRA_NOT_USED);
/*
Reopen the table if we were under LOCK TABLES.
Ignore the return value for now. It's better to
diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc
index b84a00eb0fc..3c1b231d3f2 100644
--- a/sql/sql_truncate.cc
+++ b/sql/sql_truncate.cc
@@ -358,12 +358,12 @@ bool Truncate_statement::lock_table(THD *thd, TABLE_LIST *table_ref,
{
DEBUG_SYNC(thd, "upgrade_lock_for_truncate");
/* To remove the table from the cache we need an exclusive lock. */
- if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
+ if (wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_DROP))
DBUG_RETURN(TRUE);
m_ticket_downgrade= table->mdl_ticket;
/* Close if table is going to be recreated. */
if (*hton_can_recreate)
- close_all_tables_for_name(thd, table->s, HA_EXTRA_PREPARE_FOR_DROP);
+ close_all_tables_for_name(thd, table->s, HA_EXTRA_NOT_USED);
}
else
{