From ad00de40772614e79ef8f14647d37a7d356cff5c Mon Sep 17 00:00:00 2001 From: Sreeharsha Ramanavarapu Date: Wed, 6 Sep 2017 06:45:50 +0530 Subject: Bug #26704451: INCORRECT BEHAVIOR WITH USE OF CERTAIN CHARSETS AND SHA2 Missed pushing to 5.5. --- sql/item_strfunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql/item_strfunc.cc') diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index ed02f668060..e2a2ee1b6d8 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -266,9 +266,9 @@ String *Item_func_sha2::val_str_ascii(String *str) size_t input_len; uint digest_length= 0; + input_string= args[0]->val_str(str); str->set_charset(&my_charset_bin); - input_string= args[0]->val_str(str); if (input_string == NULL) { null_value= TRUE; -- cgit v1.2.1 From c4a908cb56d3ed81879573631d1f180d4962ed4e Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 30 Jan 2018 11:35:27 +0400 Subject: MDEV-13790 UNHEX() of a somewhat complicated CONCAT() returns NULL --- sql/item_strfunc.cc | 180 ++++++++++++++++++---------------------------------- 1 file changed, 63 insertions(+), 117 deletions(-) (limited to 'sql/item_strfunc.cc') diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index c0d60d7ef8b..378f23f3109 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -630,138 +630,84 @@ String *Item_func_decode_histogram::val_str(String *str) /////////////////////////////////////////////////////////////////////////////// +/* + Realloc the result buffer. + NOTE: We should be prudent in the initial allocation unit -- the + size of the arguments is a function of data distribution, which + can be any. Instead of overcommitting at the first row, we grow + the allocated amount by the factor of 2. This ensures that no + more than 25% of memory will be overcommitted on average. + + @param IN/OUT str - the result string + @param IN length - new total space required in "str" + @retval false - on success + @retval true - on error +*/ + +bool Item_func_concat::realloc_result(String *str, uint length) const +{ + if (str->alloced_length() >= length) + return false; // Alloced space is big enough, nothing to do. + + if (str->alloced_length() == 0) + return str->alloc(length); + + /* + Item_func_concat::val_str() makes sure the result length does not grow + higher than max_allowed_packet. So "length" is limited to 1G here. + We can't say anything about the current value of str->alloced_length(), + as str was initially set by args[0]->val_str(str). + So multiplication by 2 can overflow, if args[0] for some reasons + did not limit the result to max_alloced_packet. But it's not harmful, + "str" will be realloced exactly to "length" bytes in case of overflow. + */ + uint new_length= MY_MAX(str->alloced_length() * 2, length); + return str->realloc(new_length); +} + + /** Concatenate args with the following premises: If only one arg (which is ok), return value of arg; - Don't reallocate val_str() if not absolute necessary. */ String *Item_func_concat::val_str(String *str) { DBUG_ASSERT(fixed == 1); - String *res,*res2,*use_as_buff; - uint i; - bool is_const= 0; + THD *thd= current_thd; + String *res; null_value=0; - if (!(res=args[0]->val_str(str))) + if (!(res= args[0]->val_str(str))) goto null; - use_as_buff= &tmp_value; - /* Item_subselect in --ps-protocol mode will state it as a non-const */ - is_const= args[0]->const_item() || !args[0]->used_tables(); - for (i=1 ; i < arg_count ; i++) - { - if (res->length() == 0) - { - if (!(res=args[i]->val_str(str))) - goto null; - /* - CONCAT accumulates its result in the result of its the first - non-empty argument. Because of this we need is_const to be - evaluated only for it. - */ - is_const= args[i]->const_item() || !args[i]->used_tables(); - } - else - { - if (!(res2=args[i]->val_str(use_as_buff))) - goto null; - if (res2->length() == 0) - continue; - if (res->length()+res2->length() > - current_thd->variables.max_allowed_packet) - { - push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, - ER_WARN_ALLOWED_PACKET_OVERFLOWED, - ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(), - current_thd->variables.max_allowed_packet); - goto null; - } - if (!is_const && res->alloced_length() >= res->length()+res2->length()) - { // Use old buffer - res->append(*res2); - } - else if (str->alloced_length() >= res->length()+res2->length()) - { - if (str->ptr() == res2->ptr()) - str->replace(0,0,*res); - else - { - str->copy(*res); - str->append(*res2); - } - res= str; - use_as_buff= &tmp_value; - } - else if (res == &tmp_value) - { - if (res->append(*res2)) // Must be a blob - goto null; - } - else if (res2 == &tmp_value) - { // This can happend only 1 time - if (tmp_value.replace(0,0,*res)) - goto null; - res= &tmp_value; - use_as_buff=str; // Put next arg here - } - else if (tmp_value.is_alloced() && res2->ptr() >= tmp_value.ptr() && - res2->ptr() <= tmp_value.ptr() + tmp_value.alloced_length()) - { - /* - This happens really seldom: - In this case res2 is sub string of tmp_value. We will - now work in place in tmp_value to set it to res | res2 - */ - /* Chop the last characters in tmp_value that isn't in res2 */ - tmp_value.length((uint32) (res2->ptr() - tmp_value.ptr()) + - res2->length()); - /* Place res2 at start of tmp_value, remove chars before res2 */ - if (tmp_value.replace(0,(uint32) (res2->ptr() - tmp_value.ptr()), - *res)) - goto null; - res= &tmp_value; - use_as_buff=str; // Put next arg here - } - else - { // Two big const strings - /* - NOTE: We should be prudent in the initial allocation unit -- the - size of the arguments is a function of data distribution, which - can be any. Instead of overcommitting at the first row, we grow - the allocated amount by the factor of 2. This ensures that no - more than 25% of memory will be overcommitted on average. - */ - - uint concat_len= res->length() + res2->length(); - - if (tmp_value.alloced_length() < concat_len) - { - if (tmp_value.alloced_length() == 0) - { - if (tmp_value.alloc(concat_len)) - goto null; - } - else - { - uint new_len = MY_MAX(tmp_value.alloced_length() * 2, concat_len); - if (tmp_value.realloc(new_len)) - goto null; - } - } + if (res != str) + str->copy(res->ptr(), res->length(), res->charset()); - if (tmp_value.copy(*res) || tmp_value.append(*res2)) - goto null; - - res= &tmp_value; - use_as_buff=str; - } - is_const= 0; + for (uint i= 1 ; i < arg_count ; i++) + { + uint concat_len; + if (!(res= args[i]->val_str(&tmp_value))) + goto null; + if (res->length() == 0) + continue; + if ((concat_len= str->length() + res->length()) > + thd->variables.max_allowed_packet) + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_WARN_ALLOWED_PACKET_OVERFLOWED, + ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED), func_name(), + thd->variables.max_allowed_packet); + goto null; } + DBUG_ASSERT(!res->uses_buffer_owned_by(str)); + DBUG_ASSERT(!str->uses_buffer_owned_by(res)); + if (realloc_result(str, concat_len) || str->append(*res)) + goto null; } - res->set_charset(collation.collation); - return res; + + str->set_charset(collation.collation); + return str; null: null_value=1; -- cgit v1.2.1