← Back to team overview

maria-developers team mailing list archive

Re: MDEV-13118 Wrong results with LOWER and UPPER and subquery

 

Hello Sergei,

I sent a broken patch last time.

Sending the patch again.

Thanks!


On 06/20/2017 12:45 PM, Alexander Barkov wrote:
> Hello Sergei,
> 
> 
> Please review a patch for MDEV-13118.
> 
> Thanks!
> 
commit dc7352fa2bc21fd9b66b12ec33cdacf88b478157
Author: Alexander Barkov <bar@xxxxxxxxxxx>
Date:   Tue Jun 20 12:44:36 2017 +0400

    MDEV-13118 Wrong results with LOWER and UPPER and subquery
    
    This problem is similar to MDEV-10306.
    
    1. Fixing Item_str_conv::val_str(String *str) to return the result in "str",
       and to use tmp_value only as a temporary buffer for args[0]->val_str().
       The new code version now guarantees that the result is always returned in
       "str". The trick with copy_if_not_alloced() is not used any more.
    
    2. Removing the optimization that *some* character sets used in casedn()
       and caseup(), which allowed (and required) to change the case in-place,
       overwriting the string passed as the "src" argument.
       Now all CHARSET_INFO's work in the same way:
       non of them change the source string in-place, all of them now convert
       case from the source string to the destination string, leaving
       the source string untouched.
    
    3. Adding "const" qualifier to the "char *src" parameter
       to caseup() and casedn().
    
    4. Removing duplicate implementations in ctype-mb.c.
       Now both caseup() and casedn() implementations for all CJK character sets
       use internally the same function my_casefold_mb()
       (the former my_casefold_mb_varlen()).
    
    5. Removing the "unused" attibute from parameters of some my_case{up|dn}_xxx()
       implementations, as the affected parameters are now *used* in the code.
       Previously these parameters were used only in DBUG_ASSERT().

diff --git a/include/m_ctype.h b/include/m_ctype.h
index 8d9838f..eb2d760 100644
--- a/include/m_ctype.h
+++ b/include/m_ctype.h
@@ -365,7 +365,7 @@ typedef int (*my_charset_conv_mb_wc)(CHARSET_INFO *, my_wc_t *,
 typedef int (*my_charset_conv_wc_mb)(CHARSET_INFO *, my_wc_t,
                                      uchar *, uchar *);
 typedef size_t (*my_charset_conv_case)(CHARSET_INFO *,
-                                       char *, size_t, char *, size_t);
+                                       const char *, size_t, char *, size_t);
 
 
 /* See strings/CHARSET_INFO.txt about information on this structure  */
