summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2013-01-08 15:04:14 -0800
committerIgor Babaev <igor@askmonty.org>2013-01-08 15:04:14 -0800
commit7d9df8075e4c9392f4352e6ccd86921994f264bc (patch)
tree916e10b0a8725f6226c3f9c630516d5c918c8bac /sql
parent01dca17a9c2255845c050c44e152ece256c9112e (diff)
parentac45f3b38a2098a0a29fd53f023866d6c0dce78d (diff)
downloadmariadb-git-7d9df8075e4c9392f4352e6ccd86921994f264bc.tar.gz
Merge 5.5 -> mwl248
Diffstat (limited to 'sql')
-rw-r--r--sql/mysqld.cc35
-rw-r--r--sql/scheduler.cc1
-rw-r--r--sql/sql_base.cc102
-rw-r--r--sql/sql_base.h3
-rw-r--r--sql/sql_class.cc1
-rw-r--r--sql/sql_db.cc2
-rw-r--r--sql/sql_parse.cc9
-rw-r--r--sql/sql_select.cc4
-rw-r--r--sql/sql_show.cc6
-rw-r--r--sql/sql_table.cc21
-rw-r--r--sql/threadpool_common.cc1
11 files changed, 139 insertions, 46 deletions
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index d96e23710ed..64d52014fec 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -2443,21 +2443,6 @@ void dec_connection_count(THD *thd)
/*
- Delete the THD object and decrease number of threads
-
- SYNOPSIS
- delete_thd()
- thd Thread handler
-*/
-
-void delete_thd(THD *thd)
-{
- thread_count--;
- delete thd;
-}
-
-
-/*
Unlink thd from global list of available connections and free thd
SYNOPSIS
@@ -2475,14 +2460,23 @@ void unlink_thd(THD *thd)
thd_cleanup(thd);
dec_connection_count(thd);
+
+ mysql_mutex_lock(&LOCK_status);
+ add_to_status(&global_status_var, &thd->status_var);
+ mysql_mutex_unlock(&LOCK_status);
+
mysql_mutex_lock(&LOCK_thread_count);
+ thread_count--;
+ thd->unlink();
/*
Used by binlog_reset_master. It would be cleaner to use
DEBUG_SYNC here, but that's not possible because the THD's debug
sync feature has been shut down at this point.
*/
DBUG_EXECUTE_IF("sleep_after_lock_thread_count_before_delete_thd", sleep(5););
- delete_thd(thd);
+ mysql_mutex_unlock(&LOCK_thread_count);
+
+ delete thd;
DBUG_VOID_RETURN;
}
@@ -2591,10 +2585,13 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache)
/* Mark that current_thd is not valid anymore */
my_pthread_setspecific_ptr(THR_THD, 0);
if (put_in_cache)
+ {
+ mysql_mutex_lock(&LOCK_thread_count);
put_in_cache= cache_thread();
- mysql_mutex_unlock(&LOCK_thread_count);
- if (put_in_cache)
- DBUG_RETURN(0); // Thread is reused
+ mysql_mutex_unlock(&LOCK_thread_count);
+ if (put_in_cache)
+ DBUG_RETURN(0); // Thread is reused
+ }
/* It's safe to broadcast outside a lock (COND... is not deleted here) */
DBUG_PRINT("signal", ("Broadcasting COND_thread_count"));
diff --git a/sql/scheduler.cc b/sql/scheduler.cc
index 0ae4121ef4c..54653557b16 100644
--- a/sql/scheduler.cc
+++ b/sql/scheduler.cc
@@ -35,7 +35,6 @@
static bool no_threads_end(THD *thd, bool put_in_cache)
{
unlink_thd(thd);
- mysql_mutex_unlock(&LOCK_thread_count);
return 1; // Abort handle_one_connection
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 0dd1da68a76..b7f321e6290 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2401,10 +2401,11 @@ void drop_open_table(THD *thd, TABLE *table, const char *db_name,
Check that table exists in table definition cache, on disk
or in some storage engine.
- @param thd Thread context
- @param table Table list element
- @param[out] exists Out parameter which is set to TRUE if table
- exists and to FALSE otherwise.
+ @param thd Thread context
+ @param table Table list element
+ @param fast_check Check only if share or .frm file exists
+ @param[out] exists Out parameter which is set to TRUE if table
+ exists and to FALSE otherwise.
@note This function acquires LOCK_open internally.
@@ -2416,7 +2417,8 @@ void drop_open_table(THD *thd, TABLE *table, const char *db_name,
@retval FALSE No error. 'exists' out parameter set accordingly.
*/
-bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists)
+bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool fast_check,
+ bool *exists)
{
char path[FN_REFLEN + 1];
TABLE_SHARE *share;
@@ -2424,7 +2426,8 @@ bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists)
*exists= TRUE;
- DBUG_ASSERT(thd->mdl_context.
+ DBUG_ASSERT(fast_check ||
+ thd->mdl_context.
is_lock_owner(MDL_key::TABLE, table->db,
table->table_name, MDL_SHARED));
@@ -2441,6 +2444,12 @@ bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists)
if (!access(path, F_OK))
goto end;
+ if (fast_check)
+ {
+ *exists= FALSE;
+ goto end;
+ }
+
/* .FRM file doesn't exist. Check if some engine can provide it. */
if (ha_check_if_table_exists(thd, table->db, table->table_name, exists))
{
@@ -2990,7 +2999,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
{
bool exists;
- if (check_if_table_exists(thd, table_list, &exists))
+ if (check_if_table_exists(thd, table_list, 0, &exists))
DBUG_RETURN(TRUE);
if (!exists)
@@ -4698,7 +4707,18 @@ extern "C" uchar *schema_set_get_key(const uchar *record, size_t *length,
open, see open_table() description for details.
@retval FALSE Success.
- @retval TRUE Failure (e.g. connection was killed)
+ @retval TRUE Failure (e.g. connection was killed) or table existed
+ for a CREATE TABLE.
+
+ @notes
+ In case of CREATE TABLE we avoid a wait for tables that are in use
+ by first trying to do a meta data lock with timeout == 0. If we get a
+ timeout we will check if table exists (it should) and retry with
+ normal timeout if it didn't exists.
+ Note that for CREATE TABLE IF EXISTS we only generate a warning
+ but still return TRUE (to abort the calling open_table() function).
+ On must check THD->is_error() if one wants to distinguish between warning
+ and error.
*/
bool
@@ -4710,6 +4730,10 @@ lock_table_names(THD *thd,
TABLE_LIST *table;
MDL_request global_request;
Hash_set<TABLE_LIST, schema_set_get_key> schema_set;
+ ulong org_lock_wait_timeout= lock_wait_timeout;
+ /* Check if we are using CREATE TABLE ... IF NOT EXISTS */
+ bool create_table;
+ Dummy_error_handler error_handler;
DBUG_ENTER("lock_table_names");
DBUG_ASSERT(!thd->locked_tables_mode);
@@ -4731,8 +4755,14 @@ lock_table_names(THD *thd,
}
}
- if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) &&
- ! mdl_requests.is_empty())
+ if (mdl_requests.is_empty())
+ DBUG_RETURN(FALSE);
+
+ /* Check if CREATE TABLE IF NOT EXISTS was used */
+ create_table= (tables_start && tables_start->open_strategy ==
+ TABLE_LIST::OPEN_IF_EXISTS);
+
+ if (!(flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK))
{
/*
Scoped locks: Take intention exclusive locks on all involved
@@ -4760,12 +4790,58 @@ lock_table_names(THD *thd,
global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE,
MDL_STATEMENT);
mdl_requests.push_front(&global_request);
+
+ if (create_table)
+ lock_wait_timeout= 0; // Don't wait for timeout
}
- if (thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout))
- DBUG_RETURN(TRUE);
+ for (;;)
+ {
+ bool exists= TRUE;
+ bool res;
- DBUG_RETURN(FALSE);
+ if (create_table)
+ thd->push_internal_handler(&error_handler); // Avoid warnings & errors
+ res= thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout);
+ if (create_table)
+ thd->pop_internal_handler();
+ if (!res)
+ DBUG_RETURN(FALSE); // Got locks
+
+ if (!create_table)
+ DBUG_RETURN(TRUE); // Return original error
+
+ /*
+ We come here in the case of lock timeout when executing
+ CREATE TABLE IF NOT EXISTS.
+ Verify that table really exists (it should as we got a lock conflict)
+ */
+ if (check_if_table_exists(thd, tables_start, 1, &exists))
+ DBUG_RETURN(TRUE); // Should never happen
+ if (exists)
+ {
+ if (thd->lex->create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
+ tables_start->table_name);
+ }
+ else
+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), tables_start->table_name);
+ DBUG_RETURN(TRUE);
+ }
+ /* purecov: begin inspected */
+ /*
+ We got error from acquire_locks but table didn't exists.
+ In theory this should never happen, except maybe in
+ CREATE or DROP DATABASE scenario.
+ We play safe and restart the original acquire_locks with the
+ original timeout
+ */
+ create_table= 0;
+ lock_wait_timeout= org_lock_wait_timeout;
+ /* purecov: end */
+ }
}
diff --git a/sql/sql_base.h b/sql/sql_base.h
index aa2ba9e5680..33cea7ebee0 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -302,7 +302,8 @@ TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db,
const char *table_name,
bool no_error);
void mark_tmp_table_for_reuse(TABLE *table);
-bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists);
+bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool fast_check,
+ bool *exists);
int update_virtual_fields(THD *thd, TABLE *table,
enum enum_vcol_update_mode vcol_update_mode= VCOL_UPDATE_FOR_READ);
int dynamic_column_error_message(enum_dyncol_func_result rc);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 81f021d9306..42952585e07 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1444,7 +1444,6 @@ THD::~THD()
mysql_mutex_lock(&LOCK_thd_data);
mysys_var=0; // Safety (shouldn't be needed)
mysql_mutex_unlock(&LOCK_thd_data);
- add_to_status(&global_status_var, &status_var);
/* Close connection */
#ifndef EMBEDDED_LIBRARY
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index f4e9ccfc5e6..dc8a2e9f057 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -939,7 +939,7 @@ update_binlog:
char quoted_name[FN_REFLEN+3];
// Only write drop table to the binlog for tables that no longer exist.
- if (check_if_table_exists(thd, tbl, &exists))
+ if (check_if_table_exists(thd, tbl, 0, &exists))
{
error= true;
goto exit;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 5dac052b749..de35d2f3d27 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2512,7 +2512,14 @@ case SQLCOM_PREPARE:
goto end_with_restore_list;
}
- if (!(res= open_and_lock_tables(thd, lex->query_tables, TRUE, 0)))
+ res= open_and_lock_tables(thd, lex->query_tables, TRUE, 0);
+ if (res)
+ {
+ /* Got error or warning. Set res to 1 if error */
+ if (!(res= thd->is_error()))
+ my_ok(thd); // CREATE ... IF NOT EXISTS
+ }
+ else
{
/* The table already exists */
if (create_table->table)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 3550155606e..898fd47dd24 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -7335,10 +7335,10 @@ JOIN_TAB *next_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind,
}
-JOIN_TAB *first_top_level_tab(JOIN *join, enum enum_with_const_tables with_const)
+JOIN_TAB *first_top_level_tab(JOIN *join, enum enum_with_const_tables const_tbls)
{
JOIN_TAB *tab= join->join_tab;
- if (with_const == WITH_CONST_TABLES)
+ if (const_tbls == WITHOUT_CONST_TABLES)
{
if (join->const_tables == join->table_count)
return NULL;
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 861509b30de..b5bd8efa9da 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -3185,13 +3185,13 @@ bool get_lookup_value(THD *thd, Item_func *item_func,
Item_field *item_field;
CHARSET_INFO *cs= system_charset_info;
- if (item_func->arguments()[0]->type() == Item::FIELD_ITEM &&
+ if (item_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM &&
item_func->arguments()[1]->const_item())
{
idx_field= 0;
idx_val= 1;
}
- else if (item_func->arguments()[1]->type() == Item::FIELD_ITEM &&
+ else if (item_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
item_func->arguments()[0]->const_item())
{
idx_field= 1;
@@ -3200,7 +3200,7 @@ bool get_lookup_value(THD *thd, Item_func *item_func,
else
return 0;
- item_field= (Item_field*) item_func->arguments()[idx_field];
+ item_field= (Item_field*) item_func->arguments()[idx_field]->real_item();
if (table->table != item_field->field->table)
return 0;
tmp_str= item_func->arguments()[idx_val]->val_str(&str_buff);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 5bd2b105a92..50d4c72c191 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4137,7 +4137,8 @@ bool mysql_create_table_no_lock(THD *thd,
set_table_default_charset(thd, create_info, (char*) db);
db_options= create_info->table_options;
- if (create_info->row_type != ROW_TYPE_FIXED &&
+ if (!create_info->frm_only &&
+ create_info->row_type != ROW_TYPE_FIXED &&
create_info->row_type != ROW_TYPE_DEFAULT)
db_options|= HA_OPTION_PACK_RECORD;
alias= table_case_name(create_info, table_name);
@@ -4564,7 +4565,8 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
*/
if (open_and_lock_tables(thd, thd->lex->query_tables, FALSE, 0))
{
- result= TRUE;
+ /* is_error() may be 0 if table existed and we generated a warning */
+ result= thd->is_error();
goto end;
}
@@ -4759,7 +4761,10 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
properly isolated from all concurrent operations which matter.
*/
if (open_tables(thd, &thd->lex->query_tables, &not_used, 0))
+ {
+ res= thd->is_error();
goto err;
+ }
src_table->table->use_all_columns();
DEBUG_SYNC(thd, "create_table_like_after_open");
@@ -6779,9 +6784,19 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
my_sleep(100000););
/*
Create a table with a temporary name.
- With create_info->frm_only == 1 this creates a .frm file only.
+ With create_info->frm_only == 1 this creates a .frm file only and
+ we keep the original row format.
We don't log the statement, it will be logged later.
*/
+ if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
+ {
+ DBUG_ASSERT(create_info->frm_only);
+ /* Ensure we keep the original table format */
+ create_info->table_options= ((create_info->table_options &
+ ~HA_OPTION_PACK_RECORD) |
+ (table->s->db_create_options &
+ HA_OPTION_PACK_RECORD));
+ }
tmp_disable_binlog(thd);
error= mysql_create_table_no_lock(thd, new_db, tmp_name,
create_info,
diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc
index 6b956768287..147a59df9b7 100644
--- a/sql/threadpool_common.cc
+++ b/sql/threadpool_common.cc
@@ -173,7 +173,6 @@ void threadpool_remove_connection(THD *thd)
close_connection(thd, 0);
unlink_thd(thd);
- mysql_mutex_unlock(&LOCK_thread_count);
mysql_cond_broadcast(&COND_thread_count);
/*