2965 Konstantin Osipov 2009-12-01
Backport of:
------------------------------------------------------------
revno: 2630.9.2
committer: Dmitry Lenev <dlenev@stripped>
branch nick: mysql-6.0-3726-w3
timestamp: Tue 2008-06-10 18:01:56 +0400
message:
WL#3726 "DDL locking for all metadata objects".
After review fixes in progress.
@ sql/mdl.cc
Changed mdl_acquire_shared_lock() signature to accept MDL_CONTEXT
as one of arguments as described in specification.
@ sql/mdl.h
Changed mdl_acquire_shared_lock() signature to accept MDL_CONTEXT
as one of arguments as described in specification.
@ sql/sql_base.cc
Changed mdl_acquire_shared_lock() signature to accept MDL_CONTEXT
as one of arguments as described in specification.
Renamed handle_failed_open_table_attempt() to
recover_from_failed_open_table_attempt() as suggested by review.
Added comment clarifying why we need to check TABLE::db_stat
while looking at TABLE instances open by other threads.
@ sql/sql_show.cc
Changed mdl_acquire_shared_lock() signature to accept MDL_CONTEXT
as one of arguments as described in specification.
modified:
sql/mdl.cc
sql/mdl.h
sql/sql_base.cc
sql/sql_show.cc
2964 Konstantin Osipov 2009-12-01
Backport of:
------------------------------------------------------------
revno: 2630.9.1
committer: Dmitry Lenev <dlenev@stripped>
branch nick: mysql-6.0-3726-w3
timestamp: Sun 2008-06-08 22:13:58 +0400
message:
WL#3726 "DDL locking for all metadata objects"
After review fixes in progress.
Some adjustments to the patch that removes thd->locked_tables
@ sql/sp_head.cc
Fix conditions which were wrongly translated by previous patch.
@ sql/sql_base.cc
close_thread_tables():
Add comment clarifying control flow in case of LTM_LOCK_TABLES
mode and statements requiring prelocking.
Be consistent with other places where we clear
OPTION_TABLE_LOCK flag.
lock_tables():
Always set THD::lock to 0 after freeing memory to which it
points.
modified:
sql/sp_head.cc
sql/sql_base.cc
2963 Konstantin Osipov 2009-12-01
Backport of:
------------------------------------------------------------
revno: 2630.4.27
committer: Dmitry Lenev <dlenev@stripped>
branch nick: mysql-6.0-3726-w2
timestamp: Mon 2008-06-09 14:01:19 +0400
message:
WL#3726 "DDL locking for all metadata objects".
After review fixes in progress.
Changed open_table() to return bool. This allows more easily to
distinguish cases when this function succeeds but returns no TABLE
instance (in case of view or in case of special kind of open) from
cases when we have an error. Pointer to TABLE instance is now
always returned in TABLE_LIST::table member.
This change allows to get rid of false assumption in open_tables()
implementation and makes it more clear.
modified:
sql/mysql_priv.h
sql/sql_base.cc
sql/sql_insert.cc
sql/sql_table.cc
2962 Konstantin Osipov 2009-12-01
Backport of:
----------------------------------------------------------
revno: 2630.4.26
committer: Konstantin Osipov <konstantin@stripped>
branch nick: mysql-6.0-prelocked_mode-to-push
timestamp: Fri 2008-06-06 23:19:04 +0400
message:
WL#3726: work on review comments.
Remove thd->locked_tables. Always store MYSQL_LOCK instances in
thd->lock.
Rename thd->prelocked_mode to thd->locked_tables_mode.
Use thd->locked_tables_mode to determine if we
are under LOCK TABLES. Update the code to not assume that
if thd->lock is set, LOCK TABLES mode is off.
Review comments.
@ sql/ha_ndbcluster_binlog.cc
Don't unlock the lock under LOCK TABLES (safety).
@ sql/handler.cc
There is no thd->locked_tables any more.
Update comments.
@ sql/lock.cc
There is no thd->locked_tables any more.
@ sql/log.cc
Rename thd->prelocked_mode to thd->locked_tables_mode.
@ sql/set_var.cc
Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
@ sql/sp_head.cc
Rename thd->prelocked_mode to thd->locked_tables_mode.
@ sql/sql_base.cc
Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
Remove thd->locked_tables.
@ sql/sql_cache.cc
Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
@ sql/sql_class.cc
Avoid code duplication.
Do not release the table locks prematurely if we're under LOCK TABLES.
Use thd->locked_tables_mode instead of thd->locked_tables.
@ sql/sql_class.h
Remove thd->locked_tables.
Make prelocked mode a kind of LOCK TABLES mode.
Update comments.
@ sql/sql_cursor.cc
Update comments.
@ sql/sql_insert.cc
Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
Rename thd->prelocked_mode to thd->locked_tables_mode.
@ sql/sql_load.cc
Rename thd->prelocked_mode to thd->locked_tables_mode.
@ sql/sql_parse.cc
Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
Remove thd->locked_tables.
@ sql/sql_partition.cc
Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
@ sql/sql_rename.cc
Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
@ sql/sql_select.cc
Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
@ sql/sql_table.cc
Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
@ sql/sql_trigger.cc
Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
@ sql/sql_update.cc
Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
@ sql/sql_view.cc
Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
@ storage/myisam/ha_myisam.cc
Use thd->locked_tables_mode to determine if we are under LOCK TABLES.
modified:
sql/ha_ndbcluster_binlog.cc
sql/handler.cc
sql/lock.cc
sql/log.cc
sql/set_var.cc
sql/sp_head.cc
sql/sql_base.cc
sql/sql_cache.cc
sql/sql_class.cc
sql/sql_class.h
sql/sql_cursor.cc
sql/sql_insert.cc
sql/sql_load.cc
sql/sql_parse.cc
sql/sql_partition.cc
sql/sql_rename.cc
sql/sql_select.cc
sql/sql_table.cc
sql/sql_trigger.cc
sql/sql_update.cc
sql/sql_view.cc
storage/myisam/ha_myisam.cc
=== modified file 'sql/mdl.cc'
--- a/sql/mdl.cc 2009-12-01 13:59:11 +0000
+++ b/sql/mdl.cc 2009-12-01 15:20:43 +0000
@@ -611,6 +611,7 @@ static bool can_grant_lock(MDL_LOCK *loc
This function must be called after the lock is added to a context.
+ @param context [in] Context containing request for lock
@param lock_data [in] Lock request object for lock to be acquired
@param retry [out] Indicates that conflicting lock exists and another
attempt should be made after releasing all current
@@ -622,16 +623,19 @@ static bool can_grant_lock(MDL_LOCK *loc
In the latter case "retry" parameter is set to TRUE.
*/
-bool mdl_acquire_shared_lock(MDL_LOCK_DATA *lock_data, bool *retry)
+bool mdl_acquire_shared_lock(MDL_CONTEXT *context, MDL_LOCK_DATA *lock_data,
+ bool *retry)
{
MDL_LOCK *lock;
*retry= FALSE;
DBUG_ASSERT(is_shared(lock_data) && lock_data->state == MDL_PENDING);
+ DBUG_ASSERT(lock_data->ctx == context);
+
safe_mutex_assert_not_owner(&LOCK_open);
- if (lock_data->ctx->has_global_shared_lock &&
+ if (context->has_global_shared_lock &&
lock_data->type == MDL_SHARED_UPGRADABLE)
{
my_error(ER_CANT_UPDATE_WITH_READLOCK, MYF(0));
=== modified file 'sql/mdl.h'
--- a/sql/mdl.h 2009-12-01 13:59:11 +0000
+++ b/sql/mdl.h 2009-12-01 15:20:43 +0000
@@ -164,7 +164,8 @@ inline void mdl_set_lock_type(MDL_LOCK_D
lock_data->type= lock_type;
}
-bool mdl_acquire_shared_lock(MDL_LOCK_DATA *lock_data, bool *retry);
+bool mdl_acquire_shared_lock(MDL_CONTEXT *context, MDL_LOCK_DATA *lock_data,
+ bool *retry);
bool mdl_acquire_exclusive_locks(MDL_CONTEXT *context);
bool mdl_upgrade_shared_lock_to_exclusive(MDL_CONTEXT *context,
MDL_LOCK_DATA *lock_data);
=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h 2009-12-01 13:38:00 +0000
+++ b/sql/mysql_priv.h 2009-12-01 14:58:31 +0000
@@ -1220,8 +1220,8 @@ TABLE *open_ltable(THD *thd, TABLE_LIST
uint lock_flags);
enum enum_open_table_action {OT_NO_ACTION= 0, OT_BACK_OFF_AND_RETRY,
OT_DISCOVER, OT_REPAIR};
-TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem,
- enum_open_table_action *action, uint flags);
+bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem,
+ enum_open_table_action *action, uint flags);
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);
=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc 2009-12-01 14:39:03 +0000
+++ b/sql/sp_head.cc 2009-12-01 15:04:32 +0000
@@ -1257,7 +1257,7 @@ sp_head::execute(THD *thd)
Will write this SP statement into binlog separately
(TODO: consider changing the condition to "not inside event union")
*/
- if (thd->locked_tables_mode == LTM_NONE)
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
thd->user_var_events_alloc= thd->mem_root;
err_status= i->execute(thd, &ip);
@@ -1269,7 +1269,7 @@ sp_head::execute(THD *thd)
If we've set thd->user_var_events_alloc to mem_root of this SP
statement, clean all the events allocated in it.
*/
- if (thd->locked_tables_mode == LTM_NONE)
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
{
reset_dynamic(&thd->user_var_events);
thd->user_var_events_alloc= NULL;//DEBUG
@@ -2740,7 +2740,7 @@ sp_lex_keeper::reset_lex_and_exec_core(T
thd->query_id= next_query_id();
pthread_mutex_unlock(&LOCK_thread_count);
- if (thd->locked_tables_mode == LTM_NONE)
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES)
{
/*
This statement will enter/leave prelocked mode on its own.
=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc 2009-12-01 14:39:03 +0000
+++ b/sql/sql_base.cc 2009-12-01 15:20:43 +0000
@@ -1375,6 +1375,7 @@ void close_thread_tables(THD *thd,
bool skip_mdl)
{
TABLE *table;
+ bool clear_table_lock_option= FALSE;
DBUG_ENTER("close_thread_tables");
#ifdef EXTRA_DEBUG
@@ -1446,6 +1447,11 @@ void close_thread_tables(THD *thd,
/*
We are under simple LOCK TABLES or we're inside a sub-statement
of a prelocked statement, so should not do anything else.
+
+ Note that even if we are in LTM_LOCK_TABLES mode and statement
+ requires prelocking (e.g. when we are closing tables after
+ failing ot "open" all tables required for statement execution)
+ we will exit this function a few lines below.
*/
if (! thd->lex->requires_prelocking())
DBUG_VOID_RETURN;
@@ -1462,7 +1468,7 @@ void close_thread_tables(THD *thd,
DBUG_VOID_RETURN;
thd->locked_tables_mode= LTM_NONE;
- thd->options&= ~OPTION_TABLE_LOCK;
+ clear_table_lock_option= TRUE;
/*
Note that we are leaving prelocked mode so we don't need
@@ -1502,6 +1508,9 @@ void close_thread_tables(THD *thd,
mdl_remove_all_locks(&thd->mdl_context);
}
+ if (clear_table_lock_option)
+ thd->options&= ~OPTION_TABLE_LOCK;
+
DBUG_VOID_RETURN;
}
@@ -2574,8 +2583,6 @@ void table_share_release_hook(void *shar
which will be set according to action which is
required to remedy problem appeared during attempt
to open table.
- If this is a NULL pointer, then the table is not
- put in the thread-open-list.
flags Bitmap of flags to modify how open works:
MYSQL_LOCK_IGNORE_FLUSH - Open table even if
someone has done a flush or there is a pending
@@ -2597,14 +2604,16 @@ void table_share_release_hook(void *shar
"open_type" is TAKE_EXCLUSIVE_MDL.
RETURN
- NULL Open failed. If refresh is set then one should close
- all other tables and retry the open.
- # Success. Pointer to TABLE object for open table.
+ TRUE Open failed. "action" parameter may contain type of action
+ needed to remedy problem before retrying again.
+ FALSE Success. Members of TABLE_LIST structure are filled properly (e.g.
+ TABLE_LIST::table is set for real tables and TABLE_LIST::view is
+ set for views).
*/
-TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
- enum_open_table_action *action, uint flags)
+bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
+ enum_open_table_action *action, uint flags)
{
reg1 TABLE *table;
char key[MAX_DBKEY_LENGTH];
@@ -2622,10 +2631,10 @@ TABLE *open_table(THD *thd, TABLE_LIST *
/* an open table operation needs a lot of the stack space */
if (check_stack_overrun(thd, STACK_MIN_SIZE_FOR_OPEN, (uchar *)&alias))
- DBUG_RETURN(0);
+ DBUG_RETURN(TRUE);
if (thd->killed)
- DBUG_RETURN(0);
+ DBUG_RETURN(TRUE);
key_length= (create_table_def_key(thd, key, table_list, 1) -
TMP_TABLE_KEY_EXTRA);
@@ -2659,7 +2668,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
(ulong) table->query_id, (uint) thd->server_id,
(ulong) thd->variables.pseudo_thread_id));
my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
- DBUG_RETURN(0);
+ DBUG_RETURN(TRUE);
}
table->query_id= thd->query_id;
thd->thread_specific_used= TRUE;
@@ -2672,7 +2681,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
if (flags & MYSQL_OPEN_TEMPORARY_ONLY)
{
my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->table_name);
- DBUG_RETURN(0);
+ DBUG_RETURN(TRUE);
}
/*
@@ -2770,7 +2779,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
mem_root, 0))
{
DBUG_ASSERT(table_list->view != 0);
- DBUG_RETURN(0); // VIEW
+ DBUG_RETURN(FALSE); // VIEW
}
}
}
@@ -2785,7 +2794,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
else
my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
- DBUG_RETURN(0);
+ DBUG_RETURN(TRUE);
}
/*
@@ -2809,7 +2818,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
*/
mdl_set_lock_type(mdl_lock_data, MDL_EXCLUSIVE);
if (mdl_acquire_exclusive_locks(&thd->mdl_context))
- DBUG_RETURN(0);
+ DBUG_RETURN(TRUE);
}
else
{
@@ -2828,11 +2837,11 @@ TABLE *open_table(THD *thd, TABLE_LIST *
if (flags & MYSQL_LOCK_IGNORE_FLUSH)
mdl_set_lock_type(mdl_lock_data, MDL_SHARED_HIGH_PRIO);
- if (mdl_acquire_shared_lock(mdl_lock_data, &retry))
+ if (mdl_acquire_shared_lock(&thd->mdl_context, mdl_lock_data, &retry))
{
if (retry)
*action= OT_BACK_OFF_AND_RETRY;
- DBUG_RETURN(0);
+ DBUG_RETURN(TRUE);
}
}
@@ -2854,7 +2863,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
/* Someone did a refresh while thread was opening tables */
*action= OT_BACK_OFF_AND_RETRY;
pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(0);
+ DBUG_RETURN(TRUE);
}
if (table_list->open_type == TABLE_LIST::OPEN_OR_CREATE)
@@ -2867,14 +2876,14 @@ TABLE *open_table(THD *thd, TABLE_LIST *
if (!exists)
{
pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
/* Table exists. Let us try to open it. */
}
else if (table_list->open_type == TABLE_LIST::TAKE_EXCLUSIVE_MDL)
{
pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
if (!(share= (TABLE_SHARE *)mdl_get_cached_object(mdl_lock_data)))
@@ -2921,28 +2930,14 @@ TABLE *open_table(THD *thd, TABLE_LIST *
}
pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(0);
- }
- else if (table_list->view)
- {
- /*
- We're trying to open a table for what was a view.
- This can only happen during (re-)execution.
- At prepared statement prepare the view has been opened and
- merged into the statement parse tree. After that, someone
- performed a DDL and replaced the view with a base table.
- Don't try to open the table inside a prepared statement,
- invalidate it instead.
-
- Note, the assert below is known to fail inside stored
- procedures (Bug#27011).
- */
- DBUG_ASSERT(thd->m_reprepare_observer);
- check_and_update_table_version(thd, table_list, share);
- /* Always an error. */
- DBUG_ASSERT(thd->is_error());
- goto err_unlock;
+ DBUG_RETURN(FALSE);
}
+ /*
+ Note that situation when we are trying to open a table for what
+ was a view during previous execution of PS will be handled in by
+ the caller. Here we should simply open our table even if
+ TABLE_LIST::view is true.
+ */
if (table_list->i_s_requested_object & OPEN_VIEW_ONLY)
goto err_unlock;
@@ -2992,7 +2987,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
*action= OT_BACK_OFF_AND_RETRY;
release_table_share(share);
pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(0);
+ DBUG_RETURN(TRUE);
}
/* Force close at once after usage */
thd->version= share->version;
@@ -3103,15 +3098,16 @@ TABLE *open_table(THD *thd, TABLE_LIST *
table->pos_in_table_list= table_list;
table_list->updatable= 1; // It is not derived table nor non-updatable VIEW
table->clear_column_bitmaps();
+ table_list->table= table;
DBUG_ASSERT(table->key_read == 0);
- DBUG_RETURN(table);
+ DBUG_RETURN(FALSE);
err_unlock:
release_table_share(share);
err_unlock2:
pthread_mutex_unlock(&LOCK_open);
mdl_release_lock(&thd->mdl_context, mdl_lock_data);
- DBUG_RETURN(0);
+ DBUG_RETURN(TRUE);
}
@@ -4048,18 +4044,21 @@ end_with_lock_open:
/**
- Handle failed attempt ot open table by performing requested action.
+ Recover from failed attempt ot open table by performing requested action.
@param thd Thread context
@param table Table list element for table that caused problem
@param action Type of action requested by failed open_table() call
+ @pre This function should be called only with "action" != OT_NO_ACTION.
+
@retval FALSE - Success. One should try to open tables once again.
@retval TRUE - Error
*/
-static bool handle_failed_open_table_attempt(THD *thd, TABLE_LIST *table,
- enum_open_table_action action)
+static bool
+recover_from_failed_open_table_attempt(THD *thd, TABLE_LIST *table,
+ enum_open_table_action action)
{
bool result= FALSE;
@@ -4502,6 +4501,7 @@ int open_tables(THD *thd, TABLE_LIST **s
TABLE_LIST *tables= NULL;
enum_open_table_action action;
int result=0;
+ bool error;
MEM_ROOT new_frm_mem;
/* Also used for indicating that prelocking is need */
TABLE_LIST **query_tables_last_own;
@@ -4620,64 +4620,30 @@ int open_tables(THD *thd, TABLE_LIST **s
tables->db, tables->table_name, (long) tables));
(*counter)++;
- /*
- Not a placeholder: must be a base table or a view, and the table is
- not opened yet. Try to open the table.
- */
- if (!tables->table)
+ /* Not a placeholder: must be a base table or a view. Let us open it. */
+ DBUG_ASSERT(!tables->table);
+
+ if (tables->prelocking_placeholder)
{
- if (tables->prelocking_placeholder)
- {
- /*
- For the tables added by the pre-locking code, attempt to open
- the table but fail silently if the table does not exist.
- The real failure will occur when/if a statement attempts to use
- that table.
- */
- Prelock_error_handler prelock_handler;
- thd->push_internal_handler(& prelock_handler);
- tables->table= open_table(thd, tables, &new_frm_mem, &action, flags);
- thd->pop_internal_handler();
- safe_to_ignore_table= prelock_handler.safely_trapped_errors();
- }
- else
- tables->table= open_table(thd, tables, &new_frm_mem, &action, flags);
+ /*
+ For the tables added by the pre-locking code, attempt to open
+ the table but fail silently if the table does not exist.
+ The real failure will occur when/if a statement attempts to use
+ that table.
+ */
+ Prelock_error_handler prelock_handler;
+ thd->push_internal_handler(& prelock_handler);
+ error= open_table(thd, tables, &new_frm_mem, &action, flags);
+ thd->pop_internal_handler();
+ safe_to_ignore_table= prelock_handler.safely_trapped_errors();
}
else
- DBUG_PRINT("tcache", ("referenced table: '%s'.'%s' 0x%lx",
- tables->db, tables->table_name,
- (long) tables->table));
+ error= open_table(thd, tables, &new_frm_mem, &action, flags);
- if (!tables->table)
- {
- free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
-
- if (tables->view)
- {
- /* VIEW placeholder */
- (*counter)--;
-
- /*
- tables->next_global list consists of two parts:
- 1) Query tables and underlying tables of views.
- 2) Tables used by all stored routines that this statement invokes on
- execution.
- We need to know where the bound between these two parts is. If we've
- just opened a view, which was the last table in part #1, and it
- has added its base tables after itself, adjust the boundary pointer
- accordingly.
- */
- if (query_tables_last_own == &(tables->next_global) &&
- tables->view->query_tables)
- query_tables_last_own= tables->view->query_tables_last;
- /*
- Let us free memory used by 'sroutines' hash here since we never
- call destructor for this LEX.
- */
- my_hash_free(&tables->view->sroutines);
- goto process_view_routines;
- }
+ free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
+ if (error)
+ {
/*
If in a MERGE table open, we need to remove the children list
from statement table list before restarting. Otherwise the list
@@ -4691,15 +4657,6 @@ int open_tables(THD *thd, TABLE_LIST **s
parent_l->next_global= *parent_l->table->child_last_l;
}
- /*
- FIXME This is a temporary hack. Actually we need check that will
- allow us to differentiate between error while opening/creating
- table and successful table creation.
- ...
- */
- if (tables->open_type)
- continue;
-
if (action)
{
/*
@@ -4724,7 +4681,7 @@ int open_tables(THD *thd, TABLE_LIST **s
TABLE_LIST element. Altough currently this assumption is valid
it may change in future.
*/
- if (handle_failed_open_table_attempt(thd, tables, action))
+ if (recover_from_failed_open_table_attempt(thd, tables, action))
{
result= -1;
goto err;
@@ -4742,36 +4699,73 @@ int open_tables(THD *thd, TABLE_LIST **s
result= -1; // Fatal error
break;
}
- else
+
+ /*
+ We can't rely on simple check for TABLE_LIST::view to determine
+ that this is a view since during re-execution we might reopen
+ ordinary table in place of view and thus have TABLE_LIST::view
+ set from repvious execution and TABLE_LIST::table set from
+ current.
+ */
+ if (!tables->table && tables->view)
{
+ /* VIEW placeholder */
+ (*counter)--;
+
/*
- If we are not already in prelocked mode and extended table list is not
- yet built and we have trigger for table being opened then we should
- cache all routines used by its triggers and add their tables to
- prelocking list.
- If we lock table for reading we won't update it so there is no need to
- process its triggers since they never will be activated.
+ tables->next_global list consists of two parts:
+ 1) Query tables and underlying tables of views.
+ 2) Tables used by all stored routines that this statement invokes on
+ execution.
+ We need to know where the bound between these two parts is. If we've
+ just opened a view, which was the last table in part #1, and it
+ has added its base tables after itself, adjust the boundary pointer
+ accordingly.
*/
- if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
- !thd->lex->requires_prelocking() &&
- tables->trg_event_map && tables->table->triggers &&
- tables->lock_type >= TL_WRITE_ALLOW_WRITE)
- {
- if (!query_tables_last_own)
- query_tables_last_own= thd->lex->query_tables_last;
- if (sp_cache_routines_and_add_tables_for_triggers(thd, thd->lex,
- tables))
- {
- /*
- Serious error during reading stored routines from mysql.proc table.
- Something's wrong with the table or its contents, and an error has
- been emitted; we must abort.
- */
- result= -1;
- goto err;
- }
+ if (query_tables_last_own == &(tables->next_global) &&
+ tables->view->query_tables)
+ query_tables_last_own= tables->view->query_tables_last;
+ /*
+ Let us free memory used by 'sroutines' hash here since we never
+ call destructor for this LEX.
+ */
+ my_hash_free(&tables->view->sroutines);
+ goto process_view_routines;
+ }
+
+ /*
+ Special types of open can succeed but still don't set
+ TABLE_LIST::table to anything.
+ */
+ if (tables->open_type && !tables->table)
+ continue;
+
+ /*
+ If we are not already in prelocked mode and extended table list is not
+ yet built and we have trigger for table being opened then we should
+ cache all routines used by its triggers and add their tables to
+ prelocking list.
+ If we lock table for reading we won't update it so there is no need to
+ process its triggers since they never will be activated.
+ */
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
+ !thd->lex->requires_prelocking() &&
+ tables->trg_event_map && tables->table->triggers &&
+ tables->lock_type >= TL_WRITE_ALLOW_WRITE)
+ {
+ if (!query_tables_last_own)
+ query_tables_last_own= thd->lex->query_tables_last;
+ if (sp_cache_routines_and_add_tables_for_triggers(thd, thd->lex,
+ tables))
+ {
+ /*
+ Serious error during reading stored routines from mysql.proc table.
+ Something's wrong with the table or its contents, and an error has
+ been emitted; we must abort.
+ */
+ result= -1;
+ goto err;
}
- free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC));
}
if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables_mode)
@@ -4985,6 +4979,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST
TABLE *table;
enum_open_table_action action;
bool refresh;
+ bool error;
DBUG_ENTER("open_ltable");
/* should not be used in a prelocked_mode context, see NOTE above */
@@ -4996,7 +4991,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST
table_list->required_type= FRMTYPE_TABLE;
retry:
- while (!(table= open_table(thd, table_list, thd->mem_root, &action, 0)) &&
+ while ((error= open_table(thd, table_list, thd->mem_root, &action, 0)) &&
action)
{
/*
@@ -5005,12 +5000,18 @@ retry:
might have been acquired successfully.
*/
close_thread_tables(thd, (action == OT_BACK_OFF_AND_RETRY));
- if (handle_failed_open_table_attempt(thd, table_list, action))
+ if (recover_from_failed_open_table_attempt(thd, table_list, action))
break;
}
- if (table)
+ if (!error)
{
+ /*
+ We can't have a view or some special "open_type" in this function
+ so there should be a TABLE instance.
+ */
+ DBUG_ASSERT(table_list->table);
+ table= table_list->table;
if (table->child_l)
{
/* A MERGE table must not come here. */
@@ -5023,7 +5024,6 @@ retry:
}
table_list->lock_type= lock_type;
- table_list->table= table;
table->grant= table_list->grant;
if (thd->locked_tables_mode)
{
@@ -5047,6 +5047,8 @@ retry:
}
}
}
+ else
+ table= 0;
end:
thd_proc_info(thd, 0);
@@ -5462,6 +5464,7 @@ int lock_tables(THD *thd, TABLE_LIST *ta
need to care about THD::locked_tables_root here.
*/
mysql_unlock_tables(thd, thd->lock);
+ thd->lock= 0;
thd->options&= ~(OPTION_TABLE_LOCK);
DBUG_RETURN(-1);
}
@@ -8530,7 +8533,13 @@ bool notify_thread_having_shared_lock(TH
thd_table ;
thd_table= thd_table->next)
{
- /* TODO With new MDL check for db_stat is probably a legacy */
+ /*
+ Check for TABLE::db_stat is needed since in some places we call
+ handler::close() for table instance (and set TABLE::db_stat to 0)
+ and do not remove such instances from the THD::open_tables
+ for some time, during which other thread can see those instances
+ (e.g. see partitioning code).
+ */
if (thd_table->db_stat)
signalled|= mysql_lock_abort_for_thread(thd, thd_table);
}
=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc 2009-12-01 14:39:03 +0000
+++ b/sql/sql_insert.cc 2009-12-01 14:58:31 +0000
@@ -3555,8 +3555,8 @@ static TABLE *create_table_from_items(TH
}
else
{
- if (!(table= open_table(thd, create_table, thd->mem_root, ¬_used2,
- MYSQL_OPEN_TEMPORARY_ONLY)) &&
+ if (open_table(thd, create_table, thd->mem_root, ¬_used2,
+ MYSQL_OPEN_TEMPORARY_ONLY) &&
!create_info->table_existed)
{
/*
@@ -3566,6 +3566,8 @@ static TABLE *create_table_from_items(TH
*/
drop_temporary_table(thd, create_table);
}
+ else
+ table= create_table->table;
}
}
reenable_binlog(thd);
=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc 2009-12-01 13:59:11 +0000
+++ b/sql/sql_show.cc 2009-12-01 15:20:43 +0000
@@ -3145,7 +3145,7 @@ static int fill_schema_table_from_frm(TH
*/
while (1)
{
- if (mdl_acquire_shared_lock(&mdl_lock_data, &retry))
+ if (mdl_acquire_shared_lock(&thd->mdl_context, &mdl_lock_data, &retry))
{
if (!retry || mdl_wait_for_locks(&thd->mdl_context))
{
=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc 2009-12-01 14:39:03 +0000
+++ b/sql/sql_table.cc 2009-12-01 14:58:31 +0000
@@ -7182,8 +7182,9 @@ view_err:
tbl.db= new_db;
tbl.table_name= tbl.alias= tmp_name;
/* Table is in thd->temporary_tables */
- new_table= open_table(thd, &tbl, thd->mem_root, ¬_used,
- MYSQL_LOCK_IGNORE_FLUSH);
+ (void) open_table(thd, &tbl, thd->mem_root, ¬_used,
+ MYSQL_LOCK_IGNORE_FLUSH);
+ new_table= tbl.table;
}
else
{
Attachment: [text/bzr-bundle] bzr/kostja@sun.com-20091201152043-zykxllat23hxrkcm.bundle
| Thread |
|---|
| • bzr push into mysql-5.6-next-mr branch (kostja:2962 to 2965) WL#3726 | Konstantin Osipov | 1 Dec |