@@ -565,9 +565,11 @@ extern uint my_instr_simple(CHARSET_INFO *,
 /* Functions for 8bit */
 extern size_t my_caseup_str_8bit(CHARSET_INFO *, char *);
 extern size_t my_casedn_str_8bit(CHARSET_INFO *, char *);
-extern size_t my_caseup_8bit(CHARSET_INFO *, char *src, size_t srclen,
+extern size_t my_caseup_8bit(CHARSET_INFO *,
+                             const char *src, size_t srclen,
                              char *dst, size_t dstlen);
-extern size_t my_casedn_8bit(CHARSET_INFO *, char *src, size_t srclen,
+extern size_t my_casedn_8bit(CHARSET_INFO *,
+                             const char *src, size_t srclen,
                              char *dst, size_t dstlen);
 
 extern int my_strcasecmp_8bit(CHARSET_INFO * cs, const char *, const char *);
@@ -658,17 +660,17 @@ uint my_mbcharlen_8bit(CHARSET_INFO *, uint c);
 /* Functions for multibyte charsets */
 extern size_t my_caseup_str_mb(CHARSET_INFO *, char *);
 extern size_t my_casedn_str_mb(CHARSET_INFO *, char *);
-extern size_t my_caseup_mb(CHARSET_INFO *, char *src, size_t srclen,
-                                         char *dst, size_t dstlen);
-extern size_t my_casedn_mb(CHARSET_INFO *, char *src, size_t srclen,
-                                         char *dst, size_t dstlen);
-extern size_t my_caseup_mb_varlen(CHARSET_INFO *, char *src, size_t srclen,
-                                  char *dst, size_t dstlen);
-extern size_t my_casedn_mb_varlen(CHARSET_INFO *, char *src, size_t srclen,
-                                  char *dst, size_t dstlen);
-extern size_t my_caseup_ujis(CHARSET_INFO *, char *src, size_t srclen,
+extern size_t my_caseup_mb(CHARSET_INFO *,
+                           const char *src, size_t srclen,
+                           char *dst, size_t dstlen);
+extern size_t my_casedn_mb(CHARSET_INFO *,
+                           const char *src, size_t srclen,
+                           char *dst, size_t dstlen);
+extern size_t my_caseup_ujis(CHARSET_INFO *,
+                             const char *src, size_t srclen,
                              char *dst, size_t dstlen);
-extern size_t my_casedn_ujis(CHARSET_INFO *, char *src, size_t srclen,
+extern size_t my_casedn_ujis(CHARSET_INFO *,
+                             const char *src, size_t srclen,
                              char *dst, size_t dstlen);
 extern int my_strcasecmp_mb(CHARSET_INFO * cs,const char *, const char *);
 
diff --git a/mysql-test/include/ctype_func_str.inc b/mysql-test/include/ctype_func_str.inc
new file mode 100644
index 0000000..efcb572
--- /dev/null
+++ b/mysql-test/include/ctype_func_str.inc
@@ -0,0 +1,15 @@
+--echo #
+--echo # MDEV-13118 Wrong results with LOWER and UPPER and subquery
+--echo #
+
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch=_latin1'derived_merge=on';
+CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0;
+SHOW CREATE TABLE t1;
+INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI');
+--sorted_result
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub;
+--sorted_result
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub;
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
diff --git a/mysql-test/r/ctype_binary.result b/mysql-test/r/ctype_binary.result
index 48b4818..b28d904 100644
--- a/mysql-test/r/ctype_binary.result
+++ b/mysql-test/r/ctype_binary.result
@@ -3022,6 +3022,29 @@ DROP TABLE t1;
 SELECT _binary 0x7E, _binary X'7E', _binary B'01111110';
 _binary 0x7E	_binary X'7E'	_binary B'01111110'
 ~	~	~
+SET NAMES utf8, character_set_connection=binary;
+#
+# MDEV-13118 Wrong results with LOWER and UPPER and subquery
+#
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch=_latin1'derived_merge=on';
+CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `t` varbinary(10) NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub;
+c2
+ABCDEFGHI-ABCDEFGHI
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub;
+c2
+ABCDEFGHI-ABCDEFGHI
+abcdefghi-abcdefghi
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
 #
 # End of 10.0 tests
 #
diff --git a/mysql-test/r/ctype_eucjpms.result b/mysql-test/r/ctype_eucjpms.result
index a1232c1..1e23126 100644
--- a/mysql-test/r/ctype_eucjpms.result
+++ b/mysql-test/r/ctype_eucjpms.result
@@ -33636,6 +33636,29 @@ HEX(a)	CHAR_LENGTH(a)
 DROP TABLE t1;
 SELECT _eucjpms 0x8EA0;
 ERROR HY000: Invalid eucjpms character string: '8EA0'
+SET NAMES eucjpms;
+#
+# MDEV-13118 Wrong results with LOWER and UPPER and subquery
+#
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch=_latin1'derived_merge=on';
+CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `t` varchar(10) CHARACTER SET eucjpms NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub;
+c2
+ABCDEFGHI-ABCDEFGHI
+ABCDEFGHI-ABCDEFGHI
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
 #
 # End of 10.0 tests
 #
diff --git a/mysql-test/r/ctype_euckr.result b/mysql-test/r/ctype_euckr.result
index dcb68cf..cea93b0 100644
--- a/mysql-test/r/ctype_euckr.result
+++ b/mysql-test/r/ctype_euckr.result
@@ -25274,3 +25274,32 @@ A1A1A1A1A1A120202020202020202020202020202020202020
 #
 # End of 5.6 tests
 #
+#
+# Start of 10.0 tests
+#
+SET NAMES utf8, character_set_connection=euckr;
+#
+# MDEV-13118 Wrong results with LOWER and UPPER and subquery
+#
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch=_latin1'derived_merge=on';
+CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `t` varchar(10) CHARACTER SET euckr NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub;
+c2
+ABCDEFGHI-ABCDEFGHI
+ABCDEFGHI-ABCDEFGHI
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
+#
+# End of 10.0 tests
+#
diff --git a/mysql-test/r/ctype_gbk.result b/mysql-test/r/ctype_gbk.result
index c5d997b..1302fbe 100644
--- a/mysql-test/r/ctype_gbk.result
+++ b/mysql-test/r/ctype_gbk.result
@@ -4943,6 +4943,29 @@ E05C5B
 E05B
 DROP TABLE t1;
 # Start of ctype_E05C.inc
+SET NAMES utf8, character_set_connection=gbk;
+#
+# MDEV-13118 Wrong results with LOWER and UPPER and subquery
+#
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch=_latin1'derived_merge=on';
+CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `t` varchar(10) CHARACTER SET gbk NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub;
+c2
+ABCDEFGHI-ABCDEFGHI
+ABCDEFGHI-ABCDEFGHI
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
 #
 # End of 10.0 tests
 #
diff --git a/mysql-test/r/ctype_latin1.result b/mysql-test/r/ctype_latin1.result
index eee9152..d06f772 100644
--- a/mysql-test/r/ctype_latin1.result
+++ b/mysql-test/r/ctype_latin1.result
@@ -7921,6 +7921,29 @@ DROP TABLE t1;
 SELECT _latin1 0x7E, _latin1 X'7E', _latin1 B'01111110';
 _latin1 0x7E	_latin1 X'7E'	_latin1 B'01111110'
 ~	~	~
+SET NAMES latin1;
+#
+# MDEV-13118 Wrong results with LOWER and UPPER and subquery
+#
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch=_latin1'derived_merge=on';
+CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `t` varchar(10) NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub;
+c2
+ABCDEFGHI-ABCDEFGHI
+ABCDEFGHI-ABCDEFGHI
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
 #
 # End of 10.0 tests
 #
diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result
index 8c69745..fc8bd1d 100644
--- a/mysql-test/r/ctype_ucs.result
+++ b/mysql-test/r/ctype_ucs.result
@@ -5568,6 +5568,29 @@ c2
 YWJjZGVmZ2hp-YWJjZGVmZ2hp
 DROP TABLE t1;
 SET optimizer_switch=@save_optimizer_switch;
+SET NAMES utf8, character_set_connection=ucs2;
+#
+# MDEV-13118 Wrong results with LOWER and UPPER and subquery
+#
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch=_latin1'derived_merge=on';
+CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `t` varchar(10) CHARACTER SET ucs2 NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub;
+c2
+ABCDEFGHI-ABCDEFGHI
+ABCDEFGHI-ABCDEFGHI
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
 #
 # End of 10.0 tests
 #
diff --git a/mysql-test/r/ctype_ujis.result b/mysql-test/r/ctype_ujis.result
index 413ab4e..d4589f6 100644
--- a/mysql-test/r/ctype_ujis.result
+++ b/mysql-test/r/ctype_ujis.result
@@ -25942,6 +25942,29 @@ HEX(a)	CHAR_LENGTH(a)
 DROP TABLE t1;
 SELECT _ujis 0x8EA0;
 ERROR HY000: Invalid ujis character string: '8EA0'
+SET NAMES ujis;
+#
+# MDEV-13118 Wrong results with LOWER and UPPER and subquery
+#
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch=_latin1'derived_merge=on';
+CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `t` varchar(10) CHARACTER SET ujis NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub;
+c2
+ABCDEFGHI-ABCDEFGHI
+ABCDEFGHI-ABCDEFGHI
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
 #
 # End of 10.0 tests
 #
diff --git a/mysql-test/r/ctype_utf16.result b/mysql-test/r/ctype_utf16.result
index 958ade9..e182432 100644
--- a/mysql-test/r/ctype_utf16.result
+++ b/mysql-test/r/ctype_utf16.result
@@ -2134,6 +2134,29 @@ EXECUTE stmt USING @arg00;
 CONCAT(_utf16'a' COLLATE utf16_unicode_ci, ?)
 aÿ
 DEALLOCATE PREPARE stmt;
+SET NAMES utf8, character_set_connection=utf16;
+#
+# MDEV-13118 Wrong results with LOWER and UPPER and subquery
+#
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch=_latin1'derived_merge=on';
+CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `t` varchar(10) CHARACTER SET utf16 NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub;
+c2
+ABCDEFGHI-ABCDEFGHI
+ABCDEFGHI-ABCDEFGHI
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
 #
 # End of 10.0 tests
 #
diff --git a/mysql-test/r/ctype_utf16le.result b/mysql-test/r/ctype_utf16le.result
index 8098b0d..f6a4d35 100644
--- a/mysql-test/r/ctype_utf16le.result
+++ b/mysql-test/r/ctype_utf16le.result
@@ -2319,3 +2319,32 @@ DFFFFFDFFFFF9CFFFF9DFFFF9EFFFF
 #
 # End of 5.6 tests
 #
+#
+# Start of 10.0 tests
+#
+SET NAMES utf8, character_set_connection=utf16le;
+#
+# MDEV-13118 Wrong results with LOWER and UPPER and subquery
+#
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch=_latin1'derived_merge=on';
+CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `t` varchar(10) CHARACTER SET utf16le NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub;
+c2
+ABCDEFGHI-ABCDEFGHI
+ABCDEFGHI-ABCDEFGHI
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
+#
+# Start of 10.0 tests
+#
diff --git a/mysql-test/r/ctype_utf32.result b/mysql-test/r/ctype_utf32.result
index 076cabf..28a9aa4 100644
--- a/mysql-test/r/ctype_utf32.result
+++ b/mysql-test/r/ctype_utf32.result
@@ -2216,6 +2216,29 @@ EXECUTE stmt USING @arg00;
 CONCAT(_utf32'a' COLLATE utf32_unicode_ci, ?)
 aÿ
 DEALLOCATE PREPARE stmt;
+SET NAMEs utf8, character_set_connection=utf32;
+#
+# MDEV-13118 Wrong results with LOWER and UPPER and subquery
+#
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch=_latin1'derived_merge=on';
+CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `t` varchar(10) CHARACTER SET utf32 NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub;
+c2
+ABCDEFGHI-ABCDEFGHI
+ABCDEFGHI-ABCDEFGHI
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
 #
 # End of 10.0 tests
 #
diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result
index b98f412..0de719c 100644
--- a/mysql-test/r/ctype_utf8.result
+++ b/mysql-test/r/ctype_utf8.result
@@ -10090,6 +10090,29 @@ DROP FUNCTION mysql_real_escape_string_generated;
 DROP FUNCTION iswellformed;
 DROP TABLE allbytes;
 # End of ctype_backslash.inc
+SET NAMES utf8;
+#
+# MDEV-13118 Wrong results with LOWER and UPPER and subquery
+#
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch=_latin1'derived_merge=on';
+CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `t` varchar(10) CHARACTER SET utf8 NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub;
+c2
+ABCDEFGHI-ABCDEFGHI
+ABCDEFGHI-ABCDEFGHI
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
 #
 # End of 10.0 tests
 #
diff --git a/mysql-test/r/ctype_utf8mb4.result b/mysql-test/r/ctype_utf8mb4.result
index 50382b5..9aa808d 100644
--- a/mysql-test/r/ctype_utf8mb4.result
+++ b/mysql-test/r/ctype_utf8mb4.result
@@ -3378,6 +3378,29 @@ F09F988E78
 78F09F988E
 78F09F988E78
 DROP TABLE t1;
+SET NAMES utf8mb4;
+#
+# MDEV-13118 Wrong results with LOWER and UPPER and subquery
+#
+SET @save_optimizer_switch=@@optimizer_switch;
+SET optimizer_switch=_latin1'derived_merge=on';
+CREATE TABLE t1 AS SELECT REPEAT('a', 10) AS t LIMIT 0;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `t` varchar(10) CHARACTER SET utf8mb4 NOT NULL DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+INSERT INTO t1 VALUES ('abcdefghi'),('ABCDEFGHI');
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT LOWER(t) t2 FROM t1) sub;
+c2
+abcdefghi-abcdefghi
+abcdefghi-abcdefghi
+SELECT CONCAT(t2,'-',t2) c2 FROM (SELECT UPPER(t) t2 FROM t1) sub;
+c2
+ABCDEFGHI-ABCDEFGHI
+ABCDEFGHI-ABCDEFGHI
+DROP TABLE t1;
+SET optimizer_switch=@save_optimizer_switch;
 #
 # End of tests
 #
diff --git a/mysql-test/t/ctype_binary.test b/mysql-test/t/ctype_binary.test
index 3d3f90b..e31ed0c 100644
--- a/mysql-test/t/ctype_binary.test
+++ b/mysql-test/t/ctype_binary.test
@@ -24,6 +24,9 @@ SET NAMES binary;
 --echo #
 SELECT _binary 0x7E, _binary X'7E', _binary B'01111110';
 
+SET NAMES utf8, character_set_connection=binary;
+--source include/ctype_func_str.inc
+
 --echo #
 --echo # End of 10.0 tests
 --echo #
diff --git a/mysql-test/t/ctype_eucjpms.test b/mysql-test/t/ctype_eucjpms.test
index 49ca818..fc449e7 100644
--- a/mysql-test/t/ctype_eucjpms.test
+++ b/mysql-test/t/ctype_eucjpms.test
@@ -536,6 +536,8 @@ DROP TABLE t1;
 --error ER_INVALID_CHARACTER_STRING
 SELECT _eucjpms 0x8EA0;
 
+SET NAMES eucjpms;
+--source include/ctype_func_str.inc
 
 --echo #
 --echo # End of 10.0 tests
diff --git a/mysql-test/t/ctype_euckr.test b/mysql-test/t/ctype_euckr.test
index 155b8eb..431d9a6 100644
--- a/mysql-test/t/ctype_euckr.test
+++ b/mysql-test/t/ctype_euckr.test
@@ -197,3 +197,14 @@ set collation_connection=euckr_bin;
 --echo # End of 5.6 tests
 --echo #
 
+
+--echo #
+--echo # Start of 10.0 tests
+--echo #
+
+SET NAMES utf8, character_set_connection=euckr;
+--source include/ctype_func_str.inc
+
+--echo #
+--echo # End of 10.0 tests
+--echo #
diff --git a/mysql-test/t/ctype_gbk.test b/mysql-test/t/ctype_gbk.test
index d44009b..277e5ef 100644
--- a/mysql-test/t/ctype_gbk.test
+++ b/mysql-test/t/ctype_gbk.test
@@ -199,6 +199,8 @@ let $ctype_unescape_combinations=selected;
 SET NAMES gbk;
 --source include/ctype_E05C.inc
 
+SET NAMES utf8, character_set_connection=gbk;
+--source include/ctype_func_str.inc
 
 --echo #
 --echo # End of 10.0 tests
diff --git a/mysql-test/t/ctype_latin1.test b/mysql-test/t/ctype_latin1.test
index aeaad2c..2137fd7 100644
--- a/mysql-test/t/ctype_latin1.test
+++ b/mysql-test/t/ctype_latin1.test
@@ -245,6 +245,9 @@ DROP TABLE t1;
 --echo #
 SELECT _latin1 0x7E, _latin1 X'7E', _latin1 B'01111110';
 
+SET NAMES latin1;
+--source include/ctype_func_str.inc
+
 --echo #
 --echo # End of 10.0 tests
 --echo #
diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test
index 0415662..bbb1fd9 100644
--- a/mysql-test/t/ctype_ucs.test
+++ b/mysql-test/t/ctype_ucs.test
@@ -939,6 +939,10 @@ DROP TABLE t1;
 SET optimizer_switch=@save_optimizer_switch;
 
 
+SET NAMES utf8, character_set_connection=ucs2;
+--source include/ctype_func_str.inc
+
+
 --echo #
 --echo # End of 10.0 tests
 --echo #
diff --git a/mysql-test/t/ctype_ujis.test b/mysql-test/t/ctype_ujis.test
index 48dc0e6..4198f98 100644
--- a/mysql-test/t/ctype_ujis.test
+++ b/mysql-test/t/ctype_ujis.test
@@ -1365,6 +1365,8 @@ DROP TABLE t1;
 --error ER_INVALID_CHARACTER_STRING
 SELECT _ujis 0x8EA0;
 
+SET NAMES ujis;
+--source include/ctype_func_str.inc
 
 --echo #
 --echo # End of 10.0 tests
diff --git a/mysql-test/t/ctype_utf16.test b/mysql-test/t/ctype_utf16.test
index cda8523..fc124fa 100644
--- a/mysql-test/t/ctype_utf16.test
+++ b/mysql-test/t/ctype_utf16.test
@@ -866,6 +866,10 @@ SET @arg00=_binary 0x00FF;
 EXECUTE stmt USING @arg00;
 DEALLOCATE PREPARE stmt;
 
+
+SET NAMES utf8, character_set_connection=utf16;
+--source include/ctype_func_str.inc
+
 --echo #
 --echo # End of 10.0 tests
 --echo #
diff --git a/mysql-test/t/ctype_utf16le.test b/mysql-test/t/ctype_utf16le.test
index a832690..8b9b6fe 100644
--- a/mysql-test/t/ctype_utf16le.test
+++ b/mysql-test/t/ctype_utf16le.test
@@ -744,3 +744,15 @@ SET NAMES utf8, collation_connection=utf16le_bin;
 --echo #
 --echo # End of 5.6 tests
 --echo #
+
+--echo #
+--echo # Start of 10.0 tests
+--echo #
+
+
+SET NAMES utf8, character_set_connection=utf16le;
+--source include/ctype_func_str.inc
+
+--echo #
+--echo # Start of 10.0 tests
+--echo #
diff --git a/mysql-test/t/ctype_utf32.test b/mysql-test/t/ctype_utf32.test
index 2f59520..7dd035d 100644
--- a/mysql-test/t/ctype_utf32.test
+++ b/mysql-test/t/ctype_utf32.test
@@ -966,6 +966,13 @@ SET @arg00=_binary 0x00FF;
 EXECUTE stmt USING @arg00;
 DEALLOCATE PREPARE stmt;
 
+
+#
+# MDEV-13118 Wrong results with LOWER and UPPER and subquery
+#
+SET NAMEs utf8, character_set_connection=utf32;
+--source include/ctype_func_str.inc
+
 --echo #
 --echo # End of 10.0 tests
 --echo #
diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test
index e56212c..2bfa25e 100644
--- a/mysql-test/t/ctype_utf8.test
+++ b/mysql-test/t/ctype_utf8.test
@@ -1852,6 +1852,12 @@ SELECT _utf8 0x7E, _utf8 X'7E', _utf8 B'01111110';
 let $ctype_unescape_combinations=selected;
 --source include/ctype_unescape.inc
 
+#
+# MDEV-13118 Wrong results with LOWER and UPPER and subquery
+#
+SET NAMES utf8;
+--source include/ctype_func_str.inc
+
 --echo #
 --echo # End of 10.0 tests
 --echo #
diff --git a/mysql-test/t/ctype_utf8mb4.test b/mysql-test/t/ctype_utf8mb4.test
index cf1c103..781ddf5 100644
--- a/mysql-test/t/ctype_utf8mb4.test
+++ b/mysql-test/t/ctype_utf8mb4.test
@@ -1876,6 +1876,12 @@ LOAD DATA INFILE '../../std_data/loaddata/mdev-11343.txt' INTO TABLE t1 CHARACTE
 SELECT HEX(a) FROM t1;
 DROP TABLE t1;
 
+#
+# MDEV-13118 Wrong results with LOWER and UPPER and subquery
+#
+SET NAMES utf8mb4;
+--source include/ctype_func_str.inc
+
 --echo #
 --echo # End of tests
 --echo #
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index f559677..17f86be 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1606,32 +1606,20 @@ String *Item_str_conv::val_str(String *str)
 {
   DBUG_ASSERT(fixed == 1);
   String *res;
-  if (!(res=args[0]->val_str(str)))
+  if (!(res= args[0]->val_str(&tmp_value)))
   {
     null_value=1; /* purecov: inspected */
     return 0; /* purecov: inspected */
   }
   null_value=0;
-  if (multiply == 1)
-  {
-    uint len;
-    res= copy_if_not_alloced(&tmp_value, res, res->length());
-    len= converter(collation.collation, (char*) res->ptr(), res->length(),
-                                        (char*) res->ptr(), res->length());
-    DBUG_ASSERT(len <= res->length());
-    res->length(len);
-  }
-  else
-  {
-    uint len= res->length() * multiply;
-    tmp_value.alloc(len);
-    tmp_value.set_charset(collation.collation);
-    len= converter(collation.collation, (char*) res->ptr(), res->length(),
-                                        (char*) tmp_value.ptr(), len);
-    tmp_value.length(len);
-    res= &tmp_value;
-  }
-  return res;
+
+  uint len= res->length() * multiply;
+  str->alloc(len);
+  str->set_charset(collation.collation);
+  len= converter(collation.collation, (char*) res->ptr(), res->length(),
+                                      (char*) str->ptr(), len);
+  str->length(len);
+  return str;
 }
 
 
diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c
index 2e699db..53a0e85 100644
--- a/strings/ctype-bin.c
+++ b/strings/ctype-bin.c
@@ -220,11 +220,11 @@ static size_t my_case_str_bin(CHARSET_INFO *cs __attribute__((unused)),
 
 
 static size_t my_case_bin(CHARSET_INFO *cs __attribute__((unused)),
-                          char *src __attribute__((unused)),
-                          size_t srclen,
-                          char *dst __attribute__((unused)),
-                          size_t dstlen __attribute__((unused)))
+                          const char *src, size_t srclen,
+                          char *dst, size_t dstlen)
 {
+  DBUG_ASSERT(srclen <= dstlen);
+  memcpy(dst, src, srclen);
   return srclen;
 }
 
diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c
index b706536..f35c3f0 100644
--- a/strings/ctype-euc_kr.c
+++ b/strings/ctype-euc_kr.c
@@ -9994,8 +9994,8 @@ static MY_CHARSET_HANDLER my_charset_handler=
   my_mb_ctype_mb,
   my_caseup_str_mb,
   my_casedn_str_mb,
-  my_caseup_mb_varlen, /* UPPER() can reduce length: Turkish DOTLESS i -> I */
-  my_casedn_mb,        /* LOWER() does not change length, use simple version*/
+  my_caseup_mb,        /* UPPER() can reduce length: Turkish DOTLESS i -> I */
+  my_casedn_mb,        /* LOWER() does not change length */
   my_snprintf_8bit,
   my_long10_to_str_8bit,
   my_longlong10_to_str_8bit,
diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c
index 02a9a91..318e581 100644
--- a/strings/ctype-mb.c
+++ b/strings/ctype-mb.c
@@ -71,81 +71,8 @@ get_case_info_for_ch(const CHARSET_INFO *cs, uint page, uint offs)
 
 
 /*
-  For character sets which don't change octet length in case conversion.
-*/
-size_t my_caseup_mb(CHARSET_INFO * cs, char *src, size_t srclen,
-                    char *dst __attribute__((unused)),
-                    size_t dstlen __attribute__((unused)))
-{
-  register uint32 l;
-  register char *srcend= src + srclen;
-  register const uchar *map= cs->to_upper;
-
-  DBUG_ASSERT(cs->caseup_multiply == 1);
-  DBUG_ASSERT(src == dst && srclen == dstlen);
-  DBUG_ASSERT(cs->mbmaxlen == 2);
-  
-  while (src < srcend)
-  {
-    if ((l=my_ismbchar(cs, src, srcend)))
-    {
-      MY_UNICASE_CHARACTER *ch;
-      if ((ch= get_case_info_for_ch(cs, (uchar) src[0], (uchar) src[1])))
-      {
-        *src++= ch->toupper >> 8;
-        *src++= ch->toupper & 0xFF;
-      }
-      else
-        src+= l;
-    }
-    else 
-    {
-      *src=(char) map[(uchar) *src];
-      src++;
-    }
-  }
-  return srclen;
-}
-
-
-size_t my_casedn_mb(CHARSET_INFO * cs, char *src, size_t srclen,
-                    char *dst __attribute__((unused)),
-                    size_t dstlen __attribute__((unused)))
-{
-  register uint32 l;
-  register char *srcend= src + srclen;
-  register const uchar *map=cs->to_lower;
-
-  DBUG_ASSERT(cs->casedn_multiply == 1);
-  DBUG_ASSERT(src == dst && srclen == dstlen);  
-  DBUG_ASSERT(cs->mbmaxlen == 2);
-  
-  while (src < srcend)
-  {
-    if ((l= my_ismbchar(cs, src, srcend)))
-    {
-      MY_UNICASE_CHARACTER *ch;
-      if ((ch= get_case_info_for_ch(cs, (uchar) src[0], (uchar) src[1])))
-      {
-        *src++= ch->tolower >> 8;
-        *src++= ch->tolower & 0xFF;
-      }
-      else
-        src+= l;
-    }
-    else
-    {
-      *src= (char) map[(uchar)*src];
-      src++;
-    }
-  }
-  return srclen;
-}
-
-
-/*
-  Case folding functions for character set
-  where case conversion can change string octet length.
+  Case folding functions for CJK character set.
+  Case conversion can optionally reduce string octet length.
   For example, in EUCKR,
     _euckr 0xA9A5 == "LATIN LETTER DOTLESS I" (Turkish letter)
   is upper-cased to to
@@ -153,13 +80,14 @@ size_t my_casedn_mb(CHARSET_INFO * cs, char *src, size_t srclen,
   Length is reduced in this example from two bytes to one byte.
 */
 static size_t
-my_casefold_mb_varlen(CHARSET_INFO *cs,
-                      char *src, size_t srclen,
-                      char *dst, size_t dstlen __attribute__((unused)),
-                      const uchar *map,
-                      size_t is_upper)
+my_casefold_mb(CHARSET_INFO *cs,
+               const char *src, size_t srclen,
+               char *dst, size_t dstlen __attribute__((unused)),
+               const uchar *map,
+               size_t is_upper)
 {
-  char *srcend= src + srclen, *dst0= dst;
+  const char *srcend= src + srclen;
+  char *dst0= dst;
 
   DBUG_ASSERT(cs->mbmaxlen == 2);
 
@@ -193,22 +121,22 @@ my_casefold_mb_varlen(CHARSET_INFO *cs,
 
 
 size_t
-my_casedn_mb_varlen(CHARSET_INFO * cs, char *src, size_t srclen,
+my_casedn_mb(CHARSET_INFO * cs, const char *src, size_t srclen,
                     char *dst, size_t dstlen)
 {
   DBUG_ASSERT(dstlen >= srclen * cs->casedn_multiply); 
   DBUG_ASSERT(src != dst || cs->casedn_multiply == 1);
-  return my_casefold_mb_varlen(cs, src, srclen, dst, dstlen, cs->to_lower, 0);
+  return my_casefold_mb(cs, src, srclen, dst, dstlen, cs->to_lower, 0);
 }
 
 
 size_t
-my_caseup_mb_varlen(CHARSET_INFO * cs, char *src, size_t srclen,
-                    char *dst, size_t dstlen)
+my_caseup_mb(CHARSET_INFO * cs, const char *src, size_t srclen,
+             char *dst, size_t dstlen)
 {
   DBUG_ASSERT(dstlen >= srclen * cs->caseup_multiply);
   DBUG_ASSERT(src != dst || cs->caseup_multiply == 1);
-  return my_casefold_mb_varlen(cs, src, srclen, dst, dstlen, cs->to_upper, 1);
+  return my_casefold_mb(cs, src, srclen, dst, dstlen, cs->to_upper, 1);
 }
 
 
diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c
index 7f13cef..61b14b84 100644
--- a/strings/ctype-simple.c
+++ b/strings/ctype-simple.c
@@ -214,28 +214,26 @@ size_t my_casedn_str_8bit(CHARSET_INFO * cs,char *str)
 }
 
 
-size_t my_caseup_8bit(CHARSET_INFO * cs, char *src, size_t srclen,
-                      char *dst __attribute__((unused)),
-                      size_t dstlen __attribute__((unused)))
+size_t my_caseup_8bit(CHARSET_INFO * cs, const char *src, size_t srclen,
+                      char *dst, size_t dstlen)
 {
-  char *end= src + srclen;
+  const char *end= src + srclen;
   register const uchar *map= cs->to_upper;
-  DBUG_ASSERT(src == dst && srclen == dstlen);
+  DBUG_ASSERT(srclen <= dstlen);
   for ( ; src != end ; src++)
-    *src= (char) map[(uchar) *src];
+    *dst++= (char) map[(uchar) *src];
   return srclen;
 }
 
 
-size_t my_casedn_8bit(CHARSET_INFO * cs, char *src, size_t srclen,
-                      char *dst __attribute__((unused)),
-                      size_t dstlen __attribute__((unused)))
+size_t my_casedn_8bit(CHARSET_INFO * cs, const char *src, size_t srclen,
+                      char *dst, size_t dstlen)
 {
-  char *end= src + srclen;
+  const char *end= src + srclen;
   register const uchar *map=cs->to_lower;
-  DBUG_ASSERT(src == dst && srclen == dstlen);
+  DBUG_ASSERT(srclen <= dstlen);
   for ( ; src != end ; src++)
-    *src= (char) map[(uchar) *src];
+    *dst++= (char) map[(uchar) *src];
   return srclen;
 }
 
diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c
index 318c248..724e698 100644
--- a/strings/ctype-ucs2.c
+++ b/strings/ctype-ucs2.c
@@ -1196,25 +1196,26 @@ my_tosort_utf16(MY_UNICASE_INFO *uni_plane, my_wc_t *wc)
 
 
 static size_t
-my_caseup_utf16(CHARSET_INFO *cs, char *src, size_t srclen,
-                char *dst __attribute__((unused)),
-                size_t dstlen __attribute__((unused)))
+my_caseup_utf16(CHARSET_INFO *cs, const char *src, size_t srclen,
+                char *dst, size_t dstlen)
 {
   my_wc_t wc;
   my_charset_conv_mb_wc mb_wc= cs->cset->mb_wc;
   my_charset_conv_wc_mb wc_mb= cs->cset->wc_mb;
   int res;
-  char *srcend= src + srclen;
+  const char *srcend= src + srclen;
+  char *dstend= dst + dstlen;
   MY_UNICASE_INFO *uni_plane= cs->caseinfo;
-  DBUG_ASSERT(src == dst && srclen == dstlen);
+  DBUG_ASSERT(srclen <= dstlen);
   
   while ((src < srcend) &&
          (res= mb_wc(cs, &wc, (uchar *) src, (uchar *) srcend)) > 0)
   {
     my_toupper_utf16(uni_plane, &wc);
-    if (res != wc_mb(cs, wc, (uchar *) src, (uchar *) srcend))
+    if (res != wc_mb(cs, wc, (uchar *) dst, (uchar *) dstend))
       break;
     src+= res;
+    dst+= res;
   }
   return srclen;
 }
@@ -1243,25 +1244,26 @@ my_hash_sort_utf16(CHARSET_INFO *cs, const uchar *s, size_t slen,
 
 
 static size_t
-my_casedn_utf16(CHARSET_INFO *cs, char *src, size_t srclen,
-                char *dst __attribute__((unused)),
-                size_t dstlen __attribute__((unused)))
+my_casedn_utf16(CHARSET_INFO *cs, const char *src, size_t srclen,
+                char *dst, size_t dstlen)
 {
   my_wc_t wc;
   my_charset_conv_mb_wc mb_wc= cs->cset->mb_wc;
   my_charset_conv_wc_mb wc_mb= cs->cset->wc_mb;
   int res;
-  char *srcend= src + srclen;
+  const char *srcend= src + srclen;
+  char *dstend= dst + dstlen;
   MY_UNICASE_INFO *uni_plane= cs->caseinfo;
-  DBUG_ASSERT(src == dst && srclen == dstlen);
+  DBUG_ASSERT(srclen <= dstlen);
 
   while ((src < srcend) &&
          (res= mb_wc(cs, &wc, (uchar *) src, (uchar *) srcend)) > 0)
   {
     my_tolower_utf16(uni_plane, &wc);
-    if (res != wc_mb(cs, wc, (uchar *) src, (uchar *) srcend))
+    if (res != wc_mb(cs, wc, (uchar *) dst, (uchar *) dstend))
       break;
     src+= res;
+    dst+= res;
   }
   return srclen;
 }
@@ -1987,23 +1989,24 @@ my_tosort_utf32(MY_UNICASE_INFO *uni_plane, my_wc_t *wc)
 
 
 static size_t
-my_caseup_utf32(CHARSET_INFO *cs, char *src, size_t srclen,
-                char *dst __attribute__((unused)),
-                size_t dstlen __attribute__((unused)))
+my_caseup_utf32(CHARSET_INFO *cs, const char *src, size_t srclen,
+                char *dst, size_t dstlen)
 {
   my_wc_t wc;
   int res;
-  char *srcend= src + srclen;
+  const char *srcend= src + srclen;
+  char *dstend= dst + dstlen;
   MY_UNICASE_INFO *uni_plane= cs->caseinfo;
-  DBUG_ASSERT(src == dst && srclen == dstlen);
+  DBUG_ASSERT(srclen <= dstlen);
   
   while ((src < srcend) &&
          (res= my_utf32_uni(cs, &wc, (uchar *)src, (uchar*) srcend)) > 0)
   {
     my_toupper_utf32(uni_plane, &wc);
-    if (res != my_uni_utf32(cs, wc, (uchar*) src, (uchar*) srcend))
+    if (res != my_uni_utf32(cs, wc, (uchar*) dst, (uchar*) dstend))
       break;
     src+= res;
+    dst+= res;
   }
   return srclen;
 }
@@ -2038,22 +2041,23 @@ my_hash_sort_utf32(CHARSET_INFO *cs, const uchar *s, size_t slen,
 
 
 static size_t
-my_casedn_utf32(CHARSET_INFO *cs, char *src, size_t srclen,
-                char *dst __attribute__((unused)),
-                size_t dstlen __attribute__((unused)))
+my_casedn_utf32(CHARSET_INFO *cs, const char *src, size_t srclen,
+                char *dst, size_t dstlen)
 {
   my_wc_t wc;
   int res;
-  char *srcend= src + srclen;
+  const char *srcend= src + srclen;
+  char *dstend= dst + dstlen;
   MY_UNICASE_INFO *uni_plane= cs->caseinfo;
-  DBUG_ASSERT(src == dst && srclen == dstlen);
+  DBUG_ASSERT(srclen <= dstlen);
 
   while ((res= my_utf32_uni(cs, &wc, (uchar*) src, (uchar*) srcend)) > 0)
   {
     my_tolower_utf32(uni_plane,&wc);
-    if (res != my_uni_utf32(cs, wc, (uchar*) src, (uchar*) srcend))
+    if (res != my_uni_utf32(cs, wc, (uchar*) dst, (uchar*) dstend))
       break;
     src+= res;
+    dst+= res;
   }
   return srclen;
 }
@@ -2950,23 +2954,24 @@ my_tosort_ucs2(MY_UNICASE_INFO *uni_plane, my_wc_t *wc)
     *wc= page[*wc & 0xFF].sort;
 }
 
-static size_t my_caseup_ucs2(CHARSET_INFO *cs, char *src, size_t srclen,
-                           char *dst __attribute__((unused)),
-                           size_t dstlen __attribute__((unused)))
+static size_t my_caseup_ucs2(CHARSET_INFO *cs, const char *src, size_t srclen,
+                           char *dst, size_t dstlen)
 {
   my_wc_t wc;
   int res;
-  char *srcend= src + srclen;
+  const char *srcend= src + srclen;
+  char *dstend= dst + dstlen;
   MY_UNICASE_INFO *uni_plane= cs->caseinfo;
-  DBUG_ASSERT(src == dst && srclen == dstlen);
+  DBUG_ASSERT(srclen <= dstlen);
   
   while ((src < srcend) &&
          (res= my_ucs2_uni(cs, &wc, (uchar *)src, (uchar*) srcend)) > 0)
   {
     my_toupper_ucs2(uni_plane, &wc);
-    if (res != my_uni_ucs2(cs, wc, (uchar*) src, (uchar*) srcend))
+    if (res != my_uni_ucs2(cs, wc, (uchar*) dst, (uchar*) dstend))
       break;
     src+= res;
+    dst+= res;
   }
   return srclen;
 }
@@ -2995,23 +3000,24 @@ static void my_hash_sort_ucs2(CHARSET_INFO *cs, const uchar *s, size_t slen,
 }
 
 
-static size_t my_casedn_ucs2(CHARSET_INFO *cs, char *src, size_t srclen,
-                           char *dst __attribute__((unused)),
-                           size_t dstlen __attribute__((unused)))
+static size_t my_casedn_ucs2(CHARSET_INFO *cs, const char *src, size_t srclen,
+                           char *dst, size_t dstlen)
 {
   my_wc_t wc;
   int res;
-  char *srcend= src + srclen;
+  const char *srcend= src + srclen;
+  char *dstend= dst + dstlen;
   MY_UNICASE_INFO *uni_plane= cs->caseinfo;
-  DBUG_ASSERT(src == dst && srclen == dstlen);
+  DBUG_ASSERT(srclen <= dstlen);
 
   while ((src < srcend) &&
          (res= my_ucs2_uni(cs, &wc, (uchar*) src, (uchar*) srcend)) > 0)
   {
     my_tolower_ucs2(uni_plane, &wc);
-    if (res != my_uni_ucs2(cs, wc, (uchar*) src, (uchar*) srcend))
+    if (res != my_uni_ucs2(cs, wc, (uchar*) dst, (uchar*) dstend))
       break;
     src+= res;
+    dst+= res;
   }
   return srclen;
 }
diff --git a/strings/ctype-ujis.c b/strings/ctype-ujis.c
index e7dbefe..25f8881 100644
--- a/strings/ctype-ujis.c
+++ b/strings/ctype-ujis.c
@@ -67179,12 +67179,12 @@ get_case_info_for_ch(CHARSET_INFO *cs, uint plane, uint page, uint offs)
 */
 static size_t
 my_casefold_ujis(CHARSET_INFO *cs,
-                 char *src, size_t srclen,
+                 const char *src, size_t srclen,
                  char *dst, size_t dstlen __attribute__((unused)),
                  const uchar * const map,
                  size_t is_upper)
 {
-  char *srcend= src + srclen, *dst0= dst;
+  const char *srcend= src + srclen, *dst0= dst;
 
   while (src < srcend)
   {
@@ -67226,7 +67226,7 @@ my_casefold_ujis(CHARSET_INFO *cs,
   LOWER()
 */
 size_t
-my_casedn_ujis(CHARSET_INFO * cs, char *src, size_t srclen,
+my_casedn_ujis(CHARSET_INFO * cs, const char *src, size_t srclen,
                char *dst, size_t dstlen)
 {
   DBUG_ASSERT(dstlen >= srclen * cs->casedn_multiply); 
@@ -67239,7 +67239,7 @@ my_casedn_ujis(CHARSET_INFO * cs, char *src, size_t srclen,
   UPPER()
 */
 size_t
-my_caseup_ujis(CHARSET_INFO * cs, char *src, size_t srclen,
+my_caseup_ujis(CHARSET_INFO * cs, const char *src, size_t srclen,
                char *dst, size_t dstlen)
 {
   DBUG_ASSERT(dstlen >= srclen * cs->caseup_multiply);
diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c
index f32150e..942458b 100644
--- a/strings/ctype-utf8.c
+++ b/strings/ctype-utf8.c
@@ -5066,12 +5066,13 @@ my_tosort_utf8mb3(MY_UNICASE_INFO *uni_plane, my_wc_t *wc)
     *wc= page[*wc & 0xFF].sort;
 }
 
-static size_t my_caseup_utf8(CHARSET_INFO *cs, char *src, size_t srclen,
+static size_t my_caseup_utf8(CHARSET_INFO *cs, const char *src, size_t srclen,
                              char *dst, size_t dstlen)
 {
   my_wc_t wc;
   int srcres, dstres;
-  char *srcend= src + srclen, *dstend= dst + dstlen, *dst0= dst;
+  const char *srcend= src + srclen;
+  char *dstend= dst + dstlen, *dst0= dst;
   MY_UNICASE_INFO *uni_plane= cs->caseinfo;
   DBUG_ASSERT(src != dst || cs->caseup_multiply == 1);
 
@@ -5137,12 +5138,13 @@ static size_t my_caseup_str_utf8(CHARSET_INFO *cs, char *src)
 }
 
 
-static size_t my_casedn_utf8(CHARSET_INFO *cs, char *src, size_t srclen,
+static size_t my_casedn_utf8(CHARSET_INFO *cs, const char *src, size_t srclen,
                              char *dst, size_t dstlen)
 {
   my_wc_t wc;
   int srcres, dstres;
-  char *srcend= src + srclen, *dstend= dst + dstlen, *dst0= dst;
+  const char *srcend= src + srclen;
+  char *dstend= dst + dstlen, *dst0= dst;
   MY_UNICASE_INFO *uni_plane= cs->caseinfo;
   DBUG_ASSERT(src != dst || cs->casedn_multiply == 1);
 
@@ -7582,12 +7584,13 @@ my_toupper_utf8mb4(MY_UNICASE_INFO *uni_plane, my_wc_t *wc)
 
 
 static size_t
-my_caseup_utf8mb4(CHARSET_INFO *cs, char *src, size_t srclen,
+my_caseup_utf8mb4(CHARSET_INFO *cs, const char *src, size_t srclen,
                   char *dst, size_t dstlen)
 {
   my_wc_t wc;
   int srcres, dstres;
-  char *srcend= src + srclen, *dstend= dst + dstlen, *dst0= dst;
+  const char *srcend= src + srclen;
+  char *dstend= dst + dstlen, *dst0= dst;
   MY_UNICASE_INFO *uni_plane= cs->caseinfo;
   DBUG_ASSERT(src != dst || cs->caseup_multiply == 1);
 
@@ -7669,12 +7672,13 @@ my_caseup_str_utf8mb4(CHARSET_INFO *cs, char *src)
 
 static size_t
 my_casedn_utf8mb4(CHARSET_INFO *cs,
-                  char *src, size_t srclen,
+                  const char *src, size_t srclen,
                   char *dst, size_t dstlen)
 {
   my_wc_t wc;
   int srcres, dstres;
-  char *srcend= src + srclen, *dstend= dst + dstlen, *dst0= dst;
+  const char *srcend= src + srclen;
+  char *dstend= dst + dstlen, *dst0= dst;
   MY_UNICASE_INFO *uni_plane= cs->caseinfo;
   DBUG_ASSERT(src != dst || cs->casedn_multiply == 1);
 

Follow ups

References