summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/ha_ndbcluster.cc7
-rw-r--r--sql/lock.cc7
-rw-r--r--sql/lock.h15
-rw-r--r--sql/mdl.h4
-rw-r--r--sql/sp_head.cc11
-rw-r--r--sql/sp_head.h4
-rw-r--r--sql/sql_base.cc316
-rw-r--r--sql/sql_class.h14
-rw-r--r--sql/sql_db.cc8
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h10
-rw-r--r--sql/sql_parse.cc16
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_show.cc4
-rw-r--r--sql/sql_table.cc26
-rw-r--r--sql/sql_trigger.cc6
-rw-r--r--sql/sql_view.cc2
-rw-r--r--sql/sql_yacc.yy103
-rw-r--r--sql/table.cc7
-rw-r--r--sql/table.h19
20 files changed, 357 insertions, 225 deletions
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 2d082cc71f6..2af2b064020 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -7408,9 +7408,10 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
DBUG_PRINT("info", ("Remove table %s/%s", db, file_name_str));
// Delete the table and all related files
TABLE_LIST table_list;
- bzero((char*) &table_list,sizeof(table_list));
- table_list.db= (char*) db;
- table_list.alias= table_list.table_name= (char*)file_name_str;
+ table_list.init_one_table(db, strlen(db), file_name_str,
+ strlen(file_name_str), file_name_str,
+ TL_WRITE);
+ table_list.mdl_request.set_tpye(MDL_EXCLUSIVE);
(void)mysql_rm_table_part2(thd, &table_list,
FALSE, /* if_exists */
FALSE, /* drop_temporary */
diff --git a/sql/lock.cc b/sql/lock.cc
index 758ea6cf914..8e91bd9360e 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -880,6 +880,8 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
before calling it. Also it cannot be called while holding
LOCK_open mutex. Both these invariants are enforced by asserts
in MDL_context::acquire_locks().
+ @note Initialization of MDL_request members of TABLE_LIST elements
+ is a responsibility of the caller.
@retval FALSE Success.
@retval TRUE Failure (OOM or thread was killed).
@@ -894,12 +896,7 @@ bool lock_table_names(THD *thd, TABLE_LIST *table_list)
global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE);
for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
- {
- lock_table->mdl_request.init(MDL_key::TABLE,
- lock_table->db, lock_table->table_name,
- MDL_EXCLUSIVE);
mdl_requests.push_front(&lock_table->mdl_request);
- }
mdl_requests.push_front(&global_request);
diff --git a/sql/lock.h b/sql/lock.h
index 19b23f1f42b..5425a6ccb13 100644
--- a/sql/lock.h
+++ b/sql/lock.h
@@ -15,33 +15,32 @@ typedef struct st_mysql_lock MYSQL_LOCK;
#define MYSQL_OPEN_TEMPORARY_ONLY 0x0004
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY 0x0008
#define MYSQL_LOCK_LOG_TABLE 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
+#define MYSQL_OPEN_HAS_MDL_LOCK 0x0020
/**
If in locked tables mode, ignore the locked tables and get
a new instance of the table.
*/
-#define MYSQL_OPEN_GET_NEW_TABLE 0x0080
+#define MYSQL_OPEN_GET_NEW_TABLE 0x0040
/** Don't look up the table in the list of temporary tables. */
-#define MYSQL_OPEN_SKIP_TEMPORARY 0x0100
+#define MYSQL_OPEN_SKIP_TEMPORARY 0x0080
/** Fail instead of waiting when conficting metadata lock is discovered. */
-#define MYSQL_OPEN_FAIL_ON_MDL_CONFLICT 0x0200
+#define MYSQL_OPEN_FAIL_ON_MDL_CONFLICT 0x0100
/** Open tables using MDL_SHARED lock instead of one specified in parser. */
-#define MYSQL_OPEN_FORCE_SHARED_MDL 0x0400
+#define MYSQL_OPEN_FORCE_SHARED_MDL 0x0200
/**
Open tables using MDL_SHARED_HIGH_PRIO lock instead of one specified
in parser.
*/
-#define MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL 0x0800
+#define MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL 0x0400
/**
When opening or locking the table, use the maximum timeout
(LONG_TIMEOUT = 1 year) rather than the user-supplied timeout value.
*/
-#define MYSQL_LOCK_IGNORE_TIMEOUT 0x1000
+#define MYSQL_LOCK_IGNORE_TIMEOUT 0x0800
/** Please refer to the internals manual. */
#define MYSQL_OPEN_REOPEN (MYSQL_OPEN_IGNORE_FLUSH |\
diff --git a/sql/mdl.h b/sql/mdl.h
index 2fb21a5aa18..2e296b73057 100644
--- a/sql/mdl.h
+++ b/sql/mdl.h
@@ -308,6 +308,10 @@ public:
MDL_key key;
public:
+ static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
+ { return alloc_root(mem_root, size); }
+ static void operator delete(void *ptr, MEM_ROOT *mem_root) {}
+
void init(MDL_key::enum_mdl_namespace namespace_arg,
const char *db_arg, const char *name_arg,
enum_mdl_type mdl_type_arg);
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 2e66aec91e5..2d5b648e82e 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -4010,6 +4010,11 @@ sp_head::add_used_tables_to_table_list(THD *thd,
table->prelocking_placeholder= 1;
table->belong_to_view= belong_to_view;
table->trg_event_map= stab->trg_event_map;
+ /*
+ Since we don't allow DDL on base tables in prelocked mode it
+ is safe to infer the type of metadata lock from the type of
+ table lock.
+ */
table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
table->lock_type >= TL_WRITE_ALLOW_WRITE ?
MDL_SHARED_WRITE : MDL_SHARED_READ);
@@ -4040,7 +4045,8 @@ sp_head::add_used_tables_to_table_list(THD *thd,
TABLE_LIST *
sp_add_to_query_tables(THD *thd, LEX *lex,
const char *db, const char *name,
- thr_lock_type locktype)
+ thr_lock_type locktype,
+ enum_mdl_type mdl_type)
{
TABLE_LIST *table;
@@ -4055,8 +4061,7 @@ sp_add_to_query_tables(THD *thd, LEX *lex,
table->select_lex= lex->current_select;
table->cacheable_table= 1;
table->mdl_request.init(MDL_key::TABLE, table->db, table->table_name,
- table->lock_type >= TL_WRITE_ALLOW_WRITE ?
- MDL_SHARED_WRITE : MDL_SHARED_READ);
+ mdl_type);
lex->add_to_query_tables(table);
return table;
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 165f88321a9..8975c239810 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -1346,7 +1346,9 @@ set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
TABLE_LIST *
sp_add_to_query_tables(THD *thd, LEX *lex,
const char *db, const char *name,
- thr_lock_type locktype);
+ thr_lock_type locktype,
+ enum_mdl_type mdl_type);
+
Item *
sp_prepare_func_item(THD* thd, Item **it_addr);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 28633365e28..85017886d24 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2358,82 +2358,90 @@ void table_share_release_hook(void *share)
/**
- A helper function that acquires an MDL lock for a table
- being opened.
+ Try to acquire an MDL lock for a table being opened.
+
+ @param[in,out] thd Session context, to report errors.
+ @param[out] ot_ctx Open table context, to hold the back off
+ state. If we failed to acquire a lock
+ due to a lock conflict, we add the
+ failed request to the open table context.
+ @param[in,out] mdl_request A request for an MDL lock.
+ If we managed to acquire a ticket
+ (no errors or lock conflicts occurred),
+ contains a reference to it on
+ return. However, is not modified if MDL
+ lock type- modifying flags were provided.
+ @param[in] flags flags MYSQL_OPEN_FORCE_SHARED_MDL,
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL or
+ MYSQL_OPEN_FAIL_ON_MDL_CONFLICT
+ @sa open_table().
+ @param[out] mdl_ticket Only modified if there was no error.
+ If we managed to acquire an MDL
+ lock, contains a reference to the
+ ticket, otherwise is set to NULL.
+
+ @retval TRUE An error occurred.
+ @retval FALSE No error, but perhaps a lock conflict, check mdl_ticket.
*/
static bool
-open_table_get_mdl_lock(THD *thd, TABLE_LIST *table_list,
+open_table_get_mdl_lock(THD *thd, Open_table_context *ot_ctx,
MDL_request *mdl_request,
- Open_table_context *ot_ctx,
- uint flags)
+ uint flags,
+ MDL_ticket **mdl_ticket)
{
- if (table_list->lock_strategy)
+ if (flags & (MYSQL_OPEN_FORCE_SHARED_MDL |
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL))
{
- MDL_request_list mdl_requests;
- MDL_request *global_request;
/*
- In case of CREATE TABLE .. If NOT EXISTS .. SELECT, the table
- may not yet exist. Let's acquire an exclusive lock for that
- case. If later it turns out the table existsed, we will
- downgrade the lock to shared. Note that, according to the
- locking protocol, all exclusive locks must be acquired before
- shared locks. This invariant is preserved here and is also
- enforced by asserts in metadata locking subsystem.
+ MYSQL_OPEN_FORCE_SHARED_MDL flag means that we are executing
+ PREPARE for a prepared statement and want to override
+ the type-of-operation aware metadata lock which was set
+ in the parser/during view opening with a simple shared
+ metadata lock.
+ This is necessary to allow concurrent execution of PREPARE
+ and LOCK TABLES WRITE statement against the same table.
+
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL flag means that we open
+ the table in order to get information about it for one of I_S
+ queries and also want to override the type-of-operation aware
+ shared metadata lock which was set earlier (e.g. during view
+ opening) with a high-priority shared metadata lock.
+ This is necessary to avoid unnecessary waiting and extra
+ ER_WARN_I_S_SKIPPED_TABLE warnings when accessing I_S tables.
+
+ These two flags are mutually exclusive.
*/
+ DBUG_ASSERT(!(flags & MYSQL_OPEN_FORCE_SHARED_MDL) ||
+ !(flags & MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL));
- mdl_request->set_type(MDL_EXCLUSIVE);
- DBUG_ASSERT(! thd->mdl_context.has_locks() ||
- thd->handler_tables_hash.records ||
- thd->global_read_lock.is_acquired());
-
- if (!(global_request= ot_ctx->get_global_mdl_request(thd)))
- return 1;
-
- mdl_requests.push_front(mdl_request);
- mdl_requests.push_front(global_request);
+ mdl_request= new (thd->mem_root) MDL_request(mdl_request);
+ if (mdl_request == NULL)
+ return TRUE;
- if (thd->mdl_context.acquire_locks(&mdl_requests, ot_ctx->get_timeout()))
- return 1;
+ mdl_request->set_type((flags & MYSQL_OPEN_FORCE_SHARED_MDL) ?
+ MDL_SHARED : MDL_SHARED_HIGH_PRIO);
}
- else
- {
- if (flags & MYSQL_OPEN_FORCE_SHARED_MDL)
- {
- /*
- While executing PREPARE for prepared statement we override
- type-of-operation aware type of shared metadata lock which
- was set in the parser with simple shared metadata lock.
- This is necessary to allow concurrent execution of PREPARE
- and LOCK TABLES WRITE statement which locks one of the tables
- used in the statement being prepared.
- */
- DBUG_ASSERT(!(flags & (MYSQL_OPEN_TAKE_UPGRADABLE_MDL |
- MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL)));
- mdl_request->set_type(MDL_SHARED);
- }
- else if (flags & MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL)
- {
- DBUG_ASSERT(!(flags & MYSQL_OPEN_TAKE_UPGRADABLE_MDL));
- mdl_request->set_type(MDL_SHARED_HIGH_PRIO);
- }
-
- ot_ctx->add_request(mdl_request);
+ ot_ctx->add_request(mdl_request);
- if (thd->mdl_context.try_acquire_lock(mdl_request))
- return 1;
+ if (thd->mdl_context.try_acquire_lock(mdl_request))
+ return TRUE;
- if (mdl_request->ticket == NULL)
+ if (mdl_request->ticket == NULL)
+ {
+ if (flags & MYSQL_OPEN_FAIL_ON_MDL_CONFLICT)
{
- if (flags & MYSQL_OPEN_FAIL_ON_MDL_CONFLICT)
- my_error(ER_WARN_I_S_SKIPPED_TABLE, MYF(0), table_list->db, table_list->table_name);
- else
- ot_ctx->request_backoff_action(Open_table_context::OT_WAIT_MDL_LOCK);
- return 1;
+ my_error(ER_WARN_I_S_SKIPPED_TABLE, MYF(0),
+ mdl_request->key.db_name(), mdl_request->key.name());
+ return TRUE;
}
+ if (ot_ctx->request_backoff_action(Open_table_context::OT_WAIT_MDL_LOCK,
+ mdl_request, NULL))
+ return TRUE;
}
- return 0;
+ *mdl_ticket= mdl_request->ticket;
+ return FALSE;
}
@@ -2468,11 +2476,9 @@ open_table_get_mdl_lock(THD *thd, TABLE_LIST *table_list,
is never opened. In both cases, metadata locks are always taken according
to the lock strategy.
- This function will take a exclusive metadata lock on the table if
- TABLE_LIST::lock_strategy is EXCLUSIVE_DOWNGRADABLE_MDL or EXCLUSIVE_MDL.
- If the lock strategy is EXCLUSIVE_DOWNGRADABLE_MDL and opening the table
- is successful, the exclusive metadata lock is downgraded to a shared
- lock.
+ If the lock strategy is OTLS_DOWNGRADE_IF_EXISTS and opening the table
+ is successful, the exclusive metadata lock acquired by the caller
+ is downgraded to a shared lock.
RETURN
TRUE Open failed. "action" parameter may contain type of action
@@ -2490,7 +2496,6 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
char key[MAX_DBKEY_LENGTH];
uint key_length;
char *alias= table_list->alias;
- MDL_request *mdl_request;
MDL_ticket *mdl_ticket;
int error;
TABLE_SHARE *share;
@@ -2528,7 +2533,8 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
if (thd->version != refresh_version)
{
- (void) ot_ctx->request_backoff_action(Open_table_context::OT_WAIT_TDC);
+ (void) ot_ctx->request_backoff_action(Open_table_context::OT_WAIT_TDC,
+ NULL, NULL);
DBUG_RETURN(TRUE);
}
}
@@ -2701,23 +2707,25 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
This is the normal use case.
*/
- mdl_request= &table_list->mdl_request;
if (! (flags & MYSQL_OPEN_HAS_MDL_LOCK))
{
- if (open_table_get_mdl_lock(thd, table_list, mdl_request, ot_ctx, flags))
+ if (open_table_get_mdl_lock(thd, ot_ctx, &table_list->mdl_request,
+ flags, &mdl_ticket) ||
+ mdl_ticket == NULL)
{
DEBUG_SYNC(thd, "before_open_table_wait_refresh");
DBUG_RETURN(TRUE);
}
DEBUG_SYNC(thd, "after_open_table_mdl_shared");
}
-
- /*
- Grab reference to the granted MDL lock ticket. Must be done after
- open_table_get_mdl_lock as the lock on the table might have been
- acquired previously (MYSQL_OPEN_HAS_MDL_LOCK).
- */
- mdl_ticket= mdl_request->ticket;
+ else
+ {
+ /*
+ Grab reference to the MDL lock ticket that was acquired
+ by the caller.
+ */
+ mdl_ticket= table_list->mdl_request.ticket;
+ }
hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length);
mysql_mutex_lock(&LOCK_open);
@@ -2737,7 +2745,8 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
{
/* Someone did a refresh while thread was opening tables */
mysql_mutex_unlock(&LOCK_open);
- (void) ot_ctx->request_backoff_action(Open_table_context::OT_WAIT_TDC);
+ (void) ot_ctx->request_backoff_action(Open_table_context::OT_WAIT_TDC,
+ NULL, NULL);
DBUG_RETURN(TRUE);
}
@@ -2878,7 +2887,8 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
*/
release_table_share(share);
mysql_mutex_unlock(&LOCK_open);
- (void) ot_ctx->request_backoff_action(Open_table_context::OT_WAIT_TDC);
+ (void) ot_ctx->request_backoff_action(Open_table_context::OT_WAIT_TDC,
+ NULL, NULL);
DBUG_RETURN(TRUE);
}
/* Force close at once after usage */
@@ -2918,12 +2928,14 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
if (error == 7)
{
share->version= 0;
- (void) ot_ctx->request_backoff_action(Open_table_context::OT_DISCOVER);
+ (void) ot_ctx->request_backoff_action(Open_table_context::OT_DISCOVER,
+ NULL, table_list);
}
else if (share->crashed)
{
share->version= 0;
- (void) ot_ctx->request_backoff_action(Open_table_context::OT_REPAIR);
+ (void) ot_ctx->request_backoff_action(Open_table_context::OT_REPAIR,
+ NULL, table_list);
}
goto err_unlock;
@@ -2947,7 +2959,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
table exists now we should downgrade our exclusive metadata
lock on this table to SW metadata lock.
*/
- if (table_list->lock_strategy == TABLE_LIST::EXCLUSIVE_DOWNGRADABLE_MDL &&
+ if (table_list->lock_strategy == TABLE_LIST::OTLS_DOWNGRADE_IF_EXISTS &&
!(flags & MYSQL_OPEN_HAS_MDL_LOCK))
mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_WRITE);
@@ -3782,6 +3794,8 @@ end_with_lock_open:
Open_table_context::Open_table_context(THD *thd, ulong timeout)
:m_action(OT_NO_ACTION),
+ m_failed_mdl_request(NULL),
+ m_failed_table(NULL),
m_start_of_statement_svp(thd->mdl_context.mdl_savepoint()),
m_has_locks((thd->in_multi_stmt_transaction_mode() &&
thd->mdl_context.has_locks()) ||
@@ -3801,10 +3815,8 @@ MDL_request *Open_table_context::get_global_mdl_request(THD *thd)
{
if (! m_global_mdl_request)
{
- char *buff;
- if ((buff= (char*)thd->alloc(sizeof(MDL_request))))
+ if ((m_global_mdl_request= new (thd->mem_root) MDL_request()))
{
- m_global_mdl_request= new (buff) MDL_request();
m_global_mdl_request->init(MDL_key::GLOBAL, "", "",
MDL_INTENTION_EXCLUSIVE);
}
@@ -3823,7 +3835,8 @@ MDL_request *Open_table_context::get_global_mdl_request(THD *thd)
bool
Open_table_context::
-request_backoff_action(enum_open_table_action action_arg)
+request_backoff_action(enum_open_table_action action_arg,
+ MDL_request *mdl_request, TABLE_LIST *table)
{
/*
We are inside a transaction that already holds locks and have
@@ -3847,6 +3860,19 @@ request_backoff_action(enum_open_table_action action_arg)
return TRUE;
}
m_action= action_arg;
+ /*
+ If waiting for metadata lock is requested, a pointer to
+ MDL_request object for which we were unable to acquire the
+ lock is required.
+ */
+ DBUG_ASSERT(m_action != OT_WAIT_MDL_LOCK || mdl_request);
+ m_failed_mdl_request= mdl_request;
+ /*
+ If auto-repair or discovery are requested, a pointer to table
+ list element must be provided.
+ */
+ DBUG_ASSERT((m_action != OT_DISCOVER && m_action != OT_REPAIR) || table);
+ m_failed_table= table;
return FALSE;
}
@@ -3855,10 +3881,6 @@ request_backoff_action(enum_open_table_action action_arg)
Recover from failed attempt of open table by performing requested action.
@param thd Thread context
- @param mdl_request MDL_request of the object that caused the problem.
- @param table Optional (can be NULL). Used only if action is OT_REPAIR.
- In that case a TABLE_LIST for the table to be repaired.
- @todo: It's unnecessary and should be removed.
@pre This function should be called only with "action" != OT_NO_ACTION
and after having called @sa close_tables_for_reopen().
@@ -3869,8 +3891,7 @@ request_backoff_action(enum_open_table_action action_arg)
bool
Open_table_context::
-recover_from_failed_open(THD *thd, MDL_request *mdl_request,
- TABLE_LIST *table)
+recover_from_failed_open(THD *thd)
{
bool result= FALSE;
/*
@@ -3882,7 +3903,8 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request,
switch (m_action)
{
case OT_WAIT_MDL_LOCK:
- result= thd->mdl_context.wait_for_lock(mdl_request, get_timeout());
+ result= thd->mdl_context.wait_for_lock(m_failed_mdl_request,
+ get_timeout());
break;
case OT_WAIT_TDC:
result= tdc_wait_for_old_versions(thd, &m_mdl_requests, get_timeout());
@@ -3891,7 +3913,7 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request,
case OT_DISCOVER:
{
MDL_request mdl_global_request;
- MDL_request mdl_xlock_request(mdl_request);
+ MDL_request mdl_xlock_request(&m_failed_table->mdl_request);
MDL_request_list mdl_requests;
mdl_global_request.init(MDL_key::GLOBAL, "", "",
@@ -3905,14 +3927,11 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request,
thd->mdl_context.acquire_locks(&mdl_requests, get_timeout())))
break;
- DBUG_ASSERT(mdl_request->key.mdl_namespace() == MDL_key::TABLE);
mysql_mutex_lock(&LOCK_open);
- tdc_remove_table(thd, TDC_RT_REMOVE_ALL,
- mdl_request->key.db_name(),
- mdl_request->key.name());
- ha_create_table_from_engine(thd,
- mdl_request->key.db_name(),
- mdl_request->key.name());
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
+ m_failed_table->table_name);
+ ha_create_table_from_engine(thd, m_failed_table->db,
+ m_failed_table->table_name);
mysql_mutex_unlock(&LOCK_open);
thd->warning_info->clear_warning_info(thd->query_id);
@@ -3923,7 +3942,7 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request,
case OT_REPAIR:
{
MDL_request mdl_global_request;
- MDL_request mdl_xlock_request(mdl_request);
+ MDL_request mdl_xlock_request(&m_failed_table->mdl_request);
MDL_request_list mdl_requests;
mdl_global_request.init(MDL_key::GLOBAL, "", "",
@@ -3937,14 +3956,12 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request,
thd->mdl_context.acquire_locks(&mdl_requests, get_timeout())))
break;
- DBUG_ASSERT(mdl_request->key.mdl_namespace() == MDL_key::TABLE);
mysql_mutex_lock(&LOCK_open);
- tdc_remove_table(thd, TDC_RT_REMOVE_ALL,
- mdl_request->key.db_name(),
- mdl_request->key.name());
+ tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db,
+ m_failed_table->table_name);
mysql_mutex_unlock(&LOCK_open);
- result= auto_repair_table(thd, table);
+ result= auto_repair_table(thd, m_failed_table);
thd->mdl_context.release_transactional_locks();
break;
}
@@ -3953,6 +3970,13 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request,
}
/* Remove all old requests, they will be re-added. */
m_mdl_requests.empty();
+ /*
+ Reset the pointers to conflicting MDL request and the
+ TABLE_LIST element, set when we need auto-discovery or repair,
+ for safety.
+ */
+ m_failed_mdl_request= NULL;
+ m_failed_table= NULL;
/* Prepare for possible another back-off. */
m_action= OT_NO_ACTION;
return result;
@@ -4081,7 +4105,8 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
if (rt->mdl_request.ticket == NULL)
{
/* A lock conflict. Someone's trying to modify SP metadata. */
- ot_ctx->request_backoff_action(Open_table_context::OT_WAIT_MDL_LOCK);
+ ot_ctx->request_backoff_action(Open_table_context::OT_WAIT_MDL_LOCK,
+ &rt->mdl_request, NULL);
DBUG_RETURN(TRUE);
}
DEBUG_SYNC(thd, "after_shared_lock_pname");
@@ -4228,12 +4253,14 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
*/
if (tables->view)
{
+ MDL_ticket *mdl_ticket;
/*
We still need to take a MDL lock on the merged view to protect
it from concurrent changes.
*/
- if (!open_table_get_mdl_lock(thd, tables, &tables->mdl_request,
- ot_ctx, flags))
+ if (!open_table_get_mdl_lock(thd, ot_ctx, &tables->mdl_request,
+ flags, &mdl_ticket) &&
+ mdl_ticket != NULL)
goto process_view_routines;
/* Fall-through to return error. */
}
@@ -4423,6 +4450,8 @@ end:
should be acquired.
@param tables_end End of list of tables.
@param ot_ctx Context of open_tables() operation.
+ @param flags Bitmap of flags to modify how the tables will be
+ open, see open_table() description for details.
@retval FALSE Success.
@retval TRUE Failure (e.g. connection was killed)
@@ -4431,31 +4460,30 @@ end:
static bool
open_tables_acquire_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
TABLE_LIST *tables_end,
- Open_table_context *ot_ctx)
+ Open_table_context *ot_ctx,
+ uint flags)
{
MDL_request_list mdl_requests;
TABLE_LIST *table;
DBUG_ASSERT(!thd->locked_tables_mode);
- DEBUG_SYNC(thd, "open_tables_acquire_upgradable_mdl");
for (table= tables_start; table && table != tables_end;
table= table->next_global)
{
- if (table->lock_type >= TL_WRITE_ALLOW_WRITE &&
+ if (table->mdl_request.type >= MDL_SHARED_NO_WRITE &&
!(table->open_type == OT_TEMPORARY_ONLY ||
+ (flags & MYSQL_OPEN_TEMPORARY_ONLY) ||
(table->open_type != OT_BASE_ONLY &&
+ ! (flags & MYSQL_OPEN_SKIP_TEMPORARY) &&
find_temporary_table(thd, table))))
- {
- table->mdl_request.set_type(table->lock_type > TL_WRITE_ALLOW_READ ?
- MDL_SHARED_NO_READ_WRITE :
- MDL_SHARED_NO_WRITE);
mdl_requests.push_front(&table->mdl_request);
- }
}
if (! mdl_requests.is_empty())
{
+ DEBUG_SYNC(thd, "open_tables_acquire_upgradable_mdl");
+
MDL_request *global_request= ot_ctx->get_global_mdl_request(thd);
if (global_request == NULL)
@@ -4469,11 +4497,8 @@ open_tables_acquire_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
for (table= tables_start; table && table != tables_end;
table= table->next_global)
{
- if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
- {
+ if (table->mdl_request.type >= MDL_SHARED_NO_WRITE)
table->mdl_request.ticket= NULL;
- table->mdl_request.set_type(MDL_SHARED_WRITE);
- }
}
return FALSE;
@@ -4489,6 +4514,8 @@ open_tables_acquire_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
@param tables_start Start of list of tables on which upgradable locks
should be searched for.
@param tables_end End of list of tables.
+ @param flags Bitmap of flags to modify how the tables will be
+ open, see open_table() description for details.
@retval FALSE Success.
@retval TRUE Failure (e.g. connection was killed)
@@ -4496,7 +4523,7 @@ open_tables_acquire_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
static bool
open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
- TABLE_LIST *tables_end)
+ TABLE_LIST *tables_end, uint flags)
{
TABLE_LIST *table;
@@ -4505,9 +4532,11 @@ open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
for (table= tables_start; table && table != tables_end;
table= table->next_global)
{
- if (table->lock_type >= TL_WRITE_ALLOW_WRITE &&
+ if (table->mdl_request.type >= MDL_SHARED_NO_WRITE &&
!(table->open_type == OT_TEMPORARY_ONLY ||
+ (flags & MYSQL_OPEN_TEMPORARY_ONLY) ||
(table->open_type != OT_BASE_ONLY &&
+ ! (flags & MYSQL_OPEN_SKIP_TEMPORARY) &&
find_temporary_table(thd, table))))
{
/*
@@ -4519,8 +4548,14 @@ open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
lock, all other instances of TABLE for the same table will have the
same ticket.
- Note that find_table_for_mdl_upgrade() will report an error if a
- ticket is not found.
+ Note that this works OK even for CREATE TABLE statements which
+ request X type of metadata lock. This is because under LOCK TABLES
+ such statements don't create the table but only check if it exists
+ or, in most complex case, only insert into it.
+ Thus SNRW lock should be enough.
+
+ Note that find_table_for_mdl_upgrade() will report an error if
+ no suitable ticket is found.
*/
if (!find_table_for_mdl_upgrade(thd->open_tables, table->db,
table->table_name, FALSE))
@@ -4612,21 +4647,19 @@ restart:
(in non-LOCK TABLES mode) we might have to acquire upgradable
semi-exclusive metadata locks (SNW or SNRW) on some of the
tables to be opened.
- So we acquire all such locks at once here as doing this in one
+ When executing CREATE TABLE .. If NOT EXISTS .. SELECT, the
+ table may not yet exist, in which case we acquire an exclusive
+ lock.
+ We acquire all such locks at once here as doing this in one
by one fashion may lead to deadlocks or starvation. Later when
we will be opening corresponding table pre-acquired metadata
lock will be reused (thanks to the fact that in recursive case
metadata locks are acquired without waiting).
*/
- if (flags & MYSQL_OPEN_TAKE_UPGRADABLE_MDL)
+ if (! (flags & (MYSQL_OPEN_HAS_MDL_LOCK |
+ MYSQL_OPEN_FORCE_SHARED_MDL |
+ MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL)))
{
- /*
- open_tables_acquire_upgradable_mdl() does not currenly handle
- these two flags. At this point, that does not matter as they
- are not used together with MYSQL_OPEN_TAKE_UPGRADABLE_MDL.
- */
- DBUG_ASSERT(!(flags & (MYSQL_OPEN_SKIP_TEMPORARY |
- MYSQL_OPEN_TEMPORARY_ONLY)));
if (thd->locked_tables_mode)
{
/*
@@ -4634,7 +4667,8 @@ restart:
need to check if appropriate locks were pre-acquired.
*/
if (open_tables_check_upgradable_mdl(thd, *start,
- thd->lex->first_not_own_table()))
+ thd->lex->first_not_own_table(),
+ flags))
{
error= TRUE;
goto err;
@@ -4642,7 +4676,7 @@ restart:
}
else if (open_tables_acquire_upgradable_mdl(thd, *start,
thd->lex->first_not_own_table(),
- &ot_ctx))
+ &ot_ctx, flags))
{
error= TRUE;
goto err;
@@ -4688,7 +4722,6 @@ restart:
have failed to open since closing tables can trigger removal of
elements from the table list (if MERGE tables are involved),
*/
- TABLE_LIST *failed_table= *table_to_open;
close_tables_for_reopen(thd, start, ot_ctx.start_of_statement_svp());
/*
@@ -4696,8 +4729,7 @@ restart:
TABLE_LIST element. Altough currently this assumption is valid
it may change in future.
*/
- if (ot_ctx.recover_from_failed_open(thd, &failed_table->mdl_request,
- failed_table))
+ if (ot_ctx.recover_from_failed_open(thd))
goto err;
error= FALSE;
@@ -4741,7 +4773,7 @@ restart:
{
close_tables_for_reopen(thd, start,
ot_ctx.start_of_statement_svp());
- if (ot_ctx.recover_from_failed_open(thd, &rt->mdl_request, NULL))
+ if (ot_ctx.recover_from_failed_open(thd))
goto err;
error= FALSE;
@@ -5163,6 +5195,9 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
/* open_ltable can be used only for BASIC TABLEs */
table_list->required_type= FRMTYPE_TABLE;
+ /* This function can't properly handle requests for such metadata locks. */
+ DBUG_ASSERT(table_list->mdl_request.type < MDL_SHARED_NO_WRITE);
+
while ((error= open_table(thd, table_list, thd->mem_root, &ot_ctx, lock_flags)) &&
ot_ctx.can_recover_from_failed_open())
{
@@ -5173,8 +5208,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type,
*/
thd->mdl_context.rollback_to_savepoint(ot_ctx.start_of_statement_svp());
table_list->mdl_request.ticket= 0;
- if (ot_ctx.recover_from_failed_open(thd, &table_list->mdl_request,
- table_list))
+ if (ot_ctx.recover_from_failed_open(thd))
break;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 916b79f8353..d494fdf86b5 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1329,9 +1329,9 @@ public:
};
Open_table_context(THD *thd, ulong timeout);
- bool recover_from_failed_open(THD *thd, MDL_request *mdl_request,
- TABLE_LIST *table);
- bool request_backoff_action(enum_open_table_action action_arg);
+ bool recover_from_failed_open(THD *thd);
+ bool request_backoff_action(enum_open_table_action action_arg,
+ MDL_request *mdl_request, TABLE_LIST *table);
void add_request(MDL_request *request)
{ m_mdl_requests.push_front(request); }
@@ -1362,6 +1362,14 @@ private:
MDL_request_list m_mdl_requests;
/** Back off action. */
enum enum_open_table_action m_action;
+ /** For OT_WAIT_MDL_LOCK action, the request for which we should wait. */
+ MDL_request *m_failed_mdl_request;
+ /**
+ For OT_DISCOVER and OT_REPAIR actions, the table list element for
+ the table which definition should be re-discovered or which
+ should be repaired.
+ */
+ TABLE_LIST *m_failed_table;
MDL_ticket *m_start_of_statement_svp;
/**
Whether we had any locks when this context was created.
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 15fdd842e34..2e48475f298 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -1203,6 +1203,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
table_list->alias= table_list->table_name; // If lower_case_table_names=2
table_list->internal_tmp_table= is_prefix(file->name, tmp_file_prefix);
+ table_list->mdl_request.init(MDL_key::TABLE, table_list->db,
+ table_list->table_name, MDL_EXCLUSIVE);
/* Link into list */
(*tot_list_next)= table_list;
tot_list_next= &table_list->next_local;
@@ -1918,9 +1920,11 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
Table_ident *new_ident= new Table_ident(thd, new_db, table_str, 0);
if (!old_ident || !new_ident ||
!sl->add_table_to_list(thd, old_ident, NULL,
- TL_OPTION_UPDATING, TL_IGNORE) ||
+ TL_OPTION_UPDATING, TL_IGNORE,
+ MDL_EXCLUSIVE) ||
!sl->add_table_to_list(thd, new_ident, NULL,
- TL_OPTION_UPDATING, TL_IGNORE))
+ TL_OPTION_UPDATING, TL_IGNORE,
+ MDL_EXCLUSIVE))
{
error= 1;
my_dirend(dirp);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 1795bc272f1..48474609b9b 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1978,6 +1978,7 @@ TABLE_LIST *st_select_lex_node::add_table_to_list (THD *thd, Table_ident *table,
LEX_STRING *alias,
ulong table_join_options,
thr_lock_type flags,
+ enum_mdl_type mdl_type,
List<Index_hint> *hints,
LEX_STRING *option)
{
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 2ce6bdeed42..38aac9a1042 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -502,6 +502,7 @@ public:
LEX_STRING *alias,
ulong table_options,
thr_lock_type flags= TL_UNLOCK,
+ enum_mdl_type mdl_type= MDL_SHARED_READ,
List<Index_hint> *hints= 0,
LEX_STRING *option= 0);
virtual void set_lock_for_tables(thr_lock_type lock_type) {}
@@ -799,6 +800,7 @@ public:
LEX_STRING *alias,
ulong table_options,
thr_lock_type flags= TL_UNLOCK,
+ enum_mdl_type mdl_type= MDL_SHARED_READ,
List<Index_hint> *hints= 0,
LEX_STRING *option= 0);
TABLE_LIST* get_table_list();
@@ -2249,6 +2251,7 @@ public:
yacc_yyvs= NULL;
m_set_signal_info.clear();
m_lock_type= TL_READ_DEFAULT;
+ m_mdl_type= MDL_SHARED_READ;
}
~Yacc_state();
@@ -2260,6 +2263,7 @@ public:
void reset_before_substatement()
{
m_lock_type= TL_READ_DEFAULT;
+ m_mdl_type= MDL_SHARED_READ;
}
/**
@@ -2299,6 +2303,12 @@ public:
*/
thr_lock_type m_lock_type;
+ /**
+ The type of requested metadata lock for tables added to
+ the statement table list.
+ */
+ enum_mdl_type m_mdl_type;
+
/*
TODO: move more attributes from the LEX structure here.
*/
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 60b2ffa4179..4c3f44ea75c 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1606,7 +1606,8 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
/* 'parent_lex' is used in init_query() so it must be before it. */
schema_select_lex->parent_lex= lex;
schema_select_lex->init_query();
- if (!schema_select_lex->add_table_to_list(thd, table_ident, 0, 0, TL_READ))
+ if (!schema_select_lex->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
+ MDL_SHARED_READ))
DBUG_RETURN(1);
lex->query_tables_last= query_tables_last;
break;
@@ -2544,7 +2545,7 @@ case SQLCOM_PREPARE:
/* Set strategies: reset default or 'prepared' values. */
create_table->open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
- create_table->lock_strategy= TABLE_LIST::EXCLUSIVE_DOWNGRADABLE_MDL;
+ create_table->lock_strategy= TABLE_LIST::OTLS_DOWNGRADE_IF_EXISTS;
/*
Close any open handlers for the table
@@ -3502,16 +3503,13 @@ end_with_restore_list:
thd->global_read_lock.wait_if_global_read_lock(thd, FALSE, TRUE))
goto error;
- init_mdl_requests(all_tables);
-
thd->variables.option_bits|= OPTION_TABLE_LOCK;
thd->in_lock_tables=1;
{
Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
- res= (open_and_lock_tables(thd, all_tables, FALSE,
- MYSQL_OPEN_TAKE_UPGRADABLE_MDL,
+ res= (open_and_lock_tables(thd, all_tables, FALSE, 0,
&lock_tables_prelocking_strategy) ||
thd->locked_tables_list.init_locked_tables(thd));
}
@@ -6014,6 +6012,7 @@ bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
- TL_OPTION_FORCE_INDEX : Force usage of index
- TL_OPTION_ALIAS : an alias in multi table DELETE
@param lock_type How table should be locked
+ @param mdl_type Type of metadata lock to acquire on the table.
@param use_index List of indexed used in USE INDEX
@param ignore_index List of indexed used in IGNORE INDEX
@@ -6028,6 +6027,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
LEX_STRING *alias,
ulong table_options,
thr_lock_type lock_type,
+ enum_mdl_type mdl_type,
List<Index_hint> *index_hints_arg,
LEX_STRING *option)
{
@@ -6175,9 +6175,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->next_name_resolution_table= NULL;
/* Link table in global list (all used tables) */
lex->add_to_query_tables(ptr);
- ptr->mdl_request.init(MDL_key::TABLE, ptr->db, ptr->table_name,
- (ptr->lock_type >= TL_WRITE_ALLOW_WRITE) ?
- MDL_SHARED_WRITE : MDL_SHARED_READ);
+ ptr->mdl_request.init(MDL_key::TABLE, ptr->db, ptr->table_name, mdl_type);
DBUG_RETURN(ptr);
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index c2d3c595d95..e5d7514d9f5 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1690,7 +1690,7 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
for the prepare phase.
*/
create_table->open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
- create_table->lock_strategy= TABLE_LIST::SHARED_MDL;
+ create_table->lock_strategy= TABLE_LIST::OTLS_NONE;
if (select_lex->item_list.elements)
{
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index f1db513d0e2..a33bc5943da 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2358,7 +2358,7 @@ int make_table_list(THD *thd, SELECT_LEX *sel,
Table_ident *table_ident;
table_ident= new Table_ident(thd, *db_name, *table_name, 1);
sel->init_query();
- if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ))
+ if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ, MDL_SHARED_READ))
return 1;
return 0;
}
@@ -6582,7 +6582,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
strlen(schema_table->table_name), 0);
if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */
!sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
- 0, 0, TL_READ))
+ 0, 0, TL_READ, MDL_SHARED_READ))
{
DBUG_RETURN(1);
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 2b8e7de3a60..b2a950ca4b0 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4656,6 +4656,14 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
strxmov(table_name, db, ".", table->table_name, NullS);
thd->open_options|= extra_open_options;
table->lock_type= lock_type;
+ /*
+ To make code safe for re-execution we need to reset type of MDL
+ request as code below may change it.
+ To allow concurrent execution of read-only operations we acquire
+ weak metadata lock for them.
+ */
+ table->mdl_request.set_type((lock_type >= TL_WRITE_ALLOW_READ) ?
+ MDL_SHARED_NO_READ_WRITE : MDL_SHARED_READ);
/* open only one table from local list of command */
{
TABLE_LIST *save_next_global, *save_next_local;
@@ -4677,8 +4685,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
if (view_operator_func == NULL)
table->required_type=FRMTYPE_TABLE;
- open_error= open_and_lock_tables(thd, table, TRUE,
- MYSQL_OPEN_TAKE_UPGRADABLE_MDL);
+ open_error= open_and_lock_tables(thd, table, TRUE, 0);
thd->no_warnings_for_error= 0;
table->next_global= save_next_global;
table->next_local= save_next_local;
@@ -5024,6 +5031,7 @@ send_result_message:
/* Clear the ticket released in close_thread_tables(). */
table->mdl_request.ticket= NULL;
DEBUG_SYNC(thd, "ha_admin_open_ltable");
+ table->mdl_request.set_type(MDL_SHARED_WRITE);
if ((table->table= open_ltable(thd, table, lock_type, 0)))
{
result_code= table->table->file->ha_analyze(thd, check_opt);
@@ -5461,6 +5469,7 @@ mysql_discard_or_import_tablespace(THD *thd,
not complain when we lock the table
*/
thd->tablespace_op= TRUE;
+ table_list->mdl_request.set_type(MDL_SHARED_WRITE);
if (!(table=open_ltable(thd, table_list, TL_WRITE, 0)))
{
thd->tablespace_op=FALSE;
@@ -6568,6 +6577,12 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (thd->global_read_lock.wait_if_global_read_lock(thd, FALSE, TRUE))
DBUG_RETURN(TRUE);
+
+ /*
+ TODO/FIXME: Get rid of this code branch if possible. To add insult
+ to injury it breaks locking protocol.
+ */
+ table_list->mdl_request.set_type(MDL_EXCLUSIVE);
if (lock_table_names(thd, table_list))
{
error= 1;
@@ -6608,8 +6623,7 @@ view_err:
Alter_table_prelocking_strategy alter_prelocking_strategy(alter_info);
- error= open_and_lock_tables(thd, table_list, FALSE,
- MYSQL_OPEN_TAKE_UPGRADABLE_MDL,
+ error= open_and_lock_tables(thd, table_list, FALSE, 0,
&alter_prelocking_strategy);
if (error)
@@ -7904,6 +7918,10 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list)
table_list->table= NULL;
/* Same applies to MDL ticket. */
table_list->mdl_request.ticket= NULL;
+ /* Set lock type which is appropriate for ALTER TABLE. */
+ table_list->lock_type= TL_WRITE_ALLOW_READ;
+ /* Same applies to MDL request. */
+ table_list->mdl_request.set_type(MDL_SHARED_NO_WRITE);
bzero((char*) &create_info, sizeof(create_info));
create_info.row_type=ROW_TYPE_NOT_USED;
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 9ce62d9f2a4..ae09898ada2 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -489,8 +489,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
else
{
tables->table= open_n_lock_single_table(thd, tables,
- TL_WRITE_ALLOW_READ,
- MYSQL_OPEN_TAKE_UPGRADABLE_MDL);
+ TL_WRITE_ALLOW_READ, 0);
if (! tables->table)
goto end;
tables->table->use_all_columns();
@@ -1667,7 +1666,8 @@ bool add_table_for_trigger(THD *thd,
DBUG_RETURN(TRUE);
*table= sp_add_to_query_tables(thd, lex, trg_name->m_db.str,
- tbl_name.str, TL_IGNORE);
+ tbl_name.str, TL_IGNORE,
+ MDL_SHARED_NO_WRITE);
DBUG_RETURN(*table ? FALSE : TRUE);
}
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 3a6866f4a7e..4eee9502177 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -433,7 +433,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
lex->link_first_table_back(view, link_to_local);
view->open_strategy= TABLE_LIST::OPEN_STUB;
- view->lock_strategy= TABLE_LIST::EXCLUSIVE_MDL;
+ view->lock_strategy= TABLE_LIST::OTLS_NONE;
view->open_type= OT_BASE_ONLY;
if (open_and_lock_tables(thd, lex->query_tables, TRUE, 0))
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index aa336f3c072..e5875663d4e 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -697,7 +697,8 @@ static bool add_create_index_prepare (LEX *lex, Table_ident *table)
lex->sql_command= SQLCOM_CREATE_INDEX;
if (!lex->current_select->add_table_to_list(lex->thd, table, NULL,
TL_OPTION_UPDATING,
- TL_WRITE_ALLOW_READ))
+ TL_WRITE_ALLOW_READ,
+ MDL_SHARED_NO_WRITE))
return TRUE;
lex->alter_info.reset();
lex->alter_info.flags= ALTER_ADD_INDEX;
@@ -2023,7 +2024,7 @@ create:
lex->sql_command= SQLCOM_CREATE_TABLE;
if (!lex->select_lex.add_table_to_list(thd, $5, NULL,
TL_OPTION_UPDATING,
- TL_WRITE))
+ TL_WRITE, MDL_EXCLUSIVE))
MYSQL_YYABORT;
lex->alter_info.reset();
lex->col_list.empty();
@@ -4213,7 +4214,8 @@ create2:
lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE;
src_table= lex->select_lex.add_table_to_list(thd, $2, NULL, 0,
- TL_READ);
+ TL_READ,
+ MDL_SHARED_READ);
if (! src_table)
MYSQL_YYABORT;
/* CREATE TABLE ... LIKE is not allowed for views. */
@@ -4227,7 +4229,8 @@ create2:
lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE;
src_table= lex->select_lex.add_table_to_list(thd, $3, NULL, 0,
- TL_READ);
+ TL_READ,
+ MDL_SHARED_READ);
if (! src_table)
MYSQL_YYABORT;
/* CREATE TABLE ... LIKE is not allowed for views. */
@@ -6154,7 +6157,8 @@ alter:
lex->duplicates= DUP_ERROR;
if (!lex->select_lex.add_table_to_list(thd, $4, NULL,
TL_OPTION_UPDATING,
- TL_WRITE_ALLOW_READ))
+ TL_WRITE_ALLOW_READ,
+ MDL_SHARED_NO_WRITE))
MYSQL_YYABORT;
lex->col_list.empty();
lex->select_lex.init_order();
@@ -6847,6 +6851,8 @@ checksum:
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_CHECKSUM;
+ /* Will be overriden during execution. */
+ YYPS->m_lock_type= TL_UNLOCK;
}
table_list opt_checksum_type
{}
@@ -6866,6 +6872,8 @@ repair:
lex->no_write_to_binlog= $2;
lex->check_opt.init();
lex->alter_info.reset();
+ /* Will be overriden during execution. */
+ YYPS->m_lock_type= TL_UNLOCK;
}
table_list opt_mi_repair_type
{}
@@ -6895,6 +6903,8 @@ analyze:
lex->no_write_to_binlog= $2;
lex->check_opt.init();
lex->alter_info.reset();
+ /* Will be overriden during execution. */
+ YYPS->m_lock_type= TL_UNLOCK;
}
table_list
{}
@@ -6921,6 +6931,8 @@ check:
lex->sql_command = SQLCOM_CHECK;
lex->check_opt.init();
lex->alter_info.reset();
+ /* Will be overriden during execution. */
+ YYPS->m_lock_type= TL_UNLOCK;
}
table_list opt_mi_check_type
{}
@@ -6953,6 +6965,8 @@ optimize:
lex->no_write_to_binlog= $2;
lex->check_opt.init();
lex->alter_info.reset();
+ /* Will be overriden during execution. */
+ YYPS->m_lock_type= TL_UNLOCK;
}
table_list
{}
@@ -7001,9 +7015,9 @@ table_to_table:
LEX *lex=Lex;
SELECT_LEX *sl= lex->current_select;
if (!sl->add_table_to_list(lex->thd, $1,NULL,TL_OPTION_UPDATING,
- TL_IGNORE) ||
+ TL_IGNORE, MDL_EXCLUSIVE) ||
!sl->add_table_to_list(lex->thd, $3,NULL,TL_OPTION_UPDATING,
- TL_IGNORE))
+ TL_IGNORE, MDL_EXCLUSIVE))
MYSQL_YYABORT;
}
;
@@ -7034,7 +7048,8 @@ keycache_list:
assign_to_keycache:
table_ident cache_keys_spec
{
- if (!Select->add_table_to_list(YYTHD, $1, NULL, 0, TL_READ,
+ if (!Select->add_table_to_list(YYTHD, $1, NULL, 0, TL_READ,
+ MDL_SHARED_READ,
Select->pop_index_hints()))
MYSQL_YYABORT;
}
@@ -7044,6 +7059,7 @@ assign_to_keycache_parts:
table_ident adm_partition cache_keys_spec
{
if (!Select->add_table_to_list(YYTHD, $1, NULL, 0, TL_READ,
+ MDL_SHARED_READ,
Select->pop_index_hints()))
MYSQL_YYABORT;
}
@@ -7079,6 +7095,7 @@ preload_keys:
table_ident cache_keys_spec opt_ignore_leaves
{
if (!Select->add_table_to_list(YYTHD, $1, NULL, $3, TL_READ,
+ MDL_SHARED_READ,
Select->pop_index_hints()))
MYSQL_YYABORT;
}
@@ -7088,6 +7105,7 @@ preload_keys_parts:
table_ident adm_partition cache_keys_spec opt_ignore_leaves
{
if (!Select->add_table_to_list(YYTHD, $1, NULL, $4, TL_READ,
+ MDL_SHARED_READ,
Select->pop_index_hints()))
MYSQL_YYABORT;
}
@@ -9220,6 +9238,7 @@ table_factor:
if (!($$= Select->add_table_to_list(YYTHD, $2, $3,
Select->get_table_join_options(),
YYPS->m_lock_type,
+ YYPS->m_mdl_type,
Select->pop_index_hints())))
MYSQL_YYABORT;
Select->add_joined_table($$);
@@ -9291,7 +9310,7 @@ table_factor:
MYSQL_YYABORT;
if (!($$= sel->add_table_to_list(lex->thd,
new Table_ident(unit), $5, 0,
- TL_READ)))
+ TL_READ, MDL_SHARED_READ)))
MYSQL_YYABORT;
sel->add_joined_table($$);
@@ -10126,13 +10145,17 @@ do:
*/
drop:
- DROP opt_temporary table_or_tables if_exists table_list opt_restrict
+ DROP opt_temporary table_or_tables if_exists
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_DROP_TABLE;
lex->drop_temporary= $2;
lex->drop_if_exists= $4;
+ YYPS->m_lock_type= TL_IGNORE;
+ YYPS->m_mdl_type= MDL_EXCLUSIVE;
}
+ table_list opt_restrict
+ {}
| DROP INDEX_SYM ident ON table_ident {}
{
LEX *lex=Lex;
@@ -10145,7 +10168,8 @@ drop:
lex->alter_info.drop_list.push_back(ad);
if (!lex->current_select->add_table_to_list(lex->thd, $5, NULL,
TL_OPTION_UPDATING,
- TL_WRITE_ALLOW_READ))
+ TL_WRITE_ALLOW_READ,
+ MDL_SHARED_NO_WRITE))
MYSQL_YYABORT;
}
| DROP DATABASE if_exists ident
@@ -10215,12 +10239,16 @@ drop:
{
Lex->sql_command = SQLCOM_DROP_USER;
}
- | DROP VIEW_SYM if_exists table_list opt_restrict
+ | DROP VIEW_SYM if_exists
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_DROP_VIEW;
lex->drop_if_exists= $3;
+ YYPS->m_lock_type= TL_IGNORE;
+ YYPS->m_mdl_type= MDL_EXCLUSIVE;
}
+ table_list opt_restrict
+ {}
| DROP EVENT_SYM if_exists sp_name
{
Lex->drop_if_exists= $3;
@@ -10261,7 +10289,10 @@ table_list:
table_name:
table_ident
{
- if (!Select->add_table_to_list(YYTHD, $1, NULL, TL_OPTION_UPDATING))
+ if (!Select->add_table_to_list(YYTHD, $1, NULL,
+ TL_OPTION_UPDATING,
+ YYPS->m_lock_type,
+ YYPS->m_mdl_type))
MYSQL_YYABORT;
}
;
@@ -10276,7 +10307,8 @@ table_alias_ref:
{
if (!Select->add_table_to_list(YYTHD, $1, NULL,
TL_OPTION_UPDATING | TL_OPTION_ALIAS,
- YYPS->m_lock_type))
+ YYPS->m_lock_type,
+ YYPS->m_mdl_type))
MYSQL_YYABORT;
}
;
@@ -10558,6 +10590,8 @@ delete:
lex->sql_command= SQLCOM_DELETE;
mysql_init_select(lex);
YYPS->m_lock_type= TL_WRITE_DEFAULT;
+ YYPS->m_mdl_type= MDL_SHARED_WRITE;
+
lex->ignore= 0;
lex->select_lex.init_order();
}
@@ -10568,9 +10602,11 @@ single_multi:
FROM table_ident
{
if (!Select->add_table_to_list(YYTHD, $2, NULL, TL_OPTION_UPDATING,
- YYPS->m_lock_type))
+ YYPS->m_lock_type,
+ YYPS->m_mdl_type))
MYSQL_YYABORT;
YYPS->m_lock_type= TL_READ_DEFAULT;
+ YYPS->m_mdl_type= MDL_SHARED_READ;
}
where_clause opt_order_clause
delete_limit_clause {}
@@ -10578,6 +10614,7 @@ single_multi:
{
mysql_init_multi_delete(Lex);
YYPS->m_lock_type= TL_READ_DEFAULT;
+ YYPS->m_mdl_type= MDL_SHARED_READ;
}
FROM join_table_list where_clause
{
@@ -10588,6 +10625,7 @@ single_multi:
{
mysql_init_multi_delete(Lex);
YYPS->m_lock_type= TL_READ_DEFAULT;
+ YYPS->m_mdl_type= MDL_SHARED_READ;
}
USING join_table_list where_clause
{
@@ -10611,7 +10649,8 @@ table_wild_one:
ti,
NULL,
TL_OPTION_UPDATING | TL_OPTION_ALIAS,
- YYPS->m_lock_type))
+ YYPS->m_lock_type,
+ YYPS->m_mdl_type))
MYSQL_YYABORT;
}
| ident '.' ident opt_wild
@@ -10623,7 +10662,8 @@ table_wild_one:
ti,
NULL,
TL_OPTION_UPDATING | TL_OPTION_ALIAS,
- YYPS->m_lock_type))
+ YYPS->m_lock_type,
+ YYPS->m_mdl_type))
MYSQL_YYABORT;
}
;
@@ -11137,7 +11177,15 @@ flush:
flush_options:
table_or_tables
- { Lex->type|= REFRESH_TABLES; }
+ {
+ Lex->type|= REFRESH_TABLES;
+ /*
+ Set type of metadata and table locks for
+ FLUSH TABLES table_list WITH READ LOCK.
+ */
+ YYPS->m_lock_type= TL_READ_NO_INSERT;
+ YYPS->m_mdl_type= MDL_EXCLUSIVE;
+ }
opt_table_list {}
opt_with_read_lock {}
| flush_options_list
@@ -11301,7 +11349,7 @@ load:
{
LEX *lex=Lex;
if (!Select->add_table_to_list(YYTHD, $12, NULL, TL_OPTION_UPDATING,
- $4))
+ $4, MDL_SHARED_WRITE))
MYSQL_YYABORT;
lex->field_list.empty();
lex->update_list.empty();
@@ -13007,10 +13055,14 @@ table_lock:
table_ident opt_table_alias lock_option
{
thr_lock_type lock_type= (thr_lock_type) $3;
- if (!Select->add_table_to_list(YYTHD, $1, $2, 0, lock_type))
+ bool lock_for_write= (lock_type >= TL_WRITE_ALLOW_WRITE);
+ if (!Select->add_table_to_list(YYTHD, $1, $2, 0, lock_type,
+ (lock_for_write ?
+ MDL_SHARED_NO_READ_WRITE :
+ MDL_SHARED_READ)))
MYSQL_YYABORT;
/* If table is to be write locked, protect from a impending GRL. */
- if (lock_type >= TL_WRITE_ALLOW_WRITE)
+ if (lock_for_write)
Lex->protect_against_global_read_lock= TRUE;
}
;
@@ -13765,6 +13817,7 @@ query_expression_option:
if (check_simple_select())
MYSQL_YYABORT;
YYPS->m_lock_type= TL_READ_HIGH_PRIORITY;
+ YYPS->m_mdl_type= MDL_SHARED_READ;
Select->options|= SELECT_HIGH_PRIORITY;
}
| DISTINCT { Select->options|= SELECT_DISTINCT; }
@@ -13894,7 +13947,10 @@ view_tail:
LEX *lex= thd->lex;
lex->sql_command= SQLCOM_CREATE_VIEW;
/* first table in list is target VIEW name */
- if (!lex->select_lex.add_table_to_list(thd, $3, NULL, TL_OPTION_UPDATING))
+ if (!lex->select_lex.add_table_to_list(thd, $3, NULL,
+ TL_OPTION_UPDATING,
+ TL_IGNORE,
+ MDL_EXCLUSIVE))
MYSQL_YYABORT;
}
view_list_opt AS view_select
@@ -14034,7 +14090,8 @@ trigger_tail:
if (!lex->select_lex.add_table_to_list(YYTHD, $9,
(LEX_STRING*) 0,
TL_OPTION_UPDATING,
- TL_IGNORE))
+ TL_WRITE_ALLOW_READ,
+ MDL_SHARED_NO_WRITE))
MYSQL_YYABORT;
}
;
diff --git a/sql/table.cc b/sql/table.cc
index 65918dd58f9..1e7cb747bc6 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -4659,13 +4659,6 @@ void TABLE_LIST::reinit_before_use(THD *thd)
parent_embedding->nested_join->join_list.head() == embedded);
mdl_request.ticket= NULL;
- /*
- Since we manipulate with the metadata lock type in open_table(),
- we need to reset it to the parser default, to restore things back
- to first-execution state.
- */
- mdl_request.set_type((lock_type >= TL_WRITE_ALLOW_WRITE) ?
- MDL_SHARED_WRITE : MDL_SHARED_READ);
}
/*
diff --git a/sql/table.h b/sql/table.h
index fcff0cfb0d5..ea585208b83 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1581,20 +1581,21 @@ struct TABLE_LIST
OPEN_STUB
} open_strategy;
/**
- Indicates the locking strategy for the object being opened:
- whether the associated metadata lock is shared or exclusive.
+ Indicates the locking strategy for the object being opened.
*/
enum
{
- /* Take a shared metadata lock before the object is opened. */
- SHARED_MDL= 0,
/*
- Take a exclusive metadata lock before the object is opened.
- If opening is successful, downgrade to a shared lock.
+ Take metadata lock specified by 'mdl_request' member before
+ the object is opened. Do nothing after that.
*/
- EXCLUSIVE_DOWNGRADABLE_MDL,
- /* Take a exclusive metadata lock before the object is opened. */
- EXCLUSIVE_MDL
+ OTLS_NONE= 0,
+ /*
+ Take (exclusive) metadata lock specified by 'mdl_request' member
+ before object is opened. If opening is successful, downgrade to
+ a shared lock.
+ */
+ OTLS_DOWNGRADE_IF_EXISTS
} lock_strategy;
/* For transactional locking. */
int lock_timeout; /* NOWAIT or WAIT [X] */