diff options
Diffstat (limited to 'sql/field.cc')
-rw-r--r-- | sql/field.cc | 200 |
1 files changed, 125 insertions, 75 deletions
diff --git a/sql/field.cc b/sql/field.cc index d8db3fdbae4..64ad2dc180e 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1016,6 +1016,36 @@ Item_result Field::result_merge_type(enum_field_types field_type) Static help functions *****************************************************************************/ +/** + Output a warning for erroneous conversion of strings to numerical + values. For use with ER_TRUNCATED_WRONG_VALUE[_FOR_FIELD] + + @param thd THD object + @param str pointer to string that failed to be converted + @param length length of string + @param cs charset for string + @param typestr string describing type converted to + @param error error value to output + @param field_name (for *_FOR_FIELD) name of field + @param row_num (for *_FOR_FIELD) row number + */ +static void push_numerical_conversion_warning(THD* thd, const char* str, + uint length, CHARSET_INFO* cs, + const char* typestr, int error, + const char* field_name="UNKNOWN", + ulong row_num=0) +{ + char buf[max(max(DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE, + LONGLONG_TO_STRING_CONVERSION_BUFFER_SIZE), + DECIMAL_TO_STRING_CONVERSION_BUFFER_SIZE)]; + + String tmp(buf, sizeof(buf), cs); + tmp.copy(str, length, cs); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + error, ER(error), typestr, tmp.c_ptr(), + field_name, row_num); +} + /** Check whether a field type can be partially indexed by a key. @@ -1109,14 +1139,12 @@ int Field_num::check_int(CHARSET_INFO *cs, const char *str, int length, /* Test if we get an empty string or wrong integer */ if (str == int_end || error == MY_ERRNO_EDOM) { - char buff[128]; - String tmp(buff, (uint32) sizeof(buff), system_charset_info); - tmp.copy(str, length, system_charset_info); + ErrConvString err(str, length, cs); push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), - "integer", tmp.c_ptr(), field_name, - (ulong) table->in_use->row_count); + "integer", err.ptr(), field_name, + (ulong) table->in_use->warning_info->current_row_for_warning()); return 1; } /* Test if we have garbage at the end of the given string. */ @@ -1529,7 +1557,12 @@ void Field::make_field(Send_field *field) if (orig_table && orig_table->s->db.str && *orig_table->s->db.str) { field->db_name= orig_table->s->db.str; - field->org_table_name= orig_table->s->table_name.str; + if (orig_table->pos_in_table_list && + orig_table->pos_in_table_list->schema_table) + field->org_table_name= (orig_table->pos_in_table_list-> + schema_table->table_name); + else + field->org_table_name= orig_table->s->table_name.str; } else field->org_table_name= field->db_name= ""; @@ -1772,7 +1805,7 @@ bool Field::optimize_range(uint idx, uint part) } -Field *Field::new_field(MEM_ROOT *root, struct st_table *new_table, +Field *Field::new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type __attribute__((unused))) { Field *tmp; @@ -1793,7 +1826,7 @@ Field *Field::new_field(MEM_ROOT *root, struct st_table *new_table, } -Field *Field::new_key_field(MEM_ROOT *root, struct st_table *new_table, +Field *Field::new_key_field(MEM_ROOT *root, TABLE *new_table, uchar *new_ptr, uchar *new_null_ptr, uint new_null_bit) { @@ -1810,7 +1843,7 @@ Field *Field::new_key_field(MEM_ROOT *root, struct st_table *new_table, /* This is used to generate a field in TABLE from TABLE_SHARE */ -Field *Field::clone(MEM_ROOT *root, struct st_table *new_table) +Field *Field::clone(MEM_ROOT *root, TABLE *new_table) { Field *tmp; if ((tmp= (Field*) memdup_root(root,(char*) this,size_of()))) @@ -2633,15 +2666,12 @@ int Field_new_decimal::store(const char *from, uint length, &decimal_value)) && table->in_use->abort_on_warning) { - /* Because "from" is not NUL-terminated and we use %s in the ER() */ - String from_as_str; - from_as_str.copy(from, length, &my_charset_bin); - - push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_ERROR, + ErrConvString errmsg(from, length, &my_charset_bin); + push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), - "decimal", from_as_str.c_ptr(), field_name, - (ulong) table->in_use->row_count); + "decimal", errmsg.ptr(), field_name, + (ulong) table->in_use->warning_info->current_row_for_warning()); DBUG_RETURN(err); } @@ -2656,18 +2686,15 @@ int Field_new_decimal::store(const char *from, uint length, break; case E_DEC_BAD_NUM: { - /* Because "from" is not NUL-terminated and we use %s in the ER() */ - String from_as_str; - from_as_str.copy(from, length, &my_charset_bin); - - push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, - ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), - "decimal", from_as_str.c_ptr(), field_name, - (ulong) table->in_use->row_count); - my_decimal_set_zero(&decimal_value); - - break; + ErrConvString errmsg(from, length, &my_charset_bin); + push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, + ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), + "decimal", errmsg.ptr(), field_name, + (ulong) table->in_use->warning_info-> + current_row_for_warning()); + my_decimal_set_zero(&decimal_value); + break; } } @@ -4528,10 +4555,11 @@ warn: char buf[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; String tmp(buf, sizeof(buf), &my_charset_latin1), *str; str= val_str(&tmp, 0); + ErrConvString err(str); push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_TRUNCATED_WRONG_VALUE, ER(ER_TRUNCATED_WRONG_VALUE), "INTEGER", - str->c_ptr()); + err.ptr()); } return res; } @@ -5317,7 +5345,7 @@ bool Field_time::get_date(MYSQL_TIME *ltime, uint fuzzydate) push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, ER(ER_WARN_DATA_OUT_OF_RANGE), field_name, - thd->row_count); + thd->warning_info->current_row_for_warning()); return 1; } tmp=(long) sint3korr(ptr); @@ -6311,21 +6339,20 @@ check_string_copy_error(Field_str *field, { const char *pos; char tmp[32]; - + THD *thd= field->table->in_use; + if (!(pos= well_formed_error_pos) && !(pos= cannot_convert_error_pos)) return FALSE; convert_to_printable(tmp, sizeof(tmp), pos, (end - pos), cs, 6); - push_warning_printf(field->table->in_use, - field->table->in_use->abort_on_warning ? - MYSQL_ERROR::WARN_LEVEL_ERROR : + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, + ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), "string", tmp, field->field_name, - (ulong) field->table->in_use->row_count); + thd->warning_info->current_row_for_warning()); return TRUE; } @@ -6359,7 +6386,7 @@ Field_longstr::report_if_important_data(const char *ptr, const char *end, if (test_if_important_data(field_charset, ptr, end)) { if (table->in_use->abort_on_warning) - set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1); else set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); return 2; @@ -6559,13 +6586,11 @@ double Field_string::val_real(void) !check_if_only_end_space(cs, end, (char*) ptr + field_length)))) { - char buf[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; - String tmp(buf, sizeof(buf), cs); - tmp.copy((char*) ptr, field_length, cs); + ErrConvString err((char*) ptr, field_length, cs); push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TRUNCATED_WRONG_VALUE, - ER(ER_TRUNCATED_WRONG_VALUE), - "DOUBLE", tmp.c_ptr()); + ER_TRUNCATED_WRONG_VALUE, + ER(ER_TRUNCATED_WRONG_VALUE), "DOUBLE", + err.ptr()); } return result; } @@ -6585,13 +6610,11 @@ longlong Field_string::val_int(void) !check_if_only_end_space(cs, end, (char*) ptr + field_length)))) { - char buf[LONGLONG_TO_STRING_CONVERSION_BUFFER_SIZE]; - String tmp(buf, sizeof(buf), cs); - tmp.copy((char*) ptr, field_length, cs); + ErrConvString err((char*) ptr, field_length, cs); push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_TRUNCATED_WRONG_VALUE, ER(ER_TRUNCATED_WRONG_VALUE), - "INTEGER", tmp.c_ptr()); + "INTEGER", err.ptr()); } return result; } @@ -6623,14 +6646,11 @@ my_decimal *Field_string::val_decimal(my_decimal *decimal_value) charset(), decimal_value); if (!table->in_use->no_errors && err) { - char buf[DECIMAL_TO_STRING_CONVERSION_BUFFER_SIZE]; - CHARSET_INFO *cs= charset(); - String tmp(buf, sizeof(buf), cs); - tmp.copy((char*) ptr, field_length, cs); + ErrConvString errmsg((char*) ptr, field_length, charset()); push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_TRUNCATED_WRONG_VALUE, ER(ER_TRUNCATED_WRONG_VALUE), - "DECIMAL", tmp.c_ptr()); + "DECIMAL", errmsg.ptr()); } return decimal_value; @@ -6693,9 +6713,8 @@ int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr) void Field_string::sort_string(uchar *to,uint length) { - IF_DBUG(uint tmp=) my_strnxfrm(field_charset, - to, length, - ptr, field_length); + uint tmp __attribute__((unused))= + my_strnxfrm(field_charset, to, length, ptr, field_length); DBUG_ASSERT(tmp == length); } @@ -6951,7 +6970,7 @@ uint Field_string::get_key_image(uchar *buff, uint length, imagetype type_arg) } -Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table, +Field *Field_string::new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type) { Field *field; @@ -7062,22 +7081,46 @@ int Field_varstring::store(longlong nr, bool unsigned_val) double Field_varstring::val_real(void) { ASSERT_COLUMN_MARKED_FOR_READ; - int not_used; - char *end_not_used; + int error; + char *end; + double result; + CHARSET_INFO* cs= charset(); + uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr); - return my_strntod(field_charset, (char*) ptr+length_bytes, length, - &end_not_used, ¬_used); + result= my_strntod(cs, (char*)ptr+length_bytes, length, &end, &error); + + if (!table->in_use->no_errors && + (error || (length != (uint)(end - (char*)ptr+length_bytes) && + !check_if_only_end_space(cs, end, (char*)ptr+length_bytes+length)))) + { + push_numerical_conversion_warning(current_thd, (char*)ptr+length_bytes, + length, cs,"DOUBLE", + ER_TRUNCATED_WRONG_VALUE); + } + return result; } longlong Field_varstring::val_int(void) { ASSERT_COLUMN_MARKED_FOR_READ; - int not_used; - char *end_not_used; + int error; + char *end; + CHARSET_INFO *cs= charset(); + uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr); - return my_strntoll(field_charset, (char*) ptr+length_bytes, length, 10, - &end_not_used, ¬_used); + longlong result= my_strntoll(cs, (char*) ptr+length_bytes, length, 10, + &end, &error); + + if (!table->in_use->no_errors && + (error || (length != (uint)(end - (char*)ptr+length_bytes) && + !check_if_only_end_space(cs, end, (char*)ptr+length_bytes+length)))) + { + push_numerical_conversion_warning(current_thd, (char*)ptr+length_bytes, + length, cs, "INTEGER", + ER_TRUNCATED_WRONG_VALUE); + } + return result; } String *Field_varstring::val_str(String *val_buffer __attribute__((unused)), @@ -7093,9 +7136,17 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)), my_decimal *Field_varstring::val_decimal(my_decimal *decimal_value) { ASSERT_COLUMN_MARKED_FOR_READ; + CHARSET_INFO *cs= charset(); uint length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr); - str2my_decimal(E_DEC_FATAL_ERROR, (char*) ptr+length_bytes, length, - charset(), decimal_value); + int error= str2my_decimal(E_DEC_FATAL_ERROR, (char*) ptr+length_bytes, length, + cs, decimal_value); + + if (!table->in_use->no_errors && error) + { + push_numerical_conversion_warning(current_thd, (char*)ptr+length_bytes, + length, cs, "DECIMAL", + ER_TRUNCATED_WRONG_VALUE); + } return decimal_value; } @@ -7497,7 +7548,7 @@ int Field_varstring::cmp_binary(const uchar *a_ptr, const uchar *b_ptr, } -Field *Field_varstring::new_field(MEM_ROOT *root, struct st_table *new_table, +Field *Field_varstring::new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type) { Field_varstring *res= (Field_varstring*) Field::new_field(root, new_table, @@ -7509,7 +7560,7 @@ Field *Field_varstring::new_field(MEM_ROOT *root, struct st_table *new_table, Field *Field_varstring::new_key_field(MEM_ROOT *root, - struct st_table *new_table, + TABLE *new_table, uchar *new_ptr, uchar *new_null_ptr, uint new_null_bit) { @@ -8638,7 +8689,7 @@ void Field_enum::sql_type(String &res) const } -Field *Field_enum::new_field(MEM_ROOT *root, struct st_table *new_table, +Field *Field_enum::new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type) { Field_enum *res= (Field_enum*) Field::new_field(root, new_table, keep_type); @@ -8979,7 +9030,7 @@ Field_bit::do_last_null_byte() const Field *Field_bit::new_key_field(MEM_ROOT *root, - struct st_table *new_table, + TABLE *new_table, uchar *new_ptr, uchar *new_null_ptr, uint new_null_bit) { @@ -9020,7 +9071,7 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs) set_rec_bits((1 << bit_len) - 1, bit_ptr, bit_ofs, bit_len); memset(ptr, 0xff, bytes_in_rec); if (table->in_use->really_abort_on_warning()) - set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1); else set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); return 1; @@ -9431,7 +9482,7 @@ int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs) if (bits) *ptr&= ((1 << bits) - 1); /* set first uchar */ if (table->in_use->really_abort_on_warning()) - set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1); else set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); return 1; @@ -9818,8 +9869,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, break; case MYSQL_TYPE_DATE: /* Old date type. */ - if (protocol_version != PROTOCOL_VERSION-1) - sql_type= MYSQL_TYPE_NEWDATE; + sql_type= MYSQL_TYPE_NEWDATE; /* fall trough */ case MYSQL_TYPE_NEWDATE: length= MAX_DATE_WIDTH; @@ -10314,7 +10364,7 @@ Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code, { thd->cuted_fields+= cuted_increment; push_warning_printf(thd, level, code, ER(code), field_name, - thd->row_count); + thd->warning_info->current_row_for_warning()); return 0; } return level >= MYSQL_ERROR::WARN_LEVEL_WARN; |