summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <bar@bar.intranet.mysql.r18.ru>2004-01-19 19:16:30 +0400
committerunknown <bar@bar.intranet.mysql.r18.ru>2004-01-19 19:16:30 +0400
commit162f1dc5e6f8cd24ec996aa701a50bf20b8f6a36 (patch)
treef567782e8ab2357e9f089387fcb0d454a6a02ce3 /sql
parentd89fd8281bb6795da5d897561fb19e19a631ce0e (diff)
downloadmariadb-git-162f1dc5e6f8cd24ec996aa701a50bf20b8f6a36.tar.gz
UCS-2 aligning 0xAA -> 0x00AA
Diffstat (limited to 'sql')
-rw-r--r--sql/item.h4
-rw-r--r--sql/sql_string.cc46
-rw-r--r--sql/sql_string.h1
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);