diff options
Diffstat (limited to 'sql/strfunc.cc')
-rw-r--r-- | sql/strfunc.cc | 111 |
1 files changed, 109 insertions, 2 deletions
diff --git a/sql/strfunc.cc b/sql/strfunc.cc index 308e6fd3dcd..c03365cfc2b 100644 --- a/sql/strfunc.cc +++ b/sql/strfunc.cc @@ -104,7 +104,8 @@ ulonglong find_set(TYPELIB *lib, const char *str, uint length, CHARSET_INFO *cs, > 0 position in TYPELIB->type_names +1 */ -uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match) +uint find_type(const TYPELIB *lib, const char *find, uint length, + bool part_match) { uint found_count=0, found_pos=0; const char *end= find+length; @@ -144,7 +145,8 @@ uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match) >0 Offset+1 in typelib for matched string */ -uint find_type2(TYPELIB *typelib, const char *x, uint length, CHARSET_INFO *cs) +uint find_type2(const TYPELIB *typelib, const char *x, uint length, + CHARSET_INFO *cs) { int pos; const char *j; @@ -234,3 +236,108 @@ uint check_word(TYPELIB *lib, const char *val, const char *end, *end_of_word= ptr; return res; } + + +/* + Converts a string between character sets + + SYNOPSIS + strconvert() + from_cs source character set + from source, a null terminated string + to destination buffer + to_length destination buffer length + + NOTES + 'to' is always terminated with a '\0' character. + If there is no enough space to convert whole string, + only prefix is converted, and terminated with '\0'. + + RETURN VALUES + result string length +*/ + + +uint strconvert(CHARSET_INFO *from_cs, const char *from, + CHARSET_INFO *to_cs, char *to, uint to_length, uint *errors) +{ + int cnvres; + my_wc_t wc; + char *to_start= to; + uchar *to_end= (uchar*) to + to_length - 1; + my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc; + my_charset_conv_wc_mb wc_mb= to_cs->cset->wc_mb; + uint error_count= 0; + + while (1) + { + /* + Using 'from + 10' is safe: + - it is enough to scan a single character in any character set. + - if remaining string is shorter than 10, then mb_wc will return + with error because of unexpected '\0' character. + */ + if ((cnvres= (*mb_wc)(from_cs, &wc, + (uchar*) from, (uchar*) from + 10)) > 0) + { + if (!wc) + break; + from+= cnvres; + } + else if (cnvres == MY_CS_ILSEQ) + { + error_count++; + from++; + wc= '?'; + } + else + break; // Impossible char. + +outp: + + if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0) + to+= cnvres; + else if (cnvres == MY_CS_ILUNI && wc != '?') + { + error_count++; + wc= '?'; + goto outp; + } + else + break; + } + *to= '\0'; + *errors= error_count; + return (uint32) (to - to_start); + +} + + +/* + Searches for a LEX_STRING in an LEX_STRING array. + + SYNOPSIS + find_string_in_array() + heap The array + needle The string to search for + + NOTE + The last LEX_STRING in the array should have str member set to NULL + + RETURN VALUES + -1 Not found + >=0 Ordinal position +*/ + +int find_string_in_array(LEX_STRING * const haystack, LEX_STRING * const needle, + CHARSET_INFO * const cs) +{ + const LEX_STRING *pos; + for (pos= haystack; pos->str; pos++) + if (!cs->coll->strnncollsp(cs, (uchar *) pos->str, pos->length, + (uchar *) needle->str, needle->length, 0)) + { + return (pos - haystack); + } + return -1; +} |