summaryrefslogtreecommitdiff
path: root/sql/sql_string.cc
diff options
context:
space:
mode:
authorunknown <pem@mysql.com>2004-02-10 18:44:02 +0100
committerunknown <pem@mysql.com>2004-02-10 18:44:02 +0100
commit6efd76f317be8fc5fd0a2d144a7c57506723c2ad (patch)
treef04786f8a211a4c03eab547b7332792201289ac1 /sql/sql_string.cc
parent5390589c3c5845f48d3cf251d8b3dad359e0c9b1 (diff)
parent23103e44b4cc8abfdb1da47214ff2bd7cc2f3fca (diff)
downloadmariadb-git-6efd76f317be8fc5fd0a2d144a7c57506723c2ad.tar.gz
Merge 4.1 into 5.0.
BitKeeper/etc/logging_ok: auto-union configure.in: Auto merged BitKeeper/deleted/.del-opt_ft.cc~2048ffa561f9c59: Auto merged BitKeeper/deleted/.del-opt_ft.h~24aac1d29304599a: Auto merged client/mysql.cc: Auto merged include/my_global.h: Auto merged libmysql/libmysql.c: Auto merged libmysqld/Makefile.am: Auto merged libmysqld/lib_sql.cc: Auto merged myisam/mi_check.c: Auto merged mysql-test/install_test_db.sh: Auto merged mysql-test/r/multi_update.result: Auto merged mysql-test/r/mysqldump.result: Auto merged mysql-test/r/null.result: Auto merged mysql-test/r/show_check.result: Auto merged mysql-test/r/subselect.result: Auto merged mysql-test/r/symlink.result: Auto merged mysql-test/t/multi_update.test: Auto merged mysql-test/t/null.test: Auto merged mysql-test/t/rpl_until.test: Auto merged mysql-test/t/subselect.test: Auto merged sql/Makefile.am: Auto merged sql/filesort.cc: Auto merged sql/item.cc: Auto merged sql/item_cmpfunc.cc: Auto merged sql/item_cmpfunc.h: Auto merged sql/item_create.cc: Auto merged sql/item_create.h: Auto merged sql/item_func.h: Auto merged sql/item_subselect.cc: Auto merged sql/item_sum.cc: Auto merged sql/item_sum.h: Auto merged sql/item_timefunc.cc: Auto merged sql/mysqld.cc: Auto merged sql/protocol.cc: Auto merged sql/repl_failsafe.cc: Auto merged sql/set_var.cc: Auto merged sql/slave.cc: Auto merged sql/slave.h: Auto merged sql/sql_acl.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_cache.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_db.cc: Auto merged sql/sql_delete.cc: Auto merged sql/sql_derived.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_lex.h: Auto merged sql/sql_list.h: Auto merged sql/sql_load.cc: Auto merged sql/sql_prepare.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_select.h: Auto merged sql/sql_show.cc: Auto merged sql/sql_table.cc: Auto merged sql/sql_union.cc: Auto merged sql/sql_update.cc: Auto merged sql-common/client.c: Auto merged
Diffstat (limited to 'sql/sql_string.cc')
-rw-r--r--sql/sql_string.cc126
1 files changed, 115 insertions, 11 deletions
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 61070f07266..093b85b46b7 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -24,6 +24,7 @@
#include <my_sys.h>
#include <m_string.h>
#include <m_ctype.h>
+#include <assert.h>
#ifdef HAVE_FCONVERT
#include <floatingpoint.h>
#endif
@@ -228,15 +229,117 @@ 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.
+
+ SYNPOSIS
+
+ needs_conversion()
+ arg_length Length of string to copy.
+ from_cs Character set to copy from
+ to_cs Character set to copy to
+ uint32 *offset Returns number of unaligned characters.
+
+ RETURN
+ 0 No conversion needed
+ 1 Either character set conversion or adding leading zeros
+ (e.g. for UCS-2) must be done
+*/
+
+bool String::needs_conversion(uint32 arg_length,
+ CHARSET_INFO *from_cs,
+ CHARSET_INFO *to_cs,
+ uint32 *offset)
+{
+ *offset= 0;
+ if ((to_cs == &my_charset_bin) ||
+ (to_cs == from_cs) ||
+ my_charset_same(from_cs, to_cs) ||
+ ((from_cs == &my_charset_bin) &&
+ (!(*offset=(arg_length % to_cs->mbminlen)))))
+ return FALSE;
+ return TRUE;
+}
+
+
+/*
+ Copy a multi-byte character sets with adding leading zeros.
+
+ SYNOPSIS
+
+ copy_aligned()
+ str String to copy
+ arg_length Length of string. This should NOT be dividable with
+ cs->mbminlen.
+ offset arg_length % cs->mb_minlength
+ cs Character set for 'str'
+
+ NOTES
+ 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
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+bool String::copy_aligned(const char *str,uint32 arg_length, uint32 offset,
+ CHARSET_INFO *cs)
+{
+ /* How many bytes are in incomplete character */
+ offset= cs->mbmaxlen - offset; /* How many zeros we should prepend */
+ DBUG_ASSERT(offset && offset != cs->mbmaxlen);
+
+ uint32 aligned_length= arg_length + offset;
+ if (alloc(aligned_length))
+ return TRUE;
+
+ /*
+ 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, offset);
+ memcpy(Ptr + offset, str, arg_length);
+ Ptr[aligned_length]=0;
+ /* str_length is always >= 0 as arg_length is != 0 */
+ str_length= aligned_length;
+ str_charset= cs;
+ 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 offset= (arg_length % cs->mbminlen);
+
+ if (!offset) /* All characters are complete, just copy */
+ {
+ set(str, arg_length, cs);
+ return FALSE;
+ }
+ return copy_aligned(str, arg_length, offset, 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))
- {
- return copy(str, arg_length, &my_charset_bin);
- }
+ uint32 offset;
+ if (!needs_conversion(arg_length, from_cs, to_cs, &offset))
+ return copy(str, arg_length, to_cs);
+ if ((from_cs == &my_charset_bin) && offset)
+ return copy_aligned(str, arg_length, offset, to_cs);
+
uint32 new_length= to_cs->mbmaxlen*arg_length;
if (alloc(new_length))
return TRUE;
@@ -434,7 +537,7 @@ int String::strstr(const String &s,uint32 offset)
register const char *search=s.ptr();
const char *end=Ptr+str_length-s.length()+1;
const char *search_end=s.ptr()+s.length();
-skipp:
+skip:
while (str != end)
{
if (*str++ == *search)
@@ -442,7 +545,7 @@ skipp:
register char *i,*j;
i=(char*) str; j=(char*) search+1;
while (j != search_end)
- if (*i++ != *j++) goto skipp;
+ if (*i++ != *j++) goto skip;
return (int) (str-Ptr) -1;
}
}
@@ -466,7 +569,7 @@ int String::strstr_case(const String &s,uint32 offset)
register const char *search=s.ptr();
const char *end=Ptr+str_length-s.length()+1;
const char *search_end=s.ptr()+s.length();
-skipp:
+skip:
while (str != end)
{
if (str_charset->sort_order[*str++] == str_charset->sort_order[*search])
@@ -476,7 +579,7 @@ skipp:
while (j != search_end)
if (str_charset->sort_order[*i++] !=
str_charset->sort_order[*j++])
- goto skipp;
+ goto skip;
return (int) (str-Ptr) -1;
}
}
@@ -499,7 +602,7 @@ int String::strrstr(const String &s,uint32 offset)
const char *end=Ptr+s.length()-2;
const char *search_end=s.ptr()-1;
-skipp:
+skip:
while (str != end)
{
if (*str-- == *search)
@@ -507,7 +610,7 @@ skipp:
register char *i,*j;
i=(char*) str; j=(char*) search-1;
while (j != search_end)
- if (*i-- != *j--) goto skipp;
+ if (*i-- != *j--) goto skip;
return (int) (i-Ptr) +1;
}
}
@@ -657,7 +760,8 @@ copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
while (1)
{
- if ((cnvres=from_cs->cset->mb_wc(from_cs, &wc, (uchar*) from, from_end)) > 0)
+ if ((cnvres= from_cs->cset->mb_wc(from_cs, &wc, (uchar*) from,
+ from_end)) > 0)
from+= cnvres;
else if (cnvres == MY_CS_ILSEQ)
{