summaryrefslogtreecommitdiff
path: root/sql/item_strfunc.cc
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2018-02-01 21:55:30 +0100
committerSergei Golubchik <serg@mariadb.org>2018-02-02 10:09:44 +0100
commitd4df7bc9b1fbdfb5c98134091a9ff998af60954f (patch)
treedfd2f5128ccf94b6e86d2475aee23acf53fa868c /sql/item_strfunc.cc
parent80d3eee072025f34984e474ea160651eac9e11e5 (diff)
parent96cb428b350ba48ee17ad9968d08f5318e48258c (diff)
downloadmariadb-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.cc185
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;