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.
parent bbf84d6b
...@@ -1462,3 +1462,21 @@ set @a:=null; ...@@ -1462,3 +1462,21 @@ set @a:=null;
execute my_stmt using @a; execute my_stmt using @a;
a b a b
drop table if exists t1; 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;
...@@ -1164,3 +1164,23 @@ execute my_stmt using @a; ...@@ -1164,3 +1164,23 @@ execute my_stmt using @a;
set @a:=null; set @a:=null;
execute my_stmt using @a; execute my_stmt using @a;
drop table if exists t1; 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;
...@@ -428,6 +428,21 @@ static void do_varstring2(Copy_field *copy) ...@@ -428,6 +428,21 @@ static void do_varstring2(Copy_field *copy)
length); 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 ** 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*) ...@@ -587,7 +602,8 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
return do_field_string; return do_field_string;
if (to_length != from_length) if (to_length != from_length)
return (((Field_varstring*) to)->length_bytes == 1 ? 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) else if (to_length < from_length)
return (from->charset()->mbmaxlen == 1 ? return (from->charset()->mbmaxlen == 1 ?
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment