Commit ab8bd02b authored by Tor Didriksen's avatar Tor Didriksen

Bug#18315770 BUG#12368495 FIX IS INCOMPLETE

Item_func_ltrim::val_str did not handle multibyte charsets.
Fix: factor out common code for Item_func_trim and Item_func_ltrim.
parent 2dbebf77
/* /*
Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -1588,6 +1588,42 @@ String *Item_func_substr_index::val_str(String *str) ...@@ -1588,6 +1588,42 @@ String *Item_func_substr_index::val_str(String *str)
return (&tmp_value); return (&tmp_value);
} }
/**
A helper function for trim(leading ...) for multibyte charsets.
@param res Copy of 'res' in calling functions.
@param ptr Where to start trimming.
@param end End of string to be trimmed.
@param remove_str The string to be removed from [ptr .. end)
@return Pointer to left-trimmed string.
*/
static inline
char *trim_left_mb(String *res, char *ptr, char *end, String *remove_str)
{
const char * const r_ptr= remove_str->ptr();
const uint remove_length= remove_str->length();
while (ptr + remove_length <= end)
{
uint num_bytes= 0;
while (num_bytes < remove_length)
{
uint len;
if ((len= my_ismbchar(res->charset(), ptr + num_bytes, end)))
num_bytes+= len;
else
++num_bytes;
}
if (num_bytes != remove_length)
break;
if (memcmp(ptr, r_ptr, remove_length))
break;
ptr+= remove_length;
}
return ptr;
}
/* /*
** The trim functions are extension to ANSI SQL because they trim substrings ** The trim functions are extension to ANSI SQL because they trim substrings
** They ltrim() and rtrim() functions are optimized for 1 byte strings ** They ltrim() and rtrim() functions are optimized for 1 byte strings
...@@ -1622,19 +1658,28 @@ String *Item_func_ltrim::val_str(String *str) ...@@ -1622,19 +1658,28 @@ String *Item_func_ltrim::val_str(String *str)
ptr= (char*) res->ptr(); ptr= (char*) res->ptr();
end= ptr+res->length(); end= ptr+res->length();
if (remove_length == 1) #ifdef USE_MB
if (use_mb(res->charset()))
{ {
char chr=(*remove_str)[0]; ptr= trim_left_mb(res, ptr, end, remove_str);
while (ptr != end && *ptr == chr)
ptr++;
} }
else else
#endif /* USE_MB */
{ {
const char *r_ptr=remove_str->ptr(); if (remove_length == 1)
end-=remove_length; {
while (ptr <= end && !memcmp(ptr, r_ptr, remove_length)) char chr=(*remove_str)[0];
ptr+=remove_length; while (ptr != end && *ptr == chr)
end+=remove_length; ptr++;
}
else
{
const char *r_ptr=remove_str->ptr();
end-=remove_length;
while (ptr <= end && !memcmp(ptr, r_ptr, remove_length))
ptr+=remove_length;
end+=remove_length;
}
} }
if (ptr == res->ptr()) if (ptr == res->ptr())
return res; return res;
...@@ -1728,11 +1773,8 @@ String *Item_func_trim::val_str(String *str) ...@@ -1728,11 +1773,8 @@ String *Item_func_trim::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
char buff[MAX_FIELD_WIDTH], *ptr, *end; char buff[MAX_FIELD_WIDTH], *ptr, *end;
const char *r_ptr;
String tmp(buff, sizeof(buff), system_charset_info); String tmp(buff, sizeof(buff), system_charset_info);
String *res, *remove_str; String *res, *remove_str;
uint remove_length;
LINT_INIT(remove_length);
res= args[0]->val_str(str); res= args[0]->val_str(str);
if ((null_value=args[0]->null_value)) if ((null_value=args[0]->null_value))
...@@ -1745,33 +1787,19 @@ String *Item_func_trim::val_str(String *str) ...@@ -1745,33 +1787,19 @@ String *Item_func_trim::val_str(String *str)
return 0; return 0;
} }
if ((remove_length= remove_str->length()) == 0 || const uint remove_length= remove_str->length();
if (remove_length == 0 ||
remove_length > res->length()) remove_length > res->length())
return res; return res;
ptr= (char*) res->ptr(); ptr= (char*) res->ptr();
end= ptr+res->length(); end= ptr+res->length();
r_ptr= remove_str->ptr(); const char * const r_ptr= remove_str->ptr();
#ifdef USE_MB #ifdef USE_MB
if (use_mb(res->charset())) if (use_mb(res->charset()))
{ {
while (ptr + remove_length <= end) ptr= trim_left_mb(res, ptr, end, remove_str);
{
uint num_bytes= 0;
while (num_bytes < remove_length)
{
uint len;
if ((len= my_ismbchar(res->charset(), ptr + num_bytes, end)))
num_bytes+= len;
else
++num_bytes;
}
if (num_bytes != remove_length)
break;
if (memcmp(ptr, r_ptr, remove_length))
break;
ptr+= remove_length;
}
char *p=ptr; char *p=ptr;
register uint32 l; register uint32 l;
loop: loop:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment