diff options
author | Sergei Golubchik <sergii@pisem.net> | 2013-11-19 13:16:25 +0100 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2013-11-19 13:16:25 +0100 |
commit | fa3f8a18b247d5d7d86d60d016681cc188522f80 (patch) | |
tree | 180232f5e13c81e22ae9374b41be168ed9578932 /sql | |
parent | efab095c7f8f044525ce7d2313fad5f86032baab (diff) | |
parent | 543b6e02246db25d8a61574fc709b28e7720d1a0 (diff) | |
download | mariadb-git-fa3f8a18b247d5d7d86d60d016681cc188522f80.tar.gz |
mysql-5.5.34 merge
(some patches reverted, test case added)
Diffstat (limited to 'sql')
-rw-r--r-- | sql/event_scheduler.cc | 74 | ||||
-rw-r--r-- | sql/event_scheduler.h | 2 | ||||
-rw-r--r-- | sql/events.cc | 7 | ||||
-rw-r--r-- | sql/events.h | 2 | ||||
-rw-r--r-- | sql/ha_ndbcluster_binlog.cc | 8 | ||||
-rw-r--r-- | sql/ha_partition.cc | 2 | ||||
-rw-r--r-- | sql/handler.cc | 12 | ||||
-rw-r--r-- | sql/log_event.cc | 12 | ||||
-rw-r--r-- | sql/log_event_old.cc | 5 | ||||
-rw-r--r-- | sql/mysqld.cc | 105 | ||||
-rw-r--r-- | sql/mysqld.h | 1 | ||||
-rw-r--r-- | sql/partition_info.cc | 5 | ||||
-rw-r--r-- | sql/rpl_rli.cc | 12 | ||||
-rw-r--r-- | sql/rpl_utility.cc | 22 | ||||
-rw-r--r-- | sql/slave.cc | 6 | ||||
-rw-r--r-- | sql/sp_head.cc | 35 | ||||
-rw-r--r-- | sql/sql_admin.cc | 16 | ||||
-rw-r--r-- | sql/sql_base.cc | 40 | ||||
-rw-r--r-- | sql/sql_base.h | 6 | ||||
-rw-r--r-- | sql/sql_cache.cc | 10 | ||||
-rw-r--r-- | sql/sql_class.cc | 4 | ||||
-rw-r--r-- | sql/sql_class.h | 10 | ||||
-rw-r--r-- | sql/sql_db.cc | 5 | ||||
-rw-r--r-- | sql/sql_handler.cc | 3 | ||||
-rw-r--r-- | sql/sql_lex.cc | 1 | ||||
-rw-r--r-- | sql/sql_manager.cc | 9 | ||||
-rw-r--r-- | sql/sql_parse.cc | 41 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 21 | ||||
-rw-r--r-- | sql/sql_show.cc | 8 | ||||
-rw-r--r-- | sql/sql_table.cc | 55 | ||||
-rw-r--r-- | sql/sql_view.cc | 2 | ||||
-rw-r--r-- | sql/sys_vars.cc | 8 | ||||
-rw-r--r-- | sql/transaction.cc | 50 | ||||
-rw-r--r-- | sql/transaction.h | 1 |
34 files changed, 443 insertions, 157 deletions
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index b41c9e2cda0..95152778bfd 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -241,6 +241,12 @@ event_scheduler_thread(void *arg) my_free(arg); if (!res) scheduler->run(thd); + else + { + thd->proc_info= "Clearing"; + net_end(&thd->net); + delete thd; + } DBUG_LEAVE; // Against gcc warnings my_thread_end(); @@ -368,26 +374,26 @@ Event_scheduler::~Event_scheduler() } -/* +/** Starts the scheduler (again). Creates a new THD and passes it to a forked thread. Does not wait for acknowledgement from the new thread that it has started. Asynchronous starting. Most of the needed initializations are done in the current thread to minimize the chance of failure in the spawned thread. - SYNOPSIS - Event_scheduler::start() + @param[out] err_no - errno indicating type of error which caused + failure to start scheduler thread. - RETURN VALUE - FALSE OK - TRUE Error (not reported) + @return + @retval false Success. + @retval true Error. */ bool -Event_scheduler::start() +Event_scheduler::start(int *err_no) { THD *new_thd= NULL; - bool ret= FALSE; + bool ret= false; pthread_t th; struct scheduler_param *scheduler_param_value; DBUG_ENTER("Event_scheduler::start"); @@ -400,7 +406,7 @@ Event_scheduler::start() if (!(new_thd= new THD)) { sql_print_error("Event Scheduler: Cannot initialize the scheduler thread"); - ret= TRUE; + ret= true; goto end; } pre_init_event_thread(new_thd); @@ -423,28 +429,30 @@ Event_scheduler::start() DBUG_PRINT("info", ("Setting state go RUNNING")); state= RUNNING; DBUG_PRINT("info", ("Forking new thread for scheduler. THD: 0x%lx", (long) new_thd)); - if (mysql_thread_create(key_thread_event_scheduler, - &th, &connection_attrib, event_scheduler_thread, - (void*)scheduler_param_value)) + if ((*err_no= mysql_thread_create(key_thread_event_scheduler, + &th, &connection_attrib, + event_scheduler_thread, + (void*)scheduler_param_value))) { DBUG_PRINT("error", ("cannot create a new thread")); - state= INITIALIZED; - scheduler_thd= NULL; - ret= TRUE; + sql_print_error("Event scheduler: Failed to start scheduler," + " Can not create thread for event scheduler (errno=%d)", + *err_no); new_thd->proc_info= "Clearing"; DBUG_ASSERT(new_thd->net.buff != 0); net_end(&new_thd->net); - mysql_mutex_lock(&LOCK_thread_count); - thread_count--; - dec_thread_running(); + + state= INITIALIZED; + scheduler_thd= NULL; delete new_thd; - mysql_cond_broadcast(&COND_thread_count); - mysql_mutex_unlock(&LOCK_thread_count); + + delete scheduler_param_value; + ret= true; } + end: UNLOCK_DATA(); - DBUG_RETURN(ret); } @@ -555,7 +563,20 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name) if ((res= mysql_thread_create(key_thread_event_worker, &th, &connection_attrib, event_worker_thread, event_name))) + { + mysql_mutex_lock(&LOCK_global_system_variables); + Events::opt_event_scheduler= Events::EVENTS_OFF; + mysql_mutex_unlock(&LOCK_global_system_variables); + + sql_print_error("Event_scheduler::execute_top: Can not create event worker" + " thread (errno=%d). Stopping event scheduler", res); + + new_thd->proc_info= "Clearing"; + DBUG_ASSERT(new_thd->net.buff != 0); + net_end(&new_thd->net); + goto error; + } started_events++; executed_events++; // For SHOW STATUS @@ -566,17 +587,8 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name) error: DBUG_PRINT("error", ("Event_scheduler::execute_top() res: %d", res)); if (new_thd) - { - new_thd->proc_info= "Clearing"; - DBUG_ASSERT(new_thd->net.buff != 0); - net_end(&new_thd->net); - mysql_mutex_lock(&LOCK_thread_count); - thread_count--; - dec_thread_running(); delete new_thd; - mysql_cond_broadcast(&COND_thread_count); - mysql_mutex_unlock(&LOCK_thread_count); - } + delete event_name; DBUG_RETURN(TRUE); } diff --git a/sql/event_scheduler.h b/sql/event_scheduler.h index aca4b74dd95..9435ee548d9 100644 --- a/sql/event_scheduler.h +++ b/sql/event_scheduler.h @@ -78,7 +78,7 @@ public: /* State changing methods follow */ bool - start(); + start(int *err_no); bool stop(); diff --git a/sql/events.cc b/sql/events.cc index 8b4bab9e3a6..bbeeaf65eb2 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -800,6 +800,7 @@ Events::init(bool opt_noacl_or_bootstrap) { THD *thd; + int err_no; bool res= FALSE; DBUG_ENTER("Events::init"); @@ -871,7 +872,7 @@ Events::init(bool opt_noacl_or_bootstrap) } if (event_queue->init_queue(thd) || load_events_from_db(thd) || - (opt_event_scheduler == EVENTS_ON && scheduler->start())) + (opt_event_scheduler == EVENTS_ON && scheduler->start(&err_no))) { sql_print_error("Event Scheduler: Error while loading from disk."); res= TRUE; /* fatal error: request unireg_abort */ @@ -1019,9 +1020,9 @@ Events::dump_internal_status() DBUG_VOID_RETURN; } -bool Events::start() +bool Events::start(int *err_no) { - return scheduler->start(); + return scheduler->start(err_no); } bool Events::stop() diff --git a/sql/events.h b/sql/events.h index a94fbc17135..d6fc4b5ea67 100644 --- a/sql/events.h +++ b/sql/events.h @@ -78,7 +78,7 @@ public: /* Protected using LOCK_global_system_variables only. */ static ulong opt_event_scheduler; static bool check_if_system_tables_error(); - static bool start(); + static bool start(int *err_no); static bool stop(); public: diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 856781db28a..013929c24e0 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2006, 2011, Oracle and/or its affiliates. +/* Copyright (c) 2006, 2013, Oracle and/or its affiliates. Copyright (c) 2012, 2013, Monty Proram Ab. This program is free software; you can redistribute it and/or modify @@ -2410,6 +2410,12 @@ add_ndb_binlog_index_err: thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); thd->stmt_da->can_overwrite_status= FALSE; close_thread_tables(thd); + /* + There should be no need for rolling back transaction due to deadlock + (since ndb_binlog_index is non transactional). + */ + DBUG_ASSERT(! thd->transaction_rollback_request); + thd->mdl_context.release_transactional_locks(); ndb_binlog_index= 0; thd->variables.option_bits= saved_options; diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index a08d72eb03e..f65ab41908d 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -6053,7 +6053,7 @@ void ha_partition::get_dynamic_partition_info(PARTITION_STATS *stat_info, uint part_id) { handler *file= m_file[part_id]; - file->info(HA_STATUS_CONST | HA_STATUS_TIME | HA_STATUS_VARIABLE | + file->info(HA_STATUS_TIME | HA_STATUS_VARIABLE | HA_STATUS_VARIABLE_EXTRA | HA_STATUS_NO_LOCK); stat_info->records= file->stats.records; diff --git a/sql/handler.cc b/sql/handler.cc index 5dd816fa1e5..59ed31f6076 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1484,10 +1484,16 @@ int ha_rollback_trans(THD *thd, bool all) } trans->ha_list= 0; trans->no_2pc=0; - if (is_real_trans && thd->transaction_rollback_request && - thd->transaction.xid_state.xa_state != XA_NOTR) - thd->transaction.xid_state.rm_error= thd->stmt_da->sql_errno(); } + + /* + Thanks to possibility of MDL deadlock rollback request can come even if + transaction hasn't been started in any transactional storage engine. + */ + if (is_real_trans && thd->transaction_rollback_request && + thd->transaction.xid_state.xa_state != XA_NOTR) + thd->transaction.xid_state.rm_error= thd->stmt_da->sql_errno(); + /* Always cleanup. Even if nht==0. There may be savepoints. */ if (is_real_trans) thd->transaction.cleanup(); diff --git a/sql/log_event.cc b/sql/log_event.cc index e5af1e3a4af..113234d3106 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5543,6 +5543,8 @@ error: thd->stmt_da->can_overwrite_status= FALSE; close_thread_tables(thd); /* + - If transaction rollback was requested due to deadlock + perform it and release metadata locks. - If inside a multi-statement transaction, defer the release of metadata locks until the current transaction is either committed or rolled back. This prevents @@ -5552,7 +5554,12 @@ error: - If in autocommit mode, or outside a transactional context, automatically release metadata locks of the current statement. */ - if (! thd->in_multi_stmt_transaction_mode()) + if (thd->transaction_rollback_request) + { + trans_rollback_implicit(thd); + thd->mdl_context.release_transactional_locks(); + } + else if (! thd->in_multi_stmt_transaction_mode()) thd->mdl_context.release_transactional_locks(); else thd->mdl_context.release_statement_locks(); @@ -8684,7 +8691,10 @@ static int rows_event_stmt_cleanup(Relay_log_info const *rli, THD * thd) Xid_log_event will come next which will, if some transactional engines are involved, commit the transaction and flush the pending event to the binlog. + If there was a deadlock the transaction should have been rolled back + already. So there should be no need to rollback the transaction. */ + DBUG_ASSERT(! thd->transaction_rollback_request); error|= (error ? trans_rollback_stmt(thd) : trans_commit_stmt(thd)); /* diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 4ad07793973..70b3ec12356 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2007, 2012, Oracle and/or its affiliates. +/* Copyright (c) 2007, 2013, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1808,7 +1808,10 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) Xid_log_event will come next which will, if some transactional engines are involved, commit the transaction and flush the pending event to the binlog. + If there was a deadlock the transaction should have been rolled back + already. So there should be no need to rollback the transaction. */ + DBUG_ASSERT(! thd->transaction_rollback_request); if ((error= (binlog_error ? trans_rollback_stmt(thd) : trans_commit_stmt(thd)))) rli->report(ERROR_LEVEL, error, "Error in %s event: commit of row events failed, " diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1cc82740f6a..90c1a83b9fc 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1591,11 +1591,12 @@ void kill_mysql(void) if (!kill_in_progress) { pthread_t tmp; + int error; abort_loop=1; - if (mysql_thread_create(0, /* Not instrumented */ - &tmp, &connection_attrib, kill_server_thread, - (void*) 0)) - sql_print_error("Can't create thread to kill server"); + if ((error= mysql_thread_create(0, /* Not instrumented */ + &tmp, &connection_attrib, + kill_server_thread, (void*) 0))) + sql_print_error("Can't create thread to kill server (errno= %d).", error); } #endif DBUG_VOID_RETURN; @@ -3085,10 +3086,12 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) #endif #ifdef USE_ONE_SIGNAL_HAND pthread_t tmp; - if (mysql_thread_create(0, /* Not instrumented */ - &tmp, &connection_attrib, kill_server_thread, - (void*) &sig)) - sql_print_error("Can't create thread to kill server"); + if ((error= mysql_thread_create(0, /* Not instrumented */ + &tmp, &connection_attrib, + kill_server_thread, + (void*) &sig))) + sql_print_error("Can't create thread to kill server (errno= %d)", + error); #else kill_server((void*) sig); // MIT THREAD has a alarm thread #endif @@ -4535,9 +4538,12 @@ static void create_shutdown_thread() #ifdef __WIN__ hEventShutdown=CreateEvent(0, FALSE, FALSE, shutdown_event_name); pthread_t hThread; - if (mysql_thread_create(key_thread_handle_shutdown, - &hThread, &connection_attrib, handle_shutdown, 0)) - sql_print_warning("Can't create thread to handle shutdown requests"); + int error; + if ((error= mysql_thread_create(key_thread_handle_shutdown, + &hThread, &connection_attrib, + handle_shutdown, 0))) + sql_print_warning("Can't create thread to handle shutdown requests" + " (errno= %d)", error); // On "Stop Service" we have to do regular shutdown Service.SetShutdownEvent(hEventShutdown); @@ -4551,6 +4557,7 @@ static void create_shutdown_thread() static void handle_connections_methods() { pthread_t hThread; + int error; DBUG_ENTER("handle_connections_methods"); if (hPipe == INVALID_HANDLE_VALUE && (!have_tcpip || opt_disable_networking) && @@ -4566,22 +4573,24 @@ static void handle_connections_methods() if (hPipe != INVALID_HANDLE_VALUE) { handler_count++; - if (mysql_thread_create(key_thread_handle_con_namedpipes, - &hThread, &connection_attrib, - handle_connections_namedpipes, 0)) + if ((error= mysql_thread_create(key_thread_handle_con_namedpipes, + &hThread, &connection_attrib, + handle_connections_namedpipes, 0))) { - sql_print_warning("Can't create thread to handle named pipes"); + sql_print_warning("Can't create thread to handle named pipes" + " (errno= %d)", error); handler_count--; } } if (have_tcpip && !opt_disable_networking) { handler_count++; - if (mysql_thread_create(key_thread_handle_con_sockets, - &hThread, &connection_attrib, - handle_connections_sockets_thread, 0)) + if ((error= mysql_thread_create(key_thread_handle_con_sockets, + &hThread, &connection_attrib, + handle_connections_sockets_thread, 0))) { - sql_print_warning("Can't create thread to handle TCP/IP"); + sql_print_warning("Can't create thread to handle TCP/IP", + " (errno= %d)", error); handler_count--; } } @@ -4589,11 +4598,12 @@ static void handle_connections_methods() if (opt_enable_shared_memory) { handler_count++; - if (mysql_thread_create(key_thread_handle_con_sharedmem, - &hThread, &connection_attrib, - handle_connections_shared_memory, 0)) + if ((error= mysql_thread_create(key_thread_handle_con_sharedmem, + &hThread, &connection_attrib, + handle_connections_shared_memory, 0))) { - sql_print_warning("Can't create thread to handle shared memory"); + sql_print_warning("Can't create thread to handle shared memory", + " (errno= %d)", error); handler_count--; } } @@ -4619,6 +4629,42 @@ void decrement_handler_count() #ifndef EMBEDDED_LIBRARY + +LEX_STRING sql_statement_names[(uint) SQLCOM_END + 1]; + +static void init_sql_statement_names() +{ + char *first_com= (char*) offsetof(STATUS_VAR, com_stat[0]); + char *last_com= (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_END]); + int record_size= (char*) offsetof(STATUS_VAR, com_stat[1]) + - (char*) offsetof(STATUS_VAR, com_stat[0]); + char *ptr; + uint i; + uint com_index; + + for (i= 0; i < ((uint) SQLCOM_END + 1); i++) + sql_statement_names[i]= empty_lex_str; + + SHOW_VAR *var= &com_status_vars[0]; + while (var->name != NULL) + { + ptr= var->value; + if ((first_com <= ptr) && (ptr <= last_com)) + { + com_index= ((int)(ptr - first_com))/record_size; + DBUG_ASSERT(com_index < (uint) SQLCOM_END); + sql_statement_names[com_index].str= const_cast<char *>(var->name); + sql_statement_names[com_index].length= strlen(var->name); + } + var++; + } + + DBUG_ASSERT(strcmp(sql_statement_names[(uint) SQLCOM_SELECT].str, "select") == 0); + DBUG_ASSERT(strcmp(sql_statement_names[(uint) SQLCOM_SIGNAL].str, "signal") == 0); + + sql_statement_names[(uint) SQLCOM_END].str= const_cast<char*>("error"); +} + #ifndef DBUG_OFF /* Debugging helper function to keep the locale database @@ -4694,6 +4740,7 @@ int mysqld_main(int argc, char **argv) /* Must be initialized early for comparison of options name */ system_charset_info= &my_charset_utf8_general_ci; + init_sql_statement_names(); sys_var_init(); #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE @@ -5305,11 +5352,14 @@ static void bootstrap(MYSQL_FILE *file) bootstrap_file=file; #ifndef EMBEDDED_LIBRARY // TODO: Enable this - if (mysql_thread_create(key_thread_bootstrap, - &thd->real_id, &connection_attrib, handle_bootstrap, - (void*) thd)) + int error; + if ((error= mysql_thread_create(key_thread_bootstrap, + &thd->real_id, &connection_attrib, + handle_bootstrap, + (void*) thd))) { - sql_print_warning("Can't create thread to handle bootstrap"); + sql_print_warning("Can't create thread to handle bootstrap (errno= %d)", + error); bootstrap_error=-1; DBUG_VOID_RETURN; } @@ -5406,6 +5456,7 @@ void create_thread_to_handle_connection(THD *thd) DBUG_PRINT("error", ("Can't create thread to handle request (error %d)", error)); + thread_count--; thd->killed= KILL_CONNECTION; // Safety mysql_mutex_unlock(&LOCK_thread_count); diff --git a/sql/mysqld.h b/sql/mysqld.h index 7834968200d..fc7e8f27fc4 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -208,7 +208,6 @@ extern LEX_STRING opt_init_connect, opt_init_slave; extern int bootstrap_error; extern I_List<THD> threads; extern char err_shared_dir[]; -extern TYPELIB thread_handling_typelib; /* THR_MALLOC is a key which will be used to set/get MEM_ROOT** for a thread, diff --git a/sql/partition_info.cc b/sql/partition_info.cc index a6c4fdaa6d2..8513ed854b7 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -2214,11 +2214,10 @@ int partition_info::fix_parser_data(THD *thd) { part_elem= it++; List_iterator<part_elem_value> list_val_it(part_elem->list_val_list); - j= 0; num_elements= part_elem->list_val_list.elements; DBUG_ASSERT(part_type == RANGE_PARTITION ? num_elements == 1U : TRUE); - do + for (j= 0; j < num_elements; j++) { part_elem_value *val= list_val_it++; if (column_list) @@ -2253,7 +2252,7 @@ int partition_info::fix_parser_data(THD *thd) list_val_it.remove(); } } - } while (++j < num_elements); + } } while (++i < num_parts); DBUG_RETURN(FALSE); } diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index e03d46606d5..b01f74408a6 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1,4 +1,5 @@ -/* Copyright (c) 2006, 2012, Oracle and/or its affiliates. +/* Copyright (c) 2006, 2013, Oracle and/or its affiliates. + Copyright (c) 2011, 2013, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1316,6 +1317,8 @@ void Relay_log_info::slave_close_thread_tables(THD *thd) close_thread_tables(thd); /* + - If transaction rollback was requested due to deadlock + perform it and release metadata locks. - If inside a multi-statement transaction, defer the release of metadata locks until the current transaction is either committed or rolled back. This prevents @@ -1325,7 +1328,12 @@ void Relay_log_info::slave_close_thread_tables(THD *thd) - If in autocommit mode, or outside a transactional context, automatically release metadata locks of the current statement. */ - if (! thd->in_multi_stmt_transaction_mode()) + if (thd->transaction_rollback_request) + { + trans_rollback_implicit(thd); + thd->mdl_context.release_transactional_locks(); + } + else if (! thd->in_multi_stmt_transaction_mode()) thd->mdl_context.release_transactional_locks(); else thd->mdl_context.release_statement_locks(); diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index 171112b09f0..59d92a7f09f 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -1,5 +1,5 @@ -/* - Copyright (c) 2006, 2010, Oracle and/or its affiliates. +/* Copyright (c) 2006, 2013, Oracle and/or its affiliates. + Copyright (c) 2011, 2013, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -878,6 +878,7 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE * DBUG_ENTER("table_def::create_conversion_table"); List<Create_field> field_list; + TABLE *conv_table= NULL; /* At slave, columns may differ. So we should create min(columns@master, columns@slave) columns in the @@ -919,10 +920,15 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE * break; case MYSQL_TYPE_DECIMAL: - precision= field_metadata(col); - decimals= static_cast<Field_num*>(target_table->field[col])->dec; - max_length= field_metadata(col); - break; + sql_print_error("In RBR mode, Slave received incompatible DECIMAL field " + "(old-style decimal field) from Master while creating " + "conversion table. Please consider changing datatype on " + "Master to new style decimal by executing ALTER command for" + " column Name: %s.%s.%s.", + target_table->s->db.str, + target_table->s->table_name.str, + target_table->field[col]->field_name); + goto err; case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: @@ -950,7 +956,9 @@ TABLE *table_def::create_conversion_table(THD *thd, Relay_log_info *rli, TABLE * field_def->interval= interval; } - TABLE *conv_table= create_virtual_tmp_table(thd, field_list); + conv_table= create_virtual_tmp_table(thd, field_list); + +err: if (conv_table == NULL) rli->report(ERROR_LEVEL, ER_SLAVE_CANT_CREATE_CONVERSION, ER(ER_SLAVE_CANT_CREATE_CONVERSION), diff --git a/sql/slave.cc b/sql/slave.cc index a889bb06bb9..afaca619a69 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -708,6 +708,7 @@ int start_slave_thread( { pthread_t th; ulong start_id; + int error; DBUG_ENTER("start_slave_thread"); DBUG_ASSERT(mi->inited); @@ -734,9 +735,10 @@ int start_slave_thread( } start_id= *slave_run_id; DBUG_PRINT("info",("Creating new slave thread")); - if (mysql_thread_create(thread_key, - &th, &connection_attrib, h_func, (void*)mi)) + if ((error = mysql_thread_create(thread_key, + &th, &connection_attrib, h_func, (void*)mi))) { + sql_print_error("Can't create slave thread (errno= %d).", error); if (start_lock) mysql_mutex_unlock(start_lock); DBUG_RETURN(ER_SLAVE_THREAD); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 840376b2c14..99f9b172b16 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1,5 +1,6 @@ /* - Copyright (c) 2002, 2011, Oracle and/or its affiliates. + Copyright (c) 2002, 2013, Oracle and/or its affiliates. + Copyright (c) 2011, 2013, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2150,10 +2151,18 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) close_thread_tables(thd); thd_proc_info(thd, 0); - if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode()) - thd->mdl_context.release_transactional_locks(); - else if (! thd->in_sub_stmt) - thd->mdl_context.release_statement_locks(); + if (! thd->in_sub_stmt) + { + if (thd->transaction_rollback_request) + { + trans_rollback_implicit(thd); + thd->mdl_context.release_transactional_locks(); + } + else if (! thd->in_multi_stmt_transaction_mode()) + thd->mdl_context.release_transactional_locks(); + else + thd->mdl_context.release_statement_locks(); + } thd->rollback_item_tree_changes(); @@ -3005,10 +3014,18 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, close_thread_tables(thd); thd_proc_info(thd, 0); - if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode()) - thd->mdl_context.release_transactional_locks(); - else if (! thd->in_sub_stmt) - thd->mdl_context.release_statement_locks(); + if (! thd->in_sub_stmt) + { + if (thd->transaction_rollback_request) + { + trans_rollback_implicit(thd); + thd->mdl_context.release_transactional_locks(); + } + else if (! thd->in_multi_stmt_transaction_mode()) + thd->mdl_context.release_transactional_locks(); + else + thd->mdl_context.release_statement_locks(); + } } if (m_lex->query_tables_own_last) diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 5b947401f56..b8a7afbd6c5 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -900,8 +900,20 @@ send_result_message: } } /* Error path, a admin command failed. */ - trans_commit_stmt(thd); - trans_commit_implicit(thd); + if (thd->transaction_rollback_request) + { + /* + Unlikely, but transaction rollback was requested by one of storage + engines (e.g. due to deadlock). Perform it. + */ + if (trans_rollback_stmt(thd) || trans_rollback_implicit(thd)) + goto err; + } + else + { + if (trans_commit_stmt(thd) || trans_commit_implicit(thd)) + goto err; + } close_thread_tables(thd); thd->mdl_context.release_transactional_locks(); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f0794ac7609..d54cb54dec6 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. - Copyright (c) 2010, 2011 Monty Program Ab +/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. + Copyright (c) 2010, 2013 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -4002,7 +4002,8 @@ end_unlock: /** Open_table_context */ Open_table_context::Open_table_context(THD *thd, uint flags) - :m_failed_table(NULL), + :m_thd(thd), + m_failed_table(NULL), m_start_of_statement_svp(thd->mdl_context.mdl_savepoint()), m_timeout(flags & MYSQL_LOCK_IGNORE_TIMEOUT ? LONG_TIMEOUT : thd->variables.lock_wait_timeout), @@ -4079,6 +4080,7 @@ request_backoff_action(enum_open_table_action action_arg, if (action_arg != OT_REOPEN_TABLES && m_has_locks) { my_error(ER_LOCK_DEADLOCK, MYF(0)); + mark_transaction_to_rollback(m_thd, true); return TRUE; } /* @@ -4088,7 +4090,7 @@ request_backoff_action(enum_open_table_action action_arg, if (table) { DBUG_ASSERT(action_arg == OT_DISCOVER || action_arg == OT_REPAIR); - m_failed_table= (TABLE_LIST*) current_thd->alloc(sizeof(TABLE_LIST)); + m_failed_table= (TABLE_LIST*) m_thd->alloc(sizeof(TABLE_LIST)); if (m_failed_table == NULL) return TRUE; m_failed_table->init_one_table(table->db, table->db_length, @@ -4105,8 +4107,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 - @pre This function should be called only with "action" != OT_NO_ACTION and after having called @sa close_tables_for_reopen(). @@ -4116,7 +4116,7 @@ request_backoff_action(enum_open_table_action action_arg, bool Open_table_context:: -recover_from_failed_open(THD *thd) +recover_from_failed_open() { bool result= FALSE; /* Execute the action. */ @@ -4128,33 +4128,33 @@ recover_from_failed_open(THD *thd) break; case OT_DISCOVER: { - if ((result= lock_table_names(thd, m_failed_table, NULL, + if ((result= lock_table_names(m_thd, m_failed_table, NULL, get_timeout(), MYSQL_OPEN_SKIP_TEMPORARY))) break; - tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db, + tdc_remove_table(m_thd, TDC_RT_REMOVE_ALL, m_failed_table->db, m_failed_table->table_name, FALSE); - ha_create_table_from_engine(thd, m_failed_table->db, + ha_create_table_from_engine(m_thd, m_failed_table->db, m_failed_table->table_name); - thd->warning_info->clear_warning_info(thd->query_id); - thd->clear_error(); // Clear error message - thd->mdl_context.release_transactional_locks(); + m_thd->warning_info->clear_warning_info(m_thd->query_id); + m_thd->clear_error(); // Clear error message + m_thd->mdl_context.release_transactional_locks(); break; } case OT_REPAIR: { - if ((result= lock_table_names(thd, m_failed_table, NULL, + if ((result= lock_table_names(m_thd, m_failed_table, NULL, get_timeout(), MYSQL_OPEN_SKIP_TEMPORARY))) break; - tdc_remove_table(thd, TDC_RT_REMOVE_ALL, m_failed_table->db, + tdc_remove_table(m_thd, TDC_RT_REMOVE_ALL, m_failed_table->db, m_failed_table->table_name, FALSE); - result= auto_repair_table(thd, m_failed_table); - thd->mdl_context.release_transactional_locks(); + result= auto_repair_table(m_thd, m_failed_table); + m_thd->mdl_context.release_transactional_locks(); break; } default: @@ -5055,7 +5055,7 @@ restart: TABLE_LIST element. Altough currently this assumption is valid it may change in future. */ - if (ot_ctx.recover_from_failed_open(thd)) + if (ot_ctx.recover_from_failed_open()) goto err; error= FALSE; @@ -5108,7 +5108,7 @@ restart: { close_tables_for_reopen(thd, start, ot_ctx.start_of_statement_svp()); - if (ot_ctx.recover_from_failed_open(thd)) + if (ot_ctx.recover_from_failed_open()) goto err; error= FALSE; @@ -5547,7 +5547,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)) + if (ot_ctx.recover_from_failed_open()) break; } diff --git a/sql/sql_base.h b/sql/sql_base.h index 110f2abbd1d..d49554d5473 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -543,7 +543,7 @@ public: }; Open_table_context(THD *thd, uint flags); - bool recover_from_failed_open(THD *thd); + bool recover_from_failed_open(); bool request_backoff_action(enum_open_table_action action_arg, TABLE_LIST *table); @@ -583,6 +583,8 @@ public: } private: + /* THD for which tables are opened. */ + THD *m_thd; /** For OT_DISCOVER and OT_REPAIR actions, the table list element for the table which definition should be re-discovered or which diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 2e9a183ce63..82f47f7c861 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1,4 +1,5 @@ -/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. +/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. + Copyright (c) 2010, 2013, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2033,7 +2034,12 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", */ thd->query_cache_is_applicable= 0; // Query can't be cached } - /* End the statement transaction potentially started by engine. */ + /* + End the statement transaction potentially started by engine. + Currently our engines do not request rollback from callbacks. + If this is going to change code needs to be reworked. + */ + DBUG_ASSERT(! thd->transaction_rollback_request); trans_rollback_stmt(thd); goto err_unlock; // Parse query } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 63a5af3a707..f68facb5d14 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3994,6 +3994,10 @@ extern "C" unsigned long thd_get_thread_id(const MYSQL_THD thd) return((unsigned long)thd->thread_id); } +extern "C" enum_tx_isolation thd_get_trx_isolation(const MYSQL_THD thd) +{ + return thd->tx_isolation; +} #ifdef INNODB_COMPATIBILITY_HOOKS extern "C" const struct charset_info_st *thd_charset(MYSQL_THD thd) diff --git a/sql/sql_class.h b/sql/sql_class.h index e9665959d04..a21917a0814 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1,6 +1,6 @@ /* - Copyright (c) 2000, 2012, Oracle and/or its affiliates. - Copyright (c) 2009, 2012, Monty Program Ab + Copyright (c) 2000, 2013, Oracle and/or its affiliates. + Copyright (c) 2009, 2013, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -439,6 +439,7 @@ enum killed_type #include "sql_lex.h" /* Must be here */ +extern LEX_STRING sql_statement_names[(uint) SQLCOM_END + 1]; class Delayed_insert; class select_result; class Time_zone; @@ -2839,6 +2840,11 @@ public: */ bool set_db(const char *new_db, size_t new_db_len) { + /* + Acquiring mutex LOCK_thd_data as we either free the memory allocated + for the database and reallocating the memory for the new db or memcpy + the new_db to the db. + */ mysql_mutex_lock(&LOCK_thd_data); /* Do not reallocate memory if current chunk is big enough. */ if (db && new_db && db_length >= new_db_len) diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 579c032f332..0464128bd97 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2011, Oracle and/or its affiliates. + Copyright (c) 2000, 2013, Oracle and/or its affiliates. Copyright (c) 2009, 2013, Monty Program Ab. This program is free software; you can redistribute it and/or modify @@ -1276,8 +1276,7 @@ static void mysql_change_db_impl(THD *thd, we just call THD::reset_db(). Since THD::reset_db() does not releases the previous database name, we should do it explicitly. */ - my_free(thd->db); - + thd->set_db(NULL, 0); thd->reset_db(new_db_name->str, new_db_name->length); } diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 6ff550985fa..c099a2af496 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -788,7 +788,10 @@ retry: /* Always close statement transaction explicitly, so that the engine doesn't have to count locks. + There should be no need to perform transaction + rollback due to deadlock. */ + DBUG_ASSERT(! thd->transaction_rollback_request); trans_rollback_stmt(thd); mysql_ha_close_table(handler); if (thd->stmt_arena->is_stmt_execute()) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 57f5d9b1167..6645147bd4f 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -197,6 +197,7 @@ init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex) table->map= 1; //To ensure correct calculation of const item table->get_fields_in_item_tree= TRUE; table_list->table= table; + table_list->cacheable_table= false; return FALSE; } diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc index e9ac55730d3..9d014790929 100644 --- a/sql/sql_manager.cc +++ b/sql/sql_manager.cc @@ -140,9 +140,12 @@ void start_handle_manager() if (flush_time && flush_time != ~(ulong) 0L) { pthread_t hThread; - if (mysql_thread_create(key_thread_handle_manager, - &hThread, &connection_attrib, handle_manager, 0)) - sql_print_warning("Can't create handle_manager thread"); + int error; + if ((error= mysql_thread_create(key_thread_handle_manager, + &hThread, &connection_attrib, + handle_manager, 0))) + sql_print_warning("Can't create handle_manager thread (errno= %d)", + error); } DBUG_VOID_RETURN; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e9adc3b669f..41b809774ad 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2012, Oracle and/or its affiliates. - Copyright (c) 2008, 2012, Monty Program Ab +/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. + Copyright (c) 2008, 2013, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1229,6 +1229,18 @@ bool dispatch_command(enum enum_server_command command, THD *thd, close_thread_tables(thd); thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + if (thd->transaction_rollback_request) + { + /* + Transaction rollback was requested since MDL deadlock was + discovered while trying to open tables. Rollback transaction + in all storage engines including binary log and release all + locks. + */ + trans_rollback_implicit(thd); + thd->mdl_context.release_transactional_locks(); + } + thd->cleanup_after_query(); break; } @@ -1899,7 +1911,7 @@ err: can free its locks if LOCK TABLES locked some tables before finding that it can't lock a table in its list */ - trans_commit_implicit(thd); + trans_rollback(thd); /* Close tables and release metadata locks. */ close_thread_tables(thd); DBUG_ASSERT(!thd->locked_tables_mode); @@ -1951,6 +1963,13 @@ mysql_execute_command(THD *thd) DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt); /* + Each statement or replication event which might produce deadlock + should handle transaction rollback on its own. So by the start of + the next statement transaction rollback request should be fulfilled + already. + */ + DBUG_ASSERT(! thd->transaction_rollback_request || thd->in_sub_stmt); + /* In many cases first table of main SELECT_LEX have special meaning => check that it is first table in global list and relink it first in queries_tables list if it is necessary (we need such relinking only @@ -2138,8 +2157,8 @@ mysql_execute_command(THD *thd) or triggers as all such statements prohibited there. */ DBUG_ASSERT(! thd->in_sub_stmt); - /* Commit or rollback the statement transaction. */ - thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); + /* Statement transaction still should not be started. */ + DBUG_ASSERT(thd->transaction.stmt.is_empty()); /* Commit the normal transaction if one is active. */ if (trans_commit_implicit(thd)) goto error; @@ -4567,7 +4586,17 @@ finish: DEBUG_SYNC(thd, "execute_command_after_close_tables"); #endif - if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END)) + if (! thd->in_sub_stmt && thd->transaction_rollback_request) + { + /* + We are not in sub-statement and transaction rollback was requested by + one of storage engines (e.g. due to deadlock). Rollback transaction in + all storage engines including binary log. + */ + trans_rollback_implicit(thd); + thd->mdl_context.release_transactional_locks(); + } + else if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END)) { /* No transaction control allowed in sub-statements. */ DBUG_ASSERT(! thd->in_sub_stmt); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 0446e8bf18c..ad1e291a9d7 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2002, 2012, Oracle and/or its affiliates. - Copyright (c) 2008, 2011, Monty Program Ab +/* Copyright (c) 2002, 2013, Oracle and/or its affiliates. + Copyright (c) 2008, 2013, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -115,6 +115,7 @@ When one supplies long data for a placeholder: #endif #include "lock.h" // MYSQL_OPEN_FORCE_SHARED_MDL #include "sql_handler.h" +#include "transaction.h" // trans_rollback_implicit /** A result class used to send cursor rows using the binary protocol. @@ -3399,6 +3400,22 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) close_thread_tables(thd); thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + + /* + Transaction rollback was requested since MDL deadlock was discovered + while trying to open tables. Rollback transaction in all storage + engines including binary log and release all locks. + + Once dynamic SQL is allowed as substatements the below if-statement + has to be adjusted to not do rollback in substatement. + */ + DBUG_ASSERT(! thd->in_sub_stmt); + if (thd->transaction_rollback_request) + { + trans_rollback_implicit(thd); + thd->mdl_context.release_transactional_locks(); + } + lex_end(lex); cleanup_stmt(); thd->restore_backup_statement(this, &stmt_backup); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 434d5b90652..5104eb7bb3f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2313,7 +2313,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) { Security_context *tmp_sctx= tmp->security_ctx; struct st_my_thread_var *mysys_var; - const char *val; + const char *val, *db; ulonglong max_counter; if ((!tmp->vio_ok() && !tmp->system_thread) || @@ -2340,13 +2340,13 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) table->field[2]->store(tmp_sctx->host_or_ip, strlen(tmp_sctx->host_or_ip), cs); /* DB */ - if (tmp->db) + mysql_mutex_lock(&tmp->LOCK_thd_data); + if ((db= tmp->db)) { - table->field[3]->store(tmp->db, strlen(tmp->db), cs); + table->field[3]->store(db, strlen(db), cs); table->field[3]->set_notnull(); } - mysql_mutex_lock(&tmp->LOCK_thd_data); if ((mysys_var= tmp->mysys_var)) mysql_mutex_lock(&mysys_var->mutex); /* COMMAND */ diff --git a/sql/sql_table.cc b/sql/sql_table.cc index d7102c0e3f6..eda178fcc64 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2046,6 +2046,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, bool non_tmp_error= 0; bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0; bool non_tmp_table_deleted= 0; + bool is_drop_tmp_if_exists_added= 0; String built_query; String built_trans_tmp_query, built_non_trans_tmp_query; DBUG_ENTER("mysql_rm_table_no_locks"); @@ -2074,6 +2075,15 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, table stems from the fact that such drop does not commit an ongoing transaction and changes to non-transactional tables must be written ahead of the transaction in some circumstances. + + 6- Slave SQL thread ignores all replicate-* filter rules + for temporary tables with 'IF EXISTS' clause. (See sql/sql_parse.cc: + mysql_execute_command() for details). These commands will be binlogged + as they are, even if the default database (from USE `db`) is not present + on the Slave. This can cause point in time recovery failures later + when user uses the slave's binlog to re-apply. Hence at the time of binary + logging, these commands will be written with fully qualified table names + and use `db` will be suppressed. */ if (!dont_log_query) { @@ -2097,6 +2107,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, if (thd->is_current_stmt_binlog_format_row() || if_exists) { + is_drop_tmp_if_exists_added= true; built_trans_tmp_query.set_charset(system_charset_info); built_trans_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS "); built_non_trans_tmp_query.set_charset(system_charset_info); @@ -2174,10 +2185,12 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, String *built_ptr_query= (is_trans ? &built_trans_tmp_query : &built_non_trans_tmp_query); /* - Don't write the database name if it is the current one (or if - thd->db is NULL). + Write the database name if it is not the current one or if + thd->db is NULL or 'IF EXISTS' clause is present in 'DROP TEMPORARY' + query. */ - if (thd->db == NULL || strcmp(db,thd->db) != 0) + if (thd->db == NULL || strcmp(db,thd->db) != 0 + || is_drop_tmp_if_exists_added ) { append_identifier(thd, built_ptr_query, db, db_length); built_ptr_query->append("."); @@ -2373,7 +2386,9 @@ err: error |= thd->binlog_query(THD::STMT_QUERY_TYPE, built_non_trans_tmp_query.ptr(), built_non_trans_tmp_query.length(), - FALSE, FALSE, FALSE, 0); + FALSE, FALSE, + is_drop_tmp_if_exists_added, + 0); } if (trans_tmp_table_deleted) { @@ -2383,7 +2398,9 @@ err: error |= thd->binlog_query(THD::STMT_QUERY_TYPE, built_trans_tmp_query.ptr(), built_trans_tmp_query.length(), - TRUE, FALSE, FALSE, 0); + TRUE, FALSE, + is_drop_tmp_if_exists_added, + 0); } if (non_tmp_table_deleted) { @@ -4967,7 +4984,6 @@ mysql_discard_or_import_tablespace(THD *thd, error= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); err: - trans_rollback_stmt(thd); thd->tablespace_op=FALSE; if (error == 0) @@ -7648,6 +7664,12 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, Protocol *protocol= thd->protocol; DBUG_ENTER("mysql_checksum_table"); + /* + CHECKSUM TABLE returns results and rollbacks statement transaction, + so it should not be used in stored function or trigger. + */ + DBUG_ASSERT(! thd->in_sub_stmt); + field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2)); item->maybe_null= 1; field_list.push_back(item= new Item_int("Checksum", (longlong) 1, @@ -7666,7 +7688,6 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, strxmov(table_name, table->db ,".", table->table_name, NullS); t= table->table= open_n_lock_single_table(thd, table, TL_READ, 0); - thd->clear_error(); // these errors shouldn't get client protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); @@ -7675,7 +7696,6 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, { /* Table didn't exist */ protocol->store_null(); - thd->clear_error(); } else { @@ -7763,9 +7783,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, t->file->ha_rnd_end(); } } - thd->clear_error(); - if (! thd->in_sub_stmt) - trans_rollback_stmt(thd); + trans_rollback_stmt(thd); close_thread_tables(thd); /* Don't release metadata locks, this will be done at @@ -7773,6 +7791,21 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, */ table->table=0; // For query cache } + + if (thd->transaction_rollback_request) + { + /* + If transaction rollback was requested we honor it. To do this we + abort statement and return error as not only CHECKSUM TABLE is + rolled back but the whole transaction in which it was used. + */ + thd->protocol->remove_last_row(); + goto err; + } + + /* Hide errors from client. Return NULL for problematic tables instead. */ + thd->clear_error(); + if (protocol->write()) goto err; } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 17287b27154..52872e8ea5b 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1480,7 +1480,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, objects of the view. */ if (!(table->view_sctx= (Security_context *) - thd->stmt_arena->alloc(sizeof(Security_context)))) + thd->stmt_arena->calloc(sizeof(Security_context)))) goto err; security_ctx= table->view_sctx; } diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 8bb9f57157e..9526933933f 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -667,6 +667,7 @@ static bool event_scheduler_check(sys_var *self, THD *thd, set_var *var) } static bool event_scheduler_update(sys_var *self, THD *thd, enum_var_type type) { + int err_no= 0; uint opt_event_scheduler_value= Events::opt_event_scheduler; mysql_mutex_unlock(&LOCK_global_system_variables); /* @@ -686,11 +687,14 @@ static bool event_scheduler_update(sys_var *self, THD *thd, enum_var_type type) for deadlocks. See bug#51160. */ bool ret= opt_event_scheduler_value == Events::EVENTS_ON - ? Events::start() + ? Events::start(&err_no) : Events::stop(); mysql_mutex_lock(&LOCK_global_system_variables); if (ret) - my_error(ER_EVENT_SET_VAR_ERROR, MYF(0), 0); + { + Events::opt_event_scheduler= Events::EVENTS_OFF; + my_error(ER_EVENT_SET_VAR_ERROR, MYF(0), err_no); + } return ret; } diff --git a/sql/transaction.cc b/sql/transaction.cc index 3b0af4db710..ae38e920a1d 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -268,6 +268,52 @@ bool trans_rollback(THD *thd) /** + Implicitly rollback the current transaction, typically + after deadlock was discovered. + + @param thd Current thread + + @retval False Success + @retval True Failure + + @note ha_rollback_low() which is indirectly called by this + function will mark XA transaction for rollback by + setting appropriate RM error status if there was + transaction rollback request. +*/ + +bool trans_rollback_implicit(THD *thd) +{ + int res; + DBUG_ENTER("trans_rollback_implict"); + + /* + Always commit/rollback statement transaction before manipulating + with the normal one. + Don't perform rollback in the middle of sub-statement, wait till + its end. + */ + DBUG_ASSERT(thd->transaction.stmt.is_empty() && !thd->in_sub_stmt); + + thd->server_status&= ~SERVER_STATUS_IN_TRANS; + DBUG_PRINT("info", ("clearing SERVER_STATUS_IN_TRANS")); + res= ha_rollback_trans(thd, true); + /* + We don't reset OPTION_BEGIN flag below to simulate implicit start + of new transacton in @@autocommit=1 mode. This is necessary to + preserve backward compatibility. + */ + thd->variables.option_bits&= ~(OPTION_KEEP_LOG); + thd->transaction.all.modified_non_trans_table= false; + + /* Rollback should clear transaction_rollback_request flag. */ + DBUG_ASSERT(! thd->transaction_rollback_request); + + DBUG_RETURN(test(res)); +} + + +/** Commit the single statement transaction. @note Note that if the autocommit is on, then the following call @@ -339,8 +385,6 @@ bool trans_rollback_stmt(THD *thd) if (thd->transaction.stmt.ha_list) { ha_rollback_trans(thd, FALSE); - if (thd->transaction_rollback_request && !thd->in_sub_stmt) - ha_rollback_trans(thd, TRUE); if (! thd->in_active_multi_stmt_transaction()) thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; } diff --git a/sql/transaction.h b/sql/transaction.h index e002cd4a9dc..abe7823cf9b 100644 --- a/sql/transaction.h +++ b/sql/transaction.h @@ -30,6 +30,7 @@ bool trans_begin(THD *thd, uint flags= 0); bool trans_commit(THD *thd); bool trans_commit_implicit(THD *thd); bool trans_rollback(THD *thd); +bool trans_rollback_implicit(THD *thd); bool trans_commit_stmt(THD *thd); bool trans_rollback_stmt(THD *thd); |