Commit ef6b98ee authored by Martin Hansson's avatar Martin Hansson

Merge of fix for Bug#58165.

parents df3b2340 716b64cd
...@@ -2615,6 +2615,22 @@ CONVERT(('' IN (REVERSE(CAST(('') AS DECIMAL)), '')), CHAR(3)) ...@@ -2615,6 +2615,22 @@ CONVERT(('' IN (REVERSE(CAST(('') AS DECIMAL)), '')), CHAR(3))
1 1
Warnings: Warnings:
Warning 1292 Truncated incorrect DECIMAL value: '' Warning 1292 Truncated incorrect DECIMAL value: ''
#
# Bug#58165: "my_empty_string" gets modified and causes LOAD DATA to fail
# and other crashes
#
CREATE TABLE t1 ( a TEXT );
SELECT 'aaaaaaaaaaaaaa' INTO OUTFILE 'bug58165.txt';
SELECT insert( substring_index( 'a', 'a', 'b' ), 1, 0, 'x' );
insert( substring_index( 'a', 'a', 'b' ), 1, 0, 'x' )
x
Warnings:
Warning 1292 Truncated incorrect INTEGER value: 'b'
LOAD DATA INFILE 'bug58165.txt' INTO TABLE t1;
SELECT * FROM t1;
a
aaaaaaaaaaaaaa
DROP TABLE t1;
End of 5.1 tests End of 5.1 tests
Start of 5.4 tests Start of 5.4 tests
SELECT format(12345678901234567890.123, 3); SELECT format(12345678901234567890.123, 3);
......
...@@ -1370,6 +1370,17 @@ DROP TABLE t1; ...@@ -1370,6 +1370,17 @@ DROP TABLE t1;
SELECT '1' IN ('1', SUBSTRING(-9223372036854775809, 1)); SELECT '1' IN ('1', SUBSTRING(-9223372036854775809, 1));
SELECT CONVERT(('' IN (REVERSE(CAST(('') AS DECIMAL)), '')), CHAR(3)); SELECT CONVERT(('' IN (REVERSE(CAST(('') AS DECIMAL)), '')), CHAR(3));
--echo #
--echo # Bug#58165: "my_empty_string" gets modified and causes LOAD DATA to fail
--echo # and other crashes
--echo #
CREATE TABLE t1 ( a TEXT );
SELECT 'aaaaaaaaaaaaaa' INTO OUTFILE 'bug58165.txt';
SELECT insert( substring_index( 'a', 'a', 'b' ), 1, 0, 'x' );
LOAD DATA INFILE 'bug58165.txt' INTO TABLE t1;
SELECT * FROM t1;
DROP TABLE t1;
--echo End of 5.1 tests --echo End of 5.1 tests
--echo Start of 5.4 tests --echo Start of 5.4 tests
......
...@@ -56,6 +56,9 @@ C_MODE_START ...@@ -56,6 +56,9 @@ C_MODE_START
#include "../mysys/my_static.h" // For soundex_map #include "../mysys/my_static.h" // For soundex_map
C_MODE_END C_MODE_END
/**
@todo Remove this. It is not safe to use a shared String object.
*/
String my_empty_string("",default_charset_info); String my_empty_string("",default_charset_info);
/* /*
...@@ -642,7 +645,7 @@ String *Item_func_des_encrypt::val_str(String *str) ...@@ -642,7 +645,7 @@ String *Item_func_des_encrypt::val_str(String *str)
if ((null_value= args[0]->null_value)) if ((null_value= args[0]->null_value))
return 0; // ENCRYPT(NULL) == NULL return 0; // ENCRYPT(NULL) == NULL
if ((res_length=res->length()) == 0) if ((res_length=res->length()) == 0)
return &my_empty_string; return make_empty_result();
if (arg_count == 1) if (arg_count == 1)
{ {
/* Protect against someone doing FLUSH DES_KEY_FILE */ /* Protect against someone doing FLUSH DES_KEY_FILE */
...@@ -832,7 +835,7 @@ String *Item_func_concat_ws::val_str(String *str) ...@@ -832,7 +835,7 @@ String *Item_func_concat_ws::val_str(String *str)
} }
if (i == arg_count) if (i == arg_count)
return &my_empty_string; return make_empty_result();
for (i++; i < arg_count ; i++) for (i++; i < arg_count ; i++)
{ {
...@@ -978,7 +981,7 @@ String *Item_func_reverse::val_str(String *str) ...@@ -978,7 +981,7 @@ String *Item_func_reverse::val_str(String *str)
return 0; return 0;
/* An empty string is a special case as the string pointer may be null */ /* An empty string is a special case as the string pointer may be null */
if (!res->length()) if (!res->length())
return &my_empty_string; return make_empty_result();
if (tmp_value.alloced_length() < res->length() && if (tmp_value.alloced_length() < res->length() &&
tmp_value.realloc(res->length())) tmp_value.realloc(res->length()))
{ {
...@@ -1311,8 +1314,7 @@ String *Item_func_left::val_str(String *str) ...@@ -1311,8 +1314,7 @@ String *Item_func_left::val_str(String *str)
/* if "unsigned_flag" is set, we have a *huge* positive number. */ /* if "unsigned_flag" is set, we have a *huge* positive number. */
if ((length <= 0) && (!args[1]->unsigned_flag)) if ((length <= 0) && (!args[1]->unsigned_flag))
return &my_empty_string; return make_empty_result();
if ((res->length() <= (ulonglong) length) || if ((res->length() <= (ulonglong) length) ||
(res->length() <= (char_pos= res->charpos((int) length)))) (res->length() <= (char_pos= res->charpos((int) length))))
return res; return res;
...@@ -1357,7 +1359,7 @@ String *Item_func_right::val_str(String *str) ...@@ -1357,7 +1359,7 @@ String *Item_func_right::val_str(String *str)
/* if "unsigned_flag" is set, we have a *huge* positive number. */ /* if "unsigned_flag" is set, we have a *huge* positive number. */
if ((length <= 0) && (!args[1]->unsigned_flag)) if ((length <= 0) && (!args[1]->unsigned_flag))
return &my_empty_string; /* purecov: inspected */ return make_empty_result(); /* purecov: inspected */
if (res->length() <= (ulonglong) length) if (res->length() <= (ulonglong) length)
return res; /* purecov: inspected */ return res; /* purecov: inspected */
...@@ -1397,7 +1399,7 @@ String *Item_func_substr::val_str(String *str) ...@@ -1397,7 +1399,7 @@ String *Item_func_substr::val_str(String *str)
/* Negative or zero length, will return empty string. */ /* Negative or zero length, will return empty string. */
if ((arg_count == 3) && (length <= 0) && if ((arg_count == 3) && (length <= 0) &&
(length == 0 || !args[2]->unsigned_flag)) (length == 0 || !args[2]->unsigned_flag))
return &my_empty_string; return make_empty_result();
/* Assumes that the maximum length of a String is < INT_MAX32. */ /* Assumes that the maximum length of a String is < INT_MAX32. */
/* Set here so that rest of code sees out-of-bound value as such. */ /* Set here so that rest of code sees out-of-bound value as such. */
...@@ -1408,12 +1410,12 @@ String *Item_func_substr::val_str(String *str) ...@@ -1408,12 +1410,12 @@ String *Item_func_substr::val_str(String *str)
/* Assumes that the maximum length of a String is < INT_MAX32. */ /* Assumes that the maximum length of a String is < INT_MAX32. */
if ((!args[1]->unsigned_flag && (start < INT_MIN32 || start > INT_MAX32)) || if ((!args[1]->unsigned_flag && (start < INT_MIN32 || start > INT_MAX32)) ||
(args[1]->unsigned_flag && ((ulonglong) start > INT_MAX32))) (args[1]->unsigned_flag && ((ulonglong) start > INT_MAX32)))
return &my_empty_string; return make_empty_result();
start= ((start < 0) ? res->numchars() + start : start - 1); start= ((start < 0) ? res->numchars() + start : start - 1);
start= res->charpos((int) start); start= res->charpos((int) start);
if ((start < 0) || ((uint) start + 1 > res->length())) if ((start < 0) || ((uint) start + 1 > res->length()))
return &my_empty_string; return make_empty_result();
length= res->charpos((int) length, (uint32) start); length= res->charpos((int) length, (uint32) start);
tmp_length= res->length() - start; tmp_length= res->length() - start;
...@@ -1476,7 +1478,7 @@ String *Item_func_substr_index::val_str(String *str) ...@@ -1476,7 +1478,7 @@ String *Item_func_substr_index::val_str(String *str)
null_value=0; null_value=0;
uint delimiter_length= delimiter->length(); uint delimiter_length= delimiter->length();
if (!res->length() || !delimiter_length || !count) if (!res->length() || !delimiter_length || !count)
return &my_empty_string; // Wrong parameters return make_empty_result(); // Wrong parameters
res->set_charset(collation.collation); res->set_charset(collation.collation);
...@@ -1826,7 +1828,7 @@ String *Item_func_password::val_str_ascii(String *str) ...@@ -1826,7 +1828,7 @@ String *Item_func_password::val_str_ascii(String *str)
if ((null_value=args[0]->null_value)) if ((null_value=args[0]->null_value))
return 0; return 0;
if (res->length() == 0) if (res->length() == 0)
return &my_empty_string; return make_empty_result();
my_make_scrambled_password(tmp_value, res->ptr(), res->length()); my_make_scrambled_password(tmp_value, res->ptr(), res->length());
str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, &my_charset_latin1); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, &my_charset_latin1);
return str; return str;
...@@ -1850,7 +1852,7 @@ String *Item_func_old_password::val_str_ascii(String *str) ...@@ -1850,7 +1852,7 @@ String *Item_func_old_password::val_str_ascii(String *str)
if ((null_value=args[0]->null_value)) if ((null_value=args[0]->null_value))
return 0; return 0;
if (res->length() == 0) if (res->length() == 0)
return &my_empty_string; return make_empty_result();
my_make_scrambled_password_323(tmp_value, res->ptr(), res->length()); my_make_scrambled_password_323(tmp_value, res->ptr(), res->length());
str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, &my_charset_latin1); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, &my_charset_latin1);
return str; return str;
...@@ -1878,8 +1880,7 @@ String *Item_func_encrypt::val_str(String *str) ...@@ -1878,8 +1880,7 @@ String *Item_func_encrypt::val_str(String *str)
if ((null_value=args[0]->null_value)) if ((null_value=args[0]->null_value))
return 0; return 0;
if (res->length() == 0) if (res->length() == 0)
return &my_empty_string; return make_empty_result();
if (arg_count == 1) if (arg_count == 1)
{ // generate random salt { // generate random salt
time_t timestamp=current_thd->query_start(); time_t timestamp=current_thd->query_start();
...@@ -2141,7 +2142,7 @@ String *Item_func_soundex::val_str(String *str) ...@@ -2141,7 +2142,7 @@ String *Item_func_soundex::val_str(String *str)
for ( ; ; ) /* Skip pre-space */ for ( ; ; ) /* Skip pre-space */
{ {
if ((rc= cs->cset->mb_wc(cs, &wc, (uchar*) from, (uchar*) end)) <= 0) if ((rc= cs->cset->mb_wc(cs, &wc, (uchar*) from, (uchar*) end)) <= 0)
return &my_empty_string; /* EOL or invalid byte sequence */ return make_empty_result(); /* EOL or invalid byte sequence */
if (rc == 1 && cs->ctype) if (rc == 1 && cs->ctype)
{ {
...@@ -2166,7 +2167,7 @@ String *Item_func_soundex::val_str(String *str) ...@@ -2166,7 +2167,7 @@ String *Item_func_soundex::val_str(String *str)
{ {
/* Extra safety - should not really happen */ /* Extra safety - should not really happen */
DBUG_ASSERT(false); DBUG_ASSERT(false);
return &my_empty_string; return make_empty_result();
} }
to+= rc; to+= rc;
break; break;
...@@ -2507,7 +2508,7 @@ String *Item_func_make_set::val_str(String *str) ...@@ -2507,7 +2508,7 @@ String *Item_func_make_set::val_str(String *str)
else else
{ {
if (tmp_str.copy(*res)) // Don't use 'str' if (tmp_str.copy(*res)) // Don't use 'str'
return &my_empty_string; return make_empty_result();
result= &tmp_str; result= &tmp_str;
} }
} }
...@@ -2517,11 +2518,11 @@ String *Item_func_make_set::val_str(String *str) ...@@ -2517,11 +2518,11 @@ String *Item_func_make_set::val_str(String *str)
{ // Copy data to tmp_str { // Copy data to tmp_str
if (tmp_str.alloc(result->length()+res->length()+1) || if (tmp_str.alloc(result->length()+res->length()+1) ||
tmp_str.copy(*result)) tmp_str.copy(*result))
return &my_empty_string; return make_empty_result();
result= &tmp_str; result= &tmp_str;
} }
if (tmp_str.append(STRING_WITH_LEN(","), &my_charset_bin) || tmp_str.append(*res)) if (tmp_str.append(STRING_WITH_LEN(","), &my_charset_bin) || tmp_str.append(*res))
return &my_empty_string; return make_empty_result();
} }
} }
} }
...@@ -2666,7 +2667,7 @@ String *Item_func_repeat::val_str(String *str) ...@@ -2666,7 +2667,7 @@ String *Item_func_repeat::val_str(String *str)
null_value= 0; null_value= 0;
if (count <= 0 && (count == 0 || !args[1]->unsigned_flag)) if (count <= 0 && (count == 0 || !args[1]->unsigned_flag))
return &my_empty_string; return make_empty_result();
/* Assumes that the maximum length of a String is < INT_MAX32. */ /* Assumes that the maximum length of a String is < INT_MAX32. */
/* Bounds check on count: If this is triggered, we will error. */ /* Bounds check on count: If this is triggered, we will error. */
...@@ -2948,7 +2949,7 @@ String *Item_func_conv::val_str(String *str) ...@@ -2948,7 +2949,7 @@ String *Item_func_conv::val_str(String *str)
ptr= longlong2str(dec, ans, to_base); ptr= longlong2str(dec, ans, to_base);
if (str->copy(ans, (uint32) (ptr-ans), default_charset())) if (str->copy(ans, (uint32) (ptr-ans), default_charset()))
return &my_empty_string; return make_empty_result();
return str; return str;
} }
...@@ -3115,7 +3116,7 @@ String *Item_func_hex::val_str_ascii(String *str) ...@@ -3115,7 +3116,7 @@ String *Item_func_hex::val_str_ascii(String *str)
return 0; return 0;
ptr= longlong2str(dec,ans,16); ptr= longlong2str(dec,ans,16);
if (str->copy(ans,(uint32) (ptr-ans), &my_charset_numeric)) if (str->copy(ans,(uint32) (ptr-ans), &my_charset_numeric))
return &my_empty_string; // End of memory return make_empty_result(); // End of memory
return str; return str;
} }
......
...@@ -27,6 +27,16 @@ class MY_LOCALE; ...@@ -27,6 +27,16 @@ class MY_LOCALE;
class Item_str_func :public Item_func class Item_str_func :public Item_func
{ {
protected:
/**
Sets the result value of the function an empty string, using the current
character set. No memory is allocated.
@retval A pointer to the str_value member.
*/
String *make_empty_result() {
str_value.set("", 0, collation.collation);
return &str_value;
}
public: public:
Item_str_func() :Item_func() { decimals=NOT_FIXED_DEC; } Item_str_func() :Item_func() { decimals=NOT_FIXED_DEC; }
Item_str_func(Item *a) :Item_func(a) {decimals=NOT_FIXED_DEC; } Item_str_func(Item *a) :Item_func(a) {decimals=NOT_FIXED_DEC; }
......
...@@ -51,11 +51,33 @@ bool String::real_alloc(uint32 length) ...@@ -51,11 +51,33 @@ bool String::real_alloc(uint32 length)
} }
/* /**
** Check that string is big enough. Set string[alloc_length] to 0 Allocates a new buffer on the heap for this String.
** (for C functions)
*/ - If the String's internal buffer is privately owned and heap allocated,
one of the following is performed.
- If the requested length is greater than what fits in the buffer, a new
buffer is allocated, data moved and the old buffer freed.
- If the requested length is less or equal to what fits in the buffer, a
null character is inserted at the appropriate position.
- If the String does not keep a private buffer on the heap, such a buffer
will be allocated and the string copied accoring to its length, as found
in String::length().
For C compatibility, the new string buffer is null terminated.
@param alloc_length The requested string size in characters, excluding any
null terminator.
@retval false Either the copy operation is complete or, if the size of the
new buffer is smaller than the currently allocated buffer (if one exists),
no allocation occured.
@retval true An error occured when attempting to allocate memory.
*/
bool String::realloc(uint32 alloc_length) bool String::realloc(uint32 alloc_length)
{ {
uint32 len=ALIGN_SIZE(alloc_length+1); uint32 len=ALIGN_SIZE(alloc_length+1);
...@@ -128,6 +150,17 @@ bool String::copy() ...@@ -128,6 +150,17 @@ bool String::copy()
return FALSE; return FALSE;
} }
/**
Copies the internal buffer from str. If this String has a private heap
allocated buffer where new data does not fit, a new buffer is allocated
before copying and the old buffer freed. Character set information is also
copied.
@param str The string whose internal buffer is to be copied.
@retval false Success.
@retval true Memory allocation failed.
*/
bool String::copy(const String &str) bool String::copy(const String &str)
{ {
if (alloc(str.str_length)) if (alloc(str.str_length))
......
...@@ -148,6 +148,16 @@ class String ...@@ -148,6 +148,16 @@ class String
Alloced_length=0; Alloced_length=0;
str_charset=str.str_charset; str_charset=str.str_charset;
} }
/**
Points the internal buffer to the supplied one. The old buffer is freed.
@param str Pointer to the new buffer.
@param arg_length Length of the new buffer in characters, excluding any
null character.
@param cs Character set to use for interpreting string data.
@note The new buffer will not be null terminated.
*/
inline void set(char *str,uint32 arg_length, CHARSET_INFO *cs) inline void set(char *str,uint32 arg_length, CHARSET_INFO *cs)
{ {
free(); free();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment