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-29 04:16:17+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 unique index of partial key with
underlying UTF-8 string field.
This error occurs because INSERT...ON DUPLICATE uses a wrong
procedure to copy string fields of multi-byte character sets
for index search.
mysql-test/r/innodb_mysql.result@stripped, 2007-04-29 04:15:33+05:00, gshchepa@stripped +33 -0
Added test case for bug #13191.
mysql-test/t/innodb_mysql.test@stripped, 2007-04-29 04:15:31+05:00, gshchepa@stripped +30 -0
Added test case for bug #13191.
sql/field.cc@stripped, 2007-04-29 04:15:46+05:00, gshchepa@stripped +28 -13
Fixed bug #13191.
Field_string::get_key_image() virtual function was overloaded
to implement copying of variable length character (UTF-8) fields.
Field::get_key_image() function prototype has been changed to
return byte size of copied data.
sql/field.h@stripped, 2007-04-29 04:15:39+05:00, gshchepa@stripped +42 -6
Fixed bug #13191.
Field_string::get_key_image() virtual function was overloaded
to implement copying of variable length character (UTF-8) fields.
Field::get_key_image() function prototype has been changed to
return byte size of copied data.
sql/key.cc@stripped, 2007-04-29 04:15:52+05:00, gshchepa@stripped +12 -11
Fixed bug #13191.
INSERT...ON DUPLICATE KEY UPDATE may cause error 1032:
"Can't find record in ...".
This error occurs because INSERT...ON DUPLICATE uses
a wrong procedure to copy field parts 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-29 04:15:46 +05:00
@@ -5204,6 +5204,16 @@ uint Field_string::max_packed_col_length
return (max_length > 255 ? 2 : 1)+max_length;
}
+uint 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)
+ bzero(buff + bytes, length - bytes);
+ return bytes;
+}
/****************************************************************************
** VARCHAR type (Not available for the end user yet)
@@ -5414,8 +5424,8 @@ uint Field_varstring::max_packed_col_len
return (max_length > 255 ? 2 : 1)+max_length;
}
-void Field_varstring::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
- imagetype type)
+uint Field_varstring::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
+ imagetype type)
{
uint f_length=uint2korr(ptr);
if (f_length > length)
@@ -5426,6 +5436,7 @@ void Field_varstring::get_key_image(char
if (f_length < length)
bzero(buff+HA_KEY_BLOB_LENGTH+f_length, (length-f_length));
#endif
+ return HA_KEY_BLOB_LENGTH+f_length;
}
void Field_varstring::set_key_image(char *buff,uint length, CHARSET_INFO *cs)
@@ -5724,8 +5735,8 @@ int Field_blob::cmp_binary(const char *a
/* The following is used only when comparing a key */
-void Field_blob::get_key_image(char *buff,uint length,
- CHARSET_INFO *cs, imagetype type)
+uint Field_blob::get_key_image(char *buff,uint length,
+ CHARSET_INFO *cs, imagetype type)
{
uint32 blob_length= get_length(ptr);
char *blob;
@@ -5737,16 +5748,17 @@ void Field_blob::get_key_image(char *buf
MBR mbr;
Geometry_buffer buffer;
Geometry *gobj;
+ const uint image_length= SIZEOF_STORED_DOUBLE*4;
if (blob_length < SRID_SIZE)
{
- bzero(buff, SIZEOF_STORED_DOUBLE*4);
- return;
+ bzero(buff, image_length);
+ return image_length;
}
get_ptr(&blob);
gobj= Geometry::construct(&buffer, blob, blob_length);
if (gobj->get_mbr(&mbr, &dummy))
- bzero(buff, SIZEOF_STORED_DOUBLE*4);
+ bzero(buff, image_length);
else
{
float8store(buff, mbr.xmin);
@@ -5754,7 +5766,7 @@ void Field_blob::get_key_image(char *buf
float8store(buff+16, mbr.ymin);
float8store(buff+24, mbr.ymax);
}
- return;
+ return image_length;
}
#endif /*HAVE_SPATIAL*/
@@ -5774,6 +5786,7 @@ void Field_blob::get_key_image(char *buf
}
int2store(buff,length);
memcpy(buff+HA_KEY_BLOB_LENGTH, blob, length);
+ return HA_KEY_BLOB_LENGTH+length;
}
void Field_blob::set_key_image(char *buff,uint length, CHARSET_INFO *cs)
@@ -6021,8 +6034,8 @@ uint Field_blob::max_packed_col_length(u
#ifdef HAVE_SPATIAL
-void Field_geom::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
- imagetype type)
+uint Field_geom::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
+ imagetype type)
{
char *blob;
const char *dummy;
@@ -6030,16 +6043,17 @@ void Field_geom::get_key_image(char *buf
ulong blob_length= get_length(ptr);
Geometry_buffer buffer;
Geometry *gobj;
+ const uint image_length= SIZEOF_STORED_DOUBLE*4;
if (blob_length < SRID_SIZE)
{
- bzero(buff, SIZEOF_STORED_DOUBLE*4);
- return;
+ bzero(buff, image_length);
+ return image_length;
}
get_ptr(&blob);
gobj= Geometry::construct(&buffer, blob, blob_length);
if (gobj->get_mbr(&mbr, &dummy))
- bzero(buff, SIZEOF_STORED_DOUBLE*4);
+ bzero(buff, image_length);
else
{
float8store(buff, mbr.xmin);
@@ -6047,6 +6061,7 @@ void Field_geom::get_key_image(char *buf
float8store(buff + 16, mbr.ymin);
float8store(buff + 24, mbr.ymax);
}
+ return image_length;
}
--- 1.137/sql/field.h 2007-03-26 15:17:39 +05:00
+++ 1.138/sql/field.h 2007-04-29 04:15:39 +05:00
@@ -228,9 +228,43 @@ public:
{ memcpy(buff,ptr,length); }
inline void set_image(char *buff,uint length, CHARSET_INFO *cs)
{ memcpy(ptr,buff,length); }
- virtual void get_key_image(char *buff,uint length, CHARSET_INFO *cs,
- imagetype type)
- { get_image(buff,length,cs); }
+
+
+ /*
+ Copy a field part into an output buffer.
+
+ SYNOPSIS
+ Field::get_key_image()
+ buff [out] output buffer
+ length output buffer size
+ cs charset, always same as this->charset(),
+ (to be removed in 5.x)
+ type itMBR for geometry blobs, otherwise itRAW
+
+ DESCRIPTION
+ This function makes a copy of field part of size equal to or
+ less than "length" parameter value.
+ For fields of string types (CHAR, VARCHAR, TEXT) the rest of buffer
+ is padded by zero byte.
+
+ NOTES
+ For variable length character fields (i.e. UTF-8) the "length"
+ parameter means a number of output buffer bytes as if all field
+ characters have maximal possible size (mbmaxlen). In the other words,
+ "length" parameter is a number of characters multiplied by
+ field_charset->mbmaxlen.
+
+ RETURN
+ Number of copied bytes (excluding padded zero bytes -- see above).
+ */
+
+ virtual uint get_key_image(char *buff, uint length,
+ CHARSET_INFO *cs,
+ imagetype type)
+ {
+ get_image(buff,length,cs);
+ return length;
+ }
virtual void set_key_image(char *buff,uint length, CHARSET_INFO *cs)
{ set_image(buff,length,cs); }
inline longlong val_int_offset(uint row_offset)
@@ -947,6 +981,8 @@ public:
enum_field_types real_type() const { return FIELD_TYPE_STRING; }
bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
+ virtual uint get_key_image(char *buff,uint length, CHARSET_INFO *cs,
+ imagetype type);
};
@@ -981,7 +1017,7 @@ public:
String *val_str(String*,String *);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
- void get_key_image(char *buff,uint length, CHARSET_INFO *cs, imagetype type);
+ uint get_key_image(char *buff,uint length, CHARSET_INFO *cs, imagetype type);
void set_key_image(char *buff,uint length, CHARSET_INFO *cs);
void sql_type(String &str) const;
char *pack(char *to, const char *from, uint max_length=~(uint) 0);
@@ -1060,7 +1096,7 @@ public:
store_length(length);
memcpy_fixed(ptr+packlength,&data,sizeof(char*));
}
- void get_key_image(char *buff,uint length, CHARSET_INFO *cs, imagetype type);
+ uint get_key_image(char *buff,uint length, CHARSET_INFO *cs, imagetype type);
void set_key_image(char *buff,uint length, CHARSET_INFO *cs);
void sql_type(String &str) const;
inline bool copy()
@@ -1117,7 +1153,7 @@ public:
int store(longlong nr) { return 1; }
int reset(void) { return !maybe_null() || Field_blob::reset(); }
- void get_key_image(char *buff,uint length, CHARSET_INFO *cs,imagetype type);
+ uint get_key_image(char *buff,uint length, CHARSET_INFO *cs,imagetype type);
void set_key_image(char *buff,uint length, CHARSET_INFO *cs);
};
#endif /*HAVE_SPATIAL*/
--- 1.26/sql/key.cc 2005-03-17 10:57:50 +04:00
+++ 1.27/sql/key.cc 2007-04-29 04:15:52 +05:00
@@ -89,20 +89,21 @@ 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);
+ Field *field= key_part->field;
+ CHARSET_INFO *cs= field->charset();
+ uint bytes= field->get_key_image(key, length, cs, Field::itRAW);
+ if (bytes < length)
+ cs->cset->fill(cs, key + bytes, length - bytes, ' ');
}
key+=length;
key_length-=length;
--- 1.7/mysql-test/r/innodb_mysql.result 2006-11-03 02:27:41 +04:00
+++ 1.8/mysql-test/r/innodb_mysql.result 2007-04-29 04:15:33 +05:00
@@ -128,4 +128,37 @@ show /*!50002 GLOBAL */ status like 'Han
Variable_name Value
Handler_rollback 0
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;
End of 4.1 tests
--- 1.7/mysql-test/t/innodb_mysql.test 2006-11-03 02:27:41 +04:00
+++ 1.8/mysql-test/t/innodb_mysql.test 2007-04-29 04:15:31 +05:00
@@ -161,4 +161,34 @@ show /*!50002 GLOBAL */ status like 'Han
connection default;
drop table t1;
disconnect con1;
+
+#
+# Bug #13191: INSERT...ON DUPLICATE KEY UPDATE of UTF-8 string fields
+# used in partial unique indices.
+#
+
+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;
+
--echo End of 4.1 tests
Thread |
---|
• bk commit into 4.1 tree (gshchepa:1.2636) BUG#13191 | gshchepa | 29 Apr |