diff options
author | unknown <bar@bar.intranet.mysql.r18.ru> | 2004-01-21 14:15:19 +0400 |
---|---|---|
committer | unknown <bar@bar.intranet.mysql.r18.ru> | 2004-01-21 14:15:19 +0400 |
commit | cf240e4ee83b39fbbccf92a35f394cb2793437a5 (patch) | |
tree | 058a7d4f2f63504db9bb954a87f85a755f802179 | |
parent | 53d6a088bcbab1777e32777e80a548b46f1140af (diff) | |
download | mariadb-git-cf240e4ee83b39fbbccf92a35f394cb2793437a5.tar.gz |
Further fixes for 2390: ucs2 alignment
-rw-r--r-- | mysql-test/r/ctype_ucs.result | 56 | ||||
-rw-r--r-- | mysql-test/t/ctype_ucs.test | 38 | ||||
-rw-r--r-- | sql/field.cc | 16 | ||||
-rw-r--r-- | sql/sql_string.cc | 54 | ||||
-rw-r--r-- | sql/sql_string.h | 3 |
5 files changed, 152 insertions, 15 deletions
diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index d6e9cc690a2..8d9c7579771 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -324,3 +324,59 @@ HEX(_ucs2 0x0123456789ABCDE) SELECT HEX(_ucs2 0x0123456789ABCDEF); HEX(_ucs2 0x0123456789ABCDEF) 0123456789ABCDEF +SELECT hex(cast(0xAA as char character set ucs2)); +hex(cast(0xAA as char character set ucs2)) +00AA +SELECT hex(convert(0xAA using ucs2)); +hex(convert(0xAA using ucs2)) +00AA +CREATE TABLE t1 (a char(10) character set ucs2); +INSERT INTO t1 VALUES (0xA),(0xAA),(0xAAA),(0xAAAA),(0xAAAAA); +SELECT HEX(a) FROM t1; +HEX(a) +000A +00AA +0AAA +AAAA +000AAAAA +DROP TABLE t1; +CREATE TABLE t1 (a varchar(10) character set ucs2); +INSERT INTO t1 VALUES (0xA),(0xAA),(0xAAA),(0xAAAA),(0xAAAAA); +SELECT HEX(a) FROM t1; +HEX(a) +000A +00AA +0AAA +AAAA +000AAAAA +DROP TABLE t1; +CREATE TABLE t1 (a text character set ucs2); +INSERT INTO t1 VALUES (0xA),(0xAA),(0xAAA),(0xAAAA),(0xAAAAA); +SELECT HEX(a) FROM t1; +HEX(a) +000A +00AA +0AAA +AAAA +000AAAAA +DROP TABLE t1; +CREATE TABLE t1 (a mediumtext character set ucs2); +INSERT INTO t1 VALUES (0xA),(0xAA),(0xAAA),(0xAAAA),(0xAAAAA); +SELECT HEX(a) FROM t1; +HEX(a) +000A +00AA +0AAA +AAAA +000AAAAA +DROP TABLE t1; +CREATE TABLE t1 (a longtext character set ucs2); +INSERT INTO t1 VALUES (0xA),(0xAA),(0xAAA),(0xAAAA),(0xAAAAA); +SELECT HEX(a) FROM t1; +HEX(a) +000A +00AA +0AAA +AAAA +000AAAAA +DROP TABLE t1; diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index fd2a1b1cd7d..021147e258a 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -200,7 +200,7 @@ DROP TABLE t1; # Bug #2390 -# Check alignment +# Check alignment for constants # SELECT HEX(_ucs2 0x0); SELECT HEX(_ucs2 0x01); @@ -218,3 +218,39 @@ SELECT HEX(_ucs2 0x0123456789ABC); SELECT HEX(_ucs2 0x0123456789ABCD); SELECT HEX(_ucs2 0x0123456789ABCDE); SELECT HEX(_ucs2 0x0123456789ABCDEF); + +# +# Check alignment for from-binary-conversion with CAST and CONVERT +# +SELECT hex(cast(0xAA as char character set ucs2)); +SELECT hex(convert(0xAA using ucs2)); + +# +# Check alignment for string types +# +CREATE TABLE t1 (a char(10) character set ucs2); +INSERT INTO t1 VALUES (0xA),(0xAA),(0xAAA),(0xAAAA),(0xAAAAA); +SELECT HEX(a) FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (a varchar(10) character set ucs2); +INSERT INTO t1 VALUES (0xA),(0xAA),(0xAAA),(0xAAAA),(0xAAAAA); +SELECT HEX(a) FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (a text character set ucs2); +INSERT INTO t1 VALUES (0xA),(0xAA),(0xAAA),(0xAAAA),(0xAAAAA); +SELECT HEX(a) FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (a mediumtext character set ucs2); +INSERT INTO t1 VALUES (0xA),(0xAA),(0xAAA),(0xAAAA),(0xAAAAA); +SELECT HEX(a) FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (a longtext character set ucs2); +INSERT INTO t1 VALUES (0xA),(0xAA),(0xAAA),(0xAAAA),(0xAAAAA); +SELECT HEX(a) FROM t1; +DROP TABLE t1; + +-- the same should be also done with enum and set diff --git a/sql/field.cc b/sql/field.cc index 1a0716326fe..8dc133adae8 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4055,18 +4055,13 @@ void Field_datetime::sql_type(String &res) const /* Copy a string and fill with space */ -static bool use_conversion(CHARSET_INFO *cs1, CHARSET_INFO *cs2) -{ - return (cs1 != &my_charset_bin) && (cs2 != &my_charset_bin) && (cs1!=cs2); -} - int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) { int error= 0; char buff[80]; String tmpstr(buff,sizeof(buff), &my_charset_bin); /* Convert character set if nesessary */ - if (use_conversion(cs, field_charset)) + if (String::needs_conversion(from, length, cs, field_charset)) { tmpstr.copy(from, length, cs, field_charset); from= tmpstr.ptr(); @@ -4254,7 +4249,7 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) char buff[80]; String tmpstr(buff,sizeof(buff), &my_charset_bin); /* Convert character set if nesessary */ - if (use_conversion(cs, field_charset)) + if (String::needs_conversion(from, length, cs, field_charset)) { tmpstr.copy(from, length, cs, field_charset); from= tmpstr.ptr(); @@ -4572,7 +4567,8 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) String tmpstr(buff,sizeof(buff), &my_charset_bin); /* Convert character set if nesessary */ - if ((was_conversion= use_conversion(cs, field_charset))) + if ((was_conversion= String::needs_conversion(from, length, + cs, field_charset))) { tmpstr.copy(from, length, cs, field_charset); from= tmpstr.ptr(); @@ -5082,7 +5078,7 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) char buff[80]; String tmpstr(buff,sizeof(buff), &my_charset_bin); /* Convert character set if nesessary */ - if (use_conversion(cs, field_charset)) + if (String::needs_conversion(from, length, cs, field_charset)) { tmpstr.copy(from, length, cs, field_charset); from= tmpstr.ptr(); @@ -5263,7 +5259,7 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) String tmpstr(buff,sizeof(buff), &my_charset_bin); /* Convert character set if nesessary */ - if (use_conversion(cs, field_charset)) + if (String::needs_conversion(from, length, cs, field_charset)) { tmpstr.copy(from, length, cs, field_charset); from= tmpstr.ptr(); diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 9534c5605fe..225076bc555 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -228,6 +228,32 @@ bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *cs) return FALSE; } + +/* + Checks that the source string can be just copied + to the destination string without conversion. + If either character set conversion or adding leading + zeros (e.g. for UCS-2) must be done then return + value is TRUE else FALSE. +*/ +bool String::needs_conversion(const char *str, uint32 arg_length, + CHARSET_INFO *from_cs, + CHARSET_INFO *to_cs) +{ + if (to_cs == &my_charset_bin) + return FALSE; + if (to_cs == from_cs) + return FALSE; + if (my_charset_same(from_cs, to_cs)) + return FALSE; + if ((from_cs == &my_charset_bin)) + { + if (!(arg_length % to_cs->mbminlen)) + return FALSE; + } + return TRUE; +} + /* ** For real multi-byte, ascii incompatible charactser sets, ** like UCS-2, add leading zeros if we have an incomplete character. @@ -237,15 +263,15 @@ bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *cs) ** SELECT _ucs2 0x00AA */ -bool String::set_or_copy_aligned(const char *str,uint32 arg_length, - CHARSET_INFO *cs) +bool String::copy_aligned(const char *str,uint32 arg_length, + CHARSET_INFO *cs) { /* How many bytes are in incomplete character */ uint32 offs= (arg_length % cs->mbminlen); if (!offs) /* All characters are complete, just copy */ { - set(str, arg_length, cs); + copy(str, arg_length, cs); return FALSE; } @@ -274,15 +300,35 @@ bool String::set_or_copy_aligned(const char *str,uint32 arg_length, return FALSE; } + +bool String::set_or_copy_aligned(const char *str,uint32 arg_length, + CHARSET_INFO *cs) +{ + /* How many bytes are in incomplete character */ + uint32 offs= (arg_length % cs->mbminlen); + + if (!offs) /* All characters are complete, just copy */ + { + set(str, arg_length, cs); + return FALSE; + } + return copy_aligned(str, arg_length, cs); +} + /* Copy with charset convertion */ bool String::copy(const char *str, uint32 arg_length, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) { - if ((from_cs == &my_charset_bin) || (to_cs == &my_charset_bin)) + if (!needs_conversion(str, arg_length, from_cs, to_cs)) { return copy(str, arg_length, to_cs); } + if ((from_cs == &my_charset_bin) && (arg_length % to_cs->mbminlen)) + { + return copy_aligned(str, arg_length, to_cs); + } + uint32 new_length= to_cs->mbmaxlen*arg_length; if (alloc(new_length)) return TRUE; diff --git a/sql/sql_string.h b/sql/sql_string.h index 8817aa8eab8..9c0900137e3 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -183,6 +183,9 @@ public: bool copy(); // Alloc string if not alloced bool copy(const String &s); // Allocate new string bool copy(const char *s,uint32 arg_length, CHARSET_INFO *cs); // Allocate new string + static bool needs_conversion(const char *s, uint32 arg_length, + CHARSET_INFO *cs_from, CHARSET_INFO *cs_to); + bool copy_aligned(const char *s, uint32 arg_length, CHARSET_INFO *cs); bool set_or_copy_aligned(const char *s, uint32 arg_length, CHARSET_INFO *cs); bool copy(const char*s,uint32 arg_length, CHARSET_INFO *csfrom, CHARSET_INFO *csto); |