mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
Backport of:
---------------------------------------------------------- revno: 2630.10.1 committer: Konstantin Osipov <konstantin@mysql.com> branch nick: mysql-6.0-lock-tables-tidyup timestamp: Wed 2008-06-11 15:49:58 +0400 message: WL#3726, review fixes. Now that we have metadata locks, we don't need to keep a crippled TABLE instance in the table cache to indicate that a table is locked. Remove all code that used this technique. Instead, rely on metadata locks and use the standard open_table() and close_thread_table() to manipulate with the table cache tables. Removes a list of functions that have become unused (see the comment for sql_base.cc for details). Under LOCK TABLES, keep a TABLE_LIST instance for each table that may be temporarily closed. For that, implement an own class for LOCK TABLES mode, Locked_tables_list. This is a pre-requisite patch for WL#4144. This is not exactly a backport: there is no new online ALTER table in Celosia, so the old alter table code was changed to work with the new table cache API. mysql-test/r/lock.result: Update results (WL#3726 post-review patch). mysql-test/r/trigger-compat.result: We take the table from the table cache now, thus no warning. mysql-test/suite/rpl/r/rpl_trigger.result: We take the table from the table cache now, thus no warning. mysql-test/t/lock.test: Additional tests for LOCK TABLES mode (previously not covered by the test suite (WL#3726). sql/field.h: Remove reopen_table(). sql/lock.cc: Remove an obsolete parameter of mysql_lock_remove(). It's not used anywhere now either. sql/mysql_priv.h: Add 4 new open_table() flags. Remove declarations of removed functions. sql/sp_head.cc: Rename thd->mdl_el_root to thd->locked_tables_root. sql/sql_acl.cc: Use the new implementation of unlock_locked_tables(). sql/sql_base.cc: Implement class Locked_tables_list. Implement close_all_tables_for_name(). Rewrite close_cached_tables() to use the new reopen_tables(). Remove reopen_table(), reopen_tables(), reopen_table_entry() (ex. open_unireg_entry()), close_data_files_and_leave_as_placeholders(), close_handle_and_leave_table_as_placeholder(), close_cached_table(), table_def_change_share(), reattach_merge(), reopen_name_locked_table(), unlink_open_table(). Move acquisition of a metadata lock into an own function - open_table_get_mdl_lock(). sql/sql_class.cc: Deploy class Locked_tables_list. sql/sql_class.h: Declare class Locked_tables_list. Keep one instance of this class in class THD. Rename mdl_el_root to locked_tables_root. sql/sql_db.cc: Update a comment. sql/sql_insert.cc: Use the plain open_table() to open a just created table in CREATE TABLE .. SELECT. sql/sql_parse.cc: Use thd->locked_tables_list to enter and leave LTM_LOCK_TABLES mode. sql/sql_partition.cc: Deploy the new method of working with partitioned table locks. sql/sql_servers.cc: Update to the new signature of unlock_locked_tables(). sql/sql_table.cc: In mysql_rm_table_part2(), the branch that removes a table under LOCK TABLES, make sure that the table being dropped is also removed from THD::locked_tables_list. Update ALTER TABLE and CREATE TABLE LIKE implementation to use open_table() and close_all_tables_for_name() instead of reopen_tables(). sql/sql_trigger.cc: Use the new locking way. sql/table.h: Add TABLE::pos_in_locked_tables, which is used only under LOCK TABLES.
This commit is contained in:
parent
e8a9191e64
commit
3104af49cd
20 changed files with 767 additions and 1199 deletions
|
@ -201,3 +201,48 @@ ERROR HY000: Table 't2' was locked with a READ lock and can't be updated
|
|||
UNLOCK TABLES;
|
||||
DROP TABLE t1,t2;
|
||||
End of 5.1 tests.
|
||||
#
|
||||
# Ensure that FLUSH TABLES doesn't substitute a base locked table
|
||||
# with a temporary one.
|
||||
#
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
lock table t1 write, t2 write;
|
||||
create temporary table t1 (a int);
|
||||
flush table t1;
|
||||
drop temporary table t1;
|
||||
select * from t1;
|
||||
a
|
||||
unlock tables;
|
||||
drop table t1, t2;
|
||||
#
|
||||
# Ensure that REPAIR .. USE_FRM works under LOCK TABLES.
|
||||
#
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
lock table t1 write, t2 write;
|
||||
repair table t1 use_frm;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 repair status OK
|
||||
repair table t1 use_frm;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 repair status OK
|
||||
select * from t1;
|
||||
a
|
||||
select * from t2;
|
||||
a
|
||||
repair table t2 use_frm;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t2 repair status OK
|
||||
repair table t2 use_frm;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t2 repair status OK
|
||||
select * from t1;
|
||||
a
|
||||
unlock tables;
|
||||
drop table t1, t2;
|
||||
#
|
||||
# End of 6.0 tests.
|
||||
#
|
||||
|
|
|
@ -34,8 +34,6 @@ TRIGGER_CATALOG TRIGGER_SCHEMA TRIGGER_NAME EVENT_MANIPULATION EVENT_OBJECT_CATA
|
|||
def mysqltest_db1 wl2818_trg1 INSERT def mysqltest_db1 t1 0 NULL INSERT INTO t2 VALUES(CURRENT_USER()) ROW BEFORE NULL NULL OLD NEW NULL latin1 latin1_swedish_ci latin1_swedish_ci
|
||||
def mysqltest_db1 wl2818_trg2 INSERT def mysqltest_db1 t1 0 NULL INSERT INTO t2 VALUES(CURRENT_USER()) ROW AFTER NULL NULL OLD NEW NULL mysqltest_dfn@localhost latin1 latin1_swedish_ci latin1_swedish_ci
|
||||
DROP TRIGGER wl2818_trg1;
|
||||
Warnings:
|
||||
Warning 1454 No definer attribute for trigger 'mysqltest_db1'.'wl2818_trg1'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger.
|
||||
DROP TRIGGER wl2818_trg2;
|
||||
use mysqltest_db1;
|
||||
DROP TABLE t1;
|
||||
|
|
|
@ -893,8 +893,6 @@ s
|
|||
@
|
||||
root@localhost
|
||||
DROP TRIGGER trg1;
|
||||
Warnings:
|
||||
Warning 1454 No definer attribute for trigger 'test'.'trg1'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger.
|
||||
DROP TABLE t1;
|
||||
DROP TABLE t2;
|
||||
STOP SLAVE;
|
||||
|
|
|
@ -252,3 +252,46 @@ UNLOCK TABLES;
|
|||
DROP TABLE t1,t2;
|
||||
|
||||
--echo End of 5.1 tests.
|
||||
|
||||
--echo #
|
||||
--echo # Ensure that FLUSH TABLES doesn't substitute a base locked table
|
||||
--echo # with a temporary one.
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
lock table t1 write, t2 write;
|
||||
create temporary table t1 (a int);
|
||||
flush table t1;
|
||||
drop temporary table t1;
|
||||
select * from t1;
|
||||
unlock tables;
|
||||
drop table t1, t2;
|
||||
|
||||
--echo #
|
||||
--echo # Ensure that REPAIR .. USE_FRM works under LOCK TABLES.
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
lock table t1 write, t2 write;
|
||||
repair table t1 use_frm;
|
||||
repair table t1 use_frm;
|
||||
select * from t1;
|
||||
select * from t2;
|
||||
repair table t2 use_frm;
|
||||
repair table t2 use_frm;
|
||||
select * from t1;
|
||||
unlock tables;
|
||||
drop table t1, t2;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # End of 6.0 tests.
|
||||
--echo #
|
||||
|
|
|
@ -478,7 +478,6 @@ public:
|
|||
}
|
||||
/* Hash value */
|
||||
virtual void hash(ulong *nr, ulong *nr2);
|
||||
friend bool reopen_table(THD *,struct st_table *,bool);
|
||||
friend int cre_myisam(char * name, register TABLE *form, uint options,
|
||||
ulonglong auto_increment_value);
|
||||
friend class Copy_field;
|
||||
|
|
20
sql/lock.cc
20
sql/lock.cc
|
@ -512,28 +512,15 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
|
|||
/**
|
||||
Try to find the table in the list of locked tables.
|
||||
In case of success, unlock the table and remove it from this list.
|
||||
|
||||
@note This function has a legacy side effect: the table is
|
||||
unlocked even if it is not found in the locked list.
|
||||
It's not clear if this side effect is intentional or still
|
||||
desirable. It might lead to unmatched calls to
|
||||
unlock_external(). Moreover, a discrepancy can be left
|
||||
unnoticed by the storage engine, because in
|
||||
unlock_external() we call handler::external_lock(F_UNLCK) only
|
||||
if table->current_lock is not F_UNLCK.
|
||||
If a table has more than one lock instance, removes them all.
|
||||
|
||||
@param thd thread context
|
||||
@param locked list of locked tables
|
||||
@param table the table to unlock
|
||||
@param always_unlock specify explicitly if the legacy side
|
||||
effect is desired.
|
||||
*/
|
||||
|
||||
void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table,
|
||||
bool always_unlock)
|
||||
void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table)
|
||||
{
|
||||
if (always_unlock == TRUE)
|
||||
mysql_unlock_some_tables(thd, &table, /* table count */ 1);
|
||||
if (locked)
|
||||
{
|
||||
reg1 uint i;
|
||||
|
@ -547,8 +534,7 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table,
|
|||
|
||||
DBUG_ASSERT(table->lock_position == i);
|
||||
|
||||
/* Unlock if not yet unlocked */
|
||||
if (always_unlock == FALSE)
|
||||
/* Unlock the table. */
|
||||
mysql_unlock_some_tables(thd, &table, /* table count */ 1);
|
||||
|
||||
/* Decrement table_count in advance, making below expressions easier */
|
||||
|
|
|
@ -1225,20 +1225,13 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem,
|
|||
bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias,
|
||||
char *cache_key, uint cache_key_length,
|
||||
MEM_ROOT *mem_root, uint flags);
|
||||
bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list);
|
||||
TABLE *find_locked_table(TABLE *list, const char *db, const char *table_name);
|
||||
TABLE *find_write_locked_table(TABLE *list, const char *db,
|
||||
const char *table_name);
|
||||
void detach_merge_children(TABLE *table, bool clear_refs);
|
||||
bool fix_merge_after_open(TABLE_LIST *old_child_list, TABLE_LIST **old_last,
|
||||
TABLE_LIST *new_child_list, TABLE_LIST **new_last);
|
||||
bool reopen_table(TABLE *table);
|
||||
bool reopen_tables(THD *thd, bool get_locks);
|
||||
thr_lock_type read_lock_type_for_table(THD *thd, TABLE *table);
|
||||
void close_data_files_and_leave_as_placeholders(THD *thd, const char *db,
|
||||
const char *table_name);
|
||||
void close_handle_and_leave_table_as_placeholder(TABLE *table);
|
||||
void unlock_locked_tables(THD *thd);
|
||||
void execute_init_command(THD *thd, sys_var_str *init_command_var,
|
||||
rw_lock_t *var_mutex);
|
||||
extern Field *not_found_field;
|
||||
|
@ -1388,12 +1381,12 @@ void add_join_on(TABLE_LIST *b,Item *expr);
|
|||
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b,List<String> *using_fields,
|
||||
SELECT_LEX *lex);
|
||||
bool add_proc_to_list(THD *thd, Item *item);
|
||||
bool close_cached_table(THD *thd, TABLE *table);
|
||||
bool wait_while_table_is_used(THD *thd, TABLE *table,
|
||||
enum ha_extra_function function);
|
||||
void unlink_open_table(THD *thd, TABLE *find, bool unlock);
|
||||
void drop_open_table(THD *thd, TABLE *table, const char *db_name,
|
||||
const char *table_name);
|
||||
void close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
|
||||
bool remove_from_locked_tables);
|
||||
void update_non_unique_table_error(TABLE_LIST *update,
|
||||
const char *operation,
|
||||
TABLE_LIST *duplicate);
|
||||
|
@ -1515,7 +1508,6 @@ void close_temporary_table(THD *thd, TABLE *table, bool free_share,
|
|||
void close_temporary(TABLE *table, bool free_share, bool delete_table);
|
||||
bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db,
|
||||
const char *table_name);
|
||||
void remove_db_from_cache(const char *db);
|
||||
void flush_tables();
|
||||
bool is_equal(const LEX_STRING *a, const LEX_STRING *b);
|
||||
char *make_default_log_name(char *buff,const char* log_ext);
|
||||
|
@ -1561,7 +1553,7 @@ void create_subpartition_name(char *out, const char *in1,
|
|||
|
||||
typedef struct st_lock_param_type
|
||||
{
|
||||
TABLE_LIST table_list;
|
||||
TABLE_LIST *table_list;
|
||||
ulonglong copied;
|
||||
ulonglong deleted;
|
||||
THD *thd;
|
||||
|
@ -1572,7 +1564,6 @@ typedef struct st_lock_param_type
|
|||
const char *db;
|
||||
const char *table_name;
|
||||
uchar *pack_frm_data;
|
||||
enum thr_lock_type old_lock_type;
|
||||
uint key_count;
|
||||
uint db_options;
|
||||
size_t pack_frm_len;
|
||||
|
@ -2044,12 +2035,31 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count,
|
|||
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY 0x0008
|
||||
#define MYSQL_LOCK_PERF_SCHEMA 0x0010
|
||||
#define MYSQL_OPEN_TAKE_UPGRADABLE_MDL 0x0020
|
||||
/**
|
||||
Do not try to acquire a metadata lock on the table: we
|
||||
already have one.
|
||||
*/
|
||||
#define MYSQL_OPEN_HAS_MDL_LOCK 0x0040
|
||||
/**
|
||||
If in locked tables mode, ignore the locked tables and get
|
||||
a new instance of the table.
|
||||
*/
|
||||
#define MYSQL_OPEN_GET_NEW_TABLE 0x0080
|
||||
/** Don't look up the table in the list of temporary tables. */
|
||||
#define MYSQL_OPEN_SKIP_TEMPORARY 0x0100
|
||||
|
||||
/** Please refer to the internals manual. */
|
||||
#define MYSQL_OPEN_REOPEN (MYSQL_LOCK_IGNORE_FLUSH |\
|
||||
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK |\
|
||||
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |\
|
||||
MYSQL_OPEN_GET_NEW_TABLE |\
|
||||
MYSQL_OPEN_SKIP_TEMPORARY |\
|
||||
MYSQL_OPEN_HAS_MDL_LOCK)
|
||||
|
||||
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
|
||||
void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
|
||||
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count);
|
||||
void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table,
|
||||
bool always_unlock);
|
||||
void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table);
|
||||
void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock);
|
||||
void mysql_lock_downgrade_write(THD *thd, TABLE *table,
|
||||
thr_lock_type new_lock_type);
|
||||
|
|
|
@ -3985,8 +3985,8 @@ sp_head::add_used_tables_to_table_list(THD *thd,
|
|||
table->belong_to_view= belong_to_view;
|
||||
table->trg_event_map= stab->trg_event_map;
|
||||
table->mdl_lock_data= mdl_alloc_lock(0, table->db, table->table_name,
|
||||
thd->mdl_el_root ?
|
||||
thd->mdl_el_root :
|
||||
thd->locked_tables_root ?
|
||||
thd->locked_tables_root :
|
||||
thd->mem_root);
|
||||
|
||||
/* Everyting else should be zeroed */
|
||||
|
@ -4030,8 +4030,9 @@ sp_add_to_query_tables(THD *thd, LEX *lex,
|
|||
table->select_lex= lex->current_select;
|
||||
table->cacheable_table= 1;
|
||||
table->mdl_lock_data= mdl_alloc_lock(0, table->db, table->table_name,
|
||||
thd->mdl_el_root ? thd->mdl_el_root :
|
||||
thd->mem_root);
|
||||
thd->locked_tables_root ?
|
||||
thd->locked_tables_root : thd->mem_root);
|
||||
|
||||
lex->add_to_query_tables(table);
|
||||
return table;
|
||||
}
|
||||
|
|
|
@ -676,7 +676,8 @@ my_bool acl_reload(THD *thd)
|
|||
my_bool return_val= 1;
|
||||
DBUG_ENTER("acl_reload");
|
||||
|
||||
unlock_locked_tables(thd); // Can't have locked tables here
|
||||
/* Can't have locked tables here. */
|
||||
thd->locked_tables_list.unlock_locked_tables(thd);
|
||||
|
||||
/*
|
||||
To avoid deadlocks we should obtain table locks before
|
||||
|
|
1355
sql/sql_base.cc
1355
sql/sql_base.cc
File diff suppressed because it is too large
Load diff
|
@ -469,7 +469,7 @@ THD::THD()
|
|||
debug_sync_control(0),
|
||||
#endif /* defined(ENABLED_DEBUG_SYNC) */
|
||||
main_warning_info(0),
|
||||
mdl_el_root(NULL)
|
||||
locked_tables_root(NULL)
|
||||
{
|
||||
ulong tmp;
|
||||
|
||||
|
@ -574,8 +574,6 @@ THD::THD()
|
|||
thr_lock_owner_init(&main_lock_id, &lock_info);
|
||||
|
||||
m_internal_handler= NULL;
|
||||
|
||||
init_sql_alloc(&locked_tables_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -995,7 +993,7 @@ void THD::cleanup(void)
|
|||
ha_rollback(this);
|
||||
xid_cache_delete(&transaction.xid_state);
|
||||
}
|
||||
unlock_locked_tables(this);
|
||||
locked_tables_list.unlock_locked_tables(this);
|
||||
|
||||
#if defined(ENABLED_DEBUG_SYNC)
|
||||
/* End the Debug Sync Facility. See debug_sync.cc. */
|
||||
|
@ -1074,7 +1072,6 @@ THD::~THD()
|
|||
#endif
|
||||
|
||||
free_root(&main_mem_root, MYF(0));
|
||||
free_root(&locked_tables_root, MYF(0));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
|
|
@ -1169,6 +1169,58 @@ private:
|
|||
Internal_error_handler *m_err_handler;
|
||||
};
|
||||
|
||||
/**
|
||||
Tables that were locked with LOCK TABLES statement.
|
||||
|
||||
Encapsulates a list of TABLE_LIST instances for tables
|
||||
locked by LOCK TABLES statement, memory root for metadata locks,
|
||||
and, generally, the context of LOCK TABLES statement.
|
||||
|
||||
In LOCK TABLES mode, the locked tables are kept open between
|
||||
statements.
|
||||
Therefore, we can't allocate metadata locks on execution memory
|
||||
root -- as well as tables, the locks need to stay around till
|
||||
UNLOCK TABLES is called.
|
||||
The locks are allocated in the memory root encapsulate in this
|
||||
class.
|
||||
|
||||
Some SQL commands, like FLUSH TABLE or ALTER TABLE, demand that
|
||||
the tables they operate on are closed, at least temporarily.
|
||||
This class encapsulates a list of TABLE_LIST instances, one
|
||||
for each base table from LOCK TABLES list,
|
||||
which helps conveniently close the TABLEs when it's necessary
|
||||
and later reopen them.
|
||||
|
||||
Implemented in sql_base.cc
|
||||
*/
|
||||
|
||||
class Locked_tables_list
|
||||
{
|
||||
private:
|
||||
MEM_ROOT m_locked_tables_root;
|
||||
TABLE_LIST *m_locked_tables;
|
||||
TABLE_LIST **m_locked_tables_last;
|
||||
public:
|
||||
Locked_tables_list()
|
||||
:m_locked_tables(NULL),
|
||||
m_locked_tables_last(&m_locked_tables)
|
||||
{
|
||||
init_sql_alloc(&m_locked_tables_root, MEM_ROOT_BLOCK_SIZE, 0);
|
||||
}
|
||||
void unlock_locked_tables(THD *thd);
|
||||
~Locked_tables_list()
|
||||
{
|
||||
unlock_locked_tables(0);
|
||||
}
|
||||
bool init_locked_tables(THD *thd);
|
||||
TABLE_LIST *locked_tables() { return m_locked_tables; }
|
||||
MEM_ROOT *locked_tables_root() { return &m_locked_tables_root; }
|
||||
void unlink_from_list(THD *thd, TABLE_LIST *table_list,
|
||||
bool remove_from_locked_tables);
|
||||
void unlink_all_closed_tables();
|
||||
bool reopen_tables(THD *thd);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Storage engine specific thread local data.
|
||||
|
@ -1810,6 +1862,8 @@ public:
|
|||
*/
|
||||
Parser_state *m_parser_state;
|
||||
|
||||
Locked_tables_list locked_tables_list;
|
||||
|
||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||
partition_info *work_part_info;
|
||||
#endif
|
||||
|
@ -1819,8 +1873,13 @@ public:
|
|||
struct st_debug_sync_control *debug_sync_control;
|
||||
#endif /* defined(ENABLED_DEBUG_SYNC) */
|
||||
|
||||
MEM_ROOT *mdl_el_root;
|
||||
MEM_ROOT locked_tables_root;
|
||||
/**
|
||||
Points to the memory root of Locked_tables_list if
|
||||
we're locking the tables for LOCK TABLES. Otherwise is NULL.
|
||||
This is necessary to ensure that metadata locks allocated for
|
||||
tables used in triggers will persist after statement end.
|
||||
*/
|
||||
MEM_ROOT *locked_tables_root;
|
||||
|
||||
THD();
|
||||
~THD();
|
||||
|
|
|
@ -1956,8 +1956,8 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
|
|||
|
||||
/*
|
||||
Step7: drop the old database.
|
||||
remove_db_from_cache(olddb) and query_cache_invalidate(olddb)
|
||||
are done inside mysql_rm_db(), no needs to execute them again.
|
||||
query_cache_invalidate(olddb) is done inside mysql_rm_db(), no need
|
||||
to execute them again.
|
||||
mysql_rm_db() also "unuses" if we drop the current database.
|
||||
*/
|
||||
error= mysql_rm_db(thd, old_db->str, 0, 1);
|
||||
|
|
|
@ -3542,16 +3542,22 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
|
|||
|
||||
if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
|
||||
{
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
if (reopen_name_locked_table(thd, create_table))
|
||||
enum enum_open_table_action ot_action_unused;
|
||||
/*
|
||||
Here we open the destination table, on which we already have
|
||||
an exclusive metadata lock.
|
||||
*/
|
||||
if (open_table(thd, create_table, thd->mem_root,
|
||||
&ot_action_unused, MYSQL_OPEN_REOPEN))
|
||||
{
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
quick_rm_table(create_info->db_type, create_table->db,
|
||||
table_case_name(create_info, create_table->table_name),
|
||||
0);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
}
|
||||
else
|
||||
table= create_table->table;
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -184,7 +184,7 @@ bool begin_trans(THD *thd)
|
|||
return 1;
|
||||
}
|
||||
|
||||
unlock_locked_tables(thd);
|
||||
thd->locked_tables_list.unlock_locked_tables(thd);
|
||||
|
||||
if (end_active_trans(thd))
|
||||
error= -1;
|
||||
|
@ -3583,7 +3583,7 @@ end_with_restore_list:
|
|||
done FLUSH TABLES WITH READ LOCK + BEGIN. If this assumption becomes
|
||||
false, mysqldump will not work.
|
||||
*/
|
||||
unlock_locked_tables(thd);
|
||||
thd->locked_tables_list.unlock_locked_tables(thd);
|
||||
if (thd->options & OPTION_TABLE_LOCK)
|
||||
{
|
||||
end_active_trans(thd);
|
||||
|
@ -3594,7 +3594,7 @@ end_with_restore_list:
|
|||
my_ok(thd);
|
||||
break;
|
||||
case SQLCOM_LOCK_TABLES:
|
||||
unlock_locked_tables(thd);
|
||||
thd->locked_tables_list.unlock_locked_tables(thd);
|
||||
/* we must end the trasaction first, regardless of anything */
|
||||
if (end_active_trans(thd))
|
||||
goto error;
|
||||
|
@ -3604,22 +3604,21 @@ end_with_restore_list:
|
|||
if (lex->protect_against_global_read_lock &&
|
||||
!(need_start_waiting= !wait_if_global_read_lock(thd, 0, 1)))
|
||||
goto error;
|
||||
thd->in_lock_tables=1;
|
||||
thd->options|= OPTION_TABLE_LOCK;
|
||||
alloc_mdl_locks(all_tables, &thd->locked_tables_root);
|
||||
thd->mdl_el_root= &thd->locked_tables_root;
|
||||
|
||||
if (!(res= open_and_lock_tables_derived(thd, all_tables, FALSE,
|
||||
MYSQL_OPEN_TAKE_UPGRADABLE_MDL)))
|
||||
{
|
||||
#ifdef HAVE_QUERY_CACHE
|
||||
if (thd->variables.query_cache_wlock_invalidate)
|
||||
query_cache.invalidate_locked_for_write(first_table);
|
||||
#endif /*HAVE_QUERY_CACHE*/
|
||||
thd->locked_tables_mode= LTM_LOCK_TABLES;
|
||||
my_ok(thd);
|
||||
}
|
||||
else
|
||||
alloc_mdl_locks(all_tables, thd->locked_tables_list.locked_tables_root());
|
||||
|
||||
thd->options|= OPTION_TABLE_LOCK;
|
||||
thd->in_lock_tables=1;
|
||||
thd->locked_tables_root= thd->locked_tables_list.locked_tables_root();
|
||||
|
||||
res= (open_and_lock_tables_derived(thd, all_tables, FALSE,
|
||||
MYSQL_OPEN_TAKE_UPGRADABLE_MDL) ||
|
||||
thd->locked_tables_list.init_locked_tables(thd));
|
||||
|
||||
thd->in_lock_tables= 0;
|
||||
thd->locked_tables_root= NULL;
|
||||
|
||||
if (res)
|
||||
{
|
||||
/*
|
||||
Need to end the current transaction, so the storage engine (InnoDB)
|
||||
|
@ -3630,8 +3629,14 @@ end_with_restore_list:
|
|||
end_active_trans(thd);
|
||||
thd->options&= ~(OPTION_TABLE_LOCK);
|
||||
}
|
||||
thd->in_lock_tables=0;
|
||||
thd->mdl_el_root= 0;
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_QUERY_CACHE
|
||||
if (thd->variables.query_cache_wlock_invalidate)
|
||||
query_cache.invalidate_locked_for_write(first_table);
|
||||
#endif /*HAVE_QUERY_CACHE*/
|
||||
my_ok(thd);
|
||||
}
|
||||
break;
|
||||
case SQLCOM_CREATE_DB:
|
||||
{
|
||||
|
@ -6534,8 +6539,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
|
|||
/* Link table in global list (all used tables) */
|
||||
lex->add_to_query_tables(ptr);
|
||||
ptr->mdl_lock_data= mdl_alloc_lock(0 , ptr->db, ptr->table_name,
|
||||
thd->mdl_el_root ? thd->mdl_el_root :
|
||||
thd->mem_root);
|
||||
thd->locked_tables_root ?
|
||||
thd->locked_tables_root : thd->mem_root);
|
||||
DBUG_RETURN(ptr);
|
||||
}
|
||||
|
||||
|
|
|
@ -4314,7 +4314,6 @@ set_engine_all_partitions(partition_info *part_info,
|
|||
|
||||
static int fast_end_partition(THD *thd, ulonglong copied,
|
||||
ulonglong deleted,
|
||||
TABLE *table,
|
||||
TABLE_LIST *table_list, bool is_empty,
|
||||
ALTER_PARTITION_PARAM_TYPE *lpt,
|
||||
bool written_bin_log)
|
||||
|
@ -4333,11 +4332,7 @@ static int fast_end_partition(THD *thd, ulonglong copied,
|
|||
error= 1;
|
||||
|
||||
if (error)
|
||||
{
|
||||
/* If error during commit, no need to rollback, it's done. */
|
||||
table->file->print_error(error, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
DBUG_RETURN(TRUE); /* The error has been reported */
|
||||
|
||||
if ((!is_empty) && (!written_bin_log) &&
|
||||
(!thd->lex->no_write_to_binlog))
|
||||
|
@ -6215,30 +6210,13 @@ static void release_log_entries(partition_info *part_info)
|
|||
*/
|
||||
static void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt)
|
||||
{
|
||||
int err;
|
||||
if (lpt->thd->locked_tables_mode)
|
||||
{
|
||||
/*
|
||||
When we have the table locked, it is necessary to reopen the table
|
||||
since all table objects were closed and removed as part of the
|
||||
ALTER TABLE of partitioning structure.
|
||||
*/
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
lpt->thd->in_lock_tables= 1;
|
||||
err= reopen_tables(lpt->thd, 1);
|
||||
lpt->thd->in_lock_tables= 0;
|
||||
if (err)
|
||||
{
|
||||
/*
|
||||
Issue a warning since we weren't able to regain the lock again.
|
||||
We also need to unlink table from thread's open list and from
|
||||
table_cache
|
||||
*/
|
||||
unlink_open_table(lpt->thd, lpt->table, FALSE);
|
||||
THD *thd= lpt->thd;
|
||||
|
||||
close_all_tables_for_name(thd, lpt->table->s, FALSE);
|
||||
lpt->table= 0;
|
||||
lpt->table_list->table= 0;
|
||||
if (thd->locked_tables_list.reopen_tables(thd))
|
||||
sql_print_warning("We failed to reacquire LOCKs in ALTER TABLE");
|
||||
}
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -6252,17 +6230,37 @@ static void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt)
|
|||
|
||||
static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt)
|
||||
{
|
||||
TABLE_SHARE *share= lpt->table->s;
|
||||
THD *thd= lpt->thd;
|
||||
const char *db= lpt->db;
|
||||
const char *table_name= lpt->table_name;
|
||||
TABLE *table;
|
||||
DBUG_ENTER("alter_close_tables");
|
||||
/*
|
||||
We need to also unlock tables and close all handlers.
|
||||
We set lock to zero to ensure we don't do this twice
|
||||
and we set db_stat to zero to ensure we don't close twice.
|
||||
We must keep LOCK_open while manipulating with thd->open_tables.
|
||||
Another thread may be working on it.
|
||||
*/
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
close_data_files_and_leave_as_placeholders(thd, db, table_name);
|
||||
/*
|
||||
We can safely remove locks for all tables with the same name:
|
||||
later they will all be closed anyway in
|
||||
alter_partition_lock_handling().
|
||||
*/
|
||||
for (table= thd->open_tables; table ; table= table->next)
|
||||
{
|
||||
if (!strcmp(table->s->table_name.str, share->table_name.str) &&
|
||||
!strcmp(table->s->db.str, share->db.str))
|
||||
{
|
||||
mysql_lock_remove(thd, thd->lock, table);
|
||||
table->file->close();
|
||||
table->db_stat= 0; // Mark file closed
|
||||
/*
|
||||
Ensure that we won't end up with a crippled table instance
|
||||
in the table cache if an error occurs before we reach
|
||||
alter_partition_lock_handling() and the table is closed
|
||||
by close_thread_tables() instead.
|
||||
*/
|
||||
table->s->version= 0;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
@ -6429,6 +6427,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
|
|||
DBUG_ENTER("fast_alter_partition_table");
|
||||
|
||||
lpt->thd= thd;
|
||||
lpt->table_list= table_list;
|
||||
lpt->part_info= part_info;
|
||||
lpt->alter_info= alter_info;
|
||||
lpt->create_info= create_info;
|
||||
|
@ -6745,7 +6744,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
|
|||
user
|
||||
*/
|
||||
DBUG_RETURN(fast_end_partition(thd, lpt->copied, lpt->deleted,
|
||||
table, table_list, FALSE, NULL,
|
||||
table_list, FALSE, NULL,
|
||||
written_bin_log));
|
||||
err:
|
||||
close_thread_tables(thd);
|
||||
|
|
|
@ -224,7 +224,8 @@ bool servers_reload(THD *thd)
|
|||
bool return_val= TRUE;
|
||||
DBUG_ENTER("servers_reload");
|
||||
|
||||
unlock_locked_tables(thd); // Can't have locked tables here
|
||||
/* Can't have locked tables here */
|
||||
thd->locked_tables_list.unlock_locked_tables(thd);
|
||||
|
||||
DBUG_PRINT("info", ("locking servers_cache"));
|
||||
rw_wrlock(&THR_LOCK_servers);
|
||||
|
|
159
sql/sql_table.cc
159
sql/sql_table.cc
|
@ -1966,7 +1966,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
|||
case -1:
|
||||
DBUG_ASSERT(thd->in_sub_stmt);
|
||||
error= 1;
|
||||
goto err_with_placeholders;
|
||||
goto err;
|
||||
default:
|
||||
// temporary table not found
|
||||
error= 0;
|
||||
|
@ -2003,18 +2003,19 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
|||
{
|
||||
if (thd->locked_tables_mode)
|
||||
{
|
||||
if (close_cached_table(thd, table->table))
|
||||
if (wait_while_table_is_used(thd, table->table, HA_EXTRA_FORCE_REOPEN))
|
||||
{
|
||||
error= -1;
|
||||
goto err_with_placeholders;
|
||||
goto err;
|
||||
}
|
||||
close_all_tables_for_name(thd, table->table->s, TRUE);
|
||||
table->table= 0;
|
||||
}
|
||||
|
||||
if (thd->killed)
|
||||
{
|
||||
error= -1;
|
||||
goto err_with_placeholders;
|
||||
goto err;
|
||||
}
|
||||
alias= (lower_case_table_names == 2) ? table->alias : table->table_name;
|
||||
/* remove .frm file and engine files */
|
||||
|
@ -2178,7 +2179,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
|||
*/
|
||||
}
|
||||
}
|
||||
err_with_placeholders:
|
||||
err:
|
||||
if (!drop_temporary)
|
||||
{
|
||||
/*
|
||||
|
@ -2195,7 +2196,7 @@ err_with_placeholders:
|
|||
if (thd->locked_tables_mode &&
|
||||
thd->lock && thd->lock->table_count == 0 && non_temp_tables_count > 0)
|
||||
{
|
||||
unlock_locked_tables(thd);
|
||||
thd->locked_tables_list.unlock_locked_tables(thd);
|
||||
goto end;
|
||||
}
|
||||
for (table= tables; table; table= table->next_local)
|
||||
|
@ -4315,6 +4316,7 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table,
|
|||
HA_CHECK_OPT *check_opt)
|
||||
{
|
||||
MDL_LOCK_DATA *mdl_lock_data= 0;
|
||||
enum enum_open_table_action ot_action_unused;
|
||||
DBUG_ENTER("prepare_for_restore");
|
||||
|
||||
if (table->table) // do not overwrite existing tables on restore
|
||||
|
@ -4360,16 +4362,16 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table,
|
|||
DBUG_RETURN(send_check_errmsg(thd, table, "restore",
|
||||
"Failed generating table from .frm file"));
|
||||
}
|
||||
table->mdl_lock_data= mdl_lock_data;
|
||||
}
|
||||
|
||||
/*
|
||||
Now we should be able to open the partially restored table
|
||||
to finish the restore in the handler later on
|
||||
*/
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
if (reopen_name_locked_table(thd, table))
|
||||
if (open_table(thd, table, thd->mem_root,
|
||||
&ot_action_unused, MYSQL_OPEN_REOPEN))
|
||||
{
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
if (mdl_lock_data)
|
||||
mdl_release_lock(&thd->mdl_context, mdl_lock_data);
|
||||
DBUG_RETURN(send_check_errmsg(thd, table, "restore",
|
||||
|
@ -4377,7 +4379,6 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table,
|
|||
}
|
||||
/* A MERGE table must not come here. */
|
||||
DBUG_ASSERT(!table->table || !table->table->child_l);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
@ -4392,7 +4393,10 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
|
|||
const char **ext;
|
||||
MY_STAT stat_info;
|
||||
MDL_LOCK_DATA *mdl_lock_data;
|
||||
enum enum_open_table_action ot_action_unused;
|
||||
DBUG_ENTER("prepare_for_repair");
|
||||
uint reopen_for_repair_flags= (MYSQL_LOCK_IGNORE_FLUSH |
|
||||
MYSQL_OPEN_HAS_MDL_LOCK);
|
||||
|
||||
if (!(check_opt->sql_flags & TT_USEFRM))
|
||||
DBUG_RETURN(0);
|
||||
|
@ -4428,8 +4432,9 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
|
|||
pthread_mutex_unlock(&LOCK_open);
|
||||
DBUG_RETURN(0); // Out of memory
|
||||
}
|
||||
table= &tmp_table;
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
table= &tmp_table;
|
||||
table_list->mdl_lock_data= mdl_lock_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -4490,8 +4495,9 @@ 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 (close_cached_table(thd, table))
|
||||
if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
|
||||
goto end;
|
||||
close_all_tables_for_name(thd, table_list->table->s, FALSE);
|
||||
table_list->table= 0;
|
||||
}
|
||||
/*
|
||||
|
@ -4519,21 +4525,23 @@ 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.
|
||||
*/
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
if (reopen_name_locked_table(thd, table_list))
|
||||
if (open_table(thd, table_list, thd->mem_root,
|
||||
&ot_action_unused, reopen_for_repair_flags))
|
||||
{
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
error= send_check_errmsg(thd, table_list, "repair",
|
||||
"Failed to open partially repaired table");
|
||||
goto end;
|
||||
}
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
|
||||
end:
|
||||
thd->locked_tables_list.unlink_all_closed_tables();
|
||||
if (table == &tmp_table)
|
||||
{
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
|
@ -5334,6 +5342,11 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
|||
db, table_name, reg_ext, 0);
|
||||
if (!access(dst_path, F_OK))
|
||||
goto table_exists;
|
||||
/*
|
||||
Make the metadata lock available to open_table() called to
|
||||
reopen the table down the road.
|
||||
*/
|
||||
table->mdl_lock_data= target_lock_data;
|
||||
}
|
||||
|
||||
DBUG_EXECUTE_IF("sleep_create_like_before_copy", my_sleep(6000000););
|
||||
|
@ -5463,20 +5476,16 @@ binlog:
|
|||
char buf[2048];
|
||||
String query(buf, sizeof(buf), system_charset_info);
|
||||
query.length(0); // Have to zero it since constructor doesn't
|
||||
|
||||
enum enum_open_table_action ot_action_unused;
|
||||
/*
|
||||
Here we open the destination table, on which we already have
|
||||
exclusive metada lock. This is needed for store_create_info()
|
||||
to work. The table will be closed by unlink_open_table() at
|
||||
the end of this function.
|
||||
exclusive metadata lock. This is needed for store_create_info()
|
||||
to work. The table will be closed by close_thread_table() at
|
||||
the end of this branch.
|
||||
*/
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
if (reopen_name_locked_table(thd, table))
|
||||
{
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
if (open_table(thd, table, thd->mem_root, &ot_action_unused,
|
||||
MYSQL_OPEN_REOPEN))
|
||||
goto err;
|
||||
}
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
|
||||
int result __attribute__((unused))=
|
||||
store_create_info(thd, table, &query,
|
||||
|
@ -5485,8 +5494,14 @@ binlog:
|
|||
DBUG_ASSERT(result == 0); // store_create_info() always return 0
|
||||
write_bin_log(thd, TRUE, query.ptr(), query.length());
|
||||
|
||||
DBUG_ASSERT(thd->open_tables == table->table);
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
unlink_open_table(thd, table->table, FALSE);
|
||||
/*
|
||||
When opening the table, we ignored the locked tables
|
||||
(MYSQL_OPEN_GET_NEW_TABLE). Now we can close the table without
|
||||
risking to close some locked table.
|
||||
*/
|
||||
close_thread_table(thd, &thd->open_tables);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
}
|
||||
else // Case 1
|
||||
|
@ -6789,13 +6804,14 @@ view_err:
|
|||
/*
|
||||
Then do a 'simple' rename of the table. First we need to close all
|
||||
instances of 'source' table.
|
||||
Note that if close_cached_table() returns error here (i.e. if
|
||||
Note that if wait_while_table_is_used() returns error here (i.e. if
|
||||
this thread was killed) then it must be that previous step of
|
||||
simple rename did nothing and therefore we can safely reture
|
||||
simple rename did nothing and therefore we can safely return
|
||||
without additional clean-up.
|
||||
*/
|
||||
if (close_cached_table(thd, table))
|
||||
if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
|
||||
goto err;
|
||||
close_all_tables_for_name(thd, table->s, TRUE);
|
||||
/*
|
||||
Then, we want check once again that target table does not exist.
|
||||
Actually the order of these two steps does not matter since
|
||||
|
@ -7384,11 +7400,12 @@ view_err:
|
|||
if (wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_RENAME))
|
||||
goto err_new_table_cleanup;
|
||||
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
|
||||
close_data_files_and_leave_as_placeholders(thd, db, table_name);
|
||||
close_all_tables_for_name(thd, table->s,
|
||||
new_name != table_name || new_db != db);
|
||||
|
||||
error=0;
|
||||
table_list->table= table= 0; /* Safety */
|
||||
save_old_db_type= old_db_type;
|
||||
|
||||
/*
|
||||
|
@ -7410,6 +7427,7 @@ view_err:
|
|||
/* This type cannot happen in regular ALTER. */
|
||||
new_db_type= old_db_type= NULL;
|
||||
}
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
if (mysql_rename_table(old_db_type, db, table_name, db, old_name,
|
||||
FN_TO_IS_TMP))
|
||||
{
|
||||
|
@ -7433,10 +7451,15 @@ view_err:
|
|||
FN_FROM_IS_TMP);
|
||||
}
|
||||
|
||||
if (! error)
|
||||
(void) quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
|
||||
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
|
||||
if (error)
|
||||
{
|
||||
/* This shouldn't happen. But let us play it safe. */
|
||||
goto err_with_placeholders;
|
||||
goto err_with_mdl;
|
||||
}
|
||||
|
||||
if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
|
||||
|
@ -7446,6 +7469,7 @@ view_err:
|
|||
To do this we need to obtain a handler object for it.
|
||||
NO need to tamper with MERGE tables. The real open is done later.
|
||||
*/
|
||||
enum enum_open_table_action ot_action_unused;
|
||||
TABLE *t_table;
|
||||
if (new_name != table_name || new_db != db)
|
||||
{
|
||||
|
@ -7454,51 +7478,39 @@ view_err:
|
|||
table_list->table_name_length= strlen(new_name);
|
||||
table_list->db= new_db;
|
||||
table_list->db_length= strlen(new_db);
|
||||
if (reopen_name_locked_table(thd, table_list))
|
||||
goto err_with_placeholders;
|
||||
t_table= table_list->table;
|
||||
table_list->mdl_lock_data= target_lock_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (reopen_table(table))
|
||||
goto err_with_placeholders;
|
||||
t_table= table;
|
||||
}
|
||||
/* Tell the handler that a new frm file is in place. */
|
||||
if (t_table->file->ha_create_handler_files(path, NULL, CHF_INDEX_FLAG,
|
||||
create_info))
|
||||
goto err_with_placeholders;
|
||||
if (thd->locked_tables_mode)
|
||||
{
|
||||
if (new_name == table_name && new_db == db)
|
||||
{
|
||||
/*
|
||||
We are going to reopen table down on the road, so we have to restore
|
||||
state of the TABLE object which we used for obtaining of handler
|
||||
object to make it suitable for reopening.
|
||||
Under LOCK TABLES, we have a different mdl_lock_data
|
||||
points to a different instance than the one set initially
|
||||
to request the lock.
|
||||
*/
|
||||
DBUG_ASSERT(t_table == table);
|
||||
close_handle_and_leave_table_as_placeholder(table);
|
||||
table_list->mdl_lock_data= mdl_lock_data;
|
||||
}
|
||||
else
|
||||
if (open_table(thd, table_list, thd->mem_root,
|
||||
&ot_action_unused, MYSQL_OPEN_REOPEN))
|
||||
{
|
||||
/* Unlink the new name from the list of locked tables. */
|
||||
unlink_open_table(thd, t_table, FALSE);
|
||||
}
|
||||
}
|
||||
goto err_with_mdl;
|
||||
}
|
||||
t_table= table_list->table;
|
||||
|
||||
(void) quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);
|
||||
/* Tell the handler that a new frm file is in place. */
|
||||
error= t_table->file->ha_create_handler_files(path, NULL, CHF_INDEX_FLAG,
|
||||
create_info);
|
||||
|
||||
if (thd->locked_tables_mode && new_name == table_name && new_db == db)
|
||||
{
|
||||
thd->in_lock_tables= 1;
|
||||
error= reopen_tables(thd, 1);
|
||||
thd->in_lock_tables= 0;
|
||||
if (error)
|
||||
goto err_with_placeholders;
|
||||
}
|
||||
DBUG_ASSERT(thd->open_tables == t_table);
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
close_thread_table(thd, &thd->open_tables);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
table_list->table= 0;
|
||||
|
||||
if (error)
|
||||
goto err_with_mdl;
|
||||
}
|
||||
if (thd->locked_tables_list.reopen_tables(thd))
|
||||
goto err_with_mdl;
|
||||
|
||||
thd_proc_info(thd, "end");
|
||||
|
||||
|
@ -7541,9 +7553,6 @@ view_err:
|
|||
{
|
||||
if ((new_name != table_name || new_db != db))
|
||||
{
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
unlink_open_table(thd, table, FALSE);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
mdl_release_lock(&thd->mdl_context, target_lock_data);
|
||||
mdl_release_all_locks_for_name(&thd->mdl_context, mdl_lock_data);
|
||||
}
|
||||
|
@ -7607,14 +7616,14 @@ err:
|
|||
mdl_release_lock(&thd->mdl_context, target_lock_data);
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
err_with_placeholders:
|
||||
err_with_mdl:
|
||||
/*
|
||||
An error happened while we were holding exclusive name metadata lock
|
||||
on table being altered. To be safe under LOCK TABLES we should remove
|
||||
placeholders from the list of open tables and relese metadata lock.
|
||||
on table being altered. To be safe under LOCK TABLES we should
|
||||
remove all references to the altered table from the list of locked
|
||||
tables and release the exclusive metadata lock.
|
||||
*/
|
||||
unlink_open_table(thd, table, FALSE);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
thd->locked_tables_list.unlink_all_closed_tables();
|
||||
if (target_lock_data)
|
||||
mdl_release_lock(&thd->mdl_context, target_lock_data);
|
||||
mdl_release_all_locks_for_name(&thd->mdl_context, mdl_lock_data);
|
||||
|
|
|
@ -328,6 +328,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
|
|||
bool result= TRUE;
|
||||
String stmt_query;
|
||||
bool need_start_waiting= FALSE;
|
||||
bool lock_upgrade_done= FALSE;
|
||||
|
||||
DBUG_ENTER("mysql_create_or_drop_trigger");
|
||||
|
||||
|
@ -450,72 +451,54 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
|
|||
if (!(tables->table= find_write_locked_table(thd->open_tables, tables->db,
|
||||
tables->table_name)))
|
||||
goto end;
|
||||
/*
|
||||
Ensure that table is opened only by this thread and that no other
|
||||
statement will open this table.
|
||||
*/
|
||||
if (wait_while_table_is_used(thd, tables->table, HA_EXTRA_FORCE_REOPEN))
|
||||
goto end;
|
||||
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
/* Later on we will need it to downgrade the lock */
|
||||
tables->mdl_lock_data= tables->table->mdl_lock_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Obtain exlusive meta-data lock on the table and remove TABLE
|
||||
instances from cache.
|
||||
*/
|
||||
if (lock_table_names(thd, tables))
|
||||
tables->table= open_n_lock_single_table(thd, tables,
|
||||
TL_WRITE_ALLOW_READ,
|
||||
MYSQL_OPEN_TAKE_UPGRADABLE_MDL);
|
||||
if (! tables->table)
|
||||
goto end;
|
||||
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, tables->db, tables->table_name);
|
||||
|
||||
if (reopen_name_locked_table(thd, tables))
|
||||
goto end_unlock;
|
||||
tables->table->use_all_columns();
|
||||
}
|
||||
table= tables->table;
|
||||
|
||||
if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
|
||||
goto end;
|
||||
|
||||
lock_upgrade_done= TRUE;
|
||||
|
||||
if (!table->triggers)
|
||||
{
|
||||
if (!create)
|
||||
{
|
||||
my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
|
||||
goto end_unlock;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!(table->triggers= new (&table->mem_root) Table_triggers_list(table)))
|
||||
goto end_unlock;
|
||||
goto end;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
result= (create ?
|
||||
table->triggers->create_trigger(thd, tables, &stmt_query):
|
||||
table->triggers->drop_trigger(thd, tables, &stmt_query));
|
||||
|
||||
/* Under LOCK TABLES we must reopen the table to activate the trigger. */
|
||||
if (!result && thd->locked_tables_mode)
|
||||
{
|
||||
/* Make table suitable for reopening */
|
||||
close_data_files_and_leave_as_placeholders(thd, tables->db,
|
||||
tables->table_name);
|
||||
thd->in_lock_tables= 1;
|
||||
if (reopen_tables(thd, 1))
|
||||
{
|
||||
/* To be safe remove this table from the set of LOCKED TABLES */
|
||||
unlink_open_table(thd, tables->table, FALSE);
|
||||
|
||||
/*
|
||||
Ignore reopen_tables errors for now. It's better not leave master/slave
|
||||
in a inconsistent state.
|
||||
*/
|
||||
thd->clear_error();
|
||||
}
|
||||
thd->in_lock_tables= 0;
|
||||
}
|
||||
|
||||
end_unlock:
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
|
||||
if (result)
|
||||
goto end;
|
||||
|
||||
close_all_tables_for_name(thd, table->s, FALSE);
|
||||
/*
|
||||
Reopen the table if we were under LOCK TABLES.
|
||||
Ignore the return value for now. It's better to
|
||||
keep master/slave in consistent state.
|
||||
*/
|
||||
thd->locked_tables_list.reopen_tables(thd);
|
||||
|
||||
end:
|
||||
if (!result)
|
||||
{
|
||||
|
@ -525,11 +508,11 @@ end:
|
|||
/*
|
||||
If we are under LOCK TABLES we should restore original state of meta-data
|
||||
locks. Otherwise call to close_thread_tables() will take care about both
|
||||
TABLE instance created by reopen_name_locked_table() and metadata lock.
|
||||
TABLE instance created by open_n_lock_single_table() and metadata lock.
|
||||
*/
|
||||
if (thd->locked_tables_mode && tables && tables->table)
|
||||
if (thd->locked_tables_mode && tables && lock_upgrade_done)
|
||||
mdl_downgrade_exclusive_lock(&thd->mdl_context,
|
||||
tables->table->mdl_lock_data);
|
||||
tables->mdl_lock_data);
|
||||
|
||||
if (need_start_waiting)
|
||||
start_waiting_global_read_lock(thd);
|
||||
|
|
|
@ -632,7 +632,6 @@ private:
|
|||
TABLE *share_next, **share_prev;
|
||||
|
||||
friend struct TABLE_share;
|
||||
friend bool reopen_table(TABLE *table);
|
||||
|
||||
public:
|
||||
|
||||
|
@ -679,6 +678,8 @@ public:
|
|||
/* Table's triggers, 0 if there are no of them */
|
||||
Table_triggers_list *triggers;
|
||||
TABLE_LIST *pos_in_table_list;/* Element referring to this table */
|
||||
/* Position in thd->locked_table_list under LOCK TABLES */
|
||||
TABLE_LIST *pos_in_locked_tables;
|
||||
ORDER *group;
|
||||
const char *alias; /* alias or table name */
|
||||
uchar *null_flags;
|
||||
|
|
Loading…
Reference in a new issue