diff options
author | unknown <pem@mysql.com> | 2004-02-10 18:44:02 +0100 |
---|---|---|
committer | unknown <pem@mysql.com> | 2004-02-10 18:44:02 +0100 |
commit | 6efd76f317be8fc5fd0a2d144a7c57506723c2ad (patch) | |
tree | f04786f8a211a4c03eab547b7332792201289ac1 /sql/sql_string.cc | |
parent | 5390589c3c5845f48d3cf251d8b3dad359e0c9b1 (diff) | |
parent | 23103e44b4cc8abfdb1da47214ff2bd7cc2f3fca (diff) | |
download | mariadb-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.cc | 126 |
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) { |