diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 4 | ||||
-rw-r--r-- | sql/item.cc | 11 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 33 | ||||
-rw-r--r-- | sql/sql_string.cc | 38 | ||||
-rw-r--r-- | sql/sql_table.cc | 2 |
5 files changed, 69 insertions, 19 deletions
diff --git a/sql/field.cc b/sql/field.cc index 51bb527fc85..766aaba9ce1 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1836,7 +1836,9 @@ int Field::store_time(MYSQL_TIME *ltime, timestamp_type type_arg) ASSERT_COLUMN_MARKED_FOR_WRITE; char buff[MAX_DATE_STRING_REP_LENGTH]; uint length= (uint) my_TIME_to_str(ltime, buff); - return store(buff, length, &my_charset_bin); + return store(buff, length, + (charset()->state & MY_CS_NONASCII) ? + &my_charset_latin1 : &my_charset_bin); } diff --git a/sql/item.cc b/sql/item.cc index e785f0addde..e9ac44eeba8 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -854,7 +854,7 @@ Item *Item_param::safe_charset_converter(CHARSET_INFO *tocs) cnvitem->max_length= cnvitem->str_value.numchars() * tocs->mbmaxlen; return cnvitem; } - return NULL; + return Item::safe_charset_converter(tocs); } @@ -1436,7 +1436,12 @@ left_is_superset(DTCollation *left, DTCollation *right) if (left->collation->state & MY_CS_UNICODE && (left->derivation < right->derivation || (left->derivation == right->derivation && - !(right->collation->state & MY_CS_UNICODE)))) + (!(right->collation->state & MY_CS_UNICODE) || + /* The code below makes 4-byte utf8 a superset over 3-byte utf8 */ + (left->collation->state & MY_CS_UNICODE_SUPPLEMENT && + !(right->collation->state & MY_CS_UNICODE_SUPPLEMENT) && + left->collation->mbmaxlen > right->collation->mbmaxlen && + left->collation->mbminlen == right->collation->mbminlen))))) return TRUE; /* Allow convert from ASCII */ if (right->repertoire == MY_REPERTOIRE_ASCII && @@ -1695,7 +1700,7 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname, { Item* conv; uint32 dummy_offset; - if (!String::needs_conversion(0, (*arg)->collation.collation, + if (!String::needs_conversion(1, (*arg)->collation.collation, coll.collation, &dummy_offset)) continue; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index c33e0f4c6fb..1130e4c9ffc 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2371,17 +2371,27 @@ String *Item_func_char::val_str(String *str) int32 num=(int32) args[i]->val_int(); if (!args[i]->null_value) { - char char_num= (char) num; - if (num&0xFF000000L) { - str->append((char)(num>>24)); - goto b2; - } else if (num&0xFF0000L) { - b2: str->append((char)(num>>16)); - goto b1; - } else if (num&0xFF00L) { - b1: str->append((char)(num>>8)); + char tmp[4]; + if (num & 0xFF000000L) + { + mi_int4store(tmp, num); + str->append(tmp, 4, &my_charset_bin); + } + else if (num & 0xFF0000L) + { + mi_int3store(tmp, num); + str->append(tmp, 3, &my_charset_bin); + } + else if (num & 0xFF00L) + { + mi_int2store(tmp, num); + str->append(tmp, 2, &my_charset_bin); + } + else + { + tmp[0]= (char) num; + str->append(tmp, 1, &my_charset_bin); } - str->append(&char_num, 1); } } str->realloc(str->length()); // Add end 0 (for Purify) @@ -2769,7 +2779,8 @@ String *Item_func_conv_charset::val_str(String *str) void Item_func_conv_charset::fix_length_and_dec() { collation.set(conv_charset, DERIVATION_IMPLICIT); - max_length = args[0]->max_length*conv_charset->mbmaxlen; + max_length = args[0]->max_length / args[0]->collation.collation->mbmaxlen * + conv_charset->mbmaxlen; } void Item_func_conv_charset::print(String *str, enum_query_type query_type) diff --git a/sql/sql_string.cc b/sql/sql_string.cc index e4e51aba622..75e8ca30cf0 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -412,11 +412,25 @@ bool String::append(const char *s) bool String::append(const char *s,uint32 arg_length, CHARSET_INFO *cs) { - uint32 dummy_offset; + uint32 offset; - if (needs_conversion(arg_length, cs, str_charset, &dummy_offset)) + if (needs_conversion(arg_length, cs, str_charset, &offset)) { - uint32 add_length= arg_length / cs->mbminlen * str_charset->mbmaxlen; + uint32 add_length; + if ((cs == &my_charset_bin) && offset) + { + DBUG_ASSERT(str_charset->mbminlen > offset); + offset= str_charset->mbminlen - offset; // How many characters to pad + add_length= arg_length + offset; + if (realloc(str_length + add_length)) + return TRUE; + bzero((char*) Ptr + str_length, offset); + memcpy(Ptr + str_length + offset, s, arg_length); + str_length+= add_length; + return FALSE; + } + + add_length= arg_length / cs->mbminlen * str_charset->mbmaxlen; uint dummy_errors; if (realloc(str_length + add_length)) return TRUE; @@ -966,6 +980,24 @@ well_formed_copy_nchars(CHARSET_INFO *to_cs, uint pad_length= to_cs->mbminlen - from_offset; bzero(to, pad_length); memmove(to + pad_length, from, from_offset); + /* + In some cases left zero-padding can create an incorrect character. + For example: + INSERT INTO t1 (utf32_column) VALUES (0x110000); + We'll pad the value to 0x00110000, which is a wrong UTF32 sequence! + The valid characters range is limited to 0x00000000..0x0010FFFF. + + Make sure we didn't pad to an incorrect character. + */ + if (to_cs->cset->well_formed_len(to_cs, + to, to + to_cs->mbminlen, 1, + &well_formed_error) != + to_cs->mbminlen) + { + *from_end_pos= *well_formed_error_pos= from; + *cannot_convert_error_pos= NULL; + return 0; + } nchars--; from+= from_offset; from_length-= from_offset; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2e057d6a731..d154c238229 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2776,7 +2776,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, sql_field->interval_list); List_iterator<String> int_it(sql_field->interval_list); String conv, *tmp; - char comma_buf[2]; + char comma_buf[4]; /* 4 bytes for utf32 */ int comma_length= cs->cset->wc_mb(cs, ',', (uchar*) comma_buf, (uchar*) comma_buf + sizeof(comma_buf)); |