diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/ha_berkeley.cc | 2 | ||||
-rw-r--r-- | sql/ha_innodb.cc | 33 | ||||
-rw-r--r-- | sql/ha_myisam.cc | 1 | ||||
-rw-r--r-- | sql/item_func.cc | 9 | ||||
-rw-r--r-- | sql/lock.cc | 5 | ||||
-rw-r--r-- | sql/log_event.cc | 182 | ||||
-rw-r--r-- | sql/mf_iocache.cc | 6 | ||||
-rw-r--r-- | sql/mysql_priv.h | 7 | ||||
-rw-r--r-- | sql/mysqld.cc | 75 | ||||
-rw-r--r-- | sql/opt_range.cc | 10 | ||||
-rw-r--r-- | sql/repl_failsafe.cc | 10 | ||||
-rw-r--r-- | sql/set_var.cc | 44 | ||||
-rw-r--r-- | sql/set_var.h | 25 | ||||
-rw-r--r-- | sql/slave.cc | 31 | ||||
-rw-r--r-- | sql/slave.h | 49 | ||||
-rw-r--r-- | sql/sql_base.cc | 25 | ||||
-rw-r--r-- | sql/sql_cache.cc | 31 | ||||
-rw-r--r-- | sql/sql_cache.h | 1 | ||||
-rw-r--r-- | sql/sql_class.h | 2 | ||||
-rw-r--r-- | sql/sql_db.cc | 70 | ||||
-rw-r--r-- | sql/sql_delete.cc | 9 | ||||
-rw-r--r-- | sql/sql_handler.cc | 2 | ||||
-rw-r--r-- | sql/sql_insert.cc | 15 | ||||
-rw-r--r-- | sql/sql_list.h | 5 | ||||
-rw-r--r-- | sql/sql_parse.cc | 92 | ||||
-rw-r--r-- | sql/sql_select.cc | 23 | ||||
-rw-r--r-- | sql/sql_show.cc | 4 | ||||
-rw-r--r-- | sql/sql_table.cc | 1 | ||||
-rw-r--r-- | sql/sql_update.cc | 13 | ||||
-rw-r--r-- | sql/table.cc | 33 |
30 files changed, 546 insertions, 269 deletions
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index c056241fef8..70ecc61bfb8 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -1343,7 +1343,7 @@ int ha_berkeley::index_init(uint keynr) int ha_berkeley::index_end() { int error=0; - DBUG_ENTER("index_end"); + DBUG_ENTER("ha_berkely::index_end"); if (cursor) { DBUG_PRINT("enter",("table: '%s'", table->real_name)); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 078238fe78f..b1d74b2f223 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -981,19 +981,13 @@ innobase_commit_low( } #ifdef HAVE_REPLICATION - /* TODO: Guilhem should check if master_log_name, pending - etc. are right if the master log gets rotated! Possible bug here. - Comment by Heikki March 4, 2003. */ - if (current_thd->slave_thread) { /* Update the replication position info inside InnoDB */ trx->mysql_master_log_file_name = active_mi->rli.group_master_log_name; - trx->mysql_master_log_pos = ((ib_longlong) - (active_mi->rli.group_master_log_pos + - active_mi->rli.event_len - )); + trx->mysql_master_log_pos= ((ib_longlong) + active_mi->rli.future_group_master_log_pos); } #endif /* HAVE_REPLICATION */ @@ -2110,8 +2104,27 @@ ha_innobase::write_row( DBUG_ENTER("ha_innobase::write_row"); - ut_ad(prebuilt->trx == - (trx_t*) current_thd->transaction.all.innobase_tid); + if (prebuilt->trx != + (trx_t*) current_thd->transaction.all.innobase_tid) { + char err_buf[2000]; + + fprintf(stderr, +"InnoDB: Error: the transaction object for the table handle is at\n" +"InnoDB: %lx, but for the current thread it is at %lx\n", + (ulong)prebuilt->trx, + (ulong)current_thd->transaction.all.innobase_tid); + + ut_sprintf_buf(err_buf, ((byte*)prebuilt) - 100, 200); + fprintf(stderr, +"InnoDB: Dump of 200 bytes around prebuilt: %.1000s\n", err_buf); + + ut_sprintf_buf(err_buf, + ((byte*)(&(current_thd->transaction.all))) - 100, 200); + fprintf(stderr, +"InnoDB: Dump of 200 bytes around transaction.all: %.1000s\n", err_buf); + + ut_a(0); + } statistic_increment(ha_write_count, &LOCK_status); diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index a87054333cb..a2a5f040081 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -1362,6 +1362,7 @@ int ha_myisam::create(const char *name, register TABLE *table_arg, create_info.data_file_name= info->data_file_name; create_info.index_file_name=info->index_file_name; + /* TODO: Check that the following fn_format is really needed */ error=mi_create(fn_format(buff,name,"","",2+4), table_arg->keys,keydef, (uint) (recinfo_pos-recinfo), recinfo, diff --git a/sql/item_func.cc b/sql/item_func.cc index 99a429e48fb..0b7a222c312 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -901,7 +901,8 @@ longlong Item_func_ceiling::val_int() longlong Item_func_floor::val_int() { - double value=args[0]->val(); + // the volatile's for BUG #3051 to calm optimizer down (because of gcc's bug) + volatile double value=args[0]->val(); null_value=args[0]->null_value; return (longlong) floor(value); } @@ -1838,13 +1839,11 @@ longlong Item_master_pos_wait::val_int() longlong pos = (ulong)args[1]->val_int(); longlong timeout = (arg_count==3) ? args[2]->val_int() : 0 ; #ifdef HAVE_REPLICATION - LOCK_ACTIVE_MI; - if ((event_count = active_mi->rli.wait_for_pos(thd, log_name, pos, timeout)) == -2) - { + if ((event_count = active_mi->rli.wait_for_pos(thd, log_name, pos, timeout)) == -2) + { null_value = 1; event_count=0; } - UNLOCK_ACTIVE_MI; #endif return event_count; } diff --git a/sql/lock.cc b/sql/lock.cc index 67a085ff708..171c880db3e 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -498,11 +498,14 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list) char *db= table_list->db; uint key_length; DBUG_ENTER("lock_table_name"); + DBUG_PRINT("enter",("db: %s name: %s", db, table_list->real_name)); + safe_mutex_assert_owner(&LOCK_open); key_length=(uint) (strmov(strmov(key,db)+1,table_list->real_name) -key)+ 1; + /* Only insert the table if we haven't insert it already */ for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ; table ; @@ -534,6 +537,7 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list) DBUG_RETURN(0); } + void unlock_table_name(THD *thd, TABLE_LIST *table_list) { if (table_list->table) @@ -543,6 +547,7 @@ void unlock_table_name(THD *thd, TABLE_LIST *table_list) } } + static bool locked_named_table(THD *thd, TABLE_LIST *table_list) { for (; table_list ; table_list=table_list->next) diff --git a/sql/log_event.cc b/sql/log_event.cc index a128b5809b2..049ee5c5808 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -56,11 +56,21 @@ static void pretty_print_str(FILE* file, char* str, int len) #endif /* MYSQL_CLIENT */ +#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) + +static void clear_all_errors(THD *thd, struct st_relay_log_info *rli) +{ + thd->query_error = 0; + thd->clear_error(); + *rli->last_slave_error = 0; + rli->last_slave_errno = 0; +} + + /* - ignored_error_code() + Ignore error code specified on command line */ -#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) inline int ignored_error_code(int err_code) { return ((err_code == ER_SLAVE_IGNORED_TABLE) || @@ -843,7 +853,9 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, 0 : LOG_EVENT_THREAD_SPECIFIC_F, using_trans), data_buf(0), query(query_arg), db(thd_arg->db), q_len((uint32) query_length), - error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno), + error_code(thd_arg->killed ? + ((thd_arg->system_thread & SYSTEM_THREAD_DELAYED_INSERT) ? + 0 : ER_SERVER_SHUTDOWN) : thd_arg->net.last_errno), thread_id(thd_arg->thread_id), /* save the original thread id; we already know the server id */ slave_proxy_id(thd_arg->variables.pseudo_thread_id) @@ -944,17 +956,15 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) thd->db= (char*) rewrite_db(db); /* - InnoDB internally stores the master log position it has executed so far, - i.e. the position just after the COMMIT event. - When InnoDB will want to store, the positions in rli won't have - been updated yet, so group_master_log_* will point to old BEGIN - and event_master_log* will point to the beginning of current COMMIT. - So the position to store is event_master_log_pos + event_len - since we must store the pos of the END of the current log event (COMMIT). + InnoDB internally stores the master log position it has processed so far; + position to store is of the END of the current log event. */ - rli->event_len= get_event_len(); - thd->query_error= 0; // clear error - thd->clear_error(); +#if MYSQL_VERSION_ID < 50000 + rli->future_group_master_log_pos= log_pos + get_event_len(); +#else + rli->future_group_master_log_pos= log_pos; +#endif + clear_all_errors(thd, rli); if (db_ok(thd->db, replicate_do_db, replicate_ignore_db)) { @@ -966,75 +976,85 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) VOID(pthread_mutex_unlock(&LOCK_thread_count)); thd->variables.pseudo_thread_id= thread_id; // for temp tables - /* - Sanity check to make sure the master did not get a really bad - error on the query. - */ - if (ignored_error_code((expected_error = error_code)) || + mysql_log.write(thd,COM_QUERY,"%s",thd->query); + DBUG_PRINT("query",("%s",thd->query)); + if (ignored_error_code((expected_error= error_code)) || !check_expected_error(thd,rli,expected_error)) - { - mysql_log.write(thd,COM_QUERY,"%s",thd->query); - DBUG_PRINT("query",("%s",thd->query)); mysql_parse(thd, thd->query, q_len); - + else + { /* - If we expected a non-zero error code, and we don't get the same error - code, and none of them should be ignored. + The query got a really bad error on the master (thread killed etc), + which could be inconsistent. Parse it to test the table names: if the + replicate-*-do|ignore-table rules say "this query must be ignored" then + we exit gracefully; otherwise we warn about the bad error and tell DBA + to check/fix it. */ - DBUG_PRINT("info",("expected_error: %d last_errno: %d", - expected_error, thd->net.last_errno)); - if ((expected_error != (actual_error= thd->net.last_errno)) && - expected_error && - !ignored_error_code(actual_error) && - !ignored_error_code(expected_error)) + if (mysql_test_parse_for_slave(thd, thd->query, q_len)) + clear_all_errors(thd, rli); /* Can ignore query */ + else { - slave_print_error(rli, 0, + slave_print_error(rli,expected_error, "\ +Query '%s' partially completed on the master (error on master: %d) \ +and was aborted. There is a chance that your master is inconsistent at this \ +point. If you are sure that your master is ok, run this query manually on the \ +slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; \ +START SLAVE; .", thd->query, expected_error); + thd->query_error= 1; + } + goto end; + } + + /* + If we expected a non-zero error code, and we don't get the same error + code, and none of them should be ignored. + */ + DBUG_PRINT("info",("expected_error: %d last_errno: %d", + expected_error, thd->net.last_errno)); + if ((expected_error != (actual_error= thd->net.last_errno)) && + expected_error && + !ignored_error_code(actual_error) && + !ignored_error_code(expected_error)) + { + slave_print_error(rli, 0, + "\ Query '%s' caused different errors on master and slave. \ Error on master: '%s' (%d), Error on slave: '%s' (%d). \ Default database: '%s'", - query, - ER_SAFE(expected_error), - expected_error, - actual_error ? thd->net.last_error: "no error", - actual_error, - print_slave_db_safe(db)); - thd->query_error= 1; - } - /* - If we get the same error code as expected, or they should be ignored. - */ - else if (expected_error == actual_error || - ignored_error_code(actual_error)) - { - DBUG_PRINT("info",("error ignored")); - thd->query_error= 0; - thd->clear_error(); - *rli->last_slave_error = 0; - rli->last_slave_errno = 0; - } - /* - Other cases: mostly we expected no error and get one. - */ - else if (thd->query_error || thd->is_fatal_error) - { - slave_print_error(rli,actual_error, - "Error '%s' on query '%s'. Default database: '%s'", - (actual_error ? thd->net.last_error : - "unexpected success or fatal error"), - query, - print_slave_db_safe(db)); - thd->query_error= 1; - } - } - /* - End of sanity check. If the test was wrong, the query got a really bad - error on the master, which could be inconsistent, abort and tell DBA to - check/fix it. check_expected_error() already printed the message to - stderr and rli, and set thd->query_error to 1. + query, + ER_SAFE(expected_error), + expected_error, + actual_error ? thd->net.last_error: "no error", + actual_error, + print_slave_db_safe(db)); + thd->query_error= 1; + } + /* + If we get the same error code as expected, or they should be ignored. + */ + else if (expected_error == actual_error || + ignored_error_code(actual_error)) + { + DBUG_PRINT("info",("error ignored")); + clear_all_errors(thd, rli); + } + /* + Other cases: mostly we expected no error and get one. */ + else if (thd->query_error || thd->is_fatal_error) + { + slave_print_error(rli,actual_error, + "Error '%s' on query '%s'. Default database: '%s'", + (actual_error ? thd->net.last_error : + "unexpected success or fatal error"), + query, + print_slave_db_safe(db)); + thd->query_error= 1; + } } /* End of if (db_ok(... */ +end: VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->db= 0; // prevent db from being freed thd->query= 0; // just to be sure @@ -1165,7 +1185,7 @@ int Start_log_event::exec_event(struct st_relay_log_info* rli) { slave_print_error(rli, 0, "\ Rolling back unfinished transaction (no COMMIT or ROLLBACK) from relay log. \ -Probably cause is that the master died while writing the transaction to it's \ +A probable cause is that the master died while writing the transaction to its \ binary log."); return(1); } @@ -1643,7 +1663,15 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, DBUG_ASSERT(thd->query == 0); thd->query= 0; // Should not be needed thd->query_error= 0; - thd->clear_error(); + clear_all_errors(thd, rli); + if (!use_rli_only_for_errors) + { +#if MYSQL_VERSION_ID < 50000 + rli->future_group_master_log_pos= log_pos + get_event_len(); +#else + rli->future_group_master_log_pos= log_pos; +#endif + } /* We test replicate_*_db rules. Note that we have already prepared the file @@ -2638,7 +2666,7 @@ Create_file_log_event::Create_file_log_event(const char* buf, int len, We must make copy of 'buf' as this event may have to live over a rotate log entry when used in mysqlbinlog */ - if (!(event_buf= my_memdup(buf, len, MYF(MY_WME))) || + if (!(event_buf= my_memdup((byte*) buf, len, MYF(MY_WME))) || (copy_log_event(event_buf, len, old_format))) DBUG_VOID_RETURN; @@ -3103,6 +3131,14 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) lev->exec_event is the place where the table is loaded (it calls mysql_load()). */ + +#if MYSQL_VERSION_ID < 40100 + rli->future_master_log_pos= log_pos + get_event_len(); +#elif MYSQL_VERSION_ID < 50000 + rli->future_group_master_log_pos= log_pos + get_event_len(); +#else + rli->future_group_master_log_pos= log_pos; +#endif if (lev->exec_event(0,rli,1)) { /* diff --git a/sql/mf_iocache.cc b/sql/mf_iocache.cc index b7e2a803e42..71c8d588de7 100644 --- a/sql/mf_iocache.cc +++ b/sql/mf_iocache.cc @@ -30,14 +30,8 @@ flush_io_cache(). */ -#define MAP_TO_USE_RAID #include "mysql_priv.h" #ifdef HAVE_REPLICATION -#ifdef HAVE_AIOWAIT -#include <mysys_err.h> -#include <errno.h> -static void my_aiowait(my_aio_result *result); -#endif extern "C" { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 8f86d9990fe..8724a6ab077 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -407,6 +407,7 @@ int quick_rm_table(enum db_type base,const char *db, bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list); bool mysql_change_db(THD *thd,const char *name); void mysql_parse(THD *thd,char *inBuf,uint length); +bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length); bool is_update_query(enum enum_sql_command command); bool alloc_query(THD *thd, char *packet, ulong packet_length); void mysql_init_select(LEX *lex); @@ -432,7 +433,7 @@ bool check_stack_overrun(THD *thd,char *dummy); #define check_stack_overrun(A, B) 0 #endif -void table_cache_init(void); +bool table_cache_init(void); void table_cache_free(void); uint cached_tables(void); void kill_mysql(void); @@ -815,7 +816,7 @@ extern ulong ha_read_rnd_count, ha_read_rnd_next_count; extern ulong ha_commit_count, ha_rollback_count,table_cache_size; extern ulong max_connections,max_connect_errors, connect_timeout; extern ulong slave_net_timeout; -extern ulong max_insert_delayed_threads, max_user_connections; +extern ulong max_user_connections; extern ulong long_query_count, what_to_log,flush_time; extern ulong query_buff_size, thread_stack,thread_stack_min; extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit; @@ -838,7 +839,7 @@ extern uint volatile thread_count, thread_running, global_read_lock; extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types; extern my_bool opt_safe_show_db, opt_local_infile; extern my_bool opt_slave_compressed_protocol, use_temp_pool; -extern my_bool opt_readonly; +extern my_bool opt_readonly, lower_case_file_system; extern my_bool opt_enable_named_pipe, opt_sync_frm; extern my_bool opt_secure_auth; extern char *shared_memory_base_name, *mysqld_unix_port; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 786390efd6b..6d14e079eb6 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -247,6 +247,7 @@ arg_cmp_func Arg_comparator::comparator_matrix[4][2] = bool opt_log, opt_update_log, opt_bin_log, opt_slow_log; bool opt_error_log= IF_WIN(1,0); bool opt_disable_networking=0, opt_skip_show_db=0; +bool lower_case_table_names_used= 0; bool server_id_supplied = 0; bool opt_endinfo,using_udf_functions, locked_in_memory; bool opt_using_transactions, using_update_log; @@ -266,6 +267,7 @@ my_bool opt_sync_bdb_logs, opt_sync_frm; my_bool opt_secure_auth= 0; my_bool opt_short_log_format= 0; my_bool opt_log_queries_not_using_indexes= 0; +my_bool lower_case_file_system= 0; volatile bool mqh_used = 0; uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options; @@ -295,7 +297,7 @@ ulong select_range_check_count, select_range_count, select_scan_count; ulong select_full_range_join_count,select_full_join_count; ulong specialflag=0,opened_tables=0,created_tmp_tables=0, created_tmp_disk_tables=0; -ulong max_connections,max_insert_delayed_threads,max_used_connections, +ulong max_connections,max_used_connections, max_connect_errors, max_user_connections = 0; ulong thread_id=1L,current_pid; ulong slow_launch_threads = 0; @@ -1057,8 +1059,8 @@ static void set_user(const char *user) { /* Don't give a warning, if real user is same as given with --user */ struct passwd *user_info= getpwnam(user); - - if (!user_info || user_id != user_info->pw_uid) + if ((!user_info || user_id != user_info->pw_uid) && + global_system_variables.log_warnings) fprintf(stderr, "Warning: One can only use the --user switch if running as root\n"); } @@ -1195,7 +1197,7 @@ static void server_init(void) pipe_name[sizeof(pipe_name)-1]= 0; /* Safety if too long string */ strxnmov(pipe_name, sizeof(pipe_name)-1, "\\\\.\\pipe\\", - unix_socket, NullS); + mysql_unix_port, NullS); bzero((char*) &saPipeSecurity, sizeof(saPipeSecurity)); bzero((char*) &sdPipeDescriptor, sizeof(sdPipeDescriptor)); if (!InitializeSecurityDescriptor(&sdPipeDescriptor, @@ -1753,7 +1755,8 @@ extern "C" void *signal_hand(void *arg __attribute__((unused))) This should actually be '+ max_number_of_slaves' instead of +10, but the +10 should be quite safe. */ - init_thr_alarm(max_connections+max_insert_delayed_threads+10); + init_thr_alarm(max_connections + + global_system_variables.max_insert_delayed_threads + 10); #if SIGINT != THR_KILL_SIGNAL if (test_flags & TEST_SIGINT) { @@ -2132,10 +2135,11 @@ static int init_common_variables(const char *conf_file_name, int argc, DBUG_PRINT("warning", ("Changed limits: max_open_files: %u max_connections: %ld table_cache: %ld", files, max_connections, table_cache_size)); - sql_print_error("Warning: Changed limits: max_open_files: %u max_connections: %ld table_cache: %ld", + if (global_system_variables.log_warnings) + sql_print_error("Warning: Changed limits: max_open_files: %u max_connections: %ld table_cache: %ld", files, max_connections, table_cache_size); } - else + else if (global_system_variables.log_warnings) sql_print_error("Warning: Could not increase number of max_open_files to more than %u (request: %u)", files, wanted_files); } open_files_limit= files; @@ -2267,8 +2271,9 @@ static void init_ssl() static int init_server_components() { DBUG_ENTER("init_server_components"); - table_cache_init(); - hostname_cache_init(); + if (table_cache_init() || hostname_cache_init()) + unireg_abort(1); + query_cache_result_size_limit(query_cache_limit); query_cache_set_min_res_unit(query_cache_min_res_unit); query_cache_resize(query_cache_size); @@ -2349,7 +2354,8 @@ Now disabling --log-slave-updates."); { if (mlockall(MCL_CURRENT)) { - sql_print_error("Warning: Failed to lock memory. Errno: %d\n",errno); + if (global_system_variables.log_warnings) + sql_print_error("Warning: Failed to lock memory. Errno: %d\n",errno); } else locked_in_memory=1; @@ -2523,11 +2529,27 @@ int main(int argc, char **argv) insensitive names. If this is not done the users MyISAM tables will get corrupted if accesses with names of different case. */ + DBUG_PRINT("info", ("lower_case_table_names: %d", lower_case_table_names)); if (!lower_case_table_names && - test_if_case_insensitive(mysql_real_data_home) == 1) + (lower_case_file_system= + (test_if_case_insensitive(mysql_real_data_home) == 1))) { - sql_print_error("Warning: Setting lower_case_table_names=2 because file system for %s is case insensitive", mysql_real_data_home); - lower_case_table_names= 2; + if (lower_case_table_names_used) + { + if (global_system_variables.log_warnings) + sql_print_error("\ +Warning: You have forced lower_case_table_names to 0 through a command-line \ +option, even though your file system '%s' is case insensitive. This means \ +that you can corrupt a MyISAM table by accessing it with different cases. \ +You should consider changing lower_case_table_names to 1 or 2", + mysql_real_data_home); + } + else + { + if (global_system_variables.log_warnings) + sql_print_error("Warning: Setting lower_case_table_names=2 because file system for %s is case insensitive", mysql_real_data_home); + lower_case_table_names= 2; + } } select_thread=pthread_self(); @@ -3636,7 +3658,7 @@ enum options_mysqld OPT_OPEN_FILES_LIMIT, OPT_PRELOAD_BUFFER_SIZE, OPT_QUERY_CACHE_LIMIT, OPT_QUERY_CACHE_MIN_RES_UNIT, OPT_QUERY_CACHE_SIZE, - OPT_QUERY_CACHE_TYPE, OPT_RECORD_BUFFER, + OPT_QUERY_CACHE_TYPE, OPT_QUERY_CACHE_WLOCK_INVALIDATE, OPT_RECORD_BUFFER, OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT, OPT_RELAY_LOG_PURGE, OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME, OPT_READONLY, OPT_DEBUGGING, @@ -4217,11 +4239,11 @@ replicating a LOAD DATA INFILE command.", NO_ARG, 0, 0, 0, 0, 0, 0}, {"log-warnings", 'W', "Log some not critical warnings to the log file.", (gptr*) &global_system_variables.log_warnings, - (gptr*) &max_system_variables.log_warnings, 0, GET_BOOL, NO_ARG, 0, 0, 0, + (gptr*) &max_system_variables.log_warnings, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"warnings", 'W', "Deprecated ; Use --log-warnings instead.", (gptr*) &global_system_variables.log_warnings, - (gptr*) &max_system_variables.log_warnings, 0, GET_BOOL, NO_ARG, 0, 0, 0, + (gptr*) &max_system_variables.log_warnings, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, { "back_log", OPT_BACK_LOG, "The number of outstanding connection requests MySQL can have. This comes into play when the main MySQL thread gets very many connection requests in a very short time.", @@ -4417,7 +4439,8 @@ The minimum value for this variable is 4096.", REQUIRED_ARG, MAX_CONNECT_ERRORS, 1, ~0L, 0, 1, 0}, {"max_delayed_threads", OPT_MAX_DELAYED_THREADS, "Don't start more than this number of threads to handle INSERT DELAYED statements. If set to zero, which means INSERT DELAYED is not used.", - (gptr*) &max_insert_delayed_threads, (gptr*) &max_insert_delayed_threads, + (gptr*) &global_system_variables.max_insert_delayed_threads, + (gptr*) &max_system_variables.max_insert_delayed_threads, 0, GET_ULONG, REQUIRED_ARG, 20, 0, 16384, 0, 1, 0}, {"max_error_count", OPT_MAX_ERROR_COUNT, "Max number of errors/warnings to store for a statement.", @@ -4554,12 +4577,17 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.query_cache_type, (gptr*) &max_system_variables.query_cache_type, 0, GET_ULONG, REQUIRED_ARG, 1, 0, 2, 0, 1, 0}, + {"query_cache_wlock_invalidate", OPT_QUERY_CACHE_WLOCK_INVALIDATE, + "Invalidate queries in query cache on LOCK for write", + (gptr*) &global_system_variables.query_cache_wlock_invalidate, + (gptr*) &max_system_variables.query_cache_wlock_invalidate, + 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, +#endif /*HAVE_QUERY_CACHE*/ {"query_prealloc_size", OPT_QUERY_PREALLOC_SIZE, "Persistent buffer for query parsing and execution", (gptr*) &global_system_variables.query_prealloc_size, (gptr*) &max_system_variables.query_prealloc_size, 0, GET_ULONG, REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, 1024, ~0L, 0, 1024, 0}, -#endif /*HAVE_QUERY_CACHE*/ {"read_buffer_size", OPT_RECORD_BUFFER, "Each thread that does a sequential scan allocates a buffer of this size for each table it scans. If you do many sequential scans, you may want to increase this value.", (gptr*) &global_system_variables.read_buff_size, @@ -4619,8 +4647,8 @@ The minimum value for this variable is 4096.", 1, 0}, {"table_cache", OPT_TABLE_CACHE, "The number of open tables for all threads.", (gptr*) &table_cache_size, - (gptr*) &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, 64, 1, ~0L, 0, 1, - 0}, + (gptr*) &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, 64, 1, 512*1024L, + 0, 1, 0}, {"thread_concurrency", OPT_THREAD_CONCURRENCY, "Permits the application to give the threads system a hint for the desired number of threads that should be run at the same time.", (gptr*) &concurrency, (gptr*) &concurrency, 0, GET_ULONG, REQUIRED_ARG, @@ -5622,6 +5650,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case OPT_LOWER_CASE_TABLE_NAMES: lower_case_table_names= argument ? atoi(argument) : 1; + lower_case_table_names_used= 1; break; } return 0; @@ -5901,6 +5930,7 @@ static int test_if_case_insensitive(const char *dir_name) File file; char buff[FN_REFLEN], buff2[FN_REFLEN]; MY_STAT stat_info; + DBUG_ENTER("test_if_case_insensitive"); fn_format(buff, glob_hostname, dir_name, ".lower-test", MY_UNPACK_FILENAME | MY_REPLACE_EXT | MY_REPLACE_DIR); @@ -5910,13 +5940,14 @@ static int test_if_case_insensitive(const char *dir_name) if ((file= my_create(buff, 0666, O_RDWR, MYF(0))) < 0) { sql_print_error("Warning: Can't create test file %s", buff); - return -1; + DBUG_RETURN(-1); } my_close(file, MYF(0)); if (my_stat(buff2, &stat_info, MYF(0))) result= 1; // Can access file (void) my_delete(buff, MYF(MY_WME)); - return result; + DBUG_PRINT("exit", ("result: %d", result)); + DBUG_RETURN(result); } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 6f97a5afe94..47f7cdf83df 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2154,6 +2154,7 @@ static ulong count_key_part_usage(SEL_ARG *root, SEL_ARG *key) void SEL_ARG::test_use_count(SEL_ARG *root) { + uint e_count=0; if (this == root && use_count != 1) { sql_print_error("Note: Use_count: Wrong count %lu for root",use_count); @@ -2161,7 +2162,6 @@ void SEL_ARG::test_use_count(SEL_ARG *root) } if (this->type != SEL_ARG::KEY_RANGE) return; - uint e_count=0; for (SEL_ARG *pos=first(); pos ; pos=pos->next) { e_count++; @@ -2178,8 +2178,8 @@ void SEL_ARG::test_use_count(SEL_ARG *root) } } if (e_count != elements) - sql_print_error("Warning: Wrong use count: %u for tree at %lx", e_count, - (gptr) this); + sql_print_error("Warning: Wrong use count: %u (should be %u) for tree at %lx", + e_count, elements, (gptr) this); } #endif @@ -2445,9 +2445,9 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key, } /* Get range for retrieving rows in QUICK_SELECT::get_next */ - if (!(range= new QUICK_RANGE(param->min_key, + if (!(range= new QUICK_RANGE((const char *) param->min_key, (uint) (tmp_min_key - param->min_key), - param->max_key, + (const char *) param->max_key, (uint) (tmp_max_key - param->max_key), flag))) return 1; // out of memory diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index d125c95e839..6cd07e16647 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -768,7 +768,7 @@ int load_master_data(THD* thd) We do not want anyone messing with the slave at all for the entire duration of the data load. */ - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); lock_slave_threads(active_mi); init_thread_mask(&restart_thread_mask,active_mi,0 /*not inverse*/); if (restart_thread_mask && @@ -777,7 +777,7 @@ int load_master_data(THD* thd) { send_error(thd,error); unlock_slave_threads(active_mi); - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); return 1; } @@ -911,7 +911,7 @@ int load_master_data(THD* thd) strmake(active_mi->master_log_name, row[0], sizeof(active_mi->master_log_name)); active_mi->master_log_pos = strtoull(row[1], (char**) 0, 10); - // don't hit the magic number + /* don't hit the magic number */ if (active_mi->master_log_pos < BIN_LOG_HEADER_SIZE) active_mi->master_log_pos = BIN_LOG_HEADER_SIZE; /* @@ -938,7 +938,7 @@ int load_master_data(THD* thd) { send_error(thd, 0, "Failed purging old relay logs"); unlock_slave_threads(active_mi); - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); return 1; } pthread_mutex_lock(&active_mi->rli.data_lock); @@ -969,7 +969,7 @@ int load_master_data(THD* thd) err: unlock_slave_threads(active_mi); - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); thd->proc_info = 0; mysql_close(&mysql); // safe to call since we always do mysql_init() diff --git a/sql/set_var.cc b/sql/set_var.cc index 04fe2a8ea46..68991cdbfb0 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -196,8 +196,10 @@ sys_var_long_ptr sys_max_connections("max_connections", fix_max_connections); sys_var_long_ptr sys_max_connect_errors("max_connect_errors", &max_connect_errors); -sys_var_long_ptr sys_max_delayed_threads("max_delayed_threads", - &max_insert_delayed_threads, +sys_var_thd_ulong sys_max_insert_delayed_threads("max_insert_delayed_threads", + &SV::max_insert_delayed_threads); +sys_var_thd_ulong sys_max_delayed_threads("max_delayed_threads", + &SV::max_insert_delayed_threads, fix_max_connections); sys_var_thd_ulong sys_max_error_count("max_error_count", &SV::max_error_count); @@ -290,6 +292,9 @@ sys_var_long_ptr sys_query_cache_min_res_unit("query_cache_min_res_unit", sys_var_thd_enum sys_query_cache_type("query_cache_type", &SV::query_cache_type, &query_cache_type_typelib); +sys_var_thd_bool +sys_query_cache_wlock_invalidate("query_cache_wlock_invalidate", + &SV::query_cache_wlock_invalidate); #endif /* HAVE_QUERY_CACHE */ sys_var_bool_ptr sys_secure_auth("secure_auth", &opt_secure_auth); sys_var_long_ptr sys_server_id("server_id",&server_id); @@ -419,6 +424,18 @@ static sys_var_thd_ulong sys_default_week_format("default_week_format", sys_var_thd_ulong sys_group_concat_max_len("group_concat_max_len", &SV::group_concat_max_len); +static const char license[]= "GPL"; + +/* Read only variables */ + +sys_var_const_str sys_os("version_compile_os", SYSTEM_TYPE); +sys_var_const_str sys_license("license", license); + +/* Global read-only variable describing server license */ + + + + /* List of all variables for initialisation and storage in hash This is sorted in alphabetical order to make it easy to add new variables @@ -471,6 +488,7 @@ sys_var *sys_variables[]= &sys_key_cache_division_limit, &sys_key_cache_age_threshold, &sys_last_insert_id, + &sys_license, &sys_local_infile, &sys_log_binlog, &sys_log_off, @@ -485,6 +503,7 @@ sys_var *sys_variables[]= &sys_max_connections, &sys_max_delayed_threads, &sys_max_error_count, + &sys_max_insert_delayed_threads, &sys_max_heap_table_size, &sys_max_join_size, &sys_max_length_for_sort_data, @@ -514,6 +533,7 @@ sys_var *sys_variables[]= &sys_query_cache_limit, &sys_query_cache_min_res_unit, &sys_query_cache_type, + &sys_query_cache_wlock_invalidate, #endif /* HAVE_QUERY_CACHE */ &sys_quote_show_create, &sys_rand_seed1, @@ -552,6 +572,7 @@ sys_var *sys_variables[]= &sys_trans_alloc_block_size, &sys_trans_prealloc_size, &sys_tx_isolation, + &sys_os, #ifdef HAVE_INNOBASE_DB &sys_innodb_max_dirty_pages_pct, #endif @@ -652,7 +673,8 @@ struct show_var_st init_vars[]= { {sys_key_cache_division_limit.name, (char*) &sys_key_cache_division_limit, SHOW_SYS}, {"language", language, SHOW_CHAR}, - {"large_files_support", (char*) &opt_large_files, SHOW_BOOL}, + {"large_files_support", (char*) &opt_large_files, SHOW_BOOL}, + {sys_license.name, (char*) &sys_license, SHOW_SYS}, {sys_local_infile.name, (char*) &sys_local_infile, SHOW_SYS}, #ifdef HAVE_MLOCKALL {"locked_in_memory", (char*) &locked_in_memory, SHOW_BOOL}, @@ -668,6 +690,7 @@ struct show_var_st init_vars[]= { {sys_log_warnings.name, (char*) &sys_log_warnings, SHOW_SYS}, {sys_long_query_time.name, (char*) &sys_long_query_time, SHOW_SYS}, {sys_low_priority_updates.name, (char*) &sys_low_priority_updates, SHOW_SYS}, + {"lower_case_file_system", (char*) &lower_case_file_system, SHOW_BOOL}, {"lower_case_table_names", (char*) &lower_case_table_names, SHOW_INT}, {sys_max_allowed_packet.name,(char*) &sys_max_allowed_packet, SHOW_SYS}, {sys_max_binlog_cache_size.name,(char*) &sys_max_binlog_cache_size, SHOW_SYS}, @@ -675,6 +698,8 @@ struct show_var_st init_vars[]= { {sys_max_connect_errors.name, (char*) &sys_max_connect_errors, SHOW_SYS}, {sys_max_connections.name, (char*) &sys_max_connections, SHOW_SYS}, {sys_max_delayed_threads.name,(char*) &sys_max_delayed_threads, SHOW_SYS}, + {sys_max_insert_delayed_threads.name, + (char*) &sys_max_insert_delayed_threads, SHOW_SYS}, {sys_max_error_count.name, (char*) &sys_max_error_count, SHOW_SYS}, {sys_max_heap_table_size.name,(char*) &sys_max_heap_table_size, SHOW_SYS}, {sys_max_join_size.name, (char*) &sys_max_join_size, SHOW_SYS}, @@ -770,7 +795,7 @@ struct show_var_st init_vars[]= { #endif {"version_comment", (char*) MYSQL_COMPILATION_COMMENT, SHOW_CHAR}, {"version_compile_machine", (char*) MACHINE_TYPE, SHOW_CHAR}, - {"version_compile_os", (char*) SYSTEM_TYPE, SHOW_CHAR}, + {sys_os.name, (char*) &sys_os, SHOW_SYS}, {sys_net_wait_timeout.name, (char*) &sys_net_wait_timeout, SHOW_SYS}, {NullS, NullS, SHOW_LONG} }; @@ -1062,7 +1087,8 @@ static void fix_max_relay_log_size(THD *thd, enum_var_type type) static void fix_max_connections(THD *thd, enum_var_type type) { - resize_thr_alarm(max_connections + max_insert_delayed_threads + 10); + resize_thr_alarm(max_connections + + global_system_variables.max_insert_delayed_threads + 10); } @@ -2166,7 +2192,7 @@ bool sys_var_pseudo_thread_id::check(THD *thd, set_var *var) bool sys_var_slave_skip_counter::check(THD *thd, set_var *var) { int result= 0; - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); pthread_mutex_lock(&active_mi->rli.run_lock); if (active_mi->rli.slave_running) { @@ -2174,7 +2200,7 @@ bool sys_var_slave_skip_counter::check(THD *thd, set_var *var) result=1; } pthread_mutex_unlock(&active_mi->rli.run_lock); - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); var->save_result.ulong_value= (ulong) var->value->val_int(); return result; } @@ -2182,7 +2208,7 @@ bool sys_var_slave_skip_counter::check(THD *thd, set_var *var) bool sys_var_slave_skip_counter::update(THD *thd, set_var *var) { - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); pthread_mutex_lock(&active_mi->rli.run_lock); /* The following test should normally never be true as we test this @@ -2196,7 +2222,7 @@ bool sys_var_slave_skip_counter::update(THD *thd, set_var *var) pthread_mutex_unlock(&active_mi->rli.data_lock); } pthread_mutex_unlock(&active_mi->rli.run_lock); - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); return 0; } #endif /* HAVE_REPLICATION */ diff --git a/sql/set_var.h b/sql/set_var.h index 9087a3e023e..4c5d0a53657 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -163,6 +163,31 @@ public: }; +class sys_var_const_str :public sys_var +{ +public: + char *value; // Pointer to const value + sys_var_const_str(const char *name_arg, const char *value_arg) + :sys_var(name_arg), value((char*) value_arg) + {} + bool check(THD *thd, set_var *var) + { + return 1; + } + bool update(THD *thd, set_var *var) + { + return 1; + } + SHOW_TYPE type() { return SHOW_CHAR; } + byte *value_ptr(THD *thd, enum_var_type type) { return (byte*) value; } + bool check_update_type(Item_result type) + { + return 1; + } + bool check_default(enum_var_type type) { return 1; } +}; + + class sys_var_enum :public sys_var { uint *value; diff --git a/sql/slave.cc b/sql/slave.cc index e737febdd8a..37afe456ce3 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -35,7 +35,6 @@ typedef bool (*CHECK_KILLED_FUNC)(THD*,void*); volatile bool slave_sql_running = 0, slave_io_running = 0; char* slave_load_tmpdir = 0; MASTER_INFO *active_mi; -volatile int active_mi_in_use = 0; HASH replicate_do_table, replicate_ignore_table; DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table; bool do_table_inited = 0, ignore_table_inited = 0; @@ -138,8 +137,12 @@ int init_slave() { DBUG_ENTER("init_slave"); - /* This is called when mysqld starts */ - + /* + This is called when mysqld starts. Before client connections are + accepted. However bootstrap may conflict with us if it does START SLAVE. + So it's safer to take the lock. + */ + pthread_mutex_lock(&LOCK_active_mi); /* TODO: re-write this to interate through the list of files for multi-master @@ -184,9 +187,11 @@ int init_slave() goto err; } } + pthread_mutex_unlock(&LOCK_active_mi); DBUG_RETURN(0); err: + pthread_mutex_unlock(&LOCK_active_mi); DBUG_RETURN(1); } @@ -863,7 +868,14 @@ static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/) void end_slave() { - /* This is called when the server terminates, in close_connections(). */ + /* + This is called when the server terminates, in close_connections(). + It terminates slave threads. However, some CHANGE MASTER etc may still be + running presently. If a START SLAVE was in progress, the mutex lock below + will make us wait until slave threads have started, and START SLAVE + returns, then we terminate them here. + */ + pthread_mutex_lock(&LOCK_active_mi); if (active_mi) { /* @@ -884,6 +896,7 @@ void end_slave() delete active_mi; active_mi= 0; } + pthread_mutex_unlock(&LOCK_active_mi); } @@ -1821,9 +1834,9 @@ file '%s')", fname); mi->master_log_name, (ulong) mi->master_log_pos)); + mi->rli.mi = mi; if (init_relay_log_info(&mi->rli, slave_info_fname)) goto err; - mi->rli.mi = mi; mi->inited = 1; // now change cache READ -> WRITE - must do this before flush_master_info @@ -2585,13 +2598,6 @@ int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error) case ER_NET_ERROR_ON_WRITE: case ER_SERVER_SHUTDOWN: case ER_NEW_ABORTING_CONNECTION: - slave_print_error(rli,expected_error, - "query '%s' partially completed on the master \ -and was aborted. There is a chance that your master is inconsistent at this \ -point. If you are sure that your master is ok, run this query manually on the\ - slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;\ - SLAVE START; .", thd->query); - thd->query_error= 1; return 1; default: return 0; @@ -3841,6 +3847,7 @@ bool flush_relay_log_info(RELAY_LOG_INFO* rli) error=1; if (flush_io_cache(file)) error=1; + /* Flushing the relay log is done by the slave I/O thread */ return error; } diff --git a/sql/slave.h b/sql/slave.h index d92c44dd2ba..033831f8821 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -35,12 +35,19 @@ /* MUTEXES in replication: - LOCK_active_mi: this is meant for multimaster, when we can switch from a - master to another. It protects active_mi. We don't care of it for the moment, - as active_mi never moves (it's created at startup and deleted at shutdown, - and not changed: it always points to the same MASTER_INFO struct), because we - don't have multimaster. So for the moment, mi does not move, and mi->rli does - not either. + LOCK_active_mi: [note: this was originally meant for multimaster, to switch + from a master to another, to protect active_mi] It is used to SERIALIZE ALL + administrative commands of replication: START SLAVE, STOP SLAVE, CHANGE + MASTER, RESET SLAVE, end_slave() (when mysqld stops) [init_slave() does not + need it it's called early]. Any of these commands holds the mutex from the + start till the end. This thus protects us against a handful of deadlocks + (consider start_slave_thread() which, when starting the I/O thread, releases + mi->run_lock, keeps rli->run_lock, and tries to re-acquire mi->run_lock). + + Currently active_mi never moves (it's created at startup and deleted at + shutdown, and not changed: it always points to the same MASTER_INFO struct), + because we don't have multimaster. So for the moment, mi does not move, and + mi->rli does not either. In MASTER_INFO: run_lock, data_lock run_lock protects all information about the run state: slave_running, and the @@ -51,6 +58,9 @@ In RELAY_LOG_INFO: run_lock, data_lock see MASTER_INFO + Order of acquisition: if you want to have LOCK_active_mi and a run_lock, you + must acquire LOCK_active_mi first. + In MYSQL_LOG: LOCK_log, LOCK_index of the binlog and the relay log LOCK_log: when you write to it. LOCK_index: when you create/delete a binlog (so that you have to update the .index file). @@ -73,18 +83,6 @@ enum enum_binlog_formats { BINLOG_FORMAT_323_GEQ_57 }; /* - TODO: this needs to be redone, but for now it does not matter since - we do not have multi-master yet. -*/ - -#define LOCK_ACTIVE_MI { pthread_mutex_lock(&LOCK_active_mi); \ - ++active_mi_in_use; \ - pthread_mutex_unlock(&LOCK_active_mi);} - -#define UNLOCK_ACTIVE_MI { pthread_mutex_lock(&LOCK_active_mi); \ - --active_mi_in_use; \ - pthread_mutex_unlock(&LOCK_active_mi); } - /***************************************************************************** Replication SQL Thread @@ -206,12 +204,16 @@ typedef struct st_relay_log_info bool ignore_log_space_limit; /* - InnoDB internally stores the master log position it has processed - so far; the position to store is really the sum of - pos + pending + event_len here since we must store the pos of the - END of the current log event + When it commits, InnoDB internally stores the master log position it has + processed so far; the position to store is the one of the end of the + committing event (the COMMIT query event, or the event if in autocommit + mode). */ - int event_len; +#if MYSQL_VERSION_ID < 40100 + ulonglong future_master_log_pos; +#else + ulonglong future_group_master_log_pos; +#endif time_t last_master_timestamp; @@ -550,7 +552,6 @@ extern "C" pthread_handler_decl(handle_slave_io,arg); extern "C" pthread_handler_decl(handle_slave_sql,arg); extern bool volatile abort_loop; extern MASTER_INFO main_mi, *active_mi; /* active_mi for multi-master */ -extern volatile int active_mi_in_use; extern LIST master_list; extern HASH replicate_do_table, replicate_ignore_table; extern DYNAMIC_ARRAY replicate_wild_do_table, replicate_wild_ignore_table; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 37767c555e8..3ddbeacc5df 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -46,12 +46,12 @@ extern "C" byte *table_cache_key(const byte *record,uint *length, return (byte*) entry->table_cache_key; } -void table_cache_init(void) +bool table_cache_init(void) { - VOID(hash_init(&open_cache,&my_charset_bin, - table_cache_size+16,0,0,table_cache_key, - (hash_free_key) free_cache_entry,0)); mysql_rm_tmp_tables(); + return hash_init(&open_cache, &my_charset_bin, table_cache_size+16, + 0, 0,t able_cache_key, + (hash_free_key) free_cache_entry, 0) != 0; } void table_cache_free(void) @@ -520,6 +520,16 @@ void close_temporary_tables(THD *thd) /* The -1 is to remove last ',' */ thd->clear_error(); Query_log_event qinfo(thd, query, (ulong)(end-query)-1, 0); + /* + Imagine the thread had created a temp table, then was doing a SELECT, and + the SELECT was killed. Then it's not clever to mark the statement above as + "killed", because it's not really a statement updating data, and there + are 99.99% chances it will succeed on slave. + If a real update (one updating a persistent table) was killed on the + master, then this real update will be logged with error_code=killed, + rightfully causing the slave to stop. + */ + qinfo.error_code= 0; mysql_bin_log.write(&qinfo); } thd->temporary_tables=0; @@ -1762,7 +1772,11 @@ bool rm_temporary_table(enum db_type base, char *path) *fn_ext(path)='\0'; // remove extension handler *file=get_new_handler((TABLE*) 0, base); if (file && file->delete_table(path)) + { error=1; + sql_print_error("Warning: Could not remove tmp table: '%s', error: %d", + path, my_errno); + } delete file; DBUG_RETURN(error); } @@ -2596,7 +2610,8 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, if (table->db_stat) result=1; /* Kill delayed insert threads */ - if (in_use->system_thread && ! in_use->killed) + if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) && + ! in_use->killed) { in_use->killed=1; pthread_mutex_lock(&in_use->mysys_var->mutex); diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 7c31281c926..cce6306d9fc 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1158,6 +1158,37 @@ void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used) DBUG_VOID_RETURN; } + +/* + Invalidate locked for write + + SYNOPSIS + Query_cache::invalidate_locked_for_write() + tables_used - table list + + NOTE + can be used only for opened tables +*/ +void Query_cache::invalidate_locked_for_write(TABLE_LIST *tables_used) +{ + DBUG_ENTER("Query_cache::invalidate (changed table list)"); + if (query_cache_size > 0 && tables_used) + { + STRUCT_LOCK(&structure_guard_mutex); + if (query_cache_size > 0) + { + DUMP(this); + for (; tables_used; tables_used= tables_used->next) + { + if (tables_used->lock_type & (TL_WRITE_LOW_PRIORITY | TL_WRITE)) + invalidate_table(tables_used->table); + } + } + STRUCT_UNLOCK(&structure_guard_mutex); + } + DBUG_VOID_RETURN; +} + /* Remove all cached queries that uses the given table */ diff --git a/sql/sql_cache.h b/sql/sql_cache.h index ac4f465bf79..432c7659aa5 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -375,6 +375,7 @@ protected: void invalidate(THD* thd, TABLE_LIST *tables_used, my_bool using_transactions); void invalidate(CHANGED_TABLE_LIST *tables_used); + void invalidate_locked_for_write(TABLE_LIST *tables_used); void invalidate(THD* thd, TABLE *table, my_bool using_transactions); void invalidate(THD *thd, const char *key, uint32 key_length, my_bool using_transactions); diff --git a/sql/sql_class.h b/sql/sql_class.h index 33684f93d93..5000617fafe 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -351,6 +351,7 @@ struct system_variables ulong max_length_for_sort_data; ulong max_sort_length; ulong max_tmp_tables; + ulong max_insert_delayed_threads; ulong myisam_repair_threads; ulong myisam_sort_buff_size; ulong net_buffer_length; @@ -386,6 +387,7 @@ struct system_variables my_bool log_warnings; my_bool low_priority_updates; my_bool new_mode; + my_bool query_cache_wlock_invalidate; my_bool old_passwords; /* Only charset part of these variables is sensible */ diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 80669089fc4..eed6c741f1b 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -465,6 +465,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, idx++) { FILEINFO *file=dirp->dir_entry+idx; + char *extension; DBUG_PRINT("info",("Examining: %s", file->name)); /* Check if file is a raid directory */ @@ -474,61 +475,56 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, (file->name[1] >= 'a' && file->name[1] <= 'f')) && !file->name[2] && !level) { - char newpath[FN_REFLEN]; + char newpath[FN_REFLEN], *copy_of_path; MY_DIR *new_dirp; String *dir; + uint length; strxmov(newpath,org_path,"/",file->name,NullS); - unpack_filename(newpath,newpath); + length= unpack_filename(newpath,newpath); if ((new_dirp = my_dir(newpath,MYF(MY_DONT_SORT)))) { DBUG_PRINT("my",("New subdir found: %s", newpath)); if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1)) < 0) - { - my_dirend(dirp); - DBUG_RETURN(-1); - } - raid_dirs.push_back(dir=new (&thd->mem_root) - String(newpath, &my_charset_latin1)); - dir->copy(); + goto err; + if (!(copy_of_path= thd->memdup(newpath, length+1)) || + !(dir= new (&thd->mem_root) String(copy_of_path, length)) || + raid_dirs.push_back(dir)) + goto err; continue; } found_other_files++; continue; } - if (find_type(fn_ext(file->name),&deletable_extentions,1+2) <= 0) + extension= fn_ext(file->name); + if (find_type(extension, &deletable_extentions,1+2) <= 0) { - if (find_type(fn_ext(file->name),&known_extentions,1+2) <= 0) + if (find_type(extension, &known_extentions,1+2) <= 0) found_other_files++; continue; } - strxmov(filePath,org_path,"/",file->name,NullS); if (db && !my_strcasecmp(&my_charset_latin1, - fn_ext(file->name), reg_ext)) + extension, reg_ext)) { /* Drop the table nicely */ - *fn_ext(file->name)=0; // Remove extension + *extension= 0; // Remove extension TABLE_LIST *table_list=(TABLE_LIST*) thd->calloc(sizeof(*table_list)+ strlen(db)+strlen(file->name)+2); if (!table_list) - { - my_dirend(dirp); - DBUG_RETURN(-1); - } + goto err; table_list->db= (char*) (table_list+1); - strmov(table_list->real_name=strmov(table_list->db,db)+1, - file->name); + strmov(table_list->real_name= strmov(table_list->db,db)+1, file->name); + table_list->alias= table_list->real_name; // If lower_case_table_names=2 /* Link into list */ (*tot_list_next)= table_list; tot_list_next= &table_list->next; } else { - + strxmov(filePath, org_path, "/", file->name, NullS); if (my_delete_with_symlink(filePath,MYF(MY_WME))) { - my_dirend(dirp); - DBUG_RETURN(-1); + goto err; } deleted++; } @@ -538,18 +534,15 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, if (thd->killed || (tot_list && mysql_rm_table_part2_with_lock(thd, tot_list, 1, 0, 1))) + goto err; + + /* Remove RAID directories */ { - /* Free memory for allocated raid dirs */ + List_iterator<String> it(raid_dirs); + String *dir; while ((dir= it++)) - delete dir; - my_dirend(dirp); - DBUG_RETURN(-1); - } - while ((dir= it++)) - { - if (rmdir(dir->c_ptr()) < 0) - found_other_files++; - delete dir; + if (rmdir(dir->c_ptr()) < 0) + found_other_files++; } my_dirend(dirp); @@ -560,7 +553,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, if (!found_other_files) { char tmp_path[FN_REFLEN], *pos; - char *path=unpack_filename(tmp_path,org_path); + char *path= tmp_path; + unpack_filename(tmp_path,org_path); #ifdef HAVE_READLINK int error; @@ -597,6 +591,10 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, } } DBUG_RETURN(deleted); + +err: + my_dirend(dirp); + DBUG_RETURN(-1); } @@ -627,13 +625,13 @@ bool mysql_change_db(THD *thd, const char *name) HA_CREATE_INFO create; DBUG_ENTER("mysql_change_db"); - if (!dbname || !(db_length=strip_sp(dbname))) + if (!dbname || !(db_length= strlen(dbname))) { x_free(dbname); /* purecov: inspected */ send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */ } - if ((db_length > NAME_LEN) || check_db_name(dbname)) + if (check_db_name(dbname)) { net_printf(thd, ER_WRONG_DB_NAME, dbname); x_free(dbname); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index fe7d881a863..a2f2c4abae4 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -187,6 +187,8 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order, else table->file->unlock_row(); // Row failed selection, release lock on it } + if (thd->killed && !error) + error= 1; // Aborted thd->proc_info="end"; end_read_record(&info); free_io_cache(table); // Will not do any harm @@ -389,6 +391,7 @@ bool multi_delete::send_data(List<Item> &values) DBUG_RETURN(0); } + void multi_delete::send_error(uint errcode,const char *err) { DBUG_ENTER("multi_delete::send_error"); @@ -473,15 +476,13 @@ int multi_delete::do_deletes(bool from_send_error) if ((local_error=table->file->delete_row(table->record[0]))) { table->file->print_error(local_error,MYF(0)); - if (transactional_tables) - { - DBUG_RETURN(local_error); - } break; } deleted++; } end_read_record(&info); + if (thd->killed && !local_error) + local_error= 1; if (local_error == -1) // End of file local_error = 0; } diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index d0f241b3291..be2bdfe7c6e 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -35,7 +35,7 @@ But !!! do_command calls free_root at the end of every query and frees up all the sql_alloc'ed memory. It's harder to work around... - */ +*/ #define HANDLER_TABLES_HACK(thd) { \ TABLE *tmp=thd->open_tables; \ diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index ccb8296b929..1611256eb2c 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -150,7 +150,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, */ if ((lock_type == TL_WRITE_DELAYED && ((specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) || - thd->slave_thread || !max_insert_delayed_threads)) || + thd->slave_thread || !thd->variables.max_insert_delayed_threads)) || (lock_type == TL_WRITE_CONCURRENT_INSERT && duplic == DUP_REPLACE) || (duplic == DUP_UPDATE)) lock_type=TL_WRITE; @@ -749,7 +749,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) if (!(tmp=find_handler(thd,table_list))) { /* Don't create more than max_insert_delayed_threads */ - if (delayed_insert_threads >= max_insert_delayed_threads) + if (delayed_insert_threads >= thd->variables.max_insert_delayed_threads) DBUG_RETURN(0); thd->proc_info="Creating delayed handler"; pthread_mutex_lock(&LOCK_delayed_create); @@ -1330,8 +1330,15 @@ bool delayed_insert::handle_inserts(void) pthread_mutex_lock(&mutex); delete row; - /* Let READ clients do something once in a while */ - if (group_count++ == max_rows) + /* + Let READ clients do something once in a while + We should however not break in the middle of a multi-line insert + if we have binary logging enabled as we don't want other commands + on this table until all entries has been processed + */ + if (group_count++ >= max_rows && (row= rows.head()) && + (!(row->log_query & DELAYED_LOG_BIN && using_bin_log) || + row->query)) { group_count=0; if (stacked_inserts || tables_in_use) // Let these wait a while diff --git a/sql/sql_list.h b/sql/sql_list.h index 0bbc0f87944..22e9ed37386 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -357,6 +357,10 @@ class base_ilist first_link->unlink(); // Unlink from list return first_link; } + inline struct ilink *head() + { + return (first != &last) ? first : 0; + } friend class base_list_iterator; }; @@ -389,6 +393,7 @@ public: inline void append(T* a) { base_ilist::append(a); } inline void push_back(T* a) { base_ilist::push_back(a); } inline T* get() { return (T*) base_ilist::get(); } + inline T* head() { return (T*) base_ilist::head(); } #ifndef _lint friend class I_List_iterator<T>; #endif diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3100737aaa5..dd59bef1191 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -101,6 +101,7 @@ static void unlock_locked_tables(THD *thd) } } + static bool end_active_trans(THD *thd) { int error=0; @@ -116,6 +117,15 @@ static bool end_active_trans(THD *thd) } +inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) +{ + return (table_rules_on && tables && !tables_ok(thd,tables) && + ((thd->lex.sql_command != SQLCOM_DELETE_MULTI) || + !tables_ok(thd, + (TABLE_LIST *)thd->lex->auxilliary_table_list.first))); +} + + static HASH hash_user_connections; static int get_or_create_user_conn(THD *thd, const char *user, @@ -1537,8 +1547,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, statistic_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_status); // null test to handle EOM - if (!db || !strip_sp(db) || !(alias= thd->strdup(db)) || - check_db_name(db)) + if (!db || !(alias= thd->strdup(db)) || check_db_name(db)) { net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL"); break; @@ -1554,8 +1563,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, statistic_increment(com_stat[SQLCOM_DROP_DB],&LOCK_status); char *db=thd->strdup(packet), *alias; // null test to handle EOM - if (!db || !strip_sp(db) || !(alias= thd->strdup(db)) || - check_db_name(db)) + if (!db || !(alias= thd->strdup(db)) || check_db_name(db)) { net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL"); break; @@ -1833,9 +1841,7 @@ mysql_execute_command(THD *thd) Skip if we are in the slave thread, some table rules have been given and the table list says the query should not be replicated */ - if (table_rules_on && tables && !tables_ok(thd,tables) && - ((lex->sql_command != SQLCOM_DELETE_MULTI) || - !tables_ok(thd,(TABLE_LIST *)thd->lex->auxilliary_table_list.first))) + if (all_tables_not_ok(thd,tables)) { /* we warn the slave SQL thread */ my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); @@ -2075,9 +2081,9 @@ mysql_execute_command(THD *thd) { if (check_global_access(thd, SUPER_ACL)) goto error; - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); res = change_master(thd,active_mi); - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); break; } case SQLCOM_SHOW_SLAVE_STAT: @@ -2085,9 +2091,9 @@ mysql_execute_command(THD *thd) /* Accept one of two privileges */ if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) goto error; - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); res = show_master_info(thd,active_mi); - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); break; } case SQLCOM_SHOW_MASTER_STAT: @@ -2139,7 +2145,7 @@ mysql_execute_command(THD *thd) net_printf(thd,ER_WRONG_TABLE_NAME, tables->real_name); break; } - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); /* fetch_master_table will send the error to the client on failure. Give error if the table already exists. @@ -2149,7 +2155,7 @@ mysql_execute_command(THD *thd) { send_ok(thd); } - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); break; } #endif /* HAVE_REPLICATION */ @@ -2265,9 +2271,9 @@ mysql_execute_command(THD *thd) #ifdef HAVE_REPLICATION case SQLCOM_SLAVE_START: { - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); start_slave(thd,active_mi,1 /* net report*/); - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); break; } case SQLCOM_SLAVE_STOP: @@ -2290,9 +2296,9 @@ mysql_execute_command(THD *thd) break; } { - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); stop_slave(thd,active_mi,1/* net report*/); - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); break; } #endif /* HAVE_REPLICATION */ @@ -3003,8 +3009,12 @@ mysql_execute_command(THD *thd) goto error; thd->in_lock_tables=1; thd->options|= OPTION_TABLE_LOCK; - if (!(res=open_and_lock_tables(thd,tables))) + if (!(res= open_and_lock_tables(thd, tables))) { +#ifdef HAVE_QUERY_CACHE + if (thd->variables.query_cache_wlock_invalidate) + query_cache.invalidate_locked_for_write(tables); +#endif /*HAVE_QUERY_CACHE*/ thd->locked_tables=thd->lock; thd->lock=0; send_ok(thd); @@ -3016,8 +3026,7 @@ mysql_execute_command(THD *thd) case SQLCOM_CREATE_DB: { char *alias; - if (!strip_sp(lex->name) || !(alias=thd->strdup(lex->name)) || - check_db_name(lex->name)) + if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name)) { net_printf(thd,ER_WRONG_DB_NAME, lex->name); break; @@ -3047,8 +3056,7 @@ mysql_execute_command(THD *thd) case SQLCOM_DROP_DB: { char *alias; - if (!strip_sp(lex->name) || !(alias=thd->strdup(lex->name)) || - check_db_name(lex->name)) + if (!(alias=thd->strdup(lex->name)) || check_db_name(lex->name)) { net_printf(thd, ER_WRONG_DB_NAME, lex->name); break; @@ -3908,8 +3916,11 @@ void mysql_init_multi_delete(LEX *lex) } -void -mysql_parse(THD *thd, char *inBuf, uint length) +/* + When you modify mysql_parse(), you may need to mofify + mysql_test_parse_for_slave() in this same file. +*/ +void mysql_parse(THD *thd, char *inBuf, uint length) { DBUG_ENTER("mysql_parse"); @@ -3950,6 +3961,31 @@ mysql_parse(THD *thd, char *inBuf, uint length) DBUG_VOID_RETURN; } +/* + Usable by the replication SQL thread only: just parse a query to know if it + can be ignored because of replicate-*-table rules. + + RETURN VALUES + 0 cannot be ignored + 1 can be ignored +*/ + +bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length) +{ + LEX *lex; + bool error= 0; + + mysql_init_query(thd); + lex= lex_start(thd, (uchar*) inBuf, length); + if (!yyparse((void*) thd) && ! thd->is_fatal_error && + all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first)) + error= 1; /* Ignore question */ + free_items(thd->free_list); /* Free strings used by items */ + lex_end(lex); + + return error; +} + /***************************************************************************** ** Store field definition for create @@ -4593,9 +4629,9 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, if (purge_time >= 0) mysql_bin_log.purge_logs_before_date(purge_time); } - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); rotate_relay_log(active_mi); - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); #endif if (ha_flush_logs()) result=1; @@ -4656,10 +4692,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, if (options & REFRESH_SLAVE) { tmp_write_to_binlog= 0; - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); if (reset_slave(thd, active_mi)) result=1; - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); } #endif if (options & REFRESH_USER_RESOURCES) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 467c1295517..83157aa185c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2635,6 +2635,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, ha_rows rec; double tmp; THD *thd= join->thd; + if (thd->killed) // Abort + return; if (!rest_tables) { @@ -5452,13 +5454,22 @@ free_tmp_table(THD *thd, TABLE *entry) save_proc_info=thd->proc_info; thd->proc_info="removing tmp table"; free_blobs(entry); - if (entry->db_stat && entry->file) + if (entry->file) { - (void) entry->file->close(); + if (entry->db_stat) + { + (void) entry->file->close(); + } + /* + We can't call ha_delete_table here as the table may created in mixed case + here and we have to ensure that delete_table gets the table name in + the original case. + */ + if (!(test_flags & TEST_KEEP_TMP_TABLES) || entry->db_type == DB_TYPE_HEAP) + entry->file->delete_table(entry->real_name); delete entry->file; } - if (!(test_flags & TEST_KEEP_TMP_TABLES) || entry->db_type == DB_TYPE_HEAP) - (void) ha_delete_table(entry->db_type,entry->real_name); + /* free blobs */ for (Field **ptr=entry->field ; *ptr ; ptr++) (*ptr)->free(); @@ -5931,8 +5942,8 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) if (tab->on_expr && !table->null_row) { if ((table->null_row= test(tab->on_expr->val_int() == 0))) - empty_record(table); - } + mark_as_null_row(table); + } if (!table->null_row) table->maybe_null=0; DBUG_RETURN(0); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index ff4ff43519a..d68db2cb3bc 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1806,10 +1806,10 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, break; case SHOW_SLAVE_RUNNING: { - LOCK_ACTIVE_MI; + pthread_mutex_lock(&LOCK_active_mi); end= strmov(buff, (active_mi->slave_running && active_mi->rli.slave_running) ? "ON" : "OFF"); - UNLOCK_ACTIVE_MI; + pthread_mutex_unlock(&LOCK_active_mi); break; } #endif /* HAVE_REPLICATION */ diff --git a/sql/sql_table.cc b/sql/sql_table.cc index f49a73dbf2d..f4440f27945 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2628,6 +2628,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, VOID(pthread_mutex_unlock(&LOCK_open)); goto err; } + /* Data is copied. Now we rename the old table to a temp name, rename the new one to the old name, remove all entries from the old table diff --git a/sql/sql_update.cc b/sql/sql_update.cc index f0491bc37d1..ef953eb734d 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -261,6 +261,8 @@ int mysql_update(THD *thd, } } } + if (thd->killed && !error) + error= 1; // Aborted limit= tmp_limit; end_read_record(&info); /* Change select to use tempfile */ @@ -333,6 +335,8 @@ int mysql_update(THD *thd, table->file->unlock_row(); thd->row_count++; } + if (thd->killed && !error) + error= 1; // Aborted end_read_record(&info); free_io_cache(table); // If ORDER BY thd->proc_info="end"; @@ -937,14 +941,16 @@ int multi_update::do_updates(bool from_send_error) DBUG_RETURN(0); for (cur_table= update_tables; cur_table ; cur_table= cur_table->next) { + byte *ref_pos; + TABLE *tmp_table; + table = cur_table->table; if (table == table_to_update) continue; // Already updated - org_updated= updated; - byte *ref_pos; - TABLE *tmp_table= tmp_tables[cur_table->shared]; + tmp_table= tmp_tables[cur_table->shared]; tmp_table->file->extra(HA_EXTRA_CACHE); // Change to read cache + (void) table->file->rnd_init(0); table->file->extra(HA_EXTRA_NO_CACHE); /* @@ -1011,6 +1017,7 @@ int multi_update::do_updates(bool from_send_error) else trans_safe= 0; // Can't do safe rollback } + (void) table->file->rnd_end(); } DBUG_RETURN(0); diff --git a/sql/table.cc b/sql/table.cc index d9f832cf8bb..526810de74a 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -701,8 +701,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, if (db_stat) { int err; + unpack_filename(index_file,index_file); if ((err=(outparam->file-> - ha_open(unpack_filename(index_file,index_file), + ha_open(index_file, (db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR), (db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE : ((db_stat & HA_WAIT_IF_LOCKED) || @@ -1283,7 +1284,9 @@ char *get_field(MEM_ROOT *mem, Field *field) bool check_db_name(char *name) { - char *start=name; + char *start=name; + /* Used to catch empty names and names with end space */ + bool last_char_is_space= TRUE; if (lower_case_table_names) my_casedn_str(files_charset_info, name); @@ -1291,6 +1294,7 @@ bool check_db_name(char *name) while (*name) { #if defined(USE_MB) && defined(USE_MB_IDENT) + last_char_is_space= my_isspace(default_charset_info, *name); if (use_mb(system_charset_info)) { int len=my_ismbchar(system_charset_info, name, @@ -1301,19 +1305,22 @@ bool check_db_name(char *name) continue; } } +#else + last_char_is_space= *name==' '; #endif if (*name == '/' || *name == '\\' || *name == FN_LIBCHAR || *name == FN_EXTCHAR) return 1; name++; } - return (uint) (name - start) > NAME_LEN || name == start; + return last_char_is_space || (uint) (name - start) > NAME_LEN; } /* Allow anything as a table name, as long as it doesn't contain an a '/', or a '.' character + or ' ' at the end returns 1 on error */ @@ -1323,10 +1330,17 @@ bool check_table_name(const char *name, uint length) const char *end= name+length; if (!length || length > NAME_LEN) return 1; +#if defined(USE_MB) && defined(USE_MB_IDENT) + bool last_char_is_space= FALSE; +#else + if (name[length-1]==' ') + return 1; +#endif while (name != end) { #if defined(USE_MB) && defined(USE_MB_IDENT) + last_char_is_space= my_isspace(default_charset_info, *name); if (use_mb(system_charset_info)) { int len=my_ismbchar(system_charset_info, name, end); @@ -1341,16 +1355,23 @@ bool check_table_name(const char *name, uint length) return 1; name++; } +#if defined(USE_MB) && defined(USE_MB_IDENT) + return last_char_is_space; +#else return 0; +#endif } + bool check_column_name(const char *name) { const char *start= name; - + bool last_char_is_space= TRUE; + while (*name) { #if defined(USE_MB) && defined(USE_MB_IDENT) + last_char_is_space= my_isspace(default_charset_info, *name); if (use_mb(system_charset_info)) { int len=my_ismbchar(system_charset_info, name, @@ -1361,13 +1382,15 @@ bool check_column_name(const char *name) continue; } } +#else + last_char_is_space= *name==' '; #endif if (*name == NAMES_SEP_CHAR) return 1; name++; } /* Error if empty or too long column name */ - return (name == start || (uint) (name - start) > NAME_LEN); + return last_char_is_space || (uint) (name - start) > NAME_LEN; } /* |