From 46ca22b093406d566d8f108f55111fc70b49af80 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Mon, 9 Nov 2009 17:36:13 +0000 Subject: BUG#48357: SHOW BINLOG EVENTS: Wrong offset or I/O error In function log_event.cc:Query_log_event::write, there was a cast that was triggering undefined behavior. The offending cast is the following: write_str_with_code_and_len((char **)(&start), catalog, catalog_len, Q_CATALOG_NZ_CODE); This results in calling write_str_with_code_and_len with first argument pointing to a (char **) while "start" is itself a pointer to uchar (uchar *). Inside write_str_with_..., the content of start is then be updated: (*dst)+= len; The instruction above would cause the (*dst) pointer (ie, the "start" argument, from the caller point of view, and which actually points to uchar instead of pointing to char) to be updated so that it would increment catalog_len. However, this seems to break strict-aliasing rules ultimately causing the increment and assignment to behave unexpectedly. We fix this by removing the cast and by making the types match. --- sql/log_event.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index 2cb253c9c56..9a3c6537b9e 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2138,8 +2138,8 @@ void Query_log_event::pack_info(Protocol *protocol) /** Utility function for the next method (Query_log_event::write()) . */ -static void write_str_with_code_and_len(char **dst, const char *src, - int len, uint code) +static void write_str_with_code_and_len(uchar **dst, const char *src, + uint len, uint code) { /* only 1 byte to store the length of catalog, so it should not @@ -2234,7 +2234,7 @@ bool Query_log_event::write(IO_CACHE* file) } if (catalog_len) // i.e. this var is inited (false for 4.0 events) { - write_str_with_code_and_len((char **)(&start), + write_str_with_code_and_len(&start, catalog, catalog_len, Q_CATALOG_NZ_CODE); /* In 5.0.x where x<4 masters we used to store the end zero here. This was @@ -2272,7 +2272,7 @@ bool Query_log_event::write(IO_CACHE* file) { /* In the TZ sys table, column Name is of length 64 so this should be ok */ DBUG_ASSERT(time_zone_len <= MAX_TIME_ZONE_NAME_LENGTH); - write_str_with_code_and_len((char **)(&start), + write_str_with_code_and_len(&start, time_zone_str, time_zone_len, Q_TIME_ZONE_CODE); } if (lc_time_names_number) -- cgit v1.2.1 From dfe177aa227c0bbdb4beb844ab7f62ca4e6106b6 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Tue, 24 Nov 2009 20:04:02 +0000 Subject: BUG#48340: rpl_cross_version: Found warnings/errors in server log file! Valgrind reports a conditional jump that depends on uninitialized data while doing a LOAD DATA and for this test case only. This test case, tests that loading data from a 4.0 or 4.1 instance into a 5.1 instance is working. As such it handles old binary log with a different set of events than currently 5.1 codebase uses. See the following reference for details: http://forge.mysql.com/wiki/MySQL_Internals_Binary_Log#LOAD_DATA_INFILE_Events Problem: The server is handling an Execute_load_log_event, which results in reading a Load_log_event from the binary log and applying it. When applying the Load_log_event, some variable setup is done and then mysql_load is called. Late in mysql_load execution, if not in row mode logging, the event is binlogged write_execute_load_query_log_event. In write_execute_load_query_log_event, thd->lex->local_file is inspected. The problem is that it has not been set before in the execution stack. This causes valgrind to report the warning. Fix: We fix this by initializing thd->lex->local_file to be the same as the value of Load_log_event::local_fname, when lex_start is called inside Load_log_event::do_apply_event. --- sql/log_event.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index 2cb253c9c56..73580636b7b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4510,6 +4510,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, as the present method does not call mysql_parse(). */ lex_start(thd); + thd->lex->local_file= local_fname; mysql_reset_thd_for_next_command(thd); if (!use_rli_only_for_errors) -- cgit v1.2.1 From 7853f553be39b2e3470fd72bf60b4b814dea63f0 Mon Sep 17 00:00:00 2001 From: Evgeny Potemkin Date: Tue, 1 Dec 2009 21:28:45 +0300 Subject: Bug#48508: Crash on prepared statement re-execution. Actually there is two different bugs. The first one caused crash on queries with WHERE condition over views containing WHERE condition. A wrong check for prepared statement phase led to items for view fields being allocated in the execution memory and freed at the end of execution. Thus the optimized WHERE condition refers to unallocated memory on the second execution and server crashed. The second one caused by the Item_cond::compile function not saving changes it made to the item tree. Thus on the next execution changes weren't reverted and server crashed on dereferencing of unallocated space. The new helper function called is_stmt_prepare_or_first_stmt_execute is added to the Query_arena class. The find_field_in_view function now uses is_stmt_prepare_or_first_stmt_execute() to check whether newly created view items should be freed at the end of the query execution. The Item_cond::compile function now saves changes it makes to item tree. mysql-test/r/ps.result: Added a test case for the bug#48508. mysql-test/t/ps.test: Added a test case for the bug#48508. sql/item_cmpfunc.cc: Bug#48508: Crash on prepared statement re-execution. The Item_cond::compile function now saves changes it makes to item tree. sql/sql_base.cc: Bug#48508: Crash on prepared statement re-execution. The find_field_in_view function now uses is_stmt_prepare_or_first_stmt_execute() to check whether newly created view items should be freed at the end of the query execution. sql/sql_class.h: Bug#48508: Crash on prepared statement re-execution. The Query_arena::is_stmt_prepare_or_first_sp_execute function now correctly do its check. --- sql/item_cmpfunc.cc | 2 +- sql/sql_base.cc | 3 ++- sql/sql_class.h | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 8c655cdc369..d03c68b3560 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3907,7 +3907,7 @@ Item *Item_cond::compile(Item_analyzer analyzer, byte **arg_p, byte *arg_v= *arg_p; Item *new_item= item->compile(analyzer, &arg_v, transformer, arg_t); if (new_item && new_item != item) - li.replace(new_item); + current_thd->change_item_tree(li.ref(), new_item); } return Item_func::transform(transformer, arg_t); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 178c3e12e23..88d1e8879d1 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3481,7 +3481,8 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, if (!my_strcasecmp(system_charset_info, field_it.name(), name)) { // in PS use own arena or data will be freed after prepare - if (register_tree_change && thd->stmt_arena->is_stmt_prepare_or_first_sp_execute()) + if (register_tree_change && + thd->stmt_arena->is_stmt_prepare_or_first_stmt_execute()) arena= thd->activate_stmt_arena_if_needed(&backup); /* create_item() may, or may not create a new Item, depending on diff --git a/sql/sql_class.h b/sql/sql_class.h index b41a5d5c6b7..ac058bca4f9 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -759,6 +759,8 @@ public: { return state == INITIALIZED_FOR_SP; } inline bool is_stmt_prepare_or_first_sp_execute() const { return (int)state < (int)PREPARED; } + inline bool is_stmt_prepare_or_first_stmt_execute() const + { return (int)state <= (int)PREPARED; } inline bool is_first_stmt_execute() const { return state == PREPARED; } inline bool is_stmt_execute() const { return state == PREPARED || state == EXECUTED; } -- cgit v1.2.1 From d7abca9ac38fc36eb3ff7f96409c0cabe5f5c03e Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 2 Dec 2009 15:17:08 +0400 Subject: Bug#48766 SHOW CREATE FUNCTION returns extra data in return clause Problem: SHOW CREATE FUNCTION and SELECT DTD_IDENTIFIER FROM I_S.ROUTINES returned wrong values in case of ENUM return data type and UCS2 character set. Fix: the string to collect returned data type was incorrectly set to "binary" character set, therefore UCS2 values where returned with extra '\0' characters. Setting string character set to creation_ctx->get_client_cs() in sp_find_routine(), and to system_charset_info in sp_create_routine fixes the problem. Adding tests: - the original test with Latin letters - an extra test with non-Latin letters --- sql/sp.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql') diff --git a/sql/sp.cc b/sql/sp.cc index d3c5dfb96d0..6fad1d70ffd 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -900,6 +900,7 @@ sp_create_routine(THD *thd, int type, sp_head *sp) DBUG_PRINT("enter", ("type: %d name: %.*s",type, (int) sp->m_name.length, sp->m_name.str)); String retstr(64); + retstr.set_charset(system_charset_info); DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE || type == TYPE_ENUM_FUNCTION); @@ -1403,6 +1404,7 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp, 64 -- size of "returns" column of mysql.proc. */ String retstr(64); + retstr.set_charset(sp->get_creation_ctx()->get_client_cs()); DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp)); if (sp->m_first_free_instance) -- cgit v1.2.1 From 7622134333ef91e5e88e981288aaf09f7202d54a Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 3 Dec 2009 13:22:34 +0400 Subject: Bug#44131 Binary-mode "order by" returns records in incorrect order for UTF-8 strings Problem: Item_char_typecast reported wrong max_length when casting to BINARY, which lead, in particular, in wrong "ORDER BY BINARY(char_column)" results. Fix: making Item_char_typecast report correct max_length. @ mysql-test/r/ctype_utf16.result Fixing old incorrect test result. @ mysql-test/r/ctype_utf32.result Fixing old incorrect test result. @ mysql-test/r/ctype_utf8.result Adding new test @ mysql-test/t/ctype_utf8.test Adding new test @ sql/item_timefunc.cc Making Item_char_typecast report correct max_length when cast is done to BINARY. --- sql/item_timefunc.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index b293145cc27..ded4d28ca29 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2554,9 +2554,9 @@ void Item_char_typecast::fix_length_and_dec() from_cs != &my_charset_bin && cast_cs != &my_charset_bin); collation.set(cast_cs, DERIVATION_IMPLICIT); - char_length= (cast_length >= 0) ? - cast_length : - args[0]->max_length / args[0]->collation.collation->mbmaxlen; + char_length= (cast_length >= 0) ? cast_length : + args[0]->max_length / + (cast_cs == &my_charset_bin ? 1 : args[0]->collation.collation->mbmaxlen); max_length= char_length * cast_cs->mbmaxlen; } -- cgit v1.2.1 From 9091535c5fc914aecaa51acf6e558ccd9800fd88 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 3 Dec 2009 14:07:46 +0200 Subject: Bug #48985: show create table crashes if previous access to the table was killed When checking for an error after removing the special view error handler the code was not taking into account that open_tables() may fail because of the current statement being killed. Added a check for thd->killed. Added a client program to test it. --- sql/sql_show.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 2c1f360104b..e55000c0f65 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -719,7 +719,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) thd->push_internal_handler(&view_error_suppressor); bool error= open_normal_and_derived_tables(thd, table_list, 0); thd->pop_internal_handler(); - if (error && thd->main_da.is_error()) + if (error && (thd->killed || thd->main_da.is_error())) DBUG_RETURN(TRUE); } -- cgit v1.2.1 From a4c50983f4bb06209969421dc044bfbc2932f025 Mon Sep 17 00:00:00 2001 From: Alfranio Correia Date: Fri, 4 Dec 2009 14:40:42 +0000 Subject: BUG#45292 orphan binary log created when starting server twice This patch fixes three bugs as follows. First, aborting the server while purging binary logs might generate orphan files due to how the purge operation was implemented: (purge routine - sql/log.cc - MYSQL_BIN_LOG::purge_logs) 1 - register the files to be removed in a temporary buffer. 2 - update the log-bin.index. 3 - flush the log-bin.index. 4 - erase the files whose names where register in the temporary buffer in step 1. Thus a failure while executing step 4 would generate an orphan file. Second, a similar issue might happen while creating a new binary as follows: (create routine - sql/log.cc - MYSQL_BIN_LOG::open) 1 - open the new log-bin. 2 - update the log-bin.index. Thus a failure while executing step 1 would generate an orphan file. To fix these issues, we record the files to be purged or created before really removing or adding them. So if a failure happens such records can be used to automatically remove dangling files. The new steps might be outlined as follows: (purge routine - sql/log.cc - MYSQL_BIN_LOG::purge_logs) 1 - register the files to be removed in the log-bin.~rec~ placed in the data directory. 2 - update the log-bin.index. 3 - flush the log-bin.index. 4 - delete the log-bin.~rec~. (create routine - sql/log.cc - MYSQL_BIN_LOG::open) 1 - register the file to be created in the log-bin.~rec~ placed in the data directory. 2 - open the new log-bin. 3 - update the log-bin.index. 4 - delete the log-bin.~rec~. (recovery routine - sql/log.cc - MYSQL_BIN_LOG::open_index_file) 1 - open the log-bin.index. 2 - open the log-bin.~rec~. 3 - for each file in log-bin.~rec~. 3.1 Check if the file is in the log-bin.index and if so ignore it. 3.2 Otherwise, delete it. The third issue can be described as follows. The purge operation was allowing to remove a file in use thus leading to the loss of data and possible inconsistencies between the master and slave. Roughly, the routine was only taking into account the dump threads and so if a slave was not connect the file might be delete even though it was in use. --- sql/log.cc | 434 ++++++++++++++++++++++++++++++++++++++++++--------------- sql/log.h | 26 +++- sql/mysqld.cc | 4 +- sql/rpl_rli.cc | 4 +- 4 files changed, 349 insertions(+), 119 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index b4c9e5eb4cc..f795cdab2ca 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1897,6 +1897,22 @@ void MYSQL_LOG::init(enum_log_type log_type_arg, } +bool MYSQL_LOG::init_and_set_log_file_name(const char *log_name, + const char *new_name, + enum_log_type log_type_arg, + enum cache_type io_cache_type_arg) +{ + init(log_type_arg, io_cache_type_arg); + + if (new_name && !strmov(log_file_name, new_name)) + return TRUE; + else if (!new_name && generate_new_name(log_file_name, log_name)) + return TRUE; + + return FALSE; +} + + /* Open a (new) log file. @@ -1929,17 +1945,14 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, write_error= 0; - init(log_type_arg, io_cache_type_arg); - if (!(name= my_strdup(log_name, MYF(MY_WME)))) { name= (char *)log_name; // for the error message goto err; } - if (new_name) - strmov(log_file_name, new_name); - else if (generate_new_name(log_file_name, name)) + if (init_and_set_log_file_name(name, new_name, + log_type_arg, io_cache_type_arg)) goto err; if (io_cache_type == SEQ_READ_APPEND) @@ -2429,7 +2442,7 @@ MYSQL_BIN_LOG::MYSQL_BIN_LOG() */ index_file_name[0] = 0; bzero((char*) &index_file, sizeof(index_file)); - bzero((char*) &purge_temp, sizeof(purge_temp)); + bzero((char*) &purge_index_file, sizeof(purge_index_file)); } /* this is called only once */ @@ -2473,7 +2486,7 @@ void MYSQL_BIN_LOG::init_pthread_objects() bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg, - const char *log_name) + const char *log_name, bool need_mutex) { File index_file_nr= -1; DBUG_ASSERT(!my_b_inited(&index_file)); @@ -2498,7 +2511,8 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg, init_io_cache(&index_file, index_file_nr, IO_SIZE, WRITE_CACHE, my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)), - 0, MYF(MY_WME | MY_WAIT_IF_FULL))) + 0, MYF(MY_WME | MY_WAIT_IF_FULL)) || + DBUG_EVALUATE_IF("fault_injection_openning_index", 1, 0)) { /* TODO: all operations creating/deleting the index file or a log, should @@ -2509,6 +2523,28 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg, my_close(index_file_nr,MYF(0)); return TRUE; } + +#ifdef HAVE_REPLICATION + /* + Sync the index by purging any binary log file that is not registered. + In other words, either purge binary log files that were removed from + the index but not purged from the file system due to a crash or purge + any binary log file that was created but not register in the index + due to a crash. + */ + + if (set_purge_index_file_name(index_file_name_arg) || + open_purge_index_file(FALSE) || + purge_index_entry(NULL, NULL, need_mutex) || + close_purge_index_file() || + DBUG_EVALUATE_IF("fault_injection_recovering_index", 1, 0)) + { + sql_print_error("MYSQL_BIN_LOG::open_index_file failed to sync the index " + "file."); + return TRUE; + } +#endif + return FALSE; } @@ -2533,17 +2569,44 @@ bool MYSQL_BIN_LOG::open(const char *log_name, enum cache_type io_cache_type_arg, bool no_auto_events_arg, ulong max_size_arg, - bool null_created_arg) + bool null_created_arg, + bool need_mutex) { File file= -1; + DBUG_ENTER("MYSQL_BIN_LOG::open"); DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg)); - write_error=0; + if (init_and_set_log_file_name(log_name, new_name, log_type_arg, + io_cache_type_arg)) + { + sql_print_error("MSYQL_BIN_LOG::open failed to generate new file name."); + DBUG_RETURN(1); + } + +#ifdef HAVE_REPLICATION + if (open_purge_index_file(TRUE) || + register_create_index_entry(log_file_name) || + sync_purge_index_file() || + DBUG_EVALUATE_IF("fault_injection_registering_index", 1, 0)) + { + sql_print_error("MSYQL_BIN_LOG::open failed to sync the index file."); + DBUG_RETURN(1); + } + DBUG_EXECUTE_IF("crash_create_non_critical_before_update_index", abort();); +#endif + + write_error= 0; /* open the main log file */ - if (MYSQL_LOG::open(log_name, log_type_arg, new_name, io_cache_type_arg)) + if (MYSQL_LOG::open(log_name, log_type_arg, new_name, + io_cache_type_arg)) + { +#ifdef HAVE_REPLICATION + close_purge_index_file(); +#endif DBUG_RETURN(1); /* all warnings issued */ + } init(no_auto_events_arg, max_size_arg); @@ -2569,9 +2632,6 @@ bool MYSQL_BIN_LOG::open(const char *log_name, write_file_name_to_index_file= 1; } - DBUG_ASSERT(my_b_inited(&index_file) != 0); - reinit_io_cache(&index_file, WRITE_CACHE, - my_b_filelength(&index_file), 0, 0); if (need_start_event && !no_auto_events) { /* @@ -2629,23 +2689,44 @@ bool MYSQL_BIN_LOG::open(const char *log_name, if (write_file_name_to_index_file) { +#ifdef HAVE_REPLICATION + DBUG_EXECUTE_IF("crash_create_critical_before_update_index", abort();); +#endif + + DBUG_ASSERT(my_b_inited(&index_file) != 0); + reinit_io_cache(&index_file, WRITE_CACHE, + my_b_filelength(&index_file), 0, 0); /* As this is a new log file, we write the file name to the index file. As every time we write to the index file, we sync it. */ - if (my_b_write(&index_file, (uchar*) log_file_name, - strlen(log_file_name)) || - my_b_write(&index_file, (uchar*) "\n", 1) || - flush_io_cache(&index_file) || + if (DBUG_EVALUATE_IF("fault_injection_updating_index", 1, 0) || + my_b_write(&index_file, (uchar*) log_file_name, + strlen(log_file_name)) || + my_b_write(&index_file, (uchar*) "\n", 1) || + flush_io_cache(&index_file) || my_sync(index_file.file, MYF(MY_WME))) - goto err; + goto err; + +#ifdef HAVE_REPLICATION + DBUG_EXECUTE_IF("crash_create_after_update_index", abort();); +#endif } } log_state= LOG_OPENED; +#ifdef HAVE_REPLICATION + close_purge_index_file(); +#endif + DBUG_RETURN(0); err: +#ifdef HAVE_REPLICATION + if (is_inited_purge_index_file()) + purge_index_entry(NULL, NULL, need_mutex); + close_purge_index_file(); +#endif sql_print_error("Could not use %s for logging (error %d). \ Turning logging off for the whole duration of the MySQL server process. \ To turn it on again: fix the cause, \ @@ -2902,8 +2983,15 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) name=0; // Protect against free close(LOG_CLOSE_TO_BE_OPENED); - /* First delete all old log files */ + /* + First delete all old log files and then update the index file. + As we first delete the log files and do not use sort of logging, + a crash may lead to an inconsistent state where the index has + references to non-existent files. + We need to invert the steps and use the purge_index_file methods + in order to make the operation safe. + */ if (find_log_pos(&linfo, NullS, 0)) { error=1; @@ -2970,8 +3058,8 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) } if (!thd->slave_thread) need_start_event=1; - if (!open_index_file(index_file_name, 0)) - open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0); + if (!open_index_file(index_file_name, 0, FALSE)) + open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0, FALSE); my_free((uchar*) save_name, MYF(0)); err: @@ -3158,7 +3246,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, bool need_update_threads, ulonglong *decrease_log_space) { - int error; + int error= 0; bool exit_loop= 0; LOG_INFO log_info; THD *thd= current_thd; @@ -3169,33 +3257,15 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, pthread_mutex_lock(&LOCK_index); if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/))) { - sql_print_error("MYSQL_LOG::purge_logs was called with file %s not " + sql_print_error("MYSQL_BIN_LOG::purge_logs was called with file %s not " "listed in the index.", to_log); goto err; } - /* - For crash recovery reasons the index needs to be updated before - any files are deleted. Move files to be deleted into a temp file - to be processed after the index is updated. - */ - if (!my_b_inited(&purge_temp)) + if ((error= open_purge_index_file(TRUE))) { - if ((error=open_cached_file(&purge_temp, mysql_tmpdir, TEMP_PREFIX, - DISK_BUFFER_SIZE, MYF(MY_WME)))) - { - sql_print_error("MYSQL_LOG::purge_logs failed to open purge_temp"); - goto err; - } - } - else - { - if ((error=reinit_io_cache(&purge_temp, WRITE_CACHE, 0, 0, 1))) - { - sql_print_error("MYSQL_LOG::purge_logs failed to reinit purge_temp " - "for write"); - goto err; - } + sql_print_error("MYSQL_BIN_LOG::purge_logs failed to sync the index file."); + goto err; } /* @@ -3205,51 +3275,177 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/))) goto err; while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) && + !is_active(log_info.log_file_name) && !log_in_use(log_info.log_file_name)) { - if ((error=my_b_write(&purge_temp, (const uchar*)log_info.log_file_name, - strlen(log_info.log_file_name))) || - (error=my_b_write(&purge_temp, (const uchar*)"\n", 1))) + if ((error= register_purge_index_entry(log_info.log_file_name))) { - sql_print_error("MYSQL_LOG::purge_logs failed to copy %s to purge_temp", + sql_print_error("MYSQL_BIN_LOG::purge_logs failed to copy %s to register file.", log_info.log_file_name); goto err; } if (find_next_log(&log_info, 0) || exit_loop) break; - } + } + + DBUG_EXECUTE_IF("crash_purge_before_update_index", abort();); + + if ((error= sync_purge_index_file())) + { + sql_print_error("MSYQL_BIN_LOG::purge_logs failed to flush register file."); + goto err; + } /* We know how many files to delete. Update index file. */ if ((error=update_log_index(&log_info, need_update_threads))) { - sql_print_error("MSYQL_LOG::purge_logs failed to update the index file"); + sql_print_error("MSYQL_BIN_LOG::purge_logs failed to update the index file"); goto err; } - DBUG_EXECUTE_IF("crash_after_update_index", abort();); + DBUG_EXECUTE_IF("crash_purge_critical_after_update_index", abort();); + +err: + /* Read each entry from purge_index_file and delete the file. */ + if (is_inited_purge_index_file() && + (error= purge_index_entry(thd, decrease_log_space, FALSE))) + sql_print_error("MSYQL_BIN_LOG::purge_logs failed to process registered files" + " that would be purged."); + close_purge_index_file(); + + DBUG_EXECUTE_IF("crash_purge_non_critical_after_update_index", abort();); + + if (need_mutex) + pthread_mutex_unlock(&LOCK_index); + DBUG_RETURN(error); +} - /* Switch purge_temp for read. */ - if ((error=reinit_io_cache(&purge_temp, READ_CACHE, 0, 0, 0))) +int MYSQL_BIN_LOG::set_purge_index_file_name(const char *base_file_name) +{ + int error= 0; + DBUG_ENTER("MYSQL_BIN_LOG::set_purge_index_file_name"); + if (fn_format(purge_index_file_name, base_file_name, mysql_data_home, + ".~rec~", MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH | + MY_REPLACE_EXT)) == NULL) { - sql_print_error("MSYQL_LOG::purge_logs failed to reinit purge_temp " + error= 1; + sql_print_error("MYSQL_BIN_LOG::set_purge_index_file_name failed to set " + "file name."); + } + DBUG_RETURN(error); +} + +int MYSQL_BIN_LOG::open_purge_index_file(bool destroy) +{ + int error= 0; + File file= -1; + + DBUG_ENTER("MYSQL_BIN_LOG::open_purge_index_file"); + + if (destroy) + close_purge_index_file(); + + if (!my_b_inited(&purge_index_file)) + { + if ((file= my_open(purge_index_file_name, O_RDWR | O_CREAT | O_BINARY, + MYF(MY_WME | ME_WAITTANG))) < 0 || + init_io_cache(&purge_index_file, file, IO_SIZE, + (destroy ? WRITE_CACHE : READ_CACHE), + 0, 0, MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL))) + { + error= 1; + sql_print_error("MYSQL_BIN_LOG::open_purge_index_file failed to open register " + " file."); + } + } + DBUG_RETURN(error); +} + +int MYSQL_BIN_LOG::close_purge_index_file() +{ + int error= 0; + + DBUG_ENTER("MYSQL_BIN_LOG::close_purge_index_file"); + + if (my_b_inited(&purge_index_file)) + { + end_io_cache(&purge_index_file); + error= my_close(purge_index_file.file, MYF(0)); + } + my_delete(purge_index_file_name, MYF(0)); + bzero((char*) &purge_index_file, sizeof(purge_index_file)); + + DBUG_RETURN(error); +} + +bool MYSQL_BIN_LOG::is_inited_purge_index_file() +{ + DBUG_ENTER("MYSQL_BIN_LOG::is_inited_purge_index_file"); + DBUG_RETURN (my_b_inited(&purge_index_file)); +} + +int MYSQL_BIN_LOG::sync_purge_index_file() +{ + int error= 0; + DBUG_ENTER("MYSQL_BIN_LOG::sync_purge_index_file"); + + if ((error= flush_io_cache(&purge_index_file)) || + (error= my_sync(purge_index_file.file, MYF(MY_WME)))) + DBUG_RETURN(error); + + DBUG_RETURN(error); +} + +int MYSQL_BIN_LOG::register_purge_index_entry(const char *entry) +{ + int error= 0; + DBUG_ENTER("MYSQL_BIN_LOG::register_purge_index_entry"); + + if ((error=my_b_write(&purge_index_file, (const uchar*)entry, strlen(entry))) || + (error=my_b_write(&purge_index_file, (const uchar*)"\n", 1))) + DBUG_RETURN (error); + + DBUG_RETURN(error); +} + +int MYSQL_BIN_LOG::register_create_index_entry(const char *entry) +{ + DBUG_ENTER("MYSQL_BIN_LOG::register_create_index_entry"); + DBUG_RETURN(register_purge_index_entry(entry)); +} + +int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space, + bool need_mutex) +{ + MY_STAT s; + int error= 0; + LOG_INFO log_info; + LOG_INFO check_log_info; + + DBUG_ENTER("MYSQL_BIN_LOG:purge_index_entry"); + + DBUG_ASSERT(my_b_inited(&purge_index_file)); + + if ((error=reinit_io_cache(&purge_index_file, READ_CACHE, 0, 0, 0))) + { + sql_print_error("MSYQL_BIN_LOG::purge_index_entry failed to reinit register file " "for read"); goto err; } - /* Read each entry from purge_temp and delete the file. */ for (;;) { uint length; - if ((length=my_b_gets(&purge_temp, log_info.log_file_name, + if ((length=my_b_gets(&purge_index_file, log_info.log_file_name, FN_REFLEN)) <= 1) { - if (purge_temp.error) + if (purge_index_file.error) { - error= purge_temp.error; - sql_print_error("MSYQL_LOG::purge_logs error %d reading from " - "purge_temp", error); + error= purge_index_file.error; + sql_print_error("MSYQL_BIN_LOG::purge_index_entry error %d reading from " + "register file.", error); goto err; } @@ -3260,9 +3456,6 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, /* Get rid of the trailing '\n' */ log_info.log_file_name[length-1]= 0; - ha_binlog_index_purge_file(current_thd, log_info.log_file_name); - - MY_STAT s; if (!my_stat(log_info.log_file_name, &s, MYF(0))) { if (my_errno == ENOENT) @@ -3310,64 +3503,92 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, } else { - DBUG_PRINT("info",("purging %s",log_info.log_file_name)); - if (!my_delete(log_info.log_file_name, MYF(0))) - { - if (decrease_log_space) - *decrease_log_space-= s.st_size; - } - else + if ((error= find_log_pos(&check_log_info, log_info.log_file_name, need_mutex))) { - if (my_errno == ENOENT) + if (error != LOG_INFO_EOF) { if (thd) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with deleting %s and " + "reading the binlog index file", log_info.log_file_name); } - sql_print_information("Failed to delete file '%s'", - log_info.log_file_name); - my_errno= 0; + else + { + sql_print_information("Failed to delete file '%s' and " + "read the binlog index file", + log_info.log_file_name); + } + goto err; + } + + error= 0; + if (!need_mutex) + { + /* + This is to avoid triggering an error in NDB. + */ + ha_binlog_index_purge_file(current_thd, log_info.log_file_name); + } + + DBUG_PRINT("info",("purging %s",log_info.log_file_name)); + if (!my_delete(log_info.log_file_name, MYF(0))) + { + if (decrease_log_space) + *decrease_log_space-= s.st_size; } else { - if (thd) + if (my_errno == ENOENT) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, - ER_BINLOG_PURGE_FATAL_ERR, - "a problem with deleting %s; " - "consider examining correspondence " - "of your binlog index file " - "to the actual binlog files", - log_info.log_file_name); + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + } + sql_print_information("Failed to delete file '%s'", + log_info.log_file_name); + my_errno= 0; } else { - sql_print_information("Failed to delete file '%s'; " + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with deleting %s; " "consider examining correspondence " "of your binlog index file " "to the actual binlog files", log_info.log_file_name); - } - if (my_errno == EMFILE) - { - DBUG_PRINT("info", - ("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno)); - error= LOG_INFO_EMFILE; + } + else + { + sql_print_information("Failed to delete file '%s'; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + } + if (my_errno == EMFILE) + { + DBUG_PRINT("info", + ("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno)); + error= LOG_INFO_EMFILE; + goto err; + } + error= LOG_INFO_FATAL; goto err; } - error= LOG_INFO_FATAL; - goto err; } } } } err: - close_cached_file(&purge_temp); - if (need_mutex) - pthread_mutex_unlock(&LOCK_index); DBUG_RETURN(error); } @@ -3407,7 +3628,8 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time) goto err; while (strcmp(log_file_name, log_info.log_file_name) && - !log_in_use(log_info.log_file_name)) + !is_active(log_info.log_file_name) && + !log_in_use(log_info.log_file_name)) { if (!my_stat(log_info.log_file_name, &stat_area, MYF(0))) { @@ -3416,14 +3638,6 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time) /* It's not fatal if we can't stat a log file that does not exist. */ - if (thd) - { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), - log_info.log_file_name); - } - sql_print_information("Failed to execute my_stat on file '%s'", - log_info.log_file_name); my_errno= 0; } else @@ -3618,9 +3832,9 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock) */ /* reopen index binlog file, BUG#34582 */ - if (!open_index_file(index_file_name, 0)) - open(old_name, log_type, new_name_ptr, - io_cache_type, no_auto_events, max_size, 1); + if (!open_index_file(index_file_name, 0, FALSE)) + open(old_name, log_type, new_name_ptr, + io_cache_type, no_auto_events, max_size, 1, FALSE); my_free(old_name,MYF(0)); end: @@ -5522,7 +5736,7 @@ int TC_LOG_BINLOG::open(const char *opt_name) if (using_heuristic_recover()) { /* generate a new binlog to mask a corrupted one */ - open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0); + open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0, TRUE); cleanup(); return 1; } diff --git a/sql/log.h b/sql/log.h index d306d6f7182..8b5dfcb3935 100644 --- a/sql/log.h +++ b/sql/log.h @@ -172,6 +172,10 @@ public: enum_log_type log_type, const char *new_name, enum cache_type io_cache_type_arg); + bool init_and_set_log_file_name(const char *log_name, + const char *new_name, + enum_log_type log_type_arg, + enum cache_type io_cache_type_arg); void init(enum_log_type log_type_arg, enum cache_type io_cache_type_arg); void close(uint exiting); @@ -233,14 +237,15 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG pthread_cond_t update_cond; ulonglong bytes_written; IO_CACHE index_file; + char index_file_name[FN_REFLEN]; /* - purge_temp is a temp file used in purge_logs so that the index file + purge_file is a temp file used in purge_logs so that the index file can be updated before deleting files from disk, yielding better crash recovery. It is created on demand the first time purge_logs is called and then reused for subsequent calls. It is cleaned up in cleanup(). */ - IO_CACHE purge_temp; - char index_file_name[FN_REFLEN]; + IO_CACHE purge_index_file; + char purge_index_file_name[FN_REFLEN]; /* The max size before rotation (usable only if log_type == LOG_BIN: binary logs and relay logs). @@ -349,9 +354,10 @@ public: const char *new_name, enum cache_type io_cache_type_arg, bool no_auto_events_arg, ulong max_size, - bool null_created); + bool null_created, + bool need_mutex); bool open_index_file(const char *index_file_name_arg, - const char *log_name); + const char *log_name, bool need_mutex); /* Use this to start writing a new log file */ void new_file(); @@ -384,6 +390,16 @@ public: ulonglong *decrease_log_space); int purge_logs_before_date(time_t purge_time); int purge_first_log(Relay_log_info* rli, bool included); + int set_purge_index_file_name(const char *base_file_name); + int open_purge_index_file(bool destroy); + bool is_inited_purge_index_file(); + int close_purge_index_file(); + int clean_purge_index_file(); + int sync_purge_index_file(); + int register_purge_index_entry(const char* entry); + int register_create_index_entry(const char* entry); + int purge_index_entry(THD *thd, ulonglong *decrease_log_space, + bool need_mutex); bool reset_logs(THD* thd); void close(uint exiting); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5c643b03798..de532e92fda 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3932,7 +3932,7 @@ a file name for --log-bin-index option", opt_binlog_index_name); my_free(opt_bin_logname, MYF(MY_ALLOW_ZERO_PTR)); opt_bin_logname=my_strdup(buf, MYF(0)); } - if (mysql_bin_log.open_index_file(opt_binlog_index_name, ln)) + if (mysql_bin_log.open_index_file(opt_binlog_index_name, ln, TRUE)) { unireg_abort(1); } @@ -4096,7 +4096,7 @@ a file name for --log-bin-index option", opt_binlog_index_name); } if (opt_bin_log && mysql_bin_log.open(opt_bin_logname, LOG_BIN, 0, - WRITE_CACHE, 0, max_binlog_size, 0)) + WRITE_CACHE, 0, max_binlog_size, 0, TRUE)) unireg_abort(1); #ifdef HAVE_REPLICATION diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index a26717d7acf..66de9357a53 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -182,10 +182,10 @@ a file name for --relay-log-index option", opt_relaylog_index_name); note, that if open() fails, we'll still have index file open but a destructor will take care of that */ - if (rli->relay_log.open_index_file(opt_relaylog_index_name, ln) || + if (rli->relay_log.open_index_file(opt_relaylog_index_name, ln, TRUE) || rli->relay_log.open(ln, LOG_BIN, 0, SEQ_READ_APPEND, 0, (max_relay_log_size ? max_relay_log_size : - max_binlog_size), 1)) + max_binlog_size), 1, TRUE)) { pthread_mutex_unlock(&rli->data_lock); sql_print_error("Failed in open_log() called from init_relay_log_info()"); -- cgit v1.2.1 From e53ecf2dc241a29a2ef732850ff77d4896de4412 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Fri, 4 Dec 2009 13:36:58 -0200 Subject: Bug#49141: Encode function is significantly slower in 5.1 compared to 5.0 The problem was that the multiple evaluations of a ENCODE or DECODE function within a single statement caused the random generator to be reinitialized at each evaluation, even though the parameters were constants. The solution is to initialize the random generator only once if the password (seed) parameter is constant. This patch borrows code and ideas from Georgi Kodinov's patch. mysql-test/r/func_str.result: Add test case result. mysql-test/r/ps.result: Add test case result. mysql-test/t/func_str.test: Add test case for Bug#49141 mysql-test/t/ps.test: Add test case for Bug#49141 sql/item_strfunc.cc: Move seed generation code to a separate method. Seed only once if the password (seed) argument is constant. Remove duplicated code and use a transform method to apply encoding or decoding. sql/item_strfunc.h: Add parameter to signal whether the PRNG is already seeded. Introduce transform method. Combine val_str methods. sql/sql_crypt.cc: Remove method. sql/sql_crypt.h: Seed is supplied as two long integers. --- sql/item_strfunc.cc | 71 +++++++++++++++++++++++++---------------------------- sql/item_strfunc.h | 13 +++++++++- sql/sql_crypt.cc | 9 +------ sql/sql_crypt.h | 8 +++--- 4 files changed, 51 insertions(+), 50 deletions(-) (limited to 'sql') diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 183a628f8e4..b6d3f45f4c2 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1720,68 +1720,65 @@ String *Item_func_encrypt::val_str(String *str) #endif /* HAVE_CRYPT */ } +bool Item_func_encode::seed() +{ + char buf[80]; + ulong rand_nr[2]; + String *key, tmp(buf, sizeof(buf), system_charset_info); + + if (!(key= args[1]->val_str(&tmp))) + return TRUE; + + hash_password(rand_nr, key->ptr(), key->length()); + sql_crypt.init(rand_nr); + + return FALSE; +} + void Item_func_encode::fix_length_and_dec() { max_length=args[0]->max_length; maybe_null=args[0]->maybe_null || args[1]->maybe_null; collation.set(&my_charset_bin); + /* Precompute the seed state if the item is constant. */ + seeded= args[1]->const_item() && + (args[1]->result_type() == STRING_RESULT) && !seed(); } String *Item_func_encode::val_str(String *str) { String *res; - char pw_buff[80]; - String tmp_pw_value(pw_buff, sizeof(pw_buff), system_charset_info); - String *password; DBUG_ASSERT(fixed == 1); if (!(res=args[0]->val_str(str))) { - null_value=1; /* purecov: inspected */ - return 0; /* purecov: inspected */ + null_value= 1; + return NULL; } - if (!(password=args[1]->val_str(& tmp_pw_value))) + if (!seeded && seed()) { - null_value=1; - return 0; + null_value= 1; + return NULL; } - null_value=0; - res=copy_if_not_alloced(str,res,res->length()); - SQL_CRYPT sql_crypt(password->ptr(), password->length()); - sql_crypt.init(); - sql_crypt.encode((char*) res->ptr(),res->length()); - res->set_charset(&my_charset_bin); + null_value= 0; + res= copy_if_not_alloced(str, res, res->length()); + transform(res); + sql_crypt.reinit(); + return res; } -String *Item_func_decode::val_str(String *str) +void Item_func_encode::transform(String *res) { - String *res; - char pw_buff[80]; - String tmp_pw_value(pw_buff, sizeof(pw_buff), system_charset_info); - String *password; - DBUG_ASSERT(fixed == 1); - - if (!(res=args[0]->val_str(str))) - { - null_value=1; /* purecov: inspected */ - return 0; /* purecov: inspected */ - } - - if (!(password=args[1]->val_str(& tmp_pw_value))) - { - null_value=1; - return 0; - } + sql_crypt.encode((char*) res->ptr(),res->length()); + res->set_charset(&my_charset_bin); +} - null_value=0; - res=copy_if_not_alloced(str,res,res->length()); - SQL_CRYPT sql_crypt(password->ptr(), password->length()); - sql_crypt.init(); +void Item_func_decode::transform(String *res) +{ sql_crypt.decode((char*) res->ptr(),res->length()); - return res; } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 2cdb45100ae..59241872e63 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -351,12 +351,22 @@ public: class Item_func_encode :public Item_str_func { +private: + /** Whether the PRNG has already been seeded. */ + bool seeded; +protected: + SQL_CRYPT sql_crypt; public: Item_func_encode(Item *a, Item *seed): Item_str_func(a, seed) {} String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "encode"; } +protected: + virtual void transform(String *); +private: + /** Provide a seed for the PRNG sequence. */ + bool seed(); }; @@ -364,8 +374,9 @@ class Item_func_decode :public Item_func_encode { public: Item_func_decode(Item *a, Item *seed): Item_func_encode(a, seed) {} - String *val_str(String *); const char *func_name() const { return "decode"; } +protected: + void transform(String *); }; diff --git a/sql/sql_crypt.cc b/sql/sql_crypt.cc index c4f93cc2a33..3d7d248782b 100644 --- a/sql/sql_crypt.cc +++ b/sql/sql_crypt.cc @@ -28,14 +28,7 @@ #include "mysql_priv.h" -SQL_CRYPT::SQL_CRYPT(const char *password, uint length) -{ - ulong rand_nr[2]; - hash_password(rand_nr,password, length); - crypt_init(rand_nr); -} - -void SQL_CRYPT::crypt_init(ulong *rand_nr) +void SQL_CRYPT::init(ulong *rand_nr) { uint i; randominit(&rand,rand_nr[0],rand_nr[1]); diff --git a/sql/sql_crypt.h b/sql/sql_crypt.h index a5a6bee8a58..2b56c387bd1 100644 --- a/sql/sql_crypt.h +++ b/sql/sql_crypt.h @@ -23,15 +23,15 @@ class SQL_CRYPT :public Sql_alloc struct rand_struct rand,org_rand; char decode_buff[256],encode_buff[256]; uint shift; - void crypt_init(ulong *seed); public: - SQL_CRYPT(const char *seed, uint length); + SQL_CRYPT() {} SQL_CRYPT(ulong *seed) { - crypt_init(seed); + init(seed); } ~SQL_CRYPT() {} - void init() { shift=0; rand=org_rand; } + void init(ulong *seed); + void reinit() { shift=0; rand=org_rand; } void encode(char *str, uint length); void decode(char *str, uint length); }; -- cgit v1.2.1 From f5b51bc1e29d0ae9d8ba9ec7d1c500fe09915e74 Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Fri, 4 Dec 2009 21:58:40 +0400 Subject: Fix for bug#49199: Optimizer handles incorrectly: field='const1' AND field='const2' in some cases Building multiple equality predicates containing a constant which is compared as a datetime (with a field) we should take this fact into account and compare the constant with another possible constatns as datetimes as well. E.g. for the SELECT ... WHERE a='2001-01-01' AND a='2001-01-01 00:00:00' we should compare '2001-01-01' with '2001-01-01 00:00:00' as datetimes but not as strings. mysql-test/r/select.result: Fix for bug#49199: Optimizer handles incorrectly: field='const1' AND field='const2' in some cases - test result. mysql-test/t/select.test: Fix for bug#49199: Optimizer handles incorrectly: field='const1' AND field='const2' in some cases - test case. sql/item_cmpfunc.cc: Fix for bug#49199: Optimizer handles incorrectly: field='const1' AND field='const2' in some cases - adding a constant to Item_equal compare it as a datetime value with stored one if there's a date[time] field in a equality predicate. sql/item_cmpfunc.h: Fix for bug#49199: Optimizer handles incorrectly: field='const1' AND field='const2' in some cases - adding a constant to Item_equal compare it as a datetime value with stored one if there's a date[time] field in a equality predicate. sql/sql_select.cc: Fix for bug#49199: Optimizer handles incorrectly: field='const1' AND field='const2' in some cases - adding a constant to Item_equal compare it as a datetime value with stored one if there's a date[time] field in a equality predicate. --- sql/item_cmpfunc.cc | 46 ++++++++++++++++++++++++++++++++++++++++------ sql/item_cmpfunc.h | 4 ++++ sql/sql_select.cc | 2 +- 3 files changed, 45 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index d03c68b3560..5c2fb9857d5 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4903,7 +4903,8 @@ Item *Item_bool_rowready_func2::negated_item() } Item_equal::Item_equal(Item_field *f1, Item_field *f2) - : Item_bool_func(), const_item(0), eval_item(0), cond_false(0) + : Item_bool_func(), const_item(0), eval_item(0), cond_false(0), + compare_as_dates(FALSE) { const_item_cache= 0; fields.push_back(f1); @@ -4916,6 +4917,7 @@ Item_equal::Item_equal(Item *c, Item_field *f) const_item_cache= 0; fields.push_back(f); const_item= c; + compare_as_dates= f->is_datetime(); } @@ -4930,9 +4932,45 @@ Item_equal::Item_equal(Item_equal *item_equal) fields.push_back(item); } const_item= item_equal->const_item; + compare_as_dates= item_equal->compare_as_dates; cond_false= item_equal->cond_false; } + +void Item_equal::compare_const(Item *c) +{ + if (compare_as_dates) + { + cmp.set_datetime_cmp_func(&c, &const_item); + cond_false= cmp.compare(); + } + else + { + Item_func_eq *func= new Item_func_eq(c, const_item); + func->set_cmp_func(); + func->quick_fix_field(); + cond_false= !func->val_int(); + } + if (cond_false) + const_item_cache= 1; +} + + +void Item_equal::add(Item *c, Item_field *f) +{ + if (cond_false) + return; + if (!const_item) + { + DBUG_ASSERT(f); + const_item= c; + compare_as_dates= f->is_datetime(); + return; + } + compare_const(c); +} + + void Item_equal::add(Item *c) { if (cond_false) @@ -4942,11 +4980,7 @@ void Item_equal::add(Item *c) const_item= c; return; } - Item_func_eq *func= new Item_func_eq(c, const_item); - func->set_cmp_func(); - func->quick_fix_field(); - if ((cond_false= !func->val_int())) - const_item_cache= 1; + compare_const(c); } void Item_equal::add(Item_field *f) diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index db831c7030c..89bc6f9570b 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1477,7 +1477,9 @@ class Item_equal: public Item_bool_func List fields; /* list of equal field items */ Item *const_item; /* optional constant item equal to fields items */ cmp_item *eval_item; + Arg_comparator cmp; bool cond_false; + bool compare_as_dates; public: inline Item_equal() : Item_bool_func(), const_item(0), eval_item(0), cond_false(0) @@ -1486,6 +1488,8 @@ public: Item_equal(Item *c, Item_field *f); Item_equal(Item_equal *item_equal); inline Item* get_const() { return const_item; } + void compare_const(Item *c); + void add(Item *c, Item_field *f); void add(Item *c); void add(Item_field *f); uint members(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index df7c5af3ebc..9f0843fe0db 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7237,7 +7237,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item, already contains a constant and its value is not equal to the value of const_item. */ - item_equal->add(const_item); + item_equal->add(const_item, field_item); } else { -- cgit v1.2.1 From 63ff2b4c2e7db9872515cec3d897817ac83d109c Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Sun, 6 Dec 2009 18:11:37 +0100 Subject: Bug #47391 no stack trace printed to error log on solaris after a crash This patch adds a Solaris-specific version of print_stacktrace() which uses printstack(2), available on all Solaris versions since Solaris 9. (While Solaris 11 adds support for the glibc functions backtrace_*() as of PSARC/2007/162, printstack() is used for consistency over all Solaris versions.) The symbol names are mangled, so use of c++filt may be required as described in the MySQL documentation. sql/stacktrace.c: Added Solaris-specific print_stacktrace(). --- sql/stacktrace.c | 19 +++++++++++++++++++ sql/stacktrace.h | 3 +++ 2 files changed, 22 insertions(+) (limited to 'sql') diff --git a/sql/stacktrace.c b/sql/stacktrace.c index 4e6ad68c172..295a7a3e1e2 100644 --- a/sql/stacktrace.c +++ b/sql/stacktrace.c @@ -226,6 +226,25 @@ end: stack trace is much more helpful in diagnosing the problem, so please do \n\ resolve it\n"); } + +#elif defined(__sun) + +/* Use Solaris' symbolic stack trace routine. */ +#include + +void print_stacktrace(gptr stack_bottom __attribute__((unused)), + ulong thread_stack __attribute__((unused))) +{ + if (printstack(fileno(stderr)) == -1) + fprintf(stderr, "Error when traversing the stack, stack appears corrupt.\n"); + else + fprintf(stderr, "Please read " + "http://dev.mysql.com/doc/mysql/en/using-stack-trace.html " + "and follow instructions on how to resolve the stack trace. " + "Resolved\nstack trace is much more helpful in diagnosing the " + "problem, so please do \nresolve it\n"); +} + #endif /* TARGET_OS_LINUX */ #endif /* HAVE_STACKTRACE */ diff --git a/sql/stacktrace.h b/sql/stacktrace.h index e5e17cc5b9b..718b545b775 100644 --- a/sql/stacktrace.h +++ b/sql/stacktrace.h @@ -35,6 +35,9 @@ void check_thread_lib(void); #define HAVE_STACKTRACE extern void set_exception_pointers(EXCEPTION_POINTERS *ep); #define init_stacktrace() {} +#elif defined(__sun) +#define HAVE_STACKTRACE +#define init_stacktrace() {} #endif #ifdef HAVE_STACKTRACE -- cgit v1.2.1 From c75712caa81a58164019754a3690ddf434d17f61 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Sun, 6 Dec 2009 23:12:11 +0000 Subject: BUG#49119: Master crashes when executing 'REVOKE ... ON {PROCEDURE|FUNCTION} FROM ...' The master would hit an assertion when binary log was active. This was due to the fact that the thread's diagnostics area was being cleared before writing to the binlog, independently of mysql_routine_grant returning an error or not. When mysql_routine_grant was to return an error, the return value and the diagnostics area contents would mismatch. Consequently, neither my_ok would be called nor an error would be signaled in the diagnostics area, eventually triggering the assertion in net_end_statement. We fix this by not clearing the diagnostics area at binlogging time. --- sql/sql_acl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 77c72066429..3b81a85c368 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3378,7 +3378,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, if (write_to_binlog) { - write_bin_log(thd, TRUE, thd->query(), thd->query_length()); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); } rw_unlock(&LOCK_grant); -- cgit v1.2.1 From bd308d1256fa7af7128c24f4a5e2abfb8274437a Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Mon, 7 Dec 2009 16:38:56 +0200 Subject: Bug #42760: Select doesn't return desired results when we have null values Part 2 : There was a special optimization on the ref access method for ORDER BY ... DESC that was set without actually looking on the type of the selected index for ORDER BY. Fixed the SELECT ... ORDER BY .. DESC (it uses a different code path compared to the ASC that has been fixed with the previous fix). --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9f0843fe0db..f655db0fc32 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12824,7 +12824,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, } DBUG_RETURN(1); } - if (tab->ref.key_parts <= used_key_parts) + if (tab->ref.key_parts <= used_key_parts && tab->type == JT_REF) { /* SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC -- cgit v1.2.1 From bc2b3d2ccc109768cf918d91e08639b530518ea1 Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Wed, 9 Dec 2009 14:13:56 +0800 Subject: BUG#45520 rpl_killed_ddl fails sporadically in pb2 There are three issues that caused rpl_killed_ddl fails sporadically in pb2: 1) thd->clear_error() was not called before create Query event if operation is executed successfully. 2) DATABASE d2 might do exist because the statement to CREATE or ALTER it was killed 3) because of bug 43353, kill the query that do DROP FUNCTION or DROP PROCEDURE can result in SP not found This patch fixed all above issues by: 1) Called thd->clear_error() if the operation succeeded. 2) Add IF EXISTS to the DROP DATABASE d2 statement 3) Temporarily disabled testing DROP FUNCTION/PROCEDURE IF EXISTS. mysql-test/t/rpl_killed_ddl.test: DATABASE d2 might not exists, add IF EXITS to the DROP statement sql/sql_db.cc: Called thd->clear_error() if the operation succeeded --- sql/sql_db.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_db.cc b/sql/sql_db.cc index be538783458..2ad3953625f 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -541,6 +541,7 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, file. In this case it's best to just continue as if nothing has happened. (This is a very unlikely senario) */ + thd->clear_error(); } if (!silent) @@ -644,6 +645,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) if (mysql_bin_log.is_open()) { + thd->clear_error(); Query_log_event qinfo(thd, thd->query, thd->query_length, 0, /* suppress_use */ TRUE, THD::NOT_KILLED); @@ -655,7 +657,6 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) qinfo.db = db; qinfo.db_len = (uint) strlen(db); - thd->clear_error(); /* These DDL methods and logging protected with LOCK_mysql_create_db */ mysql_bin_log.write(&qinfo); } @@ -769,6 +770,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) } if (mysql_bin_log.is_open()) { + thd->clear_error(); Query_log_event qinfo(thd, query, query_length, 0, /* suppress_use */ TRUE, THD::NOT_KILLED); /* @@ -779,7 +781,6 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) qinfo.db = db; qinfo.db_len = (uint) strlen(db); - thd->clear_error(); /* These DDL methods and logging protected with LOCK_mysql_create_db */ mysql_bin_log.write(&qinfo); } -- cgit v1.2.1 From 9060aa68afa8483883583b3b25e748f17ca6d3a5 Mon Sep 17 00:00:00 2001 From: Olav Sandstaa Date: Wed, 9 Dec 2009 10:16:11 +0100 Subject: Fix for Bug#49506 Valgrind error in make_cond_for_table_from_pred This fix has been proposed by Sergey Petrunya and has been contributed under SCA by sca@askmonty.org. The cause for this valgrind error is that in the function add_cond_and_fix() in sql_select.cc an Item_cond_and object is created. This is marked as fixed but does not have a correct table_map() attribute. Later, in make_join_select(), if engine_condition_pushdown is in use, this table map is used and results in the valgrind error. The fix is to add a call to update_used_tables() in add_cond_and_fix() so that the table map is updated correctly. This patch is tested by multiple existing tests (e.g. the tests innodb_mysql, innodb, fulltext, compress all produces this valgrind warning/error without this fix). sql/sql_select.cc: In add_cond_and_fix() add a call to update_used_tables() to ensure the table map is updated. --- sql/sql_select.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 569d8183ab6..b2a4958020a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5859,6 +5859,7 @@ inline void add_cond_and_fix(Item **e1, Item *e2) { *e1= res; res->quick_fix_field(); + res->update_used_tables(); } } else -- cgit v1.2.1 From 1285ecd4688295c0aae28b314ef8a4c9ae3b6c14 Mon Sep 17 00:00:00 2001 From: Evgeny Potemkin Date: Wed, 9 Dec 2009 18:43:45 +0300 Subject: Bug#49489: Uninitialized cache led to a wrong result. Arg_comparator uses Item_cache objects to store constants being compared when they're need a type conversion. Because this cache wasn't initialized properly Arg_comparator might produce wrong comparison result. The Arg_comparator::cache_converted_constant function now initializes cache prior to usage. mysql-test/r/select.result: Added a test case for he bug#49489. mysql-test/t/select.test: Added a test case for he bug#49489. sql/item_cmpfunc.cc: Bug#49489: Uninitialized cache led to a wrong result. The Arg_comparator::cache_converted_constant function now initializes cache prior to usage. --- sql/item_cmpfunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 5415d6f4f8a..a3c3051d790 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1023,7 +1023,7 @@ Item** Arg_comparator::cache_converted_constant(THD *thd, Item **value, (*value)->const_item() && type != (*value)->result_type()) { Item_cache *cache= Item_cache::get_cache(*value, type); - cache->store(*value); + cache->setup(*value); *cache_item= cache; return cache_item; } -- cgit v1.2.1 From 3246383301e2eacfd14bdb0f5399ab44659002fe Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Thu, 10 Dec 2009 10:05:44 +0400 Subject: Bug #49480: WHERE using YEAR columns returns unexpected results A few problems were found in the fix for bug 43668: 1) Comparison of the YEAR column with NULL always returned TRUE; 2) Comparison of the YEAR column with constants always returned unpredictable result; 3) Unnecessary conversion warnings when comparing a non-integer constant with a NULL value in the YEAR column; The problems described above have been resolved with an exception: zero (i.e. invalid) YEAR column value comparison with 00 or 2000 still fail (it is not a regression and it was not a regression), so MIN/MAX on YEAR column containing zero value still fail. mysql-test/r/type_year.result: Test case for bug #49480. mysql-test/t/type_year.test: Test case for bug #49480. sql/item_cmpfunc.cc: - The get_year_value() function has been modified to make its return value compatible with the get_datetime_value() return value (i.e. to convert numeric values into the YYYY0000000000 (YYYY-00-00 00:00:00) form. - The Arg_comparator::set_cmp_func method has been modified to use the get_year_value function if get_datetime_value() is not applicable. From now only 2 cases have a special processing there: * both comparing items have MYSQL_TYPE_YEAR field type or * one item have is MYSQL_TYPE_YEAR and other one is is_datetime()-compliant. - New helper function try_year_cmp_func() has been added for the better code readability to call from Arg_comparator::set_cmp_func(). - The Arg_comparator::compare_year method has been removed since get_year_value() is compatible with the old Arg_comparator::compare_datetime method that doesn't have problems #1-#3 (see whole patch entry commentary). sql/item_cmpfunc.h: - New helper function try_year_cmp_func() has been added for the better code readability to call from Arg_comparator::set_cmp_func(). - Unnecessary Arg_comparator::year_as_datetime and Arg_comparator::compare_year() declarations have been removed. --- sql/item_cmpfunc.cc | 144 ++++++++++++++++++---------------------------------- sql/item_cmpfunc.h | 9 ++-- 2 files changed, 51 insertions(+), 102 deletions(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 5415d6f4f8a..ed31c19e676 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -956,40 +956,9 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, if (agg_item_set_converter(coll, owner->func_name(), b, 1, MY_COLL_CMP_CONV, 1)) return 1; - } else if (type != ROW_RESULT && ((*a)->field_type() == MYSQL_TYPE_YEAR || - (*b)->field_type() == MYSQL_TYPE_YEAR)) - { - is_nulls_eq= is_owner_equal_func(); - year_as_datetime= FALSE; - - if ((*a)->is_datetime()) - { - year_as_datetime= TRUE; - get_value_a_func= &get_datetime_value; - } else if ((*a)->field_type() == MYSQL_TYPE_YEAR) - get_value_a_func= &get_year_value; - else - { - /* - Because convert_constant_item is called only for EXECUTE in PS mode - the value of get_value_x_func set in PREPARE might be not - valid for EXECUTE. - */ - get_value_a_func= NULL; - } - - if ((*b)->is_datetime()) - { - year_as_datetime= TRUE; - get_value_b_func= &get_datetime_value; - } else if ((*b)->field_type() == MYSQL_TYPE_YEAR) - get_value_b_func= &get_year_value; - else - get_value_b_func= NULL; - - func= &Arg_comparator::compare_year; - return 0; } + else if (try_year_cmp_func(type)) + return 0; a= cache_converted_constant(thd, a, &a_cache, type); b= cache_converted_constant(thd, b, &b_cache, type); @@ -997,6 +966,45 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, } +/* + Helper function to call from Arg_comparator::set_cmp_func() +*/ + +bool Arg_comparator::try_year_cmp_func(Item_result type) +{ + if (type == ROW_RESULT) + return FALSE; + + bool a_is_year= (*a)->field_type() == MYSQL_TYPE_YEAR; + bool b_is_year= (*b)->field_type() == MYSQL_TYPE_YEAR; + + if (!a_is_year && !b_is_year) + return FALSE; + + if (a_is_year && b_is_year) + { + get_value_a_func= &get_year_value; + get_value_b_func= &get_year_value; + } + else if (a_is_year && (*b)->is_datetime()) + { + get_value_a_func= &get_year_value; + get_value_b_func= &get_datetime_value; + } + else if (b_is_year && (*a)->is_datetime()) + { + get_value_b_func= &get_year_value; + get_value_a_func= &get_datetime_value; + } + else + return FALSE; + + is_nulls_eq= is_owner_equal_func(); + func= &Arg_comparator::compare_datetime; + + return TRUE; +} + /** Convert and cache a constant. @@ -1147,7 +1155,7 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, /* - Retrieves YEAR value of 19XX form from given item. + Retrieves YEAR value of 19XX-00-00 00:00:00 form from given item. SYNOPSIS get_year_value() @@ -1159,7 +1167,9 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, DESCRIPTION Retrieves the YEAR value of 19XX form from given item for comparison by the - compare_year() function. + compare_datetime() function. + Converts year to DATETIME of form YYYY-00-00 00:00:00 for the compatibility + with the get_datetime_value function result. RETURN obtained value @@ -1186,6 +1196,9 @@ get_year_value(THD *thd, Item ***item_arg, Item **cache_arg, if (value <= 1900) value+= 1900; + /* Convert year to DATETIME of form YYYY-00-00 00:00:00 (YYYY0000000000). */ + value*= 10000000000LL; + return value; } @@ -1615,67 +1628,6 @@ int Arg_comparator::compare_e_row() } -/** - Compare values as YEAR. - - @details - Compare items as YEAR for EQUAL_FUNC and for other comparison functions. - The YEAR values of form 19XX are obtained with help of the get_year_value() - function. - If one of arguments is of DATE/DATETIME type its value is obtained - with help of the get_datetime_value function. In this case YEAR values - prior to comparison are converted to the ulonglong YYYY-00-00 00:00:00 - DATETIME form. - If an argument type neither YEAR nor DATE/DATEIME then val_int function - is used to obtain value for comparison. - - RETURN - If is_nulls_eq is TRUE: - 1 if items are equal or both are null - 0 otherwise - If is_nulls_eq is FALSE: - -1 a < b - 0 a == b or at least one of items is null - 1 a > b - See the table: - is_nulls_eq | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | - a_is_null | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | - b_is_null | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | - result | 1 | 0 | 0 |0/1| 0 | 0 | 0 |-1/0/1| -*/ - -int Arg_comparator::compare_year() -{ - bool a_is_null, b_is_null; - ulonglong val1= get_value_a_func ? - (*get_value_a_func)(thd, &a, &a_cache, *b, &a_is_null) : - (*a)->val_int(); - ulonglong val2= get_value_b_func ? - (*get_value_b_func)(thd, &b, &b_cache, *a, &b_is_null) : - (*b)->val_int(); - if (!(*a)->null_value) - { - if (!(*b)->null_value) - { - if (set_null) - owner->null_value= 0; - /* Convert year to DATETIME of form YYYY-00-00 00:00:00 when necessary. */ - if((*a)->field_type() == MYSQL_TYPE_YEAR && year_as_datetime) - val1*= 10000000000LL; - if((*b)->field_type() == MYSQL_TYPE_YEAR && year_as_datetime) - val2*= 10000000000LL; - - if (val1 < val2) return is_nulls_eq ? 0 : -1; - if (val1 == val2) return is_nulls_eq ? 1 : 0; - return is_nulls_eq ? 0 : 1; - } - } - if (set_null) - owner->null_value= is_nulls_eq ? 0 : 1; - return (is_nulls_eq && (*a)->null_value == (*b)->null_value) ? 1 : 0; -} - - void Item_func_truth::fix_length_and_dec() { maybe_null= 0; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 52af6a31c0c..d4542dac820 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -42,24 +42,22 @@ class Arg_comparator: public Sql_alloc bool is_nulls_eq; // TRUE <=> compare for the EQUAL_FUNC bool set_null; // TRUE <=> set owner->null_value // when one of arguments is NULL. - bool year_as_datetime; // TRUE <=> convert YEAR value to - // the YYYY-00-00 00:00:00 DATETIME - // format. See compare_year. enum enum_date_cmp_type { CMP_DATE_DFLT= 0, CMP_DATE_WITH_DATE, CMP_DATE_WITH_STR, CMP_STR_WITH_DATE }; longlong (*get_value_a_func)(THD *thd, Item ***item_arg, Item **cache_arg, Item *warn_item, bool *is_null); longlong (*get_value_b_func)(THD *thd, Item ***item_arg, Item **cache_arg, Item *warn_item, bool *is_null); + bool try_year_cmp_func(Item_result type); public: DTCollation cmp_collation; /* Allow owner function to use string buffers. */ String value1, value2; Arg_comparator(): thd(0), a_cache(0), b_cache(0), set_null(0), - year_as_datetime(0), get_value_a_func(0), get_value_b_func(0) {}; + get_value_a_func(0), get_value_b_func(0) {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), thd(0), - a_cache(0), b_cache(0), set_null(0), year_as_datetime(0), + a_cache(0), b_cache(0), set_null(0), get_value_a_func(0), get_value_b_func(0) {}; int set_compare_func(Item_result_field *owner, Item_result type); @@ -101,7 +99,6 @@ public: int compare_real_fixed(); int compare_e_real_fixed(); int compare_datetime(); // compare args[0] & args[1] as DATETIMEs - int compare_year(); static enum enum_date_cmp_type can_compare_as_dates(Item *a, Item *b, ulonglong *const_val_arg); -- cgit v1.2.1 From 18d09c0183c022ee19eebb71b8278ef2c5219514 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Dec 2009 09:57:38 +0800 Subject: Bug #48742 Replication: incorrect help text for --init-slave The help text for --init-slave=name: "Command(s) that are executed when a slave connects to this master". This text indicate that the --init-slave option is set on a master server, and the master server passes the option's argument to slave which connects to it. This is wrong. Actually the --init-slave option just can be set on a slave server, and then the slave server executes the argument each time the SQL thread starts. Correct the help text for --init-slave option as following: "Command(s) that are executed by a slave server each time the SQL thread starts." sql/mysqld.cc: Correct the help text for --init-slave option. --- sql/mysqld.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ce1d562d0ca..b4eb96ab65a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5275,7 +5275,8 @@ Disable with --skip-large-pages.", #endif {"init-rpl-role", OPT_INIT_RPL_ROLE, "Set the replication role.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"init-slave", OPT_INIT_SLAVE, "Command(s) that are executed when a slave connects to this master", + {"init-slave", OPT_INIT_SLAVE, "Command(s) that are executed by a slave server \ +each time the SQL thread starts.", (gptr*) &opt_init_slave, (gptr*) &opt_init_slave, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"innodb", OPT_INNODB, "Enable InnoDB (if this version of MySQL supports it). \ -- cgit v1.2.1