maria-developers team mailing list archive
-
maria-developers team
-
Mailing list archive
-
Message #10759
Re: MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
Hello Sergei,
Thanks for your review. Here's a new version of the patch.
Please see comments below:
On 03/06/2017 10:50 AM, Sergei Golubchik wrote:
> Hi, Alexander!
>
> On Mar 06, Alexander Barkov wrote:
>>>> @@ -3378,16 +3379,16 @@ String *Item_func_conv_charset::val_str(String *str)
>>>> DBUG_ASSERT(fixed == 1);
>>>> if (use_cached_value)
>>>> return null_value ? 0 : &str_value;
>>>> - String *arg= args[0]->val_str(str);
>>>> + String *arg= args[0]->val_str(&tmp_value);
>>>> uint dummy_errors;
>>>> if (args[0]->null_value)
>>>> {
>>>> null_value=1;
>>>> return 0;
>>>> }
>>>> - null_value= tmp_value.copy(arg->ptr(), arg->length(), arg->charset(),
>>>> - conv_charset, &dummy_errors);
>>>> - return null_value ? 0 : check_well_formed_result(&tmp_value);
>>>> + null_value= str->copy(arg->ptr(), arg->length(), arg->charset(),
>>>> + conv_charset, &dummy_errors);
>>>> + return null_value ? 0 : check_well_formed_result(str);
>>>> }
>>>
>>> That's a good idea. I'd expect it to fix the bug for both queries, with
>>> and without SUBSTR.
>>
>> I tested this change alone, without adding the "res->is_alloced()" part.
>> It fixes both queries, with and without SUBSTR.
>
> Great!
>
>>> But (sorry) you're fixing only Item_func_conv_charset. Is it the
>>> only Item that stores the result in its internal buffer (tmp_value
>>> or str_value)? Any other item that does it will cause the same bug.
>>
>> There are more Items:
>>
>> - around 16 doing "return &tmp_value;"
>> - around 4 doing "return &str_value;"
>>
>> Here's an example of another bad result:
>>
>> DROP TABLE IF EXISTS t1;
>> CREATE TABLE t1 (t VARCHAR(10) CHARSET latin1);
>> INSERT INTO t1 VALUES('1234567');
>> SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT REVERSE(t) t2 FROM t1) sub;
>>
>> +----------------+
>> | c2 |
>> +----------------+
>> | 76543217654321 |
>> +----------------+
>>
>> It should be '7654321-7654321' instead.
>>
>> Should we fix all of them under terms of MDEV-10306?
>
> I'd say yes. What do you think?
Agreed. This version fixes around 16 classes that had the same problem,
and which only needed to swap "str" and "tmp_value" in their val_str()
implementations.
As agreed on slack, the following three classes:
- Item_str_conv
- Item_func_make_set
- Item_char_typecast
with more complex implementations will be fixed separately.
I'll create separate MDEVs for these three classes.
>
> And, by the way, could you also fix the comment in item.h around
> Item::val_str(String *) not to say that it can only change allocated
> strings? May be it should say about const (String::make_const) strings
> instead. Thanks. Also you could add something about this your CONCAT
> fix. Like, the item can use internal buffer as a temporary storage,
> but the result should be in the String argument, not the other way
> around.
Can you please suggest proper comments and proper places for them?
I got stuck with that :)
> Ideally, we'd have some way to enforce it, but I couldn't think
> of anything.
As discussed on slack, we can try something like this:
String *res= expr->val_str(str);
DBUG_ASSERT(!res || res == str || res->alloced_length() == 0);
in a few top-level places (e.g. protocol), but after the remaining three
classes are fixed. So in the current patch I'm not adding any enforcing
code.
Thanks.
>
> Regards,
> Sergei
> Chief Architect MariaDB
> and security@xxxxxxxxxxx
>
commit cec33b1026c54bd1e0e92d26053843b3bced7c81
Author: Alexander Barkov <bar@xxxxxxxxxxx>
Date: Fri Jun 16 12:58:01 2017 +0400
MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
The bug happens because of a combination of unfortunate circumstances:
1. Arguments args[0] and args[2] of Item_func_concat point recursively
(through Item_direct_view_ref's) to the same Item_func_conv_charset.
Both args[0]->args[0]->ref[0] and args[2]->args[0]->ref[0] refer to
this Item_func_conv_charset.
2. When Item_func_concat::args[0]->val_str() is called,
Item_func_conv_charset::val_str() writes its result to
Item_func_conc_charset::tmp_value.
3. Then, for optimization purposes (to avoid copying),
Item_func_substr::val_str() initializes Item_func_substr::tmp_value
to point to the buffer fragment owned by Item_func_conv_charset::tmp_value
Item_func_substr::tmp_value is returned as a result of
Item_func_concat::args[0]->val_str().
4. Due to optimization to avoid memory reallocs,
Item_func_concat::val_str() remembers the result of args[0]->val_str()
in "res" and further uses "res" to collect the return value.
5. When Item_func_concat::args[2]->val_str() is called,
Item_func_conv_charset::tmp_value gets overwritten (see #1),
which effectively overwrites args[0]'s Item_func_substr::tmp_value (see #3),
which effectively overwrites "res" (see #4).
This patch does the following:
a. Changes Item_func_conv_charset::val_str(String *str) to use
tmp_value and str the other way around. After this change tmp_value
is used to store a temporary result, while str is used to return the value.
The fixes the second problem (without SUBSTR):
SELECT CONCAT(t2,'-',t2) c2
FROM (SELECT CONVERT(t USING latin1) t2 FROM t1) sub;
As Item_func_concat::val_str() supplies two different buffers when calling
args[0]->val_str() and args[2]->val_str(), in the new reduction the result
created during args[0]->val_str() does not get overwritten by
args[2]->val_str().
b. Fixing the same problem in val_str() for similar classes
Item_func_to_base64
Item_func_from_base64
Item_func_weight_string
Item_func_hex
Item_func_unhex
Item_func_quote
Item_func_compress
Item_func_uncompress
Item_func_des_encrypt
Item_func_des_decrypt
Item_func_conv_charset
Item_func_reverse
Item_func_soundex
Item_func_aes_encrypt
Item_func_aes_decrypt
Item_func_buffer
c. Fixing Item_func::val_str_from_val_str_ascii() the same way.
Now Item_str_ascii_func::ascii_buff is used for temporary value,
while the parameter passed to val_str() is used to return the result.
This fixes the same problem when conversion (from ASCII to e.g. UCS2)
takes place. See the ctype_ucs.test for example queries that returned
wrong results before the fix.
d. Some Item_func descendand classes had temporary String buffers
(tmp_value and tmp_str), but did not really use them.
Removing these temporary buffers from:
Item_func_decode_histogram
Item_func_format
Item_func_binlog_gtid_pos
Item_func_spatial_collection:
e. Removing Item_func_buffer::tmp_value, because it's not used any more.
f. Renaming Item_func_[un]compress::buffer to "tmp_value",
for consistency with other classes.
Note, this patch does not fix the following classes
(although they have a similar problem):
Item_str_conv
Item_func_make_set
Item_char_typecast
They have a complex implementations and simple swapping between "tmp_value"
and "str" won't work. These classes will be fixed separately.
diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result
index 843b49c..8c69745 100644
--- a/mysql-test/r/ctype_ucs.result
+++ b/mysql-test/r/ctype_ucs.result
@@ -5552,5 +5552,22 @@ SELECT 'a','aa';
a aa
a aa
#
+# MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
+#
+SET NAMES utf8, character_set_connection=ucs2;
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch=_utf8'derived_merge=on';
+CREATE TABLE t1 (t VARCHAR(10) CHARSET latin1);
+INSERT INTO t1 VALUES('abcdefghi');
+SET NAMES utf8, character_set_connection=ucs2;
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT HEX(t) t2 FROM t1) sub;
+c2
+616263646566676869-616263646566676869
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT TO_BASE64(t) t2 FROM t1) sub;
+c2
+YWJjZGVmZ2hp-YWJjZGVmZ2hp
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
+#
# End of 10.0 tests
#
diff --git a/mysql-test/r/func_concat.result b/mysql-test/r/func_concat.result
index 925158a..b87ee7b 100644
--- a/mysql-test/r/func_concat.result
+++ b/mysql-test/r/func_concat.result
@@ -149,3 +149,116 @@ CALL p1();
########################################40100.000
DROP PROCEDURE p1;
# End of 5.1 tests
+#
+# Start of 10.0 tests
+#
+#
+# MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
+#
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch='derived_merge=on';
+CREATE TABLE t1 (t VARCHAR(10) CHARSET latin1);
+INSERT INTO t1 VALUES('1234567');
+SELECT CONCAT(SUBSTR(t2, 1, 3), SUBSTR(t2, 5)) c1,
+CONCAT(SUBSTR(t2,1,3),'---',SUBSTR(t2,5)) c2
+FROM (SELECT CONVERT(t USING latin1) t2 FROM t1) sub;
+c1 c2
+123567 123---567
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT CONVERT(t USING latin1) t2 FROM t1) sub;
+c2
+1234567-1234567
+DROP TABLE t1;
+CREATE TABLE t1 (t VARCHAR(10) CHARSET latin1);
+INSERT INTO t1 VALUES('1234567');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT CONVERT(t USING latin1) t2 FROM t1) sub;
+c2
+1234567-1234567
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT REVERSE(t) t2 FROM t1) sub;
+c2
+7654321-7654321
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT SOUNDEX(t) t2 FROM t1) sub;
+c2
+-
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT TO_BASE64(t) t2 FROM t1) sub;
+c2
+MTIzNDU2Nw==-MTIzNDU2Nw==
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT WEIGHT_STRING(t) t2 FROM t1) sub;
+c2
+1234567-1234567
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT HEX(t) t2 FROM t1) sub;
+c2
+31323334353637-31323334353637
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT QUOTE(t) t2 FROM t1) sub;
+c2
+'1234567'-'1234567'
+DROP TABLE t1;
+CREATE TABLE t1 (t VARCHAR(32) CHARSET latin1);
+INSERT INTO t1 VALUES(TO_BASE64('abcdefghi'));
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT FROM_BASE64(t) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+DROP TABLE t1;
+CREATE TABLE t1 (t VARCHAR(32) CHARSET latin1);
+INSERT INTO t1 VALUES(HEX('abcdefghi'));
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UNHEX(t) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+DROP TABLE t1;
+CREATE TABLE t1 (t VARCHAR(30) CHARSET latin1);
+INSERT INTO t1 VALUES('test');
+SELECT LENGTH(CONCAT(t2)) c2 FROM (SELECT AES_ENCRYPT(t,'x') t2 FROM t1) sub;
+c2
+16
+SELECT LENGTH(CONCAT(t2,'-',t2)) c2 FROM (SELECT AES_ENCRYPT(t,'x') t2 FROM t1) sub;
+c2
+33
+SELECT LENGTH(CONCAT(t2,'--',t2)) c2 FROM (SELECT AES_ENCRYPT(t,'x') t2 FROM t1) sub;
+c2
+34
+SELECT LENGTH(CONCAT(t2)) c2 FROM (SELECT AES_DECRYPT(AES_ENCRYPT(t,'x'),'x') t2 FROM t1) sub;
+c2
+4
+SELECT LENGTH(CONCAT(t2,'-',t2)) c2 FROM (SELECT AES_DECRYPT(AES_ENCRYPT(t,'x'),'x') t2 FROM t1) sub;
+c2
+9
+SELECT LENGTH(CONCAT(t2,'--',t2)) c2 FROM (SELECT AES_DECRYPT(AES_ENCRYPT(t,'x'),'x') t2 FROM t1) sub;
+c2
+10
+DROP TABLE t1;
+CREATE TABLE t1 (t VARCHAR(64) CHARSET latin1);
+INSERT INTO t1 VALUES('123456789');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT MD5(t) t2 FROM t1) sub;
+c2
+25f9e794323b453885f5181f1b624d0b-25f9e794323b453885f5181f1b624d0b
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT FORMAT(t,2) t2 FROM t1) sub;
+c2
+123,456,789.00-123,456,789.00
+DROP TABLE t1;
+CREATE TABLE t1 (t VARCHAR(32) CHARSET latin1);
+INSERT INTO t1 VALUES('abcdefghi');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT INSERT(t,3,4,'xxx') t2 FROM t1) sub;
+c2
+abxxxghi-abxxxghi
+DROP TABLE t1;
+CREATE TABLE t1 (t VARCHAR(10) CHARSET latin1);
+INSERT INTO t1 VALUES('abcdefghi');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LEFT(t,10) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT RIGHT(t,10) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT SUBSTR(t,1,10) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LTRIM(t) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT RTRIM(t) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT TRIM(t) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
diff --git a/mysql-test/r/func_crypt.result b/mysql-test/r/func_crypt.result
index 1eda56a..707e767 100644
--- a/mysql-test/r/func_crypt.result
+++ b/mysql-test/r/func_crypt.result
@@ -106,3 +106,21 @@ OLD_PASSWORD(c1) PASSWORD(c1)
77023ffe214c04ff *82E58A2C08AAFE72C8EB523069CD8ADB33F78F58
DROP TABLE t1;
End of 5.0 tests
+#
+# Start of 10.0 tests
+#
+#
+# MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
+#
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch='derived_merge=on';
+CREATE TABLE t1 (t VARCHAR(32) CHARSET latin1);
+INSERT INTO t1 VALUES('abcdefghi');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT ENCRYPT(t,'aa') t2 FROM t1) sub;
+c2
+aaHHlPHAM4sjs-aaHHlPHAM4sjs
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
+#
+# End of 10.0 tests
+#
diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result
index 2bd4920..f029542 100644
--- a/mysql-test/r/gis.result
+++ b/mysql-test/r/gis.result
@@ -1641,5 +1641,23 @@ AsText(g)
NULL
POINT(1 1)
#
+# MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
+#
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch='derived_merge=on';
+CREATE TABLE t1 (x INT, y INT);
+INSERT INTO t1 VALUES(0,0);
+SELECT LENGTH(t2) c2 FROM (SELECT ST_BUFFER(POINT(x,y), 0) t2 FROM t1) sub;
+c2
+25
+SELECT LENGTH(CONCAT(t2,'-',t2)) c2 FROM (SELECT ST_BUFFER(POINT(x,y), 0) t2 FROM t1) sub;
+c2
+51
+SELECT LENGTH(CONCAT(t2,'--',t2)) c2 FROM (SELECT ST_BUFFER(POINT(x,y), 0) t2 FROM t1) sub;
+c2
+52
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
+#
# End 10.0 tests
#
diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test
index 165d945..0415662 100644
--- a/mysql-test/t/ctype_ucs.test
+++ b/mysql-test/t/ctype_ucs.test
@@ -924,5 +924,21 @@ SELECT 'a','aa';
--echo #
+--echo # MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
+--echo #
+
+SET NAMES utf8, character_set_connection=ucs2;
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch=_utf8'derived_merge=on';
+CREATE TABLE t1 (t VARCHAR(10) CHARSET latin1);
+INSERT INTO t1 VALUES('abcdefghi');
+SET NAMES utf8, character_set_connection=ucs2;
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT HEX(t) t2 FROM t1) sub;
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT TO_BASE64(t) t2 FROM t1) sub;
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
+
+
+--echo #
--echo # End of 10.0 tests
--echo #
diff --git a/mysql-test/t/func_concat.test b/mysql-test/t/func_concat.test
index e56d112..be573f4 100644
--- a/mysql-test/t/func_concat.test
+++ b/mysql-test/t/func_concat.test
@@ -145,3 +145,94 @@ CALL p1();
DROP PROCEDURE p1;
--echo # End of 5.1 tests
+
+
+--echo #
+--echo # Start of 10.0 tests
+--echo #
+
+--echo #
+--echo # MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
+--echo #
+
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch='derived_merge=on';
+
+CREATE TABLE t1 (t VARCHAR(10) CHARSET latin1);
+INSERT INTO t1 VALUES('1234567');
+SELECT CONCAT(SUBSTR(t2, 1, 3), SUBSTR(t2, 5)) c1,
+ CONCAT(SUBSTR(t2,1,3),'---',SUBSTR(t2,5)) c2
+ FROM (SELECT CONVERT(t USING latin1) t2 FROM t1) sub;
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT CONVERT(t USING latin1) t2 FROM t1) sub;
+DROP TABLE t1;
+
+# Other functions affected by MDEV-10306
+
+CREATE TABLE t1 (t VARCHAR(10) CHARSET latin1);
+INSERT INTO t1 VALUES('1234567');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT CONVERT(t USING latin1) t2 FROM t1) sub;
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT REVERSE(t) t2 FROM t1) sub;
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT SOUNDEX(t) t2 FROM t1) sub;
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT TO_BASE64(t) t2 FROM t1) sub;
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT WEIGHT_STRING(t) t2 FROM t1) sub;
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT HEX(t) t2 FROM t1) sub;
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT QUOTE(t) t2 FROM t1) sub;
+DROP TABLE t1;
+
+CREATE TABLE t1 (t VARCHAR(32) CHARSET latin1);
+INSERT INTO t1 VALUES(TO_BASE64('abcdefghi'));
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT FROM_BASE64(t) t2 FROM t1) sub;
+DROP TABLE t1;
+
+CREATE TABLE t1 (t VARCHAR(32) CHARSET latin1);
+INSERT INTO t1 VALUES(HEX('abcdefghi'));
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UNHEX(t) t2 FROM t1) sub;
+DROP TABLE t1;
+
+CREATE TABLE t1 (t VARCHAR(30) CHARSET latin1);
+INSERT INTO t1 VALUES('test');
+SELECT LENGTH(CONCAT(t2)) c2 FROM (SELECT AES_ENCRYPT(t,'x') t2 FROM t1) sub;
+SELECT LENGTH(CONCAT(t2,'-',t2)) c2 FROM (SELECT AES_ENCRYPT(t,'x') t2 FROM t1) sub;
+SELECT LENGTH(CONCAT(t2,'--',t2)) c2 FROM (SELECT AES_ENCRYPT(t,'x') t2 FROM t1) sub;
+SELECT LENGTH(CONCAT(t2)) c2 FROM (SELECT AES_DECRYPT(AES_ENCRYPT(t,'x'),'x') t2 FROM t1) sub;
+SELECT LENGTH(CONCAT(t2,'-',t2)) c2 FROM (SELECT AES_DECRYPT(AES_ENCRYPT(t,'x'),'x') t2 FROM t1) sub;
+SELECT LENGTH(CONCAT(t2,'--',t2)) c2 FROM (SELECT AES_DECRYPT(AES_ENCRYPT(t,'x'),'x') t2 FROM t1) sub;
+DROP TABLE t1;
+
+
+# Functions not affected by MDEV-10306
+# They only had an unused tmp_value, which was removed.
+
+CREATE TABLE t1 (t VARCHAR(64) CHARSET latin1);
+INSERT INTO t1 VALUES('123456789');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT MD5(t) t2 FROM t1) sub;
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT FORMAT(t,2) t2 FROM t1) sub;
+DROP TABLE t1;
+
+# Functions not affected by MDEV-10306
+# They already use tmp_value only for internal purposes and
+# return the result in the String passed to val_str()
+
+CREATE TABLE t1 (t VARCHAR(32) CHARSET latin1);
+INSERT INTO t1 VALUES('abcdefghi');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT INSERT(t,3,4,'xxx') t2 FROM t1) sub;
+DROP TABLE t1;
+
+
+# Functions not affected by MDEV-10306
+# They use this code style:
+# String *res= args[0]->val_str(str);
+# tmp_value.set(*res, start, end);
+# return &tmp_value;
+
+CREATE TABLE t1 (t VARCHAR(10) CHARSET latin1);
+INSERT INTO t1 VALUES('abcdefghi');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LEFT(t,10) t2 FROM t1) sub;
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT RIGHT(t,10) t2 FROM t1) sub;
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT SUBSTR(t,1,10) t2 FROM t1) sub;
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LTRIM(t) t2 FROM t1) sub;
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT RTRIM(t) t2 FROM t1) sub;
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT TRIM(t) t2 FROM t1) sub;
+DROP TABLE t1;
+
+SET optimizer_switch=@save_optimizer_switch;
diff --git a/mysql-test/t/func_crypt.test b/mysql-test/t/func_crypt.test
index ca6e712..785cc63 100644
--- a/mysql-test/t/func_crypt.test
+++ b/mysql-test/t/func_crypt.test
@@ -70,3 +70,27 @@ SELECT OLD_PASSWORD(c1), PASSWORD(c1) FROM t1;
DROP TABLE t1;
--echo End of 5.0 tests
+
+
+--echo #
+--echo # Start of 10.0 tests
+--echo #
+
+--echo #
+--echo # MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
+--echo #
+
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch='derived_merge=on';
+# ENCRYPT() is not affected by MDEV-10306
+# It already uses tmp_value only for internal purposes and
+# returns the result in the String passed to val_str()
+CREATE TABLE t1 (t VARCHAR(32) CHARSET latin1);
+INSERT INTO t1 VALUES('abcdefghi');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT ENCRYPT(t,'aa') t2 FROM t1) sub;
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
+
+--echo #
+--echo # End of 10.0 tests
+--echo #
diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test
index f689902..fe7b8ff 100644
--- a/mysql-test/t/gis.test
+++ b/mysql-test/t/gis.test
@@ -1503,5 +1503,20 @@ DROP VIEW v1;
SELECT AsText(g) FROM (SELECT NULL AS g UNION SELECT Point(1,1)) AS t1;
--echo #
+--echo # MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
+--echo #
+
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch='derived_merge=on';
+CREATE TABLE t1 (x INT, y INT);
+INSERT INTO t1 VALUES(0,0);
+SELECT LENGTH(t2) c2 FROM (SELECT ST_BUFFER(POINT(x,y), 0) t2 FROM t1) sub;
+SELECT LENGTH(CONCAT(t2,'-',t2)) c2 FROM (SELECT ST_BUFFER(POINT(x,y), 0) t2 FROM t1) sub;
+SELECT LENGTH(CONCAT(t2,'--',t2)) c2 FROM (SELECT ST_BUFFER(POINT(x,y), 0) t2 FROM t1) sub;
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
+
+
+--echo #
--echo # End 10.0 tests
--echo #
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 568a28e..a9e39ab 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -1268,7 +1268,7 @@ String *Item_func_buffer::val_str(String *str_value)
{
DBUG_ENTER("Item_func_buffer::val_str");
DBUG_ASSERT(fixed == 1);
- String *obj= args[0]->val_str(&tmp_value);
+ String *obj= args[0]->val_str(str_value);
double dist= args[1]->val_real();
Geometry_buffer buffer;
Geometry *g;
diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
index 62d2198..d32edff 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -171,7 +171,6 @@ class Item_func_spatial_decomp_n: public Item_geometry_func
class Item_func_spatial_collection: public Item_geometry_func
{
- String tmp_value;
enum Geometry::wkbType coll_type;
enum Geometry::wkbType item_type;
public:
@@ -325,7 +324,6 @@ class Item_func_buffer: public Item_geometry_func
Gcalc_result_receiver res_receiver;
Gcalc_operation_reducer operation;
- String tmp_value;
public:
Item_func_buffer(Item *obj, Item *distance):
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 7cd712c..de2c25a 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -73,8 +73,14 @@ size_t username_char_length= 80;
Conversion happens only in case of "tricky" Item character set (e.g. UCS2).
Normally conversion does not happen, and val_str_ascii() is immediately
returned instead.
+
+ No matter if conversion is needed or not needed,
+ the result is always returned in "str" (see MDEV-10306 why).
+
+ @param [OUT] str - Store the result here
+ @param [IN] ascii_buffer - Use this temporary buffer to call val_str_ascii()
*/
-String *Item_func::val_str_from_val_str_ascii(String *str, String *str2)
+String *Item_func::val_str_from_val_str_ascii(String *str, String *ascii_buffer)
{
DBUG_ASSERT(fixed == 1);
@@ -86,19 +92,19 @@ String *Item_func::val_str_from_val_str_ascii(String *str, String *str2)
return res;
}
- DBUG_ASSERT(str != str2);
+ DBUG_ASSERT(str != ascii_buffer);
uint errors;
- String *res= val_str_ascii(str);
+ String *res= val_str_ascii(ascii_buffer);
if (!res)
return 0;
- if ((null_value= str2->copy(res->ptr(), res->length(),
- &my_charset_latin1, collation.collation,
- &errors)))
+ if ((null_value= str->copy(res->ptr(), res->length(),
+ &my_charset_latin1, collation.collation,
+ &errors)))
return 0;
- return str2;
+ return str;
}
@@ -368,12 +374,12 @@ void Item_func_sha2::fix_length_and_dec()
/* Implementation of AES encryption routines */
-String *Item_func_aes_encrypt::val_str(String *str)
+String *Item_func_aes_encrypt::val_str(String *str2)
{
DBUG_ASSERT(fixed == 1);
char key_buff[80];
String tmp_key_value(key_buff, sizeof(key_buff), system_charset_info);
- String *sptr= args[0]->val_str(str); // String to encrypt
+ String *sptr= args[0]->val_str(&str_value); // String to encrypt
String *key= args[1]->val_str(&tmp_key_value); // key
int aes_length;
if (sptr && key) // we need both arguments to be not NULL
@@ -381,15 +387,15 @@ String *Item_func_aes_encrypt::val_str(String *str)
null_value=0;
aes_length=my_aes_get_size(sptr->length()); // Calculate result length
- if (!str_value.alloc(aes_length)) // Ensure that memory is free
+ if (!str2->alloc(aes_length)) // Ensure that memory is free
{
// finally encrypt directly to allocated buffer.
- if (my_aes_encrypt(sptr->ptr(),sptr->length(), (char*) str_value.ptr(),
+ if (my_aes_encrypt(sptr->ptr(),sptr->length(), (char*) str2->ptr(),
key->ptr(), key->length()) == aes_length)
{
// We got the expected result length
- str_value.length((uint) aes_length);
- return &str_value;
+ str2->length((uint) aes_length);
+ return str2;
}
}
}
@@ -412,22 +418,22 @@ String *Item_func_aes_decrypt::val_str(String *str)
String *sptr, *key;
DBUG_ENTER("Item_func_aes_decrypt::val_str");
- sptr= args[0]->val_str(str); // String to decrypt
+ sptr= args[0]->val_str(&str_value); // String to decrypt
key= args[1]->val_str(&tmp_key_value); // Key
if (sptr && key) // Need to have both arguments not NULL
{
null_value=0;
- if (!str_value.alloc(sptr->length())) // Ensure that memory is free
+ if (!str->alloc(sptr->length())) // Ensure that memory is free
{
// finally decrypt directly to allocated buffer.
int length;
length=my_aes_decrypt(sptr->ptr(), sptr->length(),
- (char*) str_value.ptr(),
+ (char*) str->ptr(),
key->ptr(), key->length());
if (length >= 0) // if we got correct data data
{
- str_value.length((uint) length);
- DBUG_RETURN(&str_value);
+ str->length((uint) length);
+ DBUG_RETURN(str);
}
}
}
@@ -464,7 +470,7 @@ void Item_func_to_base64::fix_length_and_dec()
String *Item_func_to_base64::val_str_ascii(String *str)
{
- String *res= args[0]->val_str(str);
+ String *res= args[0]->val_str(&tmp_value);
bool too_long= false;
int length;
if (!res ||
@@ -472,7 +478,7 @@ String *Item_func_to_base64::val_str_ascii(String *str)
(too_long=
((uint) (length= base64_needed_encoded_length((int) res->length())) >
current_thd->variables.max_allowed_packet)) ||
- tmp_value.alloc((uint) length))
+ str->alloc((uint) length))
{
null_value= 1; // NULL input, too long input, or OOM.
if (too_long)
@@ -484,11 +490,11 @@ String *Item_func_to_base64::val_str_ascii(String *str)
}
return 0;
}
- base64_encode(res->ptr(), (int) res->length(), (char*) tmp_value.ptr());
+ base64_encode(res->ptr(), (int) res->length(), (char*) str->ptr());
DBUG_ASSERT(length > 0);
- tmp_value.length((uint) length - 1); // Without trailing '\0'
+ str->length((uint) length - 1); // Without trailing '\0'
null_value= 0;
- return &tmp_value;
+ return str;
}
@@ -509,7 +515,7 @@ void Item_func_from_base64::fix_length_and_dec()
String *Item_func_from_base64::val_str(String *str)
{
- String *res= args[0]->val_str_ascii(str);
+ String *res= args[0]->val_str_ascii(&tmp_value);
int length;
const char *end_ptr;
@@ -527,11 +533,11 @@ String *Item_func_from_base64::val_str(String *str)
goto err;
}
- if (tmp_value.alloc((uint) length))
+ if (str->alloc((uint) length))
goto err;
if ((length= base64_decode(res->ptr(), (int) res->length(),
- (char *) tmp_value.ptr(), &end_ptr, 0)) < 0 ||
+ (char *) str->ptr(), &end_ptr, 0)) < 0 ||
end_ptr < res->ptr() + res->length())
{
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
@@ -540,9 +546,9 @@ String *Item_func_from_base64::val_str(String *str)
goto err;
}
- tmp_value.length((uint) length);
+ str->length((uint) length);
null_value= 0;
- return &tmp_value;
+ return str;
err:
null_value= 1; // NULL input, too long input, OOM, or badly formed input
return 0;
@@ -797,7 +803,7 @@ String *Item_func_des_encrypt::val_str(String *str)
struct st_des_keyschedule keyschedule;
const char *append_str="********";
uint key_number, res_length, tail;
- String *res= args[0]->val_str(str);
+ String *res= args[0]->val_str(&tmp_value);
if ((null_value= args[0]->null_value))
return 0; // ENCRYPT(NULL) == NULL
@@ -821,7 +827,7 @@ String *Item_func_des_encrypt::val_str(String *str)
}
else
{
- String *keystr=args[1]->val_str(&tmp_value);
+ String *keystr= args[1]->val_str(str);
if (!keystr)
goto error;
key_number=127; // User key string
@@ -853,23 +859,23 @@ String *Item_func_des_encrypt::val_str(String *str)
tmp_arg.length(0);
tmp_arg.append(res->ptr(), res->length());
code= ER_OUT_OF_RESOURCES;
- if (tmp_arg.append(append_str, tail) || tmp_value.alloc(res_length+1))
+ if (tmp_arg.append(append_str, tail) || str->alloc(res_length+1))
goto error;
tmp_arg[res_length-1]=tail; // save extra length
- tmp_value.realloc(res_length+1);
- tmp_value.length(res_length+1);
- tmp_value.set_charset(&my_charset_bin);
- tmp_value[0]=(char) (128 | key_number);
+ str->realloc(res_length+1);
+ str->length(res_length+1);
+ str->set_charset(&my_charset_bin);
+ (*str)[0]=(char) (128 | key_number);
// Real encryption
bzero((char*) &ivec,sizeof(ivec));
DES_ede3_cbc_encrypt((const uchar*) (tmp_arg.ptr()),
- (uchar*) (tmp_value.ptr()+1),
+ (uchar*) (str->ptr()+1),
res_length,
&keyschedule.ks1,
&keyschedule.ks2,
&keyschedule.ks3,
&ivec, TRUE);
- return &tmp_value;
+ return str;
error:
push_warning_printf(current_thd,Sql_condition::WARN_LEVEL_WARN,
@@ -893,7 +899,7 @@ String *Item_func_des_decrypt::val_str(String *str)
DES_cblock ivec;
struct st_des_keyblock keyblock;
struct st_des_keyschedule keyschedule;
- String *res= args[0]->val_str(str);
+ String *res= args[0]->val_str(&tmp_value);
uint length,tail;
if ((null_value= args[0]->null_value))
@@ -917,7 +923,7 @@ String *Item_func_des_decrypt::val_str(String *str)
else
{
// We make good 24-byte (168 bit) key from given plaintext key with MD5
- String *keystr=args[1]->val_str(&tmp_value);
+ String *keystr= args[1]->val_str(str);
if (!keystr)
goto error;
@@ -932,23 +938,23 @@ String *Item_func_des_decrypt::val_str(String *str)
DES_set_key_unchecked(&keyblock.key3,&keyschedule.ks3);
}
code= ER_OUT_OF_RESOURCES;
- if (tmp_value.alloc(length-1))
+ if (str->alloc(length-1))
goto error;
bzero((char*) &ivec,sizeof(ivec));
DES_ede3_cbc_encrypt((const uchar*) res->ptr()+1,
- (uchar*) (tmp_value.ptr()),
+ (uchar*) (str->ptr()),
length-1,
&keyschedule.ks1,
&keyschedule.ks2,
&keyschedule.ks3,
&ivec, FALSE);
/* Restore old length of key */
- if ((tail=(uint) (uchar) tmp_value[length-2]) > 8)
+ if ((tail=(uint) (uchar) (*str)[length-2]) > 8)
goto wrong_key; // Wrong key
- tmp_value.length(length-1-tail);
- tmp_value.set_charset(&my_charset_bin);
- return &tmp_value;
+ str->length(length-1-tail);
+ str->set_charset(&my_charset_bin);
+ return str;
error:
push_warning_printf(current_thd,Sql_condition::WARN_LEVEL_WARN,
@@ -1136,25 +1142,26 @@ void Item_func_concat_ws::fix_length_and_dec()
String *Item_func_reverse::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- String *res = args[0]->val_str(str);
- char *ptr, *end, *tmp;
+ String *res= args[0]->val_str(&tmp_value);
+ const char *ptr, *end;
+ char *tmp;
if ((null_value=args[0]->null_value))
return 0;
/* An empty string is a special case as the string pointer may be null */
if (!res->length())
return make_empty_result();
- if (tmp_value.alloced_length() < res->length() &&
- tmp_value.realloc(res->length()))
+ if (str->alloced_length() < res->length() &&
+ str->realloc(res->length()))
{
null_value= 1;
return 0;
}
- tmp_value.length(res->length());
- tmp_value.set_charset(res->charset());
- ptr= (char *) res->ptr();
- end= ptr + res->length();
- tmp= (char *) tmp_value.ptr() + tmp_value.length();
+ str->length(res->length());
+ str->set_charset(res->charset());
+ ptr= res->ptr();
+ end= res->end();
+ tmp= (char *) str->end();
#ifdef USE_MB
if (use_mb(res->charset()))
{
@@ -1178,7 +1185,7 @@ String *Item_func_reverse::val_str(String *str)
while (ptr < end)
*--tmp= *ptr++;
}
- return &tmp_value;
+ return str;
}
@@ -2425,7 +2432,6 @@ void Item_func_soundex::fix_length_and_dec()
DBUG_ASSERT(collation.collation != NULL);
set_if_bigger(char_length, 4);
fix_char_length(char_length);
- tmp_value.set_charset(collation.collation);
}
@@ -2470,7 +2476,7 @@ static bool my_uni_isalpha(int wc)
String *Item_func_soundex::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- String *res =args[0]->val_str(str);
+ String *res= args[0]->val_str(&tmp_value);
char last_ch,ch;
CHARSET_INFO *cs= collation.collation;
my_wc_t wc;
@@ -2480,10 +2486,11 @@ String *Item_func_soundex::val_str(String *str)
if ((null_value= args[0]->null_value))
return 0; /* purecov: inspected */
- if (tmp_value.alloc(MY_MAX(res->length(), 4 * cs->mbminlen)))
- return str; /* purecov: inspected */
- char *to= (char *) tmp_value.ptr();
- char *to_end= to + tmp_value.alloced_length();
+ if (str->alloc(MY_MAX(res->length(), 4 * cs->mbminlen)))
+ return &tmp_value; /* purecov: inspected */
+ str->set_charset(collation.collation);
+ char *to= (char *) str->ptr();
+ char *to_end= to + str->alloced_length();
char *from= (char *) res->ptr(), *end= from + res->length();
for ( ; ; ) /* Skip pre-space */
@@ -2568,8 +2575,8 @@ String *Item_func_soundex::val_str(String *str)
to+= nbytes;
}
- tmp_value.length((uint) (to-tmp_value.ptr()));
- return &tmp_value;
+ str->length((uint) (to - str->ptr()));
+ return str;
}
@@ -3378,16 +3385,16 @@ String *Item_func_conv_charset::val_str(String *str)
DBUG_ASSERT(fixed == 1);
if (use_cached_value)
return null_value ? 0 : &str_value;
- String *arg= args[0]->val_str(str);
+ String *arg= args[0]->val_str(&tmp_value);
uint dummy_errors;
if (args[0]->null_value)
{
null_value=1;
return 0;
}
- null_value= tmp_value.copy(arg->ptr(), arg->length(), arg->charset(),
- conv_charset, &dummy_errors);
- return null_value ? 0 : check_well_formed_result(&tmp_value);
+ null_value= str->copy(arg->ptr(), arg->length(), arg->charset(),
+ conv_charset, &dummy_errors);
+ return null_value ? 0 : check_well_formed_result(str);
}
void Item_func_conv_charset::fix_length_and_dec()
@@ -3530,7 +3537,7 @@ String *Item_func_weight_string::val_str(String *str)
DBUG_ASSERT(fixed == 1);
if (args[0]->result_type() != STRING_RESULT ||
- !(res= args[0]->val_str(str)))
+ !(res= args[0]->val_str(&tmp_value)))
goto nl;
/*
@@ -3577,19 +3584,19 @@ String *Item_func_weight_string::val_str(String *str)
goto nl;
}
- if (tmp_value.alloc(tmp_length))
+ if (str->alloc(tmp_length))
goto nl;
frm_length= cs->coll->strnxfrm(cs,
- (uchar *) tmp_value.ptr(), tmp_length,
+ (uchar *) str->ptr(), tmp_length,
nweights ? nweights : tmp_length,
(const uchar *) res->ptr(), res->length(),
flags);
DBUG_ASSERT(frm_length <= tmp_length);
- tmp_value.length(frm_length);
+ str->length(frm_length);
null_value= 0;
- return &tmp_value;
+ return str;
nl:
null_value= 1;
@@ -3630,18 +3637,18 @@ String *Item_func_hex::val_str_ascii(String *str)
}
/* Convert given string to a hex string, character by character */
- res= args[0]->val_str(str);
- if (!res || tmp_value.alloc(res->length()*2+1))
+ res= args[0]->val_str(&tmp_value);
+ if (!res || str->alloc(res->length()*2+1))
{
null_value=1;
return 0;
}
null_value=0;
- tmp_value.length(res->length()*2);
- tmp_value.set_charset(&my_charset_latin1);
+ str->length(res->length()*2);
+ str->set_charset(&my_charset_latin1);
- octet2hex((char*) tmp_value.ptr(), res->ptr(), res->length());
- return &tmp_value;
+ octet2hex((char*) str->ptr(), res->ptr(), res->length());
+ return str;
}
/** Convert given hex string to a binary string. */
@@ -3654,8 +3661,8 @@ String *Item_func_unhex::val_str(String *str)
uint length;
DBUG_ASSERT(fixed == 1);
- res= args[0]->val_str(str);
- if (!res || tmp_value.alloc(length= (1+res->length())/2))
+ res= args[0]->val_str(&tmp_value);
+ if (!res || str->alloc(length= (1+res->length())/2))
{
null_value=1;
return 0;
@@ -3663,8 +3670,8 @@ String *Item_func_unhex::val_str(String *str)
from= res->ptr();
null_value= 0;
- tmp_value.length(length);
- to= (char*) tmp_value.ptr();
+ str->length(length);
+ to= (char*) str->ptr();
if (res->length() % 2)
{
int hex_char;
@@ -3682,7 +3689,7 @@ String *Item_func_unhex::val_str(String *str)
if ((null_value= (hex_char == -1)))
return 0;
}
- return &tmp_value;
+ return str;
}
@@ -3928,7 +3935,7 @@ String *Item_func_quote::val_str(String *str)
ulong max_allowed_packet= current_thd->variables.max_allowed_packet;
char *from, *to, *end, *start;
- String *arg= args[0]->val_str(str);
+ String *arg= args[0]->val_str(&tmp_value);
uint arg_length, new_length;
if (!arg) // Null argument
{
@@ -3955,7 +3962,7 @@ String *Item_func_quote::val_str(String *str)
set_if_smaller(new_length, max_allowed_packet);
}
- if (tmp_value.alloc(new_length))
+ if (str->alloc(new_length))
goto null;
if (collation.collation->mbmaxlen > 1)
@@ -3963,7 +3970,7 @@ String *Item_func_quote::val_str(String *str)
CHARSET_INFO *cs= collation.collation;
int mblen;
uchar *to_end;
- to= (char*) tmp_value.ptr();
+ to= (char*) str->ptr();
to_end= (uchar*) to + new_length;
/* Put leading quote */
@@ -4000,14 +4007,14 @@ String *Item_func_quote::val_str(String *str)
if ((mblen= cs->cset->wc_mb(cs, '\'', (uchar *) to, to_end)) <= 0)
goto toolong;
to+= mblen;
- new_length= to - tmp_value.ptr();
+ new_length= to - str->ptr();
goto ret;
}
/*
We replace characters from the end to the beginning
*/
- to= (char*) tmp_value.ptr() + new_length - 1;
+ to= (char*) str->ptr() + new_length - 1;
*to--= '\'';
for (start= (char*) arg->ptr(),end= start + arg_length; end-- != start; to--)
{
@@ -4037,10 +4044,10 @@ String *Item_func_quote::val_str(String *str)
*to= '\'';
ret:
- tmp_value.length(new_length);
- tmp_value.set_charset(collation.collation);
+ str->length(new_length);
+ str->set_charset(collation.collation);
null_value= 0;
- return &tmp_value;
+ return str;
toolong:
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
@@ -4113,7 +4120,7 @@ String *Item_func_compress::val_str(String *str)
char *tmp, *last_char;
DBUG_ASSERT(fixed == 1);
- if (!(res= args[0]->val_str(str)))
+ if (!(res= args[0]->val_str(&tmp_value)))
{
null_value= 1;
return 0;
@@ -4134,13 +4141,13 @@ String *Item_func_compress::val_str(String *str)
// Check new_size overflow: new_size <= res->length()
if (((uint32) (new_size+5) <= res->length()) ||
- buffer.realloc((uint32) new_size + 4 + 1))
+ str->realloc((uint32) new_size + 4 + 1))
{
null_value= 1;
return 0;
}
- body= ((Byte*)buffer.ptr()) + 4;
+ body= ((Byte*)str->ptr()) + 4;
// As far as we have checked res->is_empty() we can use ptr()
if ((err= my_compress_buffer(body, &new_size, (const uchar *)res->ptr(),
@@ -4152,7 +4159,7 @@ String *Item_func_compress::val_str(String *str)
return 0;
}
- tmp= (char*)buffer.ptr(); // int4store is a macro; avoid side effects
+ tmp= (char*) str->ptr(); // int4store is a macro; avoid side effects
int4store(tmp, res->length() & 0x3FFFFFFF);
/* This is to ensure that things works for CHAR fields, which trim ' ': */
@@ -4163,15 +4170,15 @@ String *Item_func_compress::val_str(String *str)
new_size++;
}
- buffer.length((uint32)new_size + 4);
- return &buffer;
+ str->length((uint32)new_size + 4);
+ return str;
}
String *Item_func_uncompress::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- String *res= args[0]->val_str(str);
+ String *res= args[0]->val_str(&tmp_value);
ulong new_size;
int err;
uint code;
@@ -4202,14 +4209,14 @@ String *Item_func_uncompress::val_str(String *str)
max_allowed_packet));
goto err;
}
- if (buffer.realloc((uint32)new_size))
+ if (str->realloc((uint32)new_size))
goto err;
- if ((err= uncompress((Byte*)buffer.ptr(), &new_size,
+ if ((err= uncompress((Byte*)str->ptr(), &new_size,
((const Bytef*)res->ptr())+4,res->length()-4)) == Z_OK)
{
- buffer.length((uint32) new_size);
- return &buffer;
+ str->length((uint32) new_size);
+ return str;
}
code= ((err == Z_BUF_ERROR) ? ER_ZLIB_Z_BUF_ERROR :
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 2886cb6..e4557cb 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -87,7 +87,6 @@ class Item_str_ascii_func :public Item_str_func
class Item_func_md5 :public Item_str_ascii_func
{
- String tmp_value;
public:
Item_func_md5(Item *a) :Item_str_ascii_func(a) {}
String *val_str_ascii(String *);
@@ -167,7 +166,6 @@ class Item_func_concat :public Item_str_func
class Item_func_decode_histogram :public Item_str_func
{
- String tmp_value;
public:
Item_func_decode_histogram(Item *a, Item *b)
:Item_str_func(a, b) {}
@@ -677,7 +675,6 @@ class Item_func_make_set :public Item_str_func
class Item_func_format :public Item_str_ascii_func
{
- String tmp_str;
MY_LOCALE *locale;
public:
Item_func_format(Item *org, Item *dec): Item_str_ascii_func(org, dec) {}
@@ -731,7 +728,6 @@ class Item_func_space :public Item_str_func
class Item_func_binlog_gtid_pos :public Item_str_func
{
- String tmp_value;
public:
Item_func_binlog_gtid_pos(Item *arg1,Item *arg2) :Item_str_func(arg1,arg2) {}
String *val_str(String *);
@@ -1108,7 +1104,7 @@ class Item_func_uncompressed_length : public Item_int_func
class Item_func_compress: public Item_str_func
{
- String buffer;
+ String tmp_value;
public:
Item_func_compress(Item *a):Item_str_func(a){}
void fix_length_and_dec(){max_length= (args[0]->max_length*120)/100+12;}
@@ -1118,7 +1114,7 @@ class Item_func_compress: public Item_str_func
class Item_func_uncompress: public Item_str_func
{
- String buffer;
+ String tmp_value;
public:
Item_func_uncompress(Item *a): Item_str_func(a){}
void fix_length_and_dec(){ maybe_null= 1; max_length= MAX_BLOB_WIDTH; }
Follow ups
References
-
MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
From: Alexander Barkov, 2017-02-28
-
Re: MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
From: Sergei Golubchik, 2017-03-01
-
Re: MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
From: Sergey Petrunia, 2017-03-02
-
Re: MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
From: Alexander Barkov, 2017-03-03
-
Re: MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
From: Sergei Golubchik, 2017-03-03
-
Re: MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
From: Alexander Barkov, 2017-03-06
-
Re: MDEV-10306 Wrong results with combination of CONCAT, SUBSTR and CONVERT in subquery
From: Sergei Golubchik, 2017-03-06