From d02b8a3bcc2f3f0d088a8f2dfb45a15c79d56833 Mon Sep 17 00:00:00 2001 From: Kristofer Pettersson Date: Tue, 14 Oct 2008 15:41:35 +0200 Subject: Bug#37416 When SQL_NO_CACHE is used, MySQL still lookup into the query cache The query cache module did not check for the SQL_NO_CACHE keyword before attempting to query the hash lookup table. This had a small performance impact. By introducing a check on the query string before obtaining the hash mutex we can gain some performance if the SQL_NO_CACHE directive is used often. --- sql/sql_cache.cc | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'sql') diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index b487f092f75..b4fe1e65bbc 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -363,6 +363,43 @@ TYPELIB query_cache_type_typelib= array_elements(query_cache_type_names)-1,"", query_cache_type_names, NULL }; + +/** + Helper function for determine if a SELECT statement has a SQL_NO_CACHE + directive. + + @param sql A pointer to the first white space character after SELECT + + @return + @retval TRUE The character string contains SQL_NO_CACHE + @retval FALSE No directive found. +*/ + +static bool has_no_cache_directive(char *sql) +{ + int i=0; + while (sql[i] == ' ') + ++i; + + if (my_toupper(system_charset_info, sql[i]) == 'S' && + my_toupper(system_charset_info, sql[i+1]) == 'Q' && + my_toupper(system_charset_info, sql[i+2]) == 'L' && + my_toupper(system_charset_info, sql[i+3]) == '_' && + my_toupper(system_charset_info, sql[i+4]) == 'N' && + my_toupper(system_charset_info, sql[i+5]) == 'O' && + my_toupper(system_charset_info, sql[i+6]) == '_' && + my_toupper(system_charset_info, sql[i+7]) == 'C' && + my_toupper(system_charset_info, sql[i+8]) == 'A' && + my_toupper(system_charset_info, sql[i+9]) == 'C' && + my_toupper(system_charset_info, sql[i+10]) == 'H' && + my_toupper(system_charset_info, sql[i+11]) == 'E' && + my_toupper(system_charset_info, sql[i+12]) == ' ') + return TRUE; + + return FALSE; +} + + /***************************************************************************** Query_cache_block_table method(s) *****************************************************************************/ @@ -1085,6 +1122,16 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached")); goto err; } + + if (query_length > 20 && has_no_cache_directive(&sql[i+6])) + { + /* + We do not increase 'refused' statistics here since it will be done + later when the query is parsed. + */ + DBUG_PRINT("qcache", ("The statement has a SQL_NO_CACHE directive")); + goto err; + } } #ifdef __WIN__ -- cgit v1.2.1 From ff707d56d4e0bdb21149a70e34acc5e047506c5b Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 11 Nov 2008 14:42:32 +0400 Subject: Bug#31435 ha_innodb.cc:3983: ulint convert_search_mode_to_innobase(ha_rkey_function): Asse I think we don't need to issue an error statement in the convert_search_mode_to_innobase(). Returning the PAGE_CUR_UNSUPP value is enough as allows to handle this case depending on the requirements. per-file comments: sql/ha_innodb.cc Bug#31435 ha_innodb.cc:3983: ulint convert_search_mode_to_innobase(ha_rkey_function): Asse no error issued in convert_search_mode_to_innobase. ha_innobase::records_in_range() returns HA_POS_ERROR if search mode isn't supported. --- sql/ha_innodb.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 1c0f8a6e9b3..611a1197215 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -3723,7 +3723,6 @@ convert_search_mode_to_innobase( case HA_READ_MBR_WITHIN: case HA_READ_MBR_DISJOINT: case HA_READ_MBR_EQUAL: - my_error(ER_TABLE_CANT_HANDLE_SPKEYS, MYF(0)); return(PAGE_CUR_UNSUPP); /* do not use "default:" in order to produce a gcc warning: enumeration value '...' not handled in switch @@ -5204,7 +5203,7 @@ ha_innobase::records_in_range( mode2); } else { - n_rows = 0; + n_rows = HA_POS_ERROR; } dtuple_free_for_mysql(heap1); -- cgit v1.2.1 From a01946373d5752c921c4daddfec5c6cdfdbfa627 Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Wed, 28 Jan 2009 20:59:08 +0300 Subject: Fix for bug #21205: Different number of digits for float/double/real in --ps-protocol Various parts of code used different 'precision' arguments for sprintf("%g") when converting floating point numbers to a string. This led to differences in results in some cases depending on whether the text-based or prepared statements protocol is used for a query. Fixed by changing arguments to sprintf("%g") to always be 15 (DBL_DIG) so that results are consistent regardless of the protocol. This patch will be null-merged to 6.0 as the problem does not exists there (fixed by the patch for WL#2934). client/sql_string.cc: Use 15 (DBL_DIG) as a precision argument for sprintf(), as Field_double::val_str() does. libmysql/libmysql.c: Use 15 (DBL_DIG) as a precision argument for sprintf(), as Field_double::val_str() does. mysql-test/r/archive_gis.result: Fixed test results to take additional precision into account. mysql-test/r/func_group.result: Fixed test results to take additional precision into account. mysql-test/r/func_math.result: Fixed test results to take additional precision into account. mysql-test/r/func_str.result: Fixed test results to take additional precision into account. mysql-test/r/gis.result: Fixed test results to take additional precision into account. mysql-test/r/innodb_gis.result: Fixed test results to take additional precision into account. mysql-test/r/select.result: Fixed test results to take additional precision into account. mysql-test/r/sp.result: Fixed test results to take additional precision into account. mysql-test/r/type_float.result: Fixed test results to take additional precision into account. mysql-test/t/type_float.test: Fixed test results to take additional precision into account. sql/sql_string.cc: Use 15 (DBL_DIG) as a precision argument for sprintf(), as Field_double::val_str() does. --- sql/sql_string.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 75e47dd0c8e..a7d6d5db411 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -125,7 +125,7 @@ bool String::set(double num,uint decimals, CHARSET_INFO *cs) str_charset=cs; if (decimals >= NOT_FIXED_DEC) { - uint32 len= my_sprintf(buff,(buff, "%.14g",num));// Enough for a DATETIME + uint32 len= my_sprintf(buff,(buff, "%.15g",num));// Enough for a DATETIME return copy(buff, len, &my_charset_latin1, cs, &dummy_errors); } #ifdef HAVE_FCONVERT @@ -677,7 +677,7 @@ void String::qs_append(const char *str, uint32 len) void String::qs_append(double d) { char *buff = Ptr + str_length; - str_length+= my_sprintf(buff, (buff, "%.14g", d)); + str_length+= my_sprintf(buff, (buff, "%.15g", d)); } void String::qs_append(double *d) -- cgit v1.2.1 From 0669b79363b940c4673d972d1fa8142c2d3e0823 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 10 Feb 2009 11:58:19 +0200 Subject: Bug #33813: Schema names are case-sensitive in DROP FUNCTION The parser was not using the correct fully-qualified-name production for DROP FUNCTION. Fixed by copying the production from DROP PROCEDURE. Tested in the windows specific suite to make sure it's tested on a case-insensitive file system. mysql-test/r/windows.result: Bug #33813: test case mysql-test/t/windows.test: Bug #33813: test case sql/sql_yacc.yy: Bug #33813: use the correct production for the name in DROP PROCEDURE --- sql/sql_yacc.yy | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) (limited to 'sql') diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0eefe782354..fbaf761cc33 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7507,44 +7507,17 @@ drop: lex->drop_if_exists=$3; lex->name=$4.str; } - | DROP FUNCTION_SYM if_exists ident '.' ident + | DROP FUNCTION_SYM if_exists sp_name { - THD *thd= YYTHD; - LEX *lex= thd->lex; - sp_name *spname; - if (lex->sphead) - { - my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"); - MYSQL_YYABORT; - } - lex->sql_command = SQLCOM_DROP_FUNCTION; - lex->drop_if_exists= $3; - spname= new sp_name($4, $6, true); - if (spname == NULL) - MYSQL_YYABORT; - spname->init_qname(thd); - lex->spname= spname; - } - | DROP FUNCTION_SYM if_exists ident - { - THD *thd= YYTHD; - LEX *lex= thd->lex; - LEX_STRING db= {0, 0}; - sp_name *spname; + LEX *lex= Lex; if (lex->sphead) { my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"); MYSQL_YYABORT; } - if (thd->db && lex->copy_db_to(&db.str, &db.length)) - MYSQL_YYABORT; lex->sql_command = SQLCOM_DROP_FUNCTION; lex->drop_if_exists= $3; - spname= new sp_name(db, $4, false); - if (spname == NULL) - MYSQL_YYABORT; - spname->init_qname(thd); - lex->spname= spname; + lex->spname= $4; } | DROP PROCEDURE if_exists sp_name { -- cgit v1.2.1 From fd8bf58ca972ef3f521aec03c0bd09fa3ec78335 Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Tue, 10 Feb 2009 15:38:56 +0300 Subject: Fix for bug #41868: crash or memory overrun with concat + upper, date_format functions String::realloc() did not check whether the existing string data fits in the newly allocated buffer for cases when reallocating a String object with external buffer (i.e.alloced == FALSE). This could lead to memory overruns in some cases. client/sql_string.cc: Fixed String::realloc() to check whether the existing string data fits in the newly allocated buffer for cases when reallocating a String object with external buffer. mysql-test/r/func_str.result: Added a test case for bug #41868. mysql-test/t/func_str.test: Added a test case for bug #41868. sql/sql_class.cc: After each call to Item::send() in select_send::send_data() reset buffer to its original state to reduce unnecessary malloc() calls. See comments for bug #41868 for detailed analysis. sql/sql_string.cc: Fixed String::realloc() to check whether the existing string data fits in the newly allocated buffer for cases when reallocating a String object with external buffer. --- sql/sql_class.cc | 5 +++++ sql/sql_string.cc | 15 ++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 91c0aa66761..9ff602bb62e 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1047,6 +1047,11 @@ bool select_send::send_data(List &items) my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); break; } + /* + Reset buffer to its original state, as it may have been altered in + Item::send(). + */ + buffer.set(buff, sizeof(buff), &my_charset_bin); } thd->sent_row_count++; if (!thd->vio_ok()) diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 75e47dd0c8e..ed1dc9eac77 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -71,25 +71,22 @@ bool String::realloc(uint32 alloc_length) char *new_ptr; if (alloced) { - if ((new_ptr= (char*) my_realloc(Ptr,len,MYF(MY_WME)))) - { - Ptr=new_ptr; - Alloced_length=len; - } - else - return TRUE; // Signal error + if (!(new_ptr= (char*) my_realloc(Ptr,len,MYF(MY_WME)))) + return TRUE; // Signal error } else if ((new_ptr= (char*) my_malloc(len,MYF(MY_WME)))) { + if (str_length > len - 1) + str_length= 0; if (str_length) // Avoid bugs in memcpy on AIX memcpy(new_ptr,Ptr,str_length); new_ptr[str_length]=0; - Ptr=new_ptr; - Alloced_length=len; alloced=1; } else return TRUE; // Signal error + Ptr= new_ptr; + Alloced_length= len; } Ptr[alloc_length]=0; // This make other funcs shorter return FALSE; -- cgit v1.2.1 From 5803e106282eddbfed171f5d76f5357418d32af7 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 12 Feb 2009 13:49:44 +0400 Subject: BUG#36737 - having + full text operator crashes mysql MATCH() function accepts column list as an argument. It was possible to override this requirement with aliased non-column select expression. Which results in server crash. With this fix aliased non-column select expressions are not accepted by MATCH() function, returning an error. mysql-test/r/fulltext.result: A test case for BUG#36737. mysql-test/t/fulltext.test: A test case for BUG#36737. sql/item_func.cc: Only accept fields as arguments to MATCH(). --- sql/item_func.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index 913b32ccb88..55324923fe2 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4961,7 +4961,10 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref) if (item->type() == Item::REF_ITEM) args[i]= item= *((Item_ref *)item)->ref; if (item->type() != Item::FIELD_ITEM) - key=NO_SUCH_KEY; + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "AGAINST"); + return TRUE; + } } /* Check that all columns come from the same table. -- cgit v1.2.1 From 1c5fa3b6a90ab659f42e05f16f3e65b72c661700 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 12 Feb 2009 16:36:43 +0200 Subject: Bug #33813: Schema names are case-sensitive in DROP FUNCTION Additional fix: 1. Revert the unification of DROP FUNCTION and DROP PROCEDURE, because DROP FUNCTION can be used to drop UDFs (that have a non-qualified name and don't require database name to be present and valid). 2. Fixed the case sensitivity problem by adding a call to check_db_name() (similar to the sp_name production). --- sql/sql_yacc.yy | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index fbaf761cc33..51fb5dbdfe4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7507,9 +7507,16 @@ drop: lex->drop_if_exists=$3; lex->name=$4.str; } - | DROP FUNCTION_SYM if_exists sp_name + | DROP FUNCTION_SYM if_exists ident '.' ident { - LEX *lex= Lex; + THD *thd= YYTHD; + LEX *lex= thd->lex; + sp_name *spname; + if ($4.str && check_db_name($4.str)) + { + my_error(ER_WRONG_DB_NAME, MYF(0), $4.str); + MYSQL_YYABORT; + } if (lex->sphead) { my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"); @@ -7517,7 +7524,32 @@ drop: } lex->sql_command = SQLCOM_DROP_FUNCTION; lex->drop_if_exists= $3; - lex->spname= $4; + spname= new sp_name($4, $6, true); + if (spname == NULL) + MYSQL_YYABORT; + spname->init_qname(thd); + lex->spname= spname; + } + | DROP FUNCTION_SYM if_exists ident + { + THD *thd= YYTHD; + LEX *lex= thd->lex; + LEX_STRING db= {0, 0}; + sp_name *spname; + if (lex->sphead) + { + my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"); + MYSQL_YYABORT; + } + if (thd->db && lex->copy_db_to(&db.str, &db.length)) + MYSQL_YYABORT; + lex->sql_command = SQLCOM_DROP_FUNCTION; + lex->drop_if_exists= $3; + spname= new sp_name(db, $4, false); + if (spname == NULL) + MYSQL_YYABORT; + spname->init_qname(thd); + lex->spname= spname; } | DROP PROCEDURE if_exists sp_name { -- cgit v1.2.1 From 544fa7593b92a3949b9676e9abd9ad5e7a1a5c30 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Tue, 17 Feb 2009 18:22:48 +0400 Subject: Bug#25830 SHOW TABLE STATUS behaves differently depending on table name(for 5.0 only) replace wild_case_compare with my_wildcmp which is multibyte safe function mysql-test/r/lowercase_utf8.result: test result mysql-test/t/lowercase_utf8-master.opt: test case mysql-test/t/lowercase_utf8.test: test case sql/sql_show.cc: replace wild_case_compare with my_wildcmp which is multibyte safe function --- sql/sql_show.cc | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index d6bb3427fe4..19155eec06b 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -287,11 +287,18 @@ find_files(THD *thd, List *files, const char *db, #ifndef NO_EMBEDDED_ACCESS_CHECKS uint col_access=thd->col_access; #endif + uint wild_length= 0; TABLE_LIST table_list; DBUG_ENTER("find_files"); - if (wild && !wild[0]) - wild=0; + if (wild) + { + if (!wild[0]) + wild= 0; + else + wild_length= strlen(wild); + } + bzero((char*) &table_list,sizeof(table_list)); @@ -340,8 +347,11 @@ find_files(THD *thd, List *files, const char *db, { if (lower_case_table_names) { - if (wild_case_compare(files_charset_info, file->name, wild)) - continue; + if (my_wildcmp(files_charset_info, + file->name, file->name + strlen(file->name), + wild, wild + wild_length, + wild_prefix, wild_one,wild_many)) + continue; } else if (wild_compare(file->name,wild,0)) continue; -- cgit v1.2.1 From 321646095d943c62b975126d059f22f672b41e46 Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Thu, 19 Feb 2009 11:49:35 +0300 Subject: Fix for bug #41078: With CURSOR_TYPE_READ_ONLY mysql_stmt_fetch() returns short string value. Multibyte character sets were not taken into account when calculating max_length in Item_param::convert_str_value(). As a result, string parameters of a prepared statement could be truncated later when calculating string length in characters by dividing length in bytes by the charset's mbmaxlen value (e.g. in Field_varstring::store()). Fixed by taking charset's mbmaxlen into account when calculating max_length in Item_param::convert_str_value(). sql/item.cc: Multiply string's length in characters by charset's mbmaxlen when calculating max_length. tests/mysql_client_test.c: Added a test case for bug #41078. --- sql/item.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index bc1ae683e93..c9edb7b8f6c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3010,7 +3010,7 @@ bool Item_param::convert_str_value(THD *thd) str_value.set_charset(value.cs_info.final_character_set_of_str_value); /* Here str_value is guaranteed to be in final_character_set_of_str_value */ - max_length= str_value.length(); + max_length= str_value.numchars() * str_value.charset()->mbmaxlen; decimals= 0; /* str_value_ptr is returned from val_str(). It must be not alloced -- cgit v1.2.1 From c2e23208ef7ae6b315ca4988e903bff2bc0284d4 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Thu, 19 Feb 2009 17:20:44 +0400 Subject: Bug#37601 Cast Is Not Done On Row Comparison In case of ROW item each compared pair does not check if argumet collations can be aggregated and thus appropiriate item conversion does not happen. The fix is to add the check and convertion for ROW pairs. mysql-test/r/row.result: test result mysql-test/t/row.test: test case sql/item.cc: added agg_item_set_converter() function which was a part of agg_item_charsets() func. The only difference is that agg_item_set_converter() checks and converts items using already known collation. sql/item.h: added agg_item_set_converter() function sql/item_cmpfunc.cc: In case of ROW item each compared pair does not check if argumet collations can be aggregated and thus appropiriate item conversion does not happen. The fix is to add the check and convertion for ROW pairs. --- sql/item.cc | 76 ++++++++++++++++++++++++++++++----------------------- sql/item.h | 2 ++ sql/item_cmpfunc.cc | 13 ++++++++- 3 files changed, 57 insertions(+), 34 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index c9edb7b8f6c..14422bd3e92 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1608,42 +1608,11 @@ bool agg_item_collations_for_comparison(DTCollation &c, const char *fname, } -/* - Collect arguments' character sets together. - We allow to apply automatic character set conversion in some cases. - The conditions when conversion is possible are: - - arguments A and B have different charsets - - A wins according to coercibility rules - (i.e. a column is stronger than a string constant, - an explicit COLLATE clause is stronger than a column) - - character set of A is either superset for character set of B, - or B is a string constant which can be converted into the - character set of A without data loss. - - If all of the above is true, then it's possible to convert - B into the character set of A, and then compare according - to the collation of A. - - For functions with more than two arguments: - - collect(A,B,C) ::= collect(collect(A,B),C) - Since this function calls THD::change_item_tree() on the passed Item ** - pointers, it is necessary to pass the original Item **'s, not copies. - Otherwise their values will not be properly restored (see BUG#20769). - If the items are not consecutive (eg. args[2] and args[5]), use the - item_sep argument, ie. - - agg_item_charsets(coll, fname, &args[2], 2, flags, 3) - -*/ - -bool agg_item_charsets(DTCollation &coll, const char *fname, - Item **args, uint nargs, uint flags, int item_sep) +bool agg_item_set_converter(DTCollation &coll, const char *fname, + Item **args, uint nargs, uint flags, int item_sep) { Item **arg, *safe_args[2]; - if (agg_item_collations(coll, fname, args, nargs, flags, item_sep)) - return TRUE; /* For better error reporting: save the first and the second argument. @@ -1724,6 +1693,47 @@ bool agg_item_charsets(DTCollation &coll, const char *fname, } +/* + Collect arguments' character sets together. + We allow to apply automatic character set conversion in some cases. + The conditions when conversion is possible are: + - arguments A and B have different charsets + - A wins according to coercibility rules + (i.e. a column is stronger than a string constant, + an explicit COLLATE clause is stronger than a column) + - character set of A is either superset for character set of B, + or B is a string constant which can be converted into the + character set of A without data loss. + + If all of the above is true, then it's possible to convert + B into the character set of A, and then compare according + to the collation of A. + + For functions with more than two arguments: + + collect(A,B,C) ::= collect(collect(A,B),C) + + Since this function calls THD::change_item_tree() on the passed Item ** + pointers, it is necessary to pass the original Item **'s, not copies. + Otherwise their values will not be properly restored (see BUG#20769). + If the items are not consecutive (eg. args[2] and args[5]), use the + item_sep argument, ie. + + agg_item_charsets(coll, fname, &args[2], 2, flags, 3) + +*/ + +bool agg_item_charsets(DTCollation &coll, const char *fname, + Item **args, uint nargs, uint flags, int item_sep) +{ + Item **arg, *safe_args[2]; + if (agg_item_collations(coll, fname, args, nargs, flags, item_sep)) + return TRUE; + + return agg_item_set_converter(coll, fname, args, nargs, flags, item_sep); +} + + void Item_ident_for_show::make_field(Send_field *tmp_field) { tmp_field->table_name= tmp_field->org_table_name= table_name; diff --git a/sql/item.h b/sql/item.h index 1058cc5dbb8..852b0fcc1ba 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1169,6 +1169,8 @@ bool agg_item_collations(DTCollation &c, const char *name, Item **items, uint nitems, uint flags, int item_sep); bool agg_item_collations_for_comparison(DTCollation &c, const char *name, Item **items, uint nitems, uint flags); +bool agg_item_set_converter(DTCollation &coll, const char *fname, + Item **args, uint nargs, uint flags, int item_sep); bool agg_item_charsets(DTCollation &c, const char *name, Item **items, uint nitems, uint flags, int item_sep); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 3b1d18b4252..01d3e9bed52 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -490,7 +490,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) my_error(ER_OPERAND_COLUMNS, MYF(0), (*a)->element_index(i)->cols()); return 1; } - comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)); + if (comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i))) + return 1; } break; } @@ -835,6 +836,16 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg, get_value_func= &get_time_value; return 0; } + else if (type == STRING_RESULT && + (*a)->result_type() == STRING_RESULT && + (*b)->result_type() == STRING_RESULT) + { + DTCollation coll; + coll.set((*a)->collation.collation); + if (agg_item_set_converter(coll, owner_arg->func_name(), + b, 1, MY_COLL_CMP_CONV, 1)) + return 1; + } return set_compare_func(owner_arg, type); } -- cgit v1.2.1 From 29476d879f85a81c9376b556ad9c233f2a5e073b Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 19 Feb 2009 17:30:03 +0200 Subject: Bug #42419: Server crash with "Pure virtual method called" on two concurrent connections The problem is that tables can enter open table cache for a thread without being properly cleaned up. This can happen if make_join_statistics() fails to read a const table because of e.g. a deadlock. It does set a member of TABLE structure to a value it allocates, but doesn't clean-up this setting on error nor does it set the rest of the members in JOIN to allow for automatic cleanup. As a result when such an error occurs and the next statement depends re-uses the table from the open tables cache it will get it with this TABLE::reginfo.join_tab pointing to a memory area that's freed. Fixed by making sure make_join_statistics() cleans up TABLE::reginfo.join_tab on error. mysql-test/r/innodb_mysql.result: Bug #42419: test case mysql-test/t/innodb_mysql-master.opt: Bug #42419: increase the timeout so it covers te conservative sleep 3 in the test mysql-test/t/innodb_mysql.test: Bug #42419: test case sql/sql_select.cc: Bug #42419: clean up the members of TABLE on failure in make_join_statisitcs() --- sql/sql_select.cc | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a341cf5e0e9..a820e9966dc 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2373,11 +2373,12 @@ typedef struct st_sargable_param */ static bool -make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, +make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, DYNAMIC_ARRAY *keyuse_array) { int error; TABLE *table; + TABLE_LIST *tables= tables_arg; uint i,table_count,const_count,key; table_map found_const_table_map, all_table_map, found_ref, refs; key_map const_ref, eq_part; @@ -2415,10 +2416,10 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, table_vector[i]=s->table=table=tables->table; table->pos_in_table_list= tables; error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); - if(error) + if (error) { - table->file->print_error(error, MYF(0)); - DBUG_RETURN(1); + table->file->print_error(error, MYF(0)); + goto error; } table->quick_keys.clear_all(); table->reginfo.join_tab=s; @@ -2503,7 +2504,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, { join->tables=0; // Don't use join->table my_message(ER_WRONG_OUTER_JOIN, ER(ER_WRONG_OUTER_JOIN), MYF(0)); - DBUG_RETURN(1); + goto error; } s->key_dependent= s->dependent; } @@ -2513,7 +2514,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, if (update_ref_and_keys(join->thd, keyuse_array, stat, join->tables, conds, join->cond_equal, ~outer_join, join->select_lex, &sargables)) - DBUG_RETURN(1); + goto error; /* Read tables with 0 or 1 rows (system tables) */ join->const_table_map= 0; @@ -2529,7 +2530,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, if ((tmp=join_read_const_table(s, p_pos))) { if (tmp > 0) - DBUG_RETURN(1); // Fatal error + goto error; // Fatal error } else found_const_table_map|= s->table->map; @@ -2601,7 +2602,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, if ((tmp= join_read_const_table(s, join->positions+const_count-1))) { if (tmp > 0) - DBUG_RETURN(1); // Fatal error + goto error; // Fatal error } else found_const_table_map|= table->map; @@ -2650,12 +2651,12 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, set_position(join,const_count++,s,start_keyuse); if (create_ref_for_key(join, s, start_keyuse, found_const_table_map)) - DBUG_RETURN(1); + goto error; if ((tmp=join_read_const_table(s, join->positions+const_count-1))) { if (tmp > 0) - DBUG_RETURN(1); // Fatal error + goto error; // Fatal error } else found_const_table_map|= table->map; @@ -2732,7 +2733,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, *s->on_expr_ref ? *s->on_expr_ref : conds, 1, &error); if (!select) - DBUG_RETURN(1); + goto error; records= get_quick_record_count(join->thd, select, s->table, &s->const_keys, join->row_limit); s->quick=select->quick; @@ -2778,7 +2779,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, { optimize_keyuse(join, keyuse_array); if (choose_plan(join, all_table_map & ~join->const_table_map)) - DBUG_RETURN(TRUE); + goto error; } else { @@ -2788,6 +2789,17 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds, } /* Generate an execution plan from the found optimal join order. */ DBUG_RETURN(join->thd->killed || get_best_combination(join)); + +error: + /* + Need to clean up join_tab from TABLEs in case of error. + They won't get cleaned up by JOIN::cleanup() because JOIN::join_tab + may not be assigned yet by this function (which is building join_tab). + Dangling TABLE::reginfo.join_tab may cause part_of_refkey to choke. + */ + for (tables= tables_arg; tables; tables= tables->next_leaf) + tables->table->reginfo.join_tab= NULL; + DBUG_RETURN (1); } -- cgit v1.2.1 From c1ddc60c695e49a44555049768cb8557676840aa Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 20 Feb 2009 11:42:35 +0200 Subject: fixed a warning --- sql/item.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 14422bd3e92..f32828629cf 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1726,7 +1726,6 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname, bool agg_item_charsets(DTCollation &coll, const char *fname, Item **args, uint nargs, uint flags, int item_sep) { - Item **arg, *safe_args[2]; if (agg_item_collations(coll, fname, args, nargs, flags, item_sep)) return TRUE; -- cgit v1.2.1 From 4712e6b9b8e61e468ee94ec65105e61881f77421 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Fri, 20 Feb 2009 13:55:43 +0200 Subject: Bug #37313 BINLOG Contains Incorrect server id Signed integer format specifier forced to print the binlog header with server_id negative if the unsigned value sets the sign-bit ON. Fixed with correcting the specifier to correspond to typeof(server_id) == ulong. mysql-test/r/mysqlbinlog.result: results changed. mysql-test/t/mysqlbinlog.test: displaying the expected unsignedly formatted server_id value, bug#37313. sql/log_event.cc: Format specifier is corrected to correspond to typeof(server_id). --- sql/log_event.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index ef419aaee40..90805877502 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -976,7 +976,7 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info) fputc('#', file); print_timestamp(file); - fprintf(file, " server id %d end_log_pos %s ", server_id, + fprintf(file, " server id %lu end_log_pos %s ", server_id, llstr(log_pos,llbuff)); /* mysqlbinlog --hexdump */ -- cgit v1.2.1 From 0e62c9aa6301de71164496ec7c81c871d78ce8cd Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Mon, 23 Feb 2009 14:28:26 +0200 Subject: Fix for bug #15936: "round" differs on Windows to Unix Both of our own implementations of rint(3) were inconsistent with the most common behavior of rint() on those platforms that have it: round to nearest, break ties by rounding to nearest even. Fixed by leaving just one implementation of rint() in our source tree, and changing its behavior to match the most common native implementations on other platforms. configure.in: Added checks for fenv.h and fesetround(). include/config-win.h: Removed the incorrect implementation of rint() for Windows. include/my_global.h: Added an rint() implementation for platforms that do not have it. mysql-test/r/func_math.result: Added a test case for bug #15936. mysql-test/t/func_math.test: Added a test case for bug #15936. sql/mysqld.cc: Explicitly set the FPU rounding mode with fesetround(). --- sql/mysqld.cc | 51 ++++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 23 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ca68976d939..7856309b095 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -186,39 +186,44 @@ int initgroups(const char *,unsigned int); #ifdef HAVE_FP_EXCEPT // Fix type conflict typedef fp_except fp_except_t; #endif +#endif /* __FreeBSD__ && HAVE_IEEEFP_H */ +#ifdef HAVE_FENV_H +#include +#endif +#ifdef HAVE_SYS_FPU_H +/* for IRIX to use set_fpc_csr() */ +#include +#endif +inline void setup_fpu() +{ +#if defined(__FreeBSD__) && defined(HAVE_IEEEFP_H) /* We can't handle floating point exceptions with threads, so disable this on freebsd + Don't fall for overflow, underflow,divide-by-zero or loss of precision */ - -inline void set_proper_floating_point_mode() -{ - /* Don't fall for overflow, underflow,divide-by-zero or loss of precision */ #if defined(__i386__) fpsetmask(~(FP_X_INV | FP_X_DNML | FP_X_OFL | FP_X_UFL | FP_X_DZ | FP_X_IMP)); #else - fpsetmask(~(FP_X_INV | FP_X_OFL | FP_X_UFL | FP_X_DZ | - FP_X_IMP)); -#endif -} -#elif defined(__sgi) -/* for IRIX to use set_fpc_csr() */ -#include + fpsetmask(~(FP_X_INV | FP_X_OFL | FP_X_UFL | FP_X_DZ | + FP_X_IMP)); +#endif /* __i386__ */ +#endif /* __FreeBSD__ && HAVE_IEEEFP_H */ -inline void set_proper_floating_point_mode() -{ +#ifdef HAVE_FESETROUND + /* Set FPU rounding mode to "round-to-nearest" */ + fesetround(FE_TONEAREST); +#endif /* HAVE_FESETROUND */ + +#if defined(__sgi) && defined(HAVE_SYS_FPU_H) /* Enable denormalized DOUBLE values support for IRIX */ - { - union fpc_csr n; - n.fc_word = get_fpc_csr(); - n.fc_struct.flush = 0; - set_fpc_csr(n.fc_word); - } + union fpc_csr n; + n.fc_word = get_fpc_csr(); + n.fc_struct.flush = 0; + set_fpc_csr(n.fc_word); +#endif } -#else -#define set_proper_floating_point_mode() -#endif /* __FreeBSD__ && HAVE_IEEEFP_H */ } /* cplusplus */ @@ -3279,7 +3284,7 @@ static int init_server_components() query_cache_init(); query_cache_resize(query_cache_size); randominit(&sql_rand,(ulong) server_start_time,(ulong) server_start_time/2); - set_proper_floating_point_mode(); + setup_fpu(); init_thr_lock(); #ifdef HAVE_REPLICATION init_slave_list(); -- cgit v1.2.1 From 11b20f27affcdaeb528feb2d08c920771bd875ef Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Tue, 24 Feb 2009 10:15:21 +0100 Subject: Bug#41110: crash with handler command when used concurrently with alter table Bug#41112: crash in mysql_ha_close_table/get_lock_data with alter table The problem is that the server wasn't handling robustly failures to re-open a table during a HANDLER .. READ statement. If the table needed to be re-opened due to it's storage engine being altered to one that doesn't support HANDLER, a reference (dangling pointer) to a closed table could be left in place and accessed in later attempts to fetch from the table using the handler. Also, if the server failed to set a error message if the re-open failed. These problems could lead to server crashes or hangs. The solution is to remove any references to a closed table and to set a error if reopening a table during a HANDLER .. READ statement fails. There is no test case in this change set as the test depends on a testing feature only available on 5.1 and later. sql/sql_handler.cc: Remove redundant reopen check. Set errors even if reopening table. Reset TABLE_LIST::table reference when the table is closed. --- sql/sql_handler.cc | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'sql') diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 822f2b2c419..f58a4ec4921 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -151,6 +151,9 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables) } VOID(pthread_mutex_unlock(&LOCK_open)); } + + /* Mark table as closed, ready for re-open if necessary. */ + tables->table= NULL; } /* @@ -168,8 +171,7 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables) 'reopen' is set when a handler table is to be re-opened. In this case, 'tables' is the pointer to the hashed TABLE_LIST object which has been saved on the original open. - 'reopen' is also used to suppress the sending of an 'ok' message or - error messages. + 'reopen' is also used to suppress the sending of an 'ok' message. RETURN FALSE OK @@ -205,8 +207,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) strlen(tables->alias) + 1)) { DBUG_PRINT("info",("duplicate '%s'", tables->alias)); - if (! reopen) - my_error(ER_NONUNIQ_TABLE, MYF(0), tables->alias); + my_error(ER_NONUNIQ_TABLE, MYF(0), tables->alias); goto err; } } @@ -251,8 +252,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) /* There can be only one table in '*tables'. */ if (! (tables->table->file->table_flags() & HA_CAN_SQL_HANDLER)) { - if (! reopen) - my_error(ER_ILLEGAL_HA, MYF(0), tables->alias); + my_error(ER_ILLEGAL_HA, MYF(0), tables->alias); goto err; } @@ -464,8 +464,7 @@ retry: if (need_reopen) { - mysql_ha_close_table(thd, tables); - hash_tables->table= NULL; + mysql_ha_close_table(thd, hash_tables); /* The lock might have been aborted, we need to manually reset thd->some_tables_deleted because handler's tables are closed -- cgit v1.2.1 From 0f6e7f11761cb696103b01f452b5d5afe10bea97 Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Wed, 25 Feb 2009 10:36:11 +0200 Subject: Fixed a build failure on Ubuntu 8.10 introduced by the patch for bug #15936. On some platforms fenv.h may #undef the min/max macros defined in my_global.h. Fixed by moving the #include directive for fenv.h from mysqld.cc to my_global.h before definitions for min/max. include/my_global.h: Moved #include from mysqld.cc. sql/mysqld.cc: Moved #include to my_global.h. --- sql/mysqld.cc | 3 --- 1 file changed, 3 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7856309b095..fcde4e2b626 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -187,9 +187,6 @@ int initgroups(const char *,unsigned int); typedef fp_except fp_except_t; #endif #endif /* __FreeBSD__ && HAVE_IEEEFP_H */ -#ifdef HAVE_FENV_H -#include -#endif #ifdef HAVE_SYS_FPU_H /* for IRIX to use set_fpc_csr() */ #include -- cgit v1.2.1 From d091deaf89a09881a34ef67335d042354da75c11 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Tue, 24 Feb 2009 16:17:34 +0200 Subject: fixing compilation warning and adding flush logs to test of bug#37313 --- sql/log_event.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index 90805877502..b74b38e55b2 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -976,7 +976,7 @@ void Log_event::print_header(FILE* file, PRINT_EVENT_INFO* print_event_info) fputc('#', file); print_timestamp(file); - fprintf(file, " server id %lu end_log_pos %s ", server_id, + fprintf(file, " server id %lu end_log_pos %s ", (ulong) server_id, llstr(log_pos,llbuff)); /* mysqlbinlog --hexdump */ -- cgit v1.2.1 From 2bc4ad4f1f0faa191d9b5844677030fbea402db0 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 25 Feb 2009 14:20:20 +0400 Subject: Bug#30305 Create routine in wrong context in SHOW PRIVILEGES Changed context of Create routine to Databases. mysql-test/r/grant.result: result fix mysql-test/r/sp.result: result fix sql/sql_show.cc: Changed context of Create routine to Databases. --- 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 19155eec06b..50bbdeb2771 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -106,7 +106,7 @@ static struct show_privileges_st sys_privileges[]= {"Alter", "Tables", "To alter the table"}, {"Alter routine", "Functions,Procedures", "To alter or drop stored functions/procedures"}, {"Create", "Databases,Tables,Indexes", "To create new databases and tables"}, - {"Create routine","Functions,Procedures","To use CREATE FUNCTION/PROCEDURE"}, + {"Create routine","Databases","To use CREATE FUNCTION/PROCEDURE"}, {"Create temporary tables","Databases","To use CREATE TEMPORARY TABLE"}, {"Create view", "Tables", "To create new views"}, {"Create user", "Server Admin", "To create new users"}, -- cgit v1.2.1 From 5d2fc5335411bdd05a08a9b062d3441d4308dcaa Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 25 Feb 2009 15:44:50 +0400 Subject: Bug#40345 MySQLDump prefixes view name with database name when view references other db print compact view name if the view belongs to the current database mysql-test/r/information_schema_db.result: result fix mysql-test/r/mysqldump.result: result fix mysql-test/r/view_grant.result: result fix sql/sql_show.cc: print compact view name if the view belongs to the current database --- sql/sql_show.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 50bbdeb2771..a3ccf770a3c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1232,21 +1232,25 @@ void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user, static int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) { + my_bool compact_view_name= TRUE; my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL | MODE_ORACLE | MODE_MSSQL | MODE_DB2 | MODE_MAXDB | MODE_ANSI)) != 0; - /* - Compact output format for view can be used - - if user has db of this view as current db - - if this view only references table inside it's own db - */ + if (!thd->db || strcmp(thd->db, table->view_db.str)) - table->compact_view_format= FALSE; + /* + print compact view name if the view belongs to the current database + */ + compact_view_name= table->compact_view_format= FALSE; else { + /* + Compact output format for view body can be used + if this view only references table inside it's own db + */ TABLE_LIST *tbl; table->compact_view_format= TRUE; for (tbl= thd->lex->query_tables; @@ -1267,7 +1271,7 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) view_store_options(thd, table, buff); } buff->append(STRING_WITH_LEN("VIEW ")); - if (!table->compact_view_format) + if (!compact_view_name) { append_identifier(thd, buff, table->view_db.str, table->view_db.length); buff->append('.'); -- cgit v1.2.1 From c9e1884cd6e70d89f0a0c2bce1b80f84b913f59a Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Thu, 26 Feb 2009 12:34:15 +0400 Subject: Fix for bug#19829:make test Failed in mysql_client_test *with --with-charset=utf8* Problem: wrong LONG TEXT field length is sent to a client when multibyte server character set used. Fix: always limit field length sent to a client to 2^32, as we store it in 4 byte slot. Note: mysql_client_test changed accordingly. sql/protocol.cc: Fix for bug#19829:make test Failed in mysql_client_test *with --with-charset=utf8* - limit field length sent to client to UINT_MAX32 as it may exceeds 32 bit slot for LONG TEXT fields if thd_charset->mbmaxlen > 1. tests/mysql_client_test.c: Fix for bug#19829:make test Failed in mysql_client_test *with --with-charset=utf8* - checking field members have in mind that field length is limited to UINT_MAX32. --- sql/protocol.cc | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/protocol.cc b/sql/protocol.cc index ff58d96f59b..2309bac88a9 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -616,7 +616,8 @@ bool Protocol::send_fields(List *list, uint flags) else { /* With conversion */ - uint max_char_len; + ulonglong max_length; + uint32 field_length; int2store(pos, thd_charset->number); /* For TEXT/BLOB columns, field_length describes the maximum data @@ -627,12 +628,21 @@ bool Protocol::send_fields(List *list, uint flags) char_count * mbmaxlen, where character count is taken from the definition of the column. In other words, the maximum number of characters here is limited by the column definition. + + When one has a LONG TEXT column with a single-byte + character set, and the connection character set is multi-byte, the + client may get fields longer than UINT_MAX32, due to + -> conversion. + In that case column max length does not fit into the 4 bytes + reserved for it in the protocol. */ - max_char_len= (field.type >= (int) MYSQL_TYPE_TINY_BLOB && - field.type <= (int) MYSQL_TYPE_BLOB) ? - field.length / item->collation.collation->mbminlen : - field.length / item->collation.collation->mbmaxlen; - int4store(pos+2, max_char_len * thd_charset->mbmaxlen); + max_length= (field.type >= MYSQL_TYPE_TINY_BLOB && + field.type <= MYSQL_TYPE_BLOB) ? + field.length / item->collation.collation->mbminlen : + field.length / item->collation.collation->mbmaxlen; + max_length*= thd_charset->mbmaxlen; + field_length= (max_length > UINT_MAX32) ? UINT_MAX32 : max_length; + int4store(pos + 2, field_length); } pos[6]= field.type; int2store(pos+7,field.flags); -- cgit v1.2.1 From a9d707037ab527564bb84885e0af69a2bb793219 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 26 Feb 2009 19:00:44 +0200 Subject: Bug #41354: Access control is bypassed when all columns of a view are selected by * wildcard Backported a part of the fix for 36086 to 5.0 mysql-test/r/view_grant.result: Bug #41354: test case mysql-test/t/view_grant.test: Bug #41354: test case sql/sql_acl.cc: Bug #41354: return table error when no access and * sql/sql_base.cc: Bug #41354: backported the check in bug 36086 to 5.0 --- sql/sql_acl.cc | 28 ++++++++++++++++++++++------ sql/sql_base.cc | 2 +- 2 files changed, 23 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 22135d376fe..c59c42d512a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3866,6 +3866,11 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg, Security_context *sctx= thd->security_ctx; ulong want_access= want_access_arg; const char *table_name= NULL; + /* + Flag that gets set if privilege checking has to be performed on column + level. + */ + bool using_column_privileges= FALSE; if (grant_option) { @@ -3909,6 +3914,8 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg, GRANT_COLUMN *grant_column= column_hash_search(grant_table, field_name, (uint) strlen(field_name)); + if (grant_column) + using_column_privileges= TRUE; if (!grant_column || (~grant_column->rights & want_access)) goto err; } @@ -3924,12 +3931,21 @@ err: char command[128]; get_privilege_desc(command, sizeof(command), want_access); - my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), - command, - sctx->priv_user, - sctx->host_or_ip, - fields->name(), - table_name); + /* + Do not give an error message listing a column name unless the user has + privilege to see all columns. + */ + if (using_column_privileges) + my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), + command, sctx->priv_user, + sctx->host_or_ip, table_name); + else + my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), + command, + sctx->priv_user, + sctx->host_or_ip, + fields->name(), + table_name); return 1; } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 881c6a421e8..781bbc0a553 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5479,7 +5479,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, #ifndef NO_EMBEDDED_ACCESS_CHECKS /* Ensure that we have access rights to all fields to be inserted. */ - if (!((table && (table->grant.privilege & SELECT_ACL) || + if (!((table && !tables->view && (table->grant.privilege & SELECT_ACL) || tables->view && (tables->grant.privilege & SELECT_ACL))) && !any_privileges) { -- cgit v1.2.1 From 15760fe9d8434dc9c960c123945b13890456bb5f Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 27 Feb 2009 15:25:06 +0200 Subject: Bug #41610: key_infix_len can be overwritten causing some group by queries to return no rows The algorithm of determining the best key for loose index scan is doing a loop over the available indexes and selects the one that has the best cost. It retrieves the parameters of the current index into a set of variables. If the cost of using the current index is lower than the best cost so far it copies these variables into another set of variables that contain the information for the best index so far. After having checked all the indexes it uses these variables (outside of the index loop) to create the table read plan object instance. The was a single omission : the key_infix/key_infix_len variables were used outside of the loop without being preserved in the loop for the best index so far. This causes these variables to get overwritten by the next index(es) checked. Fixed by adding variables to hold the data for the current index, passing the new variables to the function that assigns values to them and copying the new variables into the existing ones when selecting a new current best index. To avoid further such problems moved the declarations of the variables used to keep information about the current index inside the loop's compound statement. mysql-test/r/group_min_max.result: Bug #41610: test case mysql-test/t/group_min_max.test: Bug #41610: test case sql/opt_range.cc: Bug #41610: copy the infix data for the current best index --- sql/opt_range.cc | 57 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 25 deletions(-) (limited to 'sql') diff --git a/sql/opt_range.cc b/sql/opt_range.cc index ebebfafb5d8..018fc8a9d44 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -7775,32 +7775,37 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) */ KEY *cur_index_info= table->key_info; KEY *cur_index_info_end= cur_index_info + table->s->keys; - KEY_PART_INFO *cur_part= NULL; - KEY_PART_INFO *end_part; /* Last part for loops. */ - /* Last index part. */ - KEY_PART_INFO *last_part= NULL; - KEY_PART_INFO *first_non_group_part= NULL; - KEY_PART_INFO *first_non_infix_part= NULL; - uint key_infix_parts= 0; - uint cur_group_key_parts= 0; - uint cur_group_prefix_len= 0; /* Cost-related variables for the best index so far. */ double best_read_cost= DBL_MAX; ha_rows best_records= 0; SEL_ARG *best_index_tree= NULL; ha_rows best_quick_prefix_records= 0; uint best_param_idx= 0; - double cur_read_cost= DBL_MAX; - ha_rows cur_records; + + const uint pk= param->table->s->primary_key; SEL_ARG *cur_index_tree= NULL; ha_rows cur_quick_prefix_records= 0; uint cur_param_idx=MAX_KEY; - key_map cur_used_key_parts; - uint pk= param->table->s->primary_key; for (uint cur_index= 0 ; cur_index_info != cur_index_info_end ; cur_index_info++, cur_index++) { + KEY_PART_INFO *cur_part; + KEY_PART_INFO *end_part; /* Last part for loops. */ + /* Last index part. */ + KEY_PART_INFO *last_part; + KEY_PART_INFO *first_non_group_part; + KEY_PART_INFO *first_non_infix_part; + uint key_infix_parts; + uint cur_group_key_parts= 0; + uint cur_group_prefix_len= 0; + double cur_read_cost; + ha_rows cur_records; + key_map used_key_parts_map; + uint cur_key_infix_len= 0; + byte cur_key_infix[MAX_KEY_LENGTH]; + uint cur_used_key_parts; + /* Check (B1) - if current index is covering. */ if (!table->used_keys.is_set(cur_index)) goto next_index; @@ -7879,7 +7884,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) else if (join->select_distinct) { select_items_it.rewind(); - cur_used_key_parts.clear_all(); + used_key_parts_map.clear_all(); uint max_key_part= 0; while ((item= select_items_it++)) { @@ -7890,13 +7895,13 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) Check if this attribute was already present in the select list. If it was present, then its corresponding key part was alredy used. */ - if (cur_used_key_parts.is_set(key_part_nr)) + if (used_key_parts_map.is_set(key_part_nr)) continue; if (key_part_nr < 1 || key_part_nr > join->fields_list.elements) goto next_index; cur_part= cur_index_info->key_part + key_part_nr - 1; cur_group_prefix_len+= cur_part->store_length; - cur_used_key_parts.set_bit(key_part_nr); + used_key_parts_map.set_bit(key_part_nr); ++cur_group_key_parts; max_key_part= max(max_key_part,key_part_nr); } @@ -7908,7 +7913,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) */ ulonglong all_parts, cur_parts; all_parts= (1<> 1; + cur_parts= used_key_parts_map.to_ulonglong() >> 1; if (all_parts != cur_parts) goto next_index; } @@ -7958,7 +7963,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) &dummy); if (!get_constant_key_infix(cur_index_info, index_range_tree, first_non_group_part, min_max_arg_part, - last_part, thd, key_infix, &key_infix_len, + last_part, thd, cur_key_infix, + &cur_key_infix_len, &first_non_infix_part)) goto next_index; } @@ -8010,9 +8016,9 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) } /* If we got to this point, cur_index_info passes the test. */ - key_infix_parts= key_infix_len ? + key_infix_parts= cur_key_infix_len ? (first_non_infix_part - first_non_group_part) : 0; - used_key_parts= cur_group_key_parts + key_infix_parts; + cur_used_key_parts= cur_group_key_parts + key_infix_parts; /* Compute the cost of using this index. */ if (tree) @@ -8024,7 +8030,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) cur_quick_prefix_records= check_quick_select(param, cur_param_idx, cur_index_tree); } - cost_group_min_max(table, cur_index_info, used_key_parts, + cost_group_min_max(table, cur_index_info, cur_used_key_parts, cur_group_key_parts, tree, cur_index_tree, cur_quick_prefix_records, have_min, have_max, &cur_read_cost, &cur_records); @@ -8035,7 +8041,6 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) */ if (cur_read_cost < best_read_cost - (DBL_EPSILON * cur_read_cost)) { - DBUG_ASSERT(tree != 0 || cur_param_idx == MAX_KEY); index_info= cur_index_info; index= cur_index; best_read_cost= cur_read_cost; @@ -8045,11 +8050,13 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) best_param_idx= cur_param_idx; group_key_parts= cur_group_key_parts; group_prefix_len= cur_group_prefix_len; + key_infix_len= cur_key_infix_len; + if (key_infix_len) + memcpy (key_infix, cur_key_infix, sizeof (key_infix)); + used_key_parts= cur_used_key_parts; } - next_index: - cur_group_key_parts= 0; - cur_group_prefix_len= 0; + next_index:; } if (!index_info) /* No usable index found. */ DBUG_RETURN(NULL); -- cgit v1.2.1 From 97b68934bca29ab88f63d3887071248c0c602a82 Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Fri, 27 Feb 2009 16:11:15 +0200 Subject: Recommit for merging and pushing --- sql/sql_table.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_table.cc b/sql/sql_table.cc index eefe2a5596e..ff7f874ffcb 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2314,7 +2314,12 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, view_checksum(thd, table) == HA_ADMIN_WRONG_CHECKSUM) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, ER_VIEW_CHECKSUM, ER(ER_VIEW_CHECKSUM)); - result_code= HA_ADMIN_CORRUPT; + if (thd->net.last_errno == ER_NO_SUCH_TABLE) + /* A missing table is just issued as a failed command */ + result_code= HA_ADMIN_FAILED; + else + /* Default failure code is corrupt table */ + result_code= HA_ADMIN_CORRUPT; goto send_result; } -- cgit v1.2.1 From c3fec5d22ff38388f68718bf77cca183778978a1 Mon Sep 17 00:00:00 2001 From: Timothy Smith Date: Mon, 2 Mar 2009 17:57:09 -0700 Subject: Applying InnoDB snashot 5.0-ss4007, part 2. Fixes Bug #18828: If InnoDB runs out of undo slots, it returns misleading 'table is full' This is a backport of code already in 5.1+. The error message change referred to in the detailed revision comments is still pending. Detailed revision comments: r3937 | calvin | 2009-01-15 03:11:56 +0200 (Thu, 15 Jan 2009) | 17 lines branches/5.0: Backport the fix for Bug#18828. Return DB_TOO_MANY_CONCURRENT_TRXS when we run out of UNDO slots in the rollback segment. The backport is requested by MySQL under bug#41529 - Safe handling of InnoDB running out of undo log slots. This is a partial fix since the MySQL error code requested to properly report the error condition back to the client has not yet materialized. Currently we have #ifdef'd the error code translation in ha_innodb.cc. This will have to be changed as and when MySQl add the new requested code or an equivalent code that we can then use. Given the above, currently we will get the old behavior, not the "fixed" and intended behavior. Approved by: Heikki (on IM) --- sql/ha_innodb.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'sql') diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index e0b7fb6e7f5..3bae0da3e02 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -524,6 +524,20 @@ convert_error_code_to_mysql( mark_transaction_to_rollback(thd, TRUE); return(HA_ERR_LOCK_TABLE_FULL); + } else if (error == DB_TOO_MANY_CONCURRENT_TRXS) { + + /* Once MySQL add the appropriate code to errmsg.txt then + we can get rid of this #ifdef. NOTE: The code checked by + the #ifdef is the suggested name for the error condition + and the actual error code name could very well be different. + This will require some monitoring, ie. the status + of this request on our part.*/ +#ifdef ER_TOO_MANY_CONCURRENT_TRXS + return(ER_TOO_MANY_CONCURRENT_TRXS); +#else + return(HA_ERR_RECORD_FILE_FULL); +#endif + } else if (error == DB_UNSUPPORTED) { return(HA_ERR_UNSUPPORTED); -- cgit v1.2.1 From b4fdb8aec14b533db4a5ea2f99c1a9f3ce07946c Mon Sep 17 00:00:00 2001 From: He Zhenxing Date: Thu, 5 Mar 2009 18:10:44 +0800 Subject: BUG#37051 Replication rules not evaluated correctly Backporting patch to 5.0. --- sql/log_event.cc | 47 +++++++++++++++++++++++++++++++---------------- sql/log_event.h | 22 ++++++++++++++++------ sql/sql_class.cc | 6 +++++- sql/sql_class.h | 7 +++++++ sql/sql_parse.cc | 48 +++++++++++++++++++++++++++++++++++++++++++++++- sql/sql_update.cc | 2 +- 6 files changed, 107 insertions(+), 25 deletions(-) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index b74b38e55b2..ba282fd8e59 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1117,6 +1117,11 @@ void Query_log_event::pack_info(Protocol *protocol) static void write_str_with_code_and_len(char **dst, const char *src, int len, uint code) { + /* + only 1 byte to store the length of catalog, so it should not + surpass 255 + */ + DBUG_ASSERT(len <= 255); DBUG_ASSERT(src); *((*dst)++)= code; *((*dst)++)= (uchar) len; @@ -1136,16 +1141,8 @@ static void write_str_with_code_and_len(char **dst, const char *src, bool Query_log_event::write(IO_CACHE* file) { - uchar buf[QUERY_HEADER_LEN+ - 1+4+ // code of flags2 and flags2 - 1+8+ // code of sql_mode and sql_mode - 1+1+FN_REFLEN+ // code of catalog and catalog length and catalog - 1+4+ // code of autoinc and the 2 autoinc variables - 1+6+ // code of charset and charset - 1+1+MAX_TIME_ZONE_NAME_LENGTH+ // code of tz and tz length and tz name - 1+2+ // code of lc_time_names and lc_time_names_number - 1+2 // code of charset_database and charset_database_number - ], *start, *start_of_status; + uchar buf[QUERY_HEADER_LEN + MAX_SIZE_LOG_EVENT_STATUS]; + uchar *start, *start_of_status; ulong event_length; if (!query) @@ -1251,10 +1248,8 @@ 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); - *start++= Q_TIME_ZONE_CODE; - *start++= time_zone_len; - memcpy(start, time_zone_str, time_zone_len); - start+= time_zone_len; + write_str_with_code_and_len((char **)(&start), + time_zone_str, time_zone_len, Q_TIME_ZONE_CODE); } if (lc_time_names_number) { @@ -1270,7 +1265,17 @@ bool Query_log_event::write(IO_CACHE* file) int2store(start, charset_database_number); start+= 2; } + if (table_map_for_update) + { + *start++= Q_TABLE_MAP_FOR_UPDATE_CODE; + int8store(start, table_map_for_update); + start+= 8; + } /* + NOTE: When adding new status vars, please don't forget to update + the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update function + code_name in this file. + Here there could be code like if (command-line-option-which-says-"log_this_variable" && inited) { @@ -1348,7 +1353,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, auto_increment_increment(thd_arg->variables.auto_increment_increment), auto_increment_offset(thd_arg->variables.auto_increment_offset), lc_time_names_number(thd_arg->variables.lc_time_names->number), - charset_database_number(0) + charset_database_number(0), + table_map_for_update((ulonglong)thd_arg->table_map_for_update) { time_t end_time; @@ -1471,6 +1477,7 @@ code_name(int code) case Q_CATALOG_NZ_CODE: return "Q_CATALOG_NZ_CODE"; case Q_LC_TIME_NAMES_CODE: return "Q_LC_TIME_NAMES_CODE"; case Q_CHARSET_DATABASE_CODE: return "Q_CHARSET_DATABASE_CODE"; + case Q_TABLE_MAP_FOR_UPDATE_CODE: return "Q_TABLE_MAP_FOR_UPDATE_CODE"; } sprintf(buf, "CODE#%d", code); return buf; @@ -1507,7 +1514,8 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, db(NullS), catalog_len(0), status_vars_len(0), flags2_inited(0), sql_mode_inited(0), charset_inited(0), auto_increment_increment(1), auto_increment_offset(1), - time_zone_len(0), lc_time_names_number(0), charset_database_number(0) + time_zone_len(0), lc_time_names_number(0), charset_database_number(0), + table_map_for_update(0) { ulong data_len; uint32 tmp; @@ -1649,6 +1657,11 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, charset_database_number= uint2korr(pos); pos+= 2; break; + case Q_TABLE_MAP_FOR_UPDATE_CODE: + CHECK_SPACE(pos, end, 8); + table_map_for_update= uint8korr(pos); + pos+= 8; + break; default: /* That's why you must write status vars in growing order of code */ DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\ @@ -2036,6 +2049,8 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli, else thd->variables.collation_database= thd->db_charset; + thd->table_map_for_update= (table_map)table_map_for_update; + /* Execute the query (note that we bypass dispatch_command()) */ const char* found_semicolon= NULL; mysql_parse(thd, thd->query, thd->query_length, &found_semicolon); diff --git a/sql/log_event.h b/sql/log_event.h index 5b065a33dd1..6ccbf8e4d5c 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -204,12 +204,15 @@ struct sql_ex_info packet (i.e. a query) sent from client to master; First, an auxiliary log_event status vars estimation: */ -#define MAX_SIZE_LOG_EVENT_STATUS (4 /* flags2 */ + \ - 8 /* sql mode */ + \ - 1 + 1 + 255 /* catalog */ + \ - 4 /* autoinc */ + \ - 6 /* charset */ + \ - MAX_TIME_ZONE_NAME_LENGTH) +#define MAX_SIZE_LOG_EVENT_STATUS (1 + 4 /* type, flags2 */ + \ + 1 + 8 /* type, sql_mode */ + \ + 1 + 1 + 255 /* type, length, catalog */ + \ + 1 + 4 /* type, auto_increment */ + \ + 1 + 6 /* type, charset */ + \ + 1 + 1 + 255 /* type, length, time_zone */ + \ + 1 + 2 /* type, lc_time_names_number */ + \ + 1 + 2 /* type, charset_database_number */ + \ + 1 + 8 /* type, table_map_for_update */) #define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \ LOG_EVENT_HEADER_LEN + /* write_header */ \ QUERY_HEADER_LEN + /* write_data */ \ @@ -273,6 +276,8 @@ struct sql_ex_info #define Q_LC_TIME_NAMES_CODE 7 #define Q_CHARSET_DATABASE_CODE 8 + +#define Q_TABLE_MAP_FOR_UPDATE_CODE 9 /* Intvar event post-header */ #define I_TYPE_OFFSET 0 @@ -800,6 +805,11 @@ public: const char *time_zone_str; uint lc_time_names_number; /* 0 means en_US */ uint charset_database_number; + /* + map for tables that will be updated for a multi-table update query + statement, for other query statements, this will be zero. + */ + ulonglong table_map_for_update; #ifndef MYSQL_CLIENT diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 9ff602bb62e..4ea621f428d 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -172,7 +172,9 @@ THD::THD() /* statement id */ 0), Open_tables_state(refresh_version), lock_id(&main_lock_id), - user_time(0), in_sub_stmt(0), global_read_lock(0), is_fatal_error(0), + user_time(0), in_sub_stmt(0), + table_map_for_update(0), + global_read_lock(0), is_fatal_error(0), transaction_rollback_request(0), is_fatal_sub_stmt_error(0), rand_used(0), time_zone_used(0), last_insert_id_used(0), last_insert_id_used_bin_log(0), insert_id_used(0), @@ -651,6 +653,8 @@ void THD::cleanup_after_query() free_items(); /* Reset where. */ where= THD::DEFAULT_WHERE; + /* reset table map for multi-table update */ + table_map_for_update= 0; } diff --git a/sql/sql_class.h b/sql/sql_class.h index cc7ef7809d4..3e3dfcd08fa 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1358,6 +1358,13 @@ public: Note: in the parser, stmt_arena == thd, even for PS/SP. */ Query_arena *stmt_arena; + + /* + map for tables that will be updated for a multi-table update query + statement, for other query statements, this will be zero. + */ + table_map table_map_for_update; + /* next_insert_id is set on SET INSERT_ID= #. This is used as the next generated auto_increment value in handler.cc diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 1d3632fd468..dafe4baa9e5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2584,6 +2584,10 @@ mysql_execute_command(THD *thd) TABLE_LIST *all_tables; /* most outer SELECT_LEX_UNIT of query */ SELECT_LEX_UNIT *unit= &lex->unit; +#ifdef HAVE_REPLICATION + /* have table map for update for multi-update statement (BUG#37051) */ + bool have_table_map_for_update= FALSE; +#endif /* Saved variable value */ DBUG_ENTER("mysql_execute_command"); thd->net.no_send_error= 0; @@ -2663,6 +2667,48 @@ mysql_execute_command(THD *thd) // force searching in slave.cc:tables_ok() all_tables->updating= 1; } + + /* + For fix of BUG#37051, the master stores the table map for update + in the Query_log_event, and the value is assigned to + thd->variables.table_map_for_update before executing the update + query. + + If thd->variables.table_map_for_update is set, then we are + replicating from a new master, we can use this value to apply + filter rules without opening all the tables. However If + thd->variables.table_map_for_update is not set, then we are + replicating from an old master, so we just skip this and + continue with the old method. And of course, the bug would still + exist for old masters. + */ + if (lex->sql_command == SQLCOM_UPDATE_MULTI && + thd->table_map_for_update) + { + have_table_map_for_update= TRUE; + table_map table_map_for_update= thd->table_map_for_update; + uint nr= 0; + TABLE_LIST *table; + for (table=all_tables; table; table=table->next_global, nr++) + { + if (table_map_for_update & ((table_map)1 << nr)) + table->updating= TRUE; + else + table->updating= FALSE; + } + + if (all_tables_not_ok(thd, all_tables)) + { + /* we warn the slave SQL thread */ + my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0)); + if (thd->one_shot_set) + reset_one_shot_variables(thd); + DBUG_RETURN(0); + } + + for (table=all_tables; table; table=table->next_global) + table->updating= TRUE; + } /* Check if statment should be skipped because of slave filtering @@ -3608,7 +3654,7 @@ end_with_restore_list: #ifdef HAVE_REPLICATION /* Check slave filtering rules */ - if (unlikely(thd->slave_thread)) + if (unlikely(thd->slave_thread && !have_table_map_for_update)) { if (all_tables_not_ok(thd, all_tables)) { diff --git a/sql/sql_update.cc b/sql/sql_update.cc index f15db220a3b..8a3f5bcdc26 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -775,7 +775,7 @@ reopen_tables: DBUG_RETURN(TRUE); } - tables_for_update= get_table_map(fields); + thd->table_map_for_update= tables_for_update= get_table_map(fields); /* Setup timestamp handling and locking mode -- cgit v1.2.1 From ac821c65701d38ced2d3167cf9c54559599d4f52 Mon Sep 17 00:00:00 2001 From: Kristofer Pettersson Date: Thu, 5 Mar 2009 13:37:46 +0100 Subject: Bug#40363 Bug 20023 is not fixed on 5.0 This is a back port from 5.1 to 5.0. Fix for BUG 20023: mysql_change_user() resets the value of SQL_BIG_SELECTS. The bug was that SQL_BIG_SELECTS was not properly set in COM_CHANGE_USER. The fix is to update SQL_BIG_SELECTS properly. sql/sql_class.cc: Update THD::options with the respect to SQL_BIG_SELECTS in COM_CHANGE_USER. tests/mysql_client_test.c: Add a test case BUG#20023. --- sql/sql_class.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 883291ec460..e00323ebab1 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -341,6 +341,12 @@ void THD::init(void) if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES; options= thd_startup_options; + + if (variables.max_join_size == HA_POS_ERROR) + options |= OPTION_BIG_SELECTS; + else + options &= ~OPTION_BIG_SELECTS; + transaction.all.modified_non_trans_table= transaction.stmt.modified_non_trans_table= FALSE; open_options=ha_open_options; update_lock_default= (variables.low_priority_updates ? -- cgit v1.2.1 From 56ae3bd15536ab220568d43fccfa350dc521b2d9 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Mon, 9 Mar 2009 12:22:52 +0200 Subject: fixed a win32 compile warning --- sql/protocol.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/protocol.cc b/sql/protocol.cc index 2309bac88a9..a1e349bf30b 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -641,7 +641,8 @@ bool Protocol::send_fields(List *list, uint flags) field.length / item->collation.collation->mbminlen : field.length / item->collation.collation->mbmaxlen; max_length*= thd_charset->mbmaxlen; - field_length= (max_length > UINT_MAX32) ? UINT_MAX32 : max_length; + field_length= (max_length > UINT_MAX32) ? + UINT_MAX32 : (unit32) max_length; int4store(pos + 2, field_length); } pos[6]= field.type; -- cgit v1.2.1 From 7541fec52d0926888b7d41b86b72319db2755031 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Mon, 9 Mar 2009 12:49:18 +0200 Subject: fixed a typo --- sql/protocol.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/protocol.cc b/sql/protocol.cc index a1e349bf30b..261852e44a8 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -642,7 +642,7 @@ bool Protocol::send_fields(List *list, uint flags) field.length / item->collation.collation->mbmaxlen; max_length*= thd_charset->mbmaxlen; field_length= (max_length > UINT_MAX32) ? - UINT_MAX32 : (unit32) max_length; + UINT_MAX32 : (uint32) max_length; int4store(pos + 2, field_length); } pos[6]= field.type; -- cgit v1.2.1 From d3d6f4fdad8176abe0d8981d79a925731df9a5d0 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 11 Mar 2009 14:10:44 +0200 Subject: Bug #43354: Use key hint can crash server in explain extended query The copy of the original arguments of a aggregate function was not initialized until after fix_fields(). Sometimes (e.g. when there's an error processing the statement) the print() can be called with no corresponding fix_fields() call. Fixed by adding a check if the Item is fixed before using the arguments copy. mysql-test/r/explain.result: Bug #43354: test case mysql-test/t/explain.test: Bug #43354: test case sql/item_sum.cc: Bug #43354: use the argument list copy only if it's initialized --- sql/item_sum.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_sum.cc b/sql/item_sum.cc index d33d92a5238..57045f52825 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -440,7 +440,8 @@ void Item_sum::make_field(Send_field *tmp_field) void Item_sum::print(String *str) { - Item **pargs= orig_args; + /* orig_args is not filled with valid values until fix_fields() */ + Item **pargs= fixed ? orig_args : args; str->append(func_name()); for (uint i=0 ; i < arg_count ; i++) { -- cgit v1.2.1 From 3033ea85a20fb5afd4cab8a816ff72fd4d784778 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Mon, 9 Mar 2009 20:57:03 +0200 Subject: Bug #42434: license of mysys MD5 implementation is not GPL-compatible Took the Xfree implementation (based on the same rewrite as the NDB one) and added it instead of the current implementation. Added a macro to make the calls to MD5 more streamlined. client/mysqlmanager-pwgen.c: Bug #42434: changed to call the macro include/my_md5.h: Bug #42434: use the Xfree implementation mysys/md5.c: Bug #42434: use the Xfree implementation sql/item_strfunc.cc: Bug #42434: changed to call the macro sql/table.cc: Bug #42434: changed to call the macro tools/mysqlmanager.c: Bug #42434: changed to call the macro --- sql/item_strfunc.cc | 5 +---- sql/table.cc | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'sql') diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 34f974042a5..158eb8e3bb0 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -101,13 +101,10 @@ String *Item_func_md5::val_str(String *str) str->set_charset(&my_charset_bin); if (sptr) { - my_MD5_CTX context; unsigned char digest[16]; null_value=0; - my_MD5Init (&context); - my_MD5Update (&context,(unsigned char *) sptr->ptr(), sptr->length()); - my_MD5Final (digest, &context); + MY_MD5_HASH(digest,(unsigned char *) sptr->ptr(), sptr->length()); if (str->alloc(32)) // Ensure that memory is free { null_value=1; diff --git a/sql/table.cc b/sql/table.cc index 3abd2c24c94..6dc1f3ab99e 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1792,11 +1792,8 @@ void st_table::reset_item_list(List *item_list) const void TABLE_LIST::calc_md5(char *buffer) { - my_MD5_CTX context; uchar digest[16]; - my_MD5Init(&context); - my_MD5Update(&context,(uchar *) query.str, query.length); - my_MD5Final(digest, &context); + MY_MD5_HASH(digest, (uchar *) query.str, query.length); sprintf((char *) buffer, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", digest[0], digest[1], digest[2], digest[3], -- cgit v1.2.1 From f35b4218eaa2bf831ab682b3674851a1cc6ee65a Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 13 Mar 2009 15:51:25 +0200 Subject: Bug #22047 : Time in SHOW PROCESSLIST for SQL thread in replication seems to become negative THD::start_time has a dual meaning : it's either the time since the process entered a given state or is the transaction time returned by e.g. NOW(). This causes problems, as sometimes THD::start_time may be set to a value that is correct and needed when used as a base for NOW(), but these times may be arbitrary (SET @@timestamp) or non-local (coming from the master through the replication feed). If one such non-local time is set there's no way to return a correct value for e.g. SHOW PROCESSLIST or SELECT ... FROM INFORMATION_SCHEMA.PROCESSLIST. Fixed by making the Time column in SHOW PROCESSLIST SIGNED LONG instead of UNSIGNED LONG and doing the correct conversions. Note that no reliable test suite can be constructed, since it would require knowing the local time and can't be achieved by the means of the current test suite. sql/sql_show.cc: Bug #22047: make the Time in SHOW PROCESSLIST LONG from LONG UNSIGNED --- sql/sql_show.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index a3ccf770a3c..fee3d076436 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1338,7 +1338,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) field_list.push_back(field=new Item_empty_string("db",NAME_LEN)); field->maybe_null=1; field_list.push_back(new Item_empty_string("Command",16)); - field_list.push_back(new Item_return_int("Time",7, FIELD_TYPE_LONG)); + field_list.push_back(field= new Item_return_int("Time",7, FIELD_TYPE_LONG)); + field->unsigned_flag= 0; field_list.push_back(field=new Item_empty_string("State",30)); field->maybe_null=1; field_list.push_back(field=new Item_empty_string("Info",max_query_length)); @@ -1439,7 +1440,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) else protocol->store(command_name[thd_info->command], system_charset_info); if (thd_info->start_time) - protocol->store((uint32) (now - thd_info->start_time)); + protocol->store_long ((longlong) (now - thd_info->start_time)); else protocol->store_null(); protocol->store(thd_info->state_info, system_charset_info); -- cgit v1.2.1