diff options
author | unknown <bar@bar.intranet.mysql.r18.ru> | 2004-01-19 19:16:30 +0400 |
---|---|---|
committer | unknown <bar@bar.intranet.mysql.r18.ru> | 2004-01-19 19:16:30 +0400 |
commit | 162f1dc5e6f8cd24ec996aa701a50bf20b8f6a36 (patch) | |
tree | f567782e8ab2357e9f089387fcb0d454a6a02ce3 /sql | |
parent | d89fd8281bb6795da5d897561fb19e19a631ce0e (diff) | |
download | mariadb-git-162f1dc5e6f8cd24ec996aa701a50bf20b8f6a36.tar.gz |
UCS-2 aligning 0xAA -> 0x00AA
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.h | 4 | ||||
-rw-r--r-- | sql/sql_string.cc | 46 | ||||
-rw-r--r-- | sql/sql_string.h | 1 |
3 files changed, 49 insertions, 2 deletions
diff --git a/sql/item.h b/sql/item.h index 5def1e2b710..e6ed8109534 100644 --- a/sql/item.h +++ b/sql/item.h @@ -477,7 +477,7 @@ public: CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) { collation.set(cs, dv); - str_value.set(str,length,cs); + str_value.set_or_copy_aligned(str,length,cs); /* We have to have a different max_length than 'length' here to ensure that we get the right length if we do use the item @@ -493,7 +493,7 @@ public: CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) { collation.set(cs, dv); - str_value.set(str,length,cs); + str_value.set_or_copy_aligned(str,length,cs); max_length= str_value.numchars()*cs->mbmaxlen; set_name(name_par,0,cs); decimals=NOT_FIXED_DEC; diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 89f48607969..9534c5605fe 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -228,6 +228,52 @@ bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *cs) return FALSE; } +/* +** For real multi-byte, ascii incompatible charactser sets, +** like UCS-2, add leading zeros if we have an incomplete character. +** Thus, +** SELECT _ucs2 0xAA +** will automatically be converted into +** SELECT _ucs2 0x00AA +*/ + +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; + } + + offs= cs->mbmaxlen - offs; /* How many zeros we should prepend */ + uint32 aligned_length= arg_length + offs; + if (alloc(aligned_length)) + return TRUE; + + /* + Probably this condition is not really necessary + because if aligned_length is 0 then offs is 0 too + and we'll return after calling set(). + */ + if ((str_length= aligned_length)) + { + /* + Note, this is only safe for little-endian UCS-2. + If we add big-endian UCS-2 sometimes, this code + will be more complicated. But it's OK for now. + */ + bzero((char*)Ptr, offs); + memcpy(Ptr + offs, str, arg_length); + } + Ptr[aligned_length]=0; + str_charset=cs; + return FALSE; +} + /* Copy with charset convertion */ bool String::copy(const char *str, uint32 arg_length, diff --git a/sql/sql_string.h b/sql/sql_string.h index 325611737ca..8817aa8eab8 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -183,6 +183,7 @@ 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 + 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); bool append(const String &s); |