Commit 695bcb9e authored by unknown's avatar unknown
Browse files

Bug#19960 Inconsistent results when joining InnoDB tables using partial UTF8 indexes

  Adding a multibyte-aware VARCHAR copying function, to put correct column prefix,
  taking in account number of characters (instead just limiting on number of bytes).
  For example, for a KEY(col(3)) on a UTF8 column when copying the string 'foo bar foo',
  we should put only 3 leftmost characters: 'foo'.
  9 characters were incorrectly put before this fix.


mysql-test/r/ctype_utf8.result:
  Adding test case
mysql-test/t/ctype_utf8.test:
  Adding test case
sql/field_conv.cc:
  Adding multibyte aware copy function for VARCHAR
parent 2bfeecca
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -1462,3 +1462,21 @@ set @a:=null;
execute my_stmt using @a;
a	b
drop table if exists t1;
CREATE TABLE t1 (
colA int(11) NOT NULL,
colB varchar(255) character set utf8 NOT NULL,
PRIMARY KEY  (colA)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO t1 (colA, colB) VALUES (1, 'foo'), (2, 'foo bar');
CREATE TABLE t2 (
colA int(11) NOT NULL,
colB varchar(255) character set utf8 NOT NULL,
KEY bad  (colA,colB(3))
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO t2 (colA, colB) VALUES (1, 'foo'),(2, 'foo bar');
SELECT * FROM t1 JOIN t2 ON t1.colA=t2.colA AND t1.colB=t2.colB
WHERE t1.colA < 3;
colA	colB	colA	colB
1	foo	1	foo
2	foo bar	2	foo bar
DROP TABLE t1, t2;
+20 −0
Original line number Diff line number Diff line
@@ -1164,3 +1164,23 @@ execute my_stmt using @a;
set @a:=null;
execute my_stmt using @a;
drop table if exists t1;

#
# Bug#19960: Inconsistent results when joining
# InnoDB tables using partial UTF8 indexes
#
CREATE TABLE t1 (
  colA int(11) NOT NULL,
  colB varchar(255) character set utf8 NOT NULL,
   PRIMARY KEY  (colA)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO t1 (colA, colB) VALUES (1, 'foo'), (2, 'foo bar');
CREATE TABLE t2 (
  colA int(11) NOT NULL,
  colB varchar(255) character set utf8 NOT NULL,
   KEY bad  (colA,colB(3))
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO t2 (colA, colB) VALUES (1, 'foo'),(2, 'foo bar');
SELECT * FROM t1 JOIN t2 ON t1.colA=t2.colA AND t1.colB=t2.colB
WHERE t1.colA < 3;
DROP TABLE t1, t2;
+17 −1
Original line number Diff line number Diff line
@@ -428,6 +428,21 @@ static void do_varstring2(Copy_field *copy)
         length);
}


static void do_varstring2_mb(Copy_field *copy)
{
  int well_formed_error;
  CHARSET_INFO *cs= copy->from_field->charset();
  uint char_length= (copy->to_length - HA_KEY_BLOB_LENGTH) / cs->mbmaxlen;
  uint from_length= uint2korr(copy->from_ptr);
  const char *from_beg= copy->from_ptr + HA_KEY_BLOB_LENGTH;
  uint length= cs->cset->well_formed_len(cs, from_beg, from_beg + from_length,
                                         char_length, &well_formed_error);
  int2store(copy->to_ptr, length);
  memcpy(copy->to_ptr+HA_KEY_BLOB_LENGTH, from_beg, length);
}
 

/***************************************************************************
** The different functions that fills in a Copy_field class
***************************************************************************/
@@ -587,7 +602,8 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
          return do_field_string;
        if (to_length != from_length)
          return (((Field_varstring*) to)->length_bytes == 1 ?
                  do_varstring1 : do_varstring2);
                  do_varstring1 : (from->charset()->mbmaxlen == 1 ?
                                   do_varstring2 : do_varstring2_mb));
      }
      else if (to_length < from_length)
	return (from->charset()->mbmaxlen == 1 ?