From 3b1fefbf14c40feea638b210a40ad88b078fd628 Mon Sep 17 00:00:00 2001
From: unknown <bar@mysql.com/bar.myoffice.izhnet.ru>
Date: Wed, 4 Jul 2007 16:17:40 +0500
Subject: [PATCH] Bug#29333 myisam corruption with character set cp932 collate
 cp932_japanese_ci   Problem: wrong comparison with trailing space.   This
 problem was fixed for all other character sets under terms of   bug 7788
 ""Table is full" occurs during a multitable update".   ctype-cp932.c was
 forgotten.   Fix: applying the same fix for ctype-cp932.c.   (see
 ctype-sjis.c as an example of a previously correctly fixed file)

mysql-test/r/ctype_cp932.result:
  Adding test
mysql-test/t/ctype_cp932.test:
  Adding test
strings/ctype-cp932.c:
  Applying the same fix which was done for all other
      character sets under terms of bug 7788.
strings/ctype-utf8.c:
  Fixing the same problem for utf8_general_cs,
  which was forgotten in bug 7788 as well.
---
 mysql-test/r/ctype_cp932.result | 16 ++++++++++++++++
 mysql-test/t/ctype_cp932.test   | 22 ++++++++++++++++++++++
 strings/ctype-cp932.c           | 14 +++++++++++---
 strings/ctype-utf8.c            | 29 ++++++++++++++++++-----------
 4 files changed, 67 insertions(+), 14 deletions(-)

diff --git a/mysql-test/r/ctype_cp932.result b/mysql-test/r/ctype_cp932.result
index 6caf22645a..e3598f0077 100755
--- a/mysql-test/r/ctype_cp932.result
+++ b/mysql-test/r/ctype_cp932.result
@@ -11335,6 +11335,22 @@ cp932_bin	6109
 cp932_bin	61
 cp932_bin	6120
 drop table t1;
+create table t2 (a char(1));
+insert into t2 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7');
+insert into t2 values ('8'),('9'),('A'),('B'),('C'),('D'),('E'),('F');
+create table t1 (
+a varchar(2) character set cp932
+) engine=myisam;
+insert into t1
+select unhex(concat(t24.a, t23.a, t22.a, t21.a))
+from t2 t21, t2 t22, t2 t23, t2 t24;
+delete from t1 where a='';
+alter table t1 add key(a);
+check table t1;
+Table	Op	Msg_type	Msg_text
+test.t1	check	status	OK
+drop table t1;
+drop table t2;
 create table t1 (col1 varchar(1)) character set cp932;
 insert into t1 values ('a');
 insert into t1 values ('ab');
diff --git a/mysql-test/t/ctype_cp932.test b/mysql-test/t/ctype_cp932.test
index 48376b8e78..633f3af0d2 100644
--- a/mysql-test/t/ctype_cp932.test
+++ b/mysql-test/t/ctype_cp932.test
@@ -403,6 +403,28 @@ SET collation_connection='cp932_japanese_ci';
 SET collation_connection='cp932_bin';
 -- source include/ctype_filesort.inc
 
+#
+# Bug#29333 myisam corruption with
+# character set cp932 collate cp932_japanese_ci
+#
+create table t2 (a char(1));
+insert into t2 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7');
+insert into t2 values ('8'),('9'),('A'),('B'),('C'),('D'),('E'),('F');
+create table t1 (
+  a varchar(2) character set cp932
+) engine=myisam;
+--disable_warnings
+insert into t1
+select unhex(concat(t24.a, t23.a, t22.a, t21.a))
+from t2 t21, t2 t22, t2 t23, t2 t24;
+--enable_warnings
+delete from t1 where a='';
+alter table t1 add key(a);
+check table t1;
+drop table t1;
+drop table t2;
+
+
 #
 # Bug#12547: Inserting long string into varchar causes table crash in cp932
 #
