From: Date: April 26 2007 11:24pm Subject: bk commit into 4.1 tree (gshchepa:1.2637) BUG#13191 List-Archive: http://lists.mysql.com/commits/25564 X-Bug: 13191 Message-Id: <20070426212528.553FD1C52D@localhost.localdomain> Below is the list of changes that have just been committed into a local 4.1 repository of uchum. When uchum does a push these changes will be propagated to the main repository and, within 24 hours after the push, to the public repository. For information on how to access the public repository see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html ChangeSet@stripped, 2007-04-27 02:24:11+05:00, gshchepa@stripped +5 -0 Fixed bug #13191. INSERT...ON DUPLICATE KEY UPDATE may cause error 1032: "Can't find record in ..." if we are inserting into InnoDB table where unique index of limited key length has underlying UTF-8 string field of larger length. This occurs because INSERT...ON DUPLICATE uses trivial copying algorithm of key parts data for index search ignoring difference between the number of key bytes and the number of key characters. mysql-test/r/insert_update.result@stripped, 2007-04-27 01:55:01+05:00, gshchepa@stripped +33 -0 Added test case for bug #13191. mysql-test/t/insert_update.test@stripped, 2007-04-27 01:54:43+05:00, gshchepa@stripped +42 -2 Added test case for bug #13191. sql/field.cc@stripped, 2007-04-27 02:12:17+05:00, gshchepa@stripped +9 -0 Fixed bug #13191. INSERT...ON DUPLICATE KEY UPDATE may cause error 1032: "Can't find record in ...". This occurs because INSERT...ON DUPLICATE uses trivial copying algorithm of key parts data for index search. Field_string::get_key_image() virtual function overloaded to implement multibyte-data-aware copying. sql/field.h@stripped, 2007-04-27 02:12:02+05:00, gshchepa@stripped +2 -0 Fixed bug #13191. INSERT...ON DUPLICATE KEY UPDATE may cause error 1032: "Can't find record in ...". This occurs because INSERT...ON DUPLICATE uses trivial copying algorithm of key parts data for index search. Field_string::get_key_image() virtual function overloaded to implement multibyte-data-aware copying. sql/key.cc@stripped, 2007-04-27 02:15:00+05:00, gshchepa@stripped +9 -11 Fixed bug #13191. INSERT...ON DUPLICATE KEY UPDATE may cause error 1032: "Can't find record in ...". This occurs because INSERT...ON DUPLICATE uses trivial copying algorithm of key parts data for index search. key_copy() function has been fixed. # This is a BitKeeper patch. What follows are the unified diffs for the # set of deltas contained in the patch. The rest of the patch, the part # that BitKeeper cares about, is below these diffs. # User: gshchepa # Host: gshchepa.loc # Root: /home/uchum/work/bk-trees/mysql-4.1-opt-13191 --- 1.235/sql/field.cc 2007-01-31 09:51:03 +04:00 +++ 1.236/sql/field.cc 2007-04-27 02:12:17 +05:00 @@ -5204,6 +5204,15 @@ uint Field_string::max_packed_col_length return (max_length > 255 ? 2 : 1)+max_length; } +void Field_string::get_key_image(char *buff, uint length, CHARSET_INFO *cs, + imagetype type_arg) +{ + uint bytes = my_charpos(cs, ptr, ptr + field_length, + length / field_charset->mbmaxlen); + memcpy(buff, ptr, bytes); + if (bytes < length) + memset(buff+bytes, 0x20, (length-bytes)); +} /**************************************************************************** ** VARCHAR type (Not available for the end user yet) --- 1.137/sql/field.h 2007-03-26 15:17:39 +05:00 +++ 1.138/sql/field.h 2007-04-27 02:12:02 +05:00 @@ -947,6 +947,8 @@ public: enum_field_types real_type() const { return FIELD_TYPE_STRING; } bool has_charset(void) const { return charset() == &my_charset_bin ? FALSE : TRUE; } + void get_key_image(char *buff, uint length, CHARSET_INFO *cs, + imagetype type_arg); }; --- 1.26/sql/key.cc 2005-03-17 10:57:50 +04:00 +++ 1.27/sql/key.cc 2007-04-27 02:15:00 +05:00 @@ -89,20 +89,18 @@ void key_copy(byte *key,TABLE *table,uin } if (key_part->key_part_flag & HA_BLOB_PART) { - char *pos; - ulong blob_length=((Field_blob*) key_part->field)->get_length(); - key_length-=2; - ((Field_blob*) key_part->field)->get_ptr(&pos); - length=min(key_length,key_part->length); - set_if_smaller(blob_length,length); - int2store(key,(uint) blob_length); - key+=2; // Skip length info - memcpy(key,pos,blob_length); + key_length-= HA_KEY_BLOB_LENGTH; + length= min(key_length, key_part->length); + key_part->field->get_key_image((char *) key, length, + key_part->field->charset(), + Field::itRAW); + key+= HA_KEY_BLOB_LENGTH; } else { - length=min(key_length,key_part->length); - memcpy(key,table->record[0]+key_part->offset,(size_t) length); + length= min(key_length,key_part->length); + key_part->field->get_key_image((char *) key, length, + key_part->field->charset(), Field::itRAW); } key+=length; key_length-=length; --- 1.17/mysql-test/r/insert_update.result 2006-09-08 12:24:07 +05:00 +++ 1.18/mysql-test/r/insert_update.result 2007-04-27 01:55:01 +05:00 @@ -219,3 +219,36 @@ SELECT * FROM t1; a b 45 2 DROP TABLE t1; +CREATE TABLE t1(c1 TEXT, UNIQUE (c1(1)), cnt INT DEFAULT 1) +ENGINE=INNODB CHARACTER SET UTF8; +INSERT INTO t1 (c1) VALUES ('1a'); +SELECT * FROM t1; +c1 cnt +1a 1 +INSERT INTO t1 (c1) VALUES ('1b') ON DUPLICATE KEY UPDATE cnt=cnt+1; +SELECT * FROM t1; +c1 cnt +1a 2 +DROP TABLE t1; +CREATE TABLE t1(c1 VARCHAR(2), UNIQUE (c1(1)), cnt INT DEFAULT 1) +ENGINE=INNODB CHARACTER SET UTF8; +INSERT INTO t1 (c1) VALUES ('1a'); +SELECT * FROM t1; +c1 cnt +1a 1 +INSERT INTO t1 (c1) VALUES ('1b') ON DUPLICATE KEY UPDATE cnt=cnt+1; +SELECT * FROM t1; +c1 cnt +1a 2 +DROP TABLE t1; +CREATE TABLE t1(c1 CHAR(2), UNIQUE (c1(1)), cnt INT DEFAULT 1) +ENGINE=INNODB CHARACTER SET UTF8; +INSERT INTO t1 (c1) VALUES ('1a'); +SELECT * FROM t1; +c1 cnt +1a 1 +INSERT INTO t1 (c1) VALUES ('1b') ON DUPLICATE KEY UPDATE cnt=cnt+1; +SELECT * FROM t1; +c1 cnt +1a 2 +DROP TABLE t1; --- 1.18/mysql-test/t/insert_update.test 2006-09-08 12:24:07 +05:00 +++ 1.19/mysql-test/t/insert_update.test 2007-04-27 01:54:43 +05:00 @@ -1,3 +1,5 @@ +-- source include/have_innodb.inc + --disable_warnings DROP TABLE IF EXISTS t1; --enable_warnings @@ -119,8 +121,6 @@ DROP TABLE t1; # Bug#21555: incorrect behavior with INSERT ... ON DUPL KEY UPDATE and VALUES # - -# End of 4.1 tests CREATE TABLE t1 ( a BIGINT UNSIGNED, @@ -139,3 +139,43 @@ INSERT INTO t1 VALUES (45, 1) ON DUPLICA SELECT * FROM t1; DROP TABLE t1; + +# +# Bug #13191: INSERT...ON DUPLICATE KEY UPDATE of the key of the +# limited length larger than length of underlying UTF-8 string field. +# + +CREATE TABLE t1(c1 TEXT, UNIQUE (c1(1)), cnt INT DEFAULT 1) +ENGINE=INNODB CHARACTER SET UTF8; + +INSERT INTO t1 (c1) VALUES ('1a'); +SELECT * FROM t1; + +INSERT INTO t1 (c1) VALUES ('1b') ON DUPLICATE KEY UPDATE cnt=cnt+1; +SELECT * FROM t1; + +DROP TABLE t1; + +CREATE TABLE t1(c1 VARCHAR(2), UNIQUE (c1(1)), cnt INT DEFAULT 1) +ENGINE=INNODB CHARACTER SET UTF8; + +INSERT INTO t1 (c1) VALUES ('1a'); +SELECT * FROM t1; + +INSERT INTO t1 (c1) VALUES ('1b') ON DUPLICATE KEY UPDATE cnt=cnt+1; +SELECT * FROM t1; + +DROP TABLE t1; + +CREATE TABLE t1(c1 CHAR(2), UNIQUE (c1(1)), cnt INT DEFAULT 1) +ENGINE=INNODB CHARACTER SET UTF8; + +INSERT INTO t1 (c1) VALUES ('1a'); +SELECT * FROM t1; + +INSERT INTO t1 (c1) VALUES ('1b') ON DUPLICATE KEY UPDATE cnt=cnt+1; +SELECT * FROM t1; + +DROP TABLE t1; + +# End of 4.1 tests