diff options
Diffstat (limited to 'sql/field.cc')
-rw-r--r-- | sql/field.cc | 144 |
1 files changed, 116 insertions, 28 deletions
diff --git a/sql/field.cc b/sql/field.cc index c96a5a6d809..5356fbc773a 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -46,6 +46,8 @@ template class List_iterator<create_field>; uchar Field_null::null[1]={1}; const char field_separator=','; +#define DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE 320 + /***************************************************************************** Static help functions *****************************************************************************/ @@ -876,7 +878,7 @@ int Field_decimal::store(double nr) reg4 uint i,length; char fyllchar,*to; - char buff[320]; + char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; fyllchar = zerofill ? (char) '0' : (char) ' '; #ifdef HAVE_SNPRINTF @@ -1758,6 +1760,7 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs) len-= tmp; from+= tmp; my_errno=0; + if (unsigned_flag) { if (!len || *from == '-') @@ -1774,6 +1777,34 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs) if (error || (from+len != end && table->in_use->count_cuted_fields && !test_if_int(from,len,end,cs))) + error= 1; +#if SIZEOF_LONG > 4 + if (unsigned_flag) + { + if ((ulong) tmp > UINT_MAX32) + { + tmp= UINT_MAX32; + error= 1; + my_errno=ERANGE; + } + } + else + { + if (tmp > INT_MAX32) + { + tmp= INT_MAX32; + error= 1; + my_errno=ERANGE; + } + else if (tmp < INT_MIN32) + { + tmp= INT_MIN32; + error= 1; + my_errno=ERANGE; + } + } +#endif + if (error) { set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, 1); error= 1; @@ -2695,7 +2726,7 @@ String *Field_double::val_str(String *val_buffer, #endif doubleget(nr,ptr); - uint to_length=max(field_length,320); + uint to_length=max(field_length, DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE); val_buffer->alloc(to_length); char *to=(char*) val_buffer->ptr(); @@ -2707,7 +2738,8 @@ String *Field_double::val_str(String *val_buffer, else { #ifdef HAVE_FCONVERT - char buff[320],*pos=buff; + char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; + char *pos= buff; int decpt,sign,tmp_dec=dec; VOID(fconvert(nr,tmp_dec,&decpt,&sign,buff)); @@ -2877,7 +2909,8 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg, :Field_str(ptr_arg, 19, (uchar*) 0,0, unireg_check_arg, field_name_arg, table_arg, cs) { - flags|=ZEROFILL_FLAG; /* 4.0 MYD compatibility */ + /* For 4.0 MYD and 4.0 InnoDB compatibility */ + flags|= ZEROFILL_FLAG | UNSIGNED_FLAG; if (table && !table->timestamp_field && unireg_check != NONE) { @@ -4231,13 +4264,40 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) } -int Field_string::store(double nr) +/* + Store double value in Field_string or Field_varstring. + + SYNOPSIS + store(double nr) + nr number + + DESCRIPTION + Pretty prints double number into field_length characters buffer. +*/ + +int Field_str::store(double nr) { - char buff[MAX_FIELD_WIDTH],*end; - int width=min(field_length,DBL_DIG+5); - sprintf(buff,"%-*.*g",width,max(width-5,0),nr); - end=strcend(buff,' '); - return Field_string::store(buff,(uint) (end - buff), &my_charset_bin); + char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; + uint length; + bool use_scientific_notation= TRUE; + use_scientific_notation= TRUE; +if (field_length < 32 && fabs(nr) < log_10[field_length]-1) + use_scientific_notation= FALSE; + length= (uint) my_sprintf(buff, (buff, "%-.*g", + (use_scientific_notation ? + max(0, (int)field_length-5) : + field_length), + nr)); + /* + +1 below is because "precision" in %g above means the + max. number of significant digits, not the output width. + Thus the width can be larger than number of significant digits by 1 + (for decimal point) + the test for field_length < 5 is for extreme cases, + like inserting 500.0 in char(1) + */ + DBUG_ASSERT(field_length < 5 || length <= field_length+1); + return store((const char *)buff, min(length, field_length), charset()); } @@ -4313,7 +4373,7 @@ void Field_string::sql_type(String &res) const (field_length > 3 && (table->db_options_in_use & HA_OPTION_PACK_RECORD) ? - (has_charset() ? "varchar" : "varbinary") : + (has_charset() ? "varchar" : "varbinary") : (has_charset() ? "char" : "binary")), (int) field_length / charset()->mbmaxlen); res.length(length); @@ -4332,6 +4392,21 @@ char *Field_string::pack(char *to, const char *from, uint max_length) } +char *Field_string::pack_key(char *to, const char *from, uint max_length) +{ + uint length= min(field_length,max_length); + uint char_length= max_length/field_charset->mbmaxlen; + if (length > char_length) + char_length= my_charpos(field_charset, from, from+length, char_length); + set_if_smaller(length, char_length); + while (length && from[length-1] == ' ') + length--; + *to= (uchar)length; + memcpy(to+1, from, length); + return to+1+length; +} + + const char *Field_string::unpack(char *to, const char *from) { uint length= (uint) (uchar) *from++; @@ -4409,16 +4484,6 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) } -int Field_varstring::store(double nr) -{ - char buff[MAX_FIELD_WIDTH],*end; - int width=min(field_length,DBL_DIG+5); - sprintf(buff,"%-*.*g",width,max(width-5,0),nr); - end=strcend(buff,' '); - return Field_varstring::store(buff,(uint) (end - buff), &my_charset_bin); -} - - int Field_varstring::store(longlong nr) { char buff[64]; @@ -4505,6 +4570,24 @@ char *Field_varstring::pack(char *to, const char *from, uint max_length) } +char *Field_varstring::pack_key(char *to, const char *from, uint max_length) +{ + uint length=uint2korr(from); + uint char_length= (field_charset->mbmaxlen > 1) ? + max_length/field_charset->mbmaxlen : max_length; + from+=HA_KEY_BLOB_LENGTH; + if (length > char_length) + char_length= my_charpos(field_charset, from, from+length, char_length); + set_if_smaller(length, char_length); + *to++= (char) (length & 255); + if (max_length > 255) + *to++= (char) (length >> 8); + if (length) + memcpy(to, from, length); + return to+length; +} + + const char *Field_varstring::unpack(char *to, const char *from) { uint length; @@ -5080,16 +5163,17 @@ char *Field_blob::pack_key(char *to, const char *from, uint max_length) char *save=ptr; ptr=(char*) from; uint32 length=get_length(); // Length of from string - if (length > max_length) - length=max_length; + uint char_length= (field_charset->mbmaxlen > 1) ? + max_length/field_charset->mbmaxlen : max_length; + if (length) + get_ptr((char**) &from); + if (length > char_length) + char_length= my_charpos(field_charset, from, from+length, char_length); + set_if_smaller(length, char_length); *to++= (uchar) length; if (max_length > 255) // 2 byte length *to++= (uchar) (length >> 8); - if (length) - { - get_ptr((char**) &from); - memcpy(to, from, length); - } + memcpy(to, from, length); ptr=save; // Restore org row pointer return to+length; } @@ -5666,6 +5750,10 @@ void create_field::create_length_to_internal_length(void) pack_length= calc_pack_length(sql_type == FIELD_TYPE_VAR_STRING ? FIELD_TYPE_STRING : sql_type, length); break; + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + length*= charset->mbmaxlen; + break; default: /* do nothing */ break; |