diff --git a/strings/ctype-cp932.c b/strings/ctype-cp932.c
index 0ece0ef127..4232564803 100644
--- a/strings/ctype-cp932.c
+++ b/strings/ctype-cp932.c
@@ -250,9 +250,16 @@ static int my_strnncollsp_cp932(CHARSET_INFO *cs __attribute__((unused)),
   const uchar *a_end= a + a_length;
   const uchar *b_end= b + b_length;
   int res= my_strnncoll_cp932_internal(cs, &a, a_length, &b, b_length);
+
+#ifndef VARCHAR_WITH_DIFF_ENDSPACE_ARE_DIFFERENT_FOR_UNIQUE
+  diff_if_only_endspace_difference= 0;
+#endif
+
   if (!res && (a != a_end || b != b_end))
   {
-    int swap= 0;
+    int swap= 1;
+    if (diff_if_only_endspace_difference)
+      res= 1;                                   /* Assume 'a' is bigger */
     /*
       Check the next not space character of the longer key. If it's < ' ',
       then it's smaller than the other key.
@@ -263,11 +270,12 @@ static int my_strnncollsp_cp932(CHARSET_INFO *cs __attribute__((unused)),
       a_end= b_end;
       a= b;
       swap= -1;				/* swap sign of result */
+      res= -res;
     }
     for (; a < a_end ; a++)
     {
-      if (*a != ' ')
-	return ((int) *a - (int) ' ') ^ swap;
+      if (*a != (uchar) ' ')
+	return (*a < (uchar) ' ') ? -swap : swap;
     }
   }
   return res;
diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c
index 387ce16a43..4682868562 100644
--- a/strings/ctype-utf8.c
+++ b/strings/ctype-utf8.c
@@ -2802,16 +2802,19 @@ static int my_strnncoll_utf8_cs(CHARSET_INFO *cs,
 static int my_strnncollsp_utf8_cs(CHARSET_INFO *cs, 
                                   const uchar *s, uint slen,
                                   const uchar *t, uint tlen,
-                                  my_bool diff_if_only_endspace_difference
-                                  __attribute__((unused)))
+                                  my_bool diff_if_only_endspace_difference)
 {
-  int s_res,t_res;
-  my_wc_t s_wc,t_wc;
-  const uchar *se= s+slen;
-  const uchar *te= t+tlen;
-  int save_diff = 0;
+  int s_res, t_res, res;
+  my_wc_t s_wc, t_wc;
+  const uchar *se= s + slen;
+  const uchar *te= t + tlen;
+  int save_diff= 0;
   MY_UNICASE_INFO **uni_plane= cs->caseinfo;
-  
+
+#ifndef VARCHAR_WITH_DIFF_ENDSPACE_ARE_DIFFERENT_FOR_UNIQUE
+  diff_if_only_endspace_difference= 0;
+#endif
+    
   while ( s < se && t < te )
   {
     int plane;
@@ -2843,16 +2846,20 @@ static int my_strnncollsp_utf8_cs(CHARSET_INFO *cs,
   
   slen= se-s;
   tlen= te-t;
+  res= 0;
   
   if (slen != tlen)
   {
-    int swap= 0;
+    int swap= 1;
+    if (diff_if_only_endspace_difference)
+      res= 1;                                   /* Assume 'a' is bigger */
     if (slen < tlen)
     {
       slen= tlen;
       s= t;
       se= te;
       swap= -1;
+      res= -res;
     }
     /*
       This following loop uses the fact that in UTF-8
@@ -2866,8 +2873,8 @@ static int my_strnncollsp_utf8_cs(CHARSET_INFO *cs,
     */
     for ( ; s < se; s++)
     {
-      if (*s != ' ')
-        return ((int)*s -  (int) ' ') ^ swap;
+      if (*s != (uchar) ' ')
+        return (*s < (uchar) ' ') ? -swap : swap;
     }
   }
   return save_diff;
-- 
2.30.9