From: Martin Hansson Date: January 13 2011 8:21am Subject: bzr push into mysql-trunk branch (martin.hansson:3493 to 3494) Bug#58165 List-Archive: http://lists.mysql.com/commits/128588 X-Bug: 58165 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1108344183==" --===============1108344183== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline 3494 Martin Hansson 2011-01-13 [merge] Merge of fix for Bug#58165. modified: mysql-test/r/func_str.result mysql-test/t/func_str.test sql/item_strfunc.cc sql/item_strfunc.h sql/sql_string.cc sql/sql_string.h 3493 Olav Sandstaa 2011-01-13 Fix for Bug#58816 Extra temporary duplicate rows in result set when switching ICP off. The wrong result was caused by that the handler object was in an inconsistent state when running the query. The same handler object was previously used by an explain for the same query. When doing the explain the optimizer pushed down an index condition to the handler. This set information about the pushed index condition as well as setting the member variable in_range_check_pushed_down to true. The inconsistency that this resulted in was that when the explain statement completed and the handler object was ready for re-use the information about the pushed index condition was reset but the in_range_check_pushed_down was still true. When executing the same query (after disabling index condition pushdown) using the same handler object with the in_range_check_pushed_down still being true caused that neither the server nor the storage engine were performing the range check. This resulted in that we would read to the end of the table for the first range instead of stopping at the end of range criterion. The fix for this problem is to add code to handler::ha_reset() to to reset both information about the pushed index condition and the in_range_check_pushed_down. This method is called when a statement closes its tables and the handler object is made ready for reuse. @ mysql-test/include/icp_tests.inc Test case for Bug#58816 Extra temporary duplicate rows in result set when switching ICP off. @ mysql-test/r/innodb_icp.result Test case for Bug#58816 Extra temporary duplicate rows in result set when switching ICP off. @ mysql-test/r/innodb_icp_all.result Test case for Bug#58816 Extra temporary duplicate rows in result set when switching ICP off. @ mysql-test/r/innodb_icp_none.result Test case for Bug#58816 Extra temporary duplicate rows in result set when switching ICP off. @ mysql-test/r/myisam_icp.result Test case for Bug#58816 Extra temporary duplicate rows in result set when switching ICP off. @ mysql-test/r/myisam_icp_all.result Test case for Bug#58816 Extra temporary duplicate rows in result set when switching ICP off. @ mysql-test/r/myisam_icp_none.result Test case for Bug#58816 Extra temporary duplicate rows in result set when switching ICP off. @ sql/handler.cc When an explain is run on a statement using index condition pushdown it will leave the handler object in an inconsistent state where the information about the pushed index condition is reset while the value of in_range_check_pushed_down is still true. If this handler object is later re-used for a range query it might lead to more records being found due to the range condition is not evaluated neither by the server nor the storage engine. The fix for this is to extend handler::ha_reset() to reset both the information about pushed index condition and the in_range_check_pushed_down. @ storage/innobase/handler/ha_innodb.cc Move resetting of the handler's ICP member variables to handler::ha_reset(). @ storage/myisam/ha_myisam.cc Move resetting of the handler's ICP member variables to handler::ha_reset(). modified: mysql-test/include/icp_tests.inc mysql-test/r/innodb_icp.result mysql-test/r/innodb_icp_all.result mysql-test/r/innodb_icp_none.result mysql-test/r/myisam_icp.result mysql-test/r/myisam_icp_all.result mysql-test/r/myisam_icp_none.result sql/handler.cc storage/innobase/handler/ha_innodb.cc storage/myisam/ha_myisam.cc === modified file 'mysql-test/r/func_str.result' --- a/mysql-test/r/func_str.result 2010-12-14 16:29:15 +0000 +++ b/mysql-test/r/func_str.result 2011-01-13 08:19:52 +0000 @@ -2615,6 +2615,22 @@ CONVERT(('' IN (REVERSE(CAST(('') AS DEC 1 Warnings: 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 Start of 5.4 tests SELECT format(12345678901234567890.123, 3); === modified file 'mysql-test/t/func_str.test' --- a/mysql-test/t/func_str.test 2010-12-14 16:29:15 +0000 +++ b/mysql-test/t/func_str.test 2011-01-13 08:19:52 +0000 @@ -1370,6 +1370,17 @@ DROP TABLE t1; SELECT '1' IN ('1', SUBSTRING(-9223372036854775809, 1)); 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 Start of 5.4 tests === modified file 'sql/item_strfunc.cc' --- a/sql/item_strfunc.cc 2010-12-20 10:28:06 +0000 +++ b/sql/item_strfunc.cc 2011-01-13 08:19:52 +0000 @@ -57,6 +57,9 @@ C_MODE_START #include "../mysys/my_static.h" // For soundex_map C_MODE_END +/** + @todo Remove this. It is not safe to use a shared String object. + */ String my_empty_string("",default_charset_info); /* @@ -739,7 +742,7 @@ String *Item_func_des_encrypt::val_str(S if ((null_value= args[0]->null_value)) return 0; // ENCRYPT(NULL) == NULL if ((res_length=res->length()) == 0) - return &my_empty_string; + return make_empty_result(); if (arg_count == 1) { /* Protect against someone doing FLUSH DES_KEY_FILE */ @@ -929,7 +932,7 @@ String *Item_func_concat_ws::val_str(Str } if (i == arg_count) - return &my_empty_string; + return make_empty_result(); for (i++; i < arg_count ; i++) { @@ -1075,7 +1078,7 @@ String *Item_func_reverse::val_str(Strin return 0; /* An empty string is a special case as the string pointer may be null */ if (!res->length()) - return &my_empty_string; + return make_empty_result(); if (tmp_value.alloced_length() < res->length() && tmp_value.realloc(res->length())) { @@ -1408,8 +1411,7 @@ String *Item_func_left::val_str(String * /* if "unsigned_flag" is set, we have a *huge* positive number. */ if ((length <= 0) && (!args[1]->unsigned_flag)) - return &my_empty_string; - + return make_empty_result(); if ((res->length() <= (ulonglong) length) || (res->length() <= (char_pos= res->charpos((int) length)))) return res; @@ -1454,7 +1456,7 @@ String *Item_func_right::val_str(String /* if "unsigned_flag" is set, we have a *huge* positive number. */ if ((length <= 0) && (!args[1]->unsigned_flag)) - return &my_empty_string; /* purecov: inspected */ + return make_empty_result(); /* purecov: inspected */ if (res->length() <= (ulonglong) length) return res; /* purecov: inspected */ @@ -1494,7 +1496,7 @@ String *Item_func_substr::val_str(String /* Negative or zero length, will return empty string. */ if ((arg_count == 3) && (length <= 0) && (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. */ /* Set here so that rest of code sees out-of-bound value as such. */ @@ -1505,12 +1507,12 @@ String *Item_func_substr::val_str(String /* Assumes that the maximum length of a String is < INT_MAX32. */ if ((!args[1]->unsigned_flag && (start < INT_MIN32 || 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= res->charpos((int) start); if ((start < 0) || ((uint) start + 1 > res->length())) - return &my_empty_string; + return make_empty_result(); length= res->charpos((int) length, (uint32) start); tmp_length= res->length() - start; @@ -1573,7 +1575,7 @@ String *Item_func_substr_index::val_str( null_value=0; uint delimiter_length= delimiter->length(); if (!res->length() || !delimiter_length || !count) - return &my_empty_string; // Wrong parameters + return make_empty_result(); // Wrong parameters res->set_charset(collation.collation); @@ -1923,7 +1925,7 @@ String *Item_func_password::val_str_asci if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) - return &my_empty_string; + return make_empty_result(); my_make_scrambled_password(tmp_value, res->ptr(), res->length()); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, &my_charset_latin1); return str; @@ -1947,7 +1949,7 @@ String *Item_func_old_password::val_str_ if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) - return &my_empty_string; + return make_empty_result(); my_make_scrambled_password_323(tmp_value, res->ptr(), res->length()); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, &my_charset_latin1); return str; @@ -1975,8 +1977,7 @@ String *Item_func_encrypt::val_str(Strin if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) - return &my_empty_string; - + return make_empty_result(); if (arg_count == 1) { // generate random salt time_t timestamp=current_thd->query_start(); @@ -2238,7 +2239,7 @@ String *Item_func_soundex::val_str(Strin for ( ; ; ) /* Skip pre-space */ { 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) { @@ -2263,7 +2264,7 @@ String *Item_func_soundex::val_str(Strin { /* Extra safety - should not really happen */ DBUG_ASSERT(false); - return &my_empty_string; + return make_empty_result(); } to+= rc; break; @@ -2604,7 +2605,7 @@ String *Item_func_make_set::val_str(Stri else { if (tmp_str.copy(*res)) // Don't use 'str' - return &my_empty_string; + return make_empty_result(); result= &tmp_str; } } @@ -2614,11 +2615,11 @@ String *Item_func_make_set::val_str(Stri { // Copy data to tmp_str if (tmp_str.alloc(result->length()+res->length()+1) || tmp_str.copy(*result)) - return &my_empty_string; + return make_empty_result(); result= &tmp_str; } if (tmp_str.append(STRING_WITH_LEN(","), &my_charset_bin) || tmp_str.append(*res)) - return &my_empty_string; + return make_empty_result(); } } } @@ -2763,7 +2764,7 @@ String *Item_func_repeat::val_str(String null_value= 0; 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. */ /* Bounds check on count: If this is triggered, we will error. */ @@ -3045,7 +3046,7 @@ String *Item_func_conv::val_str(String * ptr= longlong2str(dec, ans, to_base); if (str->copy(ans, (uint32) (ptr-ans), default_charset())) - return &my_empty_string; + return make_empty_result(); return str; } @@ -3264,7 +3265,7 @@ String *Item_func_hex::val_str_ascii(Str return 0; ptr= longlong2str(dec,ans,16); 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; } === modified file 'sql/item_strfunc.h' --- a/sql/item_strfunc.h 2010-12-02 13:44:21 +0000 +++ b/sql/item_strfunc.h 2011-01-13 08:19:52 +0000 @@ -27,6 +27,16 @@ class MY_LOCALE; 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: Item_str_func() :Item_func() { decimals=NOT_FIXED_DEC; } Item_str_func(Item *a) :Item_func(a) {decimals=NOT_FIXED_DEC; } === modified file 'sql/sql_string.cc' --- a/sql/sql_string.cc 2010-12-14 13:26:35 +0000 +++ b/sql/sql_string.cc 2011-01-13 08:19:52 +0000 @@ -51,11 +51,33 @@ bool String::real_alloc(uint32 length) } -/* -** Check that string is big enough. Set string[alloc_length] to 0 -** (for C functions) -*/ +/** + Allocates a new buffer on the heap for this String. + + - 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) { uint32 len=ALIGN_SIZE(alloc_length+1); @@ -128,6 +150,17 @@ bool String::copy() 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) { if (alloc(str.str_length)) === modified file 'sql/sql_string.h' --- a/sql/sql_string.h 2010-10-27 14:46:44 +0000 +++ b/sql/sql_string.h 2011-01-13 08:19:52 +0000 @@ -148,6 +148,16 @@ public: Alloced_length=0; 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) { free(); --===============1108344183== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/martin.hansson@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: martin.hansson@stripped\ # n7mg2swpu1xb5fjp # target_branch: file:///data0/martin/bzrroot/bug58165/t/ # testament_sha1: c50059ec63068969e42564d2da1802070b04075e # timestamp: 2011-01-13 09:21:42 +0100 # source_branch: file:///data0/martin/bzrroot/bug58165/5.5/ # base_revision_id: olav.sandstaa@stripped\ # xtc6rhbo1g9iaiqm # # Begin bundle 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 3G4eLPW5IPU/wLuSKcKEgaH/g4g= --===============1108344183==--