diff options
author | Sergei Golubchik <serg@mariadb.org> | 2018-02-01 21:55:30 +0100 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2018-02-02 10:09:44 +0100 |
commit | d4df7bc9b1fbdfb5c98134091a9ff998af60954f (patch) | |
tree | dfd2f5128ccf94b6e86d2475aee23acf53fa868c /sql/item_strfunc.cc | |
parent | 80d3eee072025f34984e474ea160651eac9e11e5 (diff) | |
parent | 96cb428b350ba48ee17ad9968d08f5318e48258c (diff) | |
download | mariadb-git-d4df7bc9b1fbdfb5c98134091a9ff998af60954f.tar.gz |
Merge branch 'github/10.0' into 10.1
Diffstat (limited to 'sql/item_strfunc.cc')
-rw-r--r-- | sql/item_strfunc.cc | 185 |
1 files changed, 65 insertions, 120 deletions
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 04927f88b77..cd47257a77b 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. - Copyright (c) 2009, 2017, MariaDB + Copyright (c) 2009, 2018, MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -203,9 +203,9 @@ String *Item_func_sha2::val_str_ascii(String *str) const char *input_ptr; size_t input_len; + 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; @@ -546,139 +546,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; - is_const= args[0]->const_item(); - 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(); - } - 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) - { - THD *thd= current_thd; - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_WARN_ALLOWED_PACKET_OVERFLOWED, - ER_THD(thd, ER_WARN_ALLOWED_PACKET_OVERFLOWED), - func_name(), - 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; |