1717
1717
/****************************************************************************
1718
Functions for the Field_decimal class
1719
This is an number stored as a pre-space (or pre-zero) string
1720
****************************************************************************/
1723
Field_decimal::reset(void)
1725
Field_decimal::store(STRING_WITH_LEN("0"),&my_charset_bin);
1729
void Field_decimal::overflow(bool negative)
1731
uint len=field_length;
1732
uchar *to=ptr, filler= '9';
1734
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
1739
/* Put - sign as a first digit so we'll have -999..999 or 999..999 */
1745
filler= '0'; // Fill up with 0
1749
Handle unsigned integer without zerofill, in which case
1750
the number should be of format ' 0' or ' 0.000'
1752
uint whole_part=field_length- (dec ? dec+2 : 1);
1753
// Fill with spaces up to the first digit
1754
bfill(to, whole_part, ' ');
1757
// The main code will also handle the 0 before the decimal point
1761
bfill(to, len, filler);
1763
ptr[field_length-dec-1]='.';
1768
int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs)
1770
ASSERT_COLUMN_MARKED_FOR_WRITE;
1771
char buff[STRING_BUFFER_USUAL_SIZE];
1772
String tmp(buff,sizeof(buff), &my_charset_bin);
1773
const uchar *from= (uchar*) from_arg;
1775
/* Convert character set if the old one is multi uchar */
1776
if (cs->mbmaxlen > 1)
1779
tmp.copy((char*) from, len, cs, &my_charset_bin, &dummy_errors);
1780
from= (uchar*) tmp.ptr();
1784
const uchar *end= from+len;
1785
/* The pointer where the field value starts (i.e., "where to write") */
1787
uint tmp_dec, tmp_uint;
1789
The sign of the number : will be 0 (means positive but sign not
1790
specified), '+' or '-'
1793
/* The pointers where prezeros start and stop */
1794
const uchar *pre_zeros_from, *pre_zeros_end;
1795
/* The pointers where digits at the left of '.' start and stop */
1796
const uchar *int_digits_from, *int_digits_end;
1797
/* The pointers where digits at the right of '.' start and stop */
1798
const uchar *frac_digits_from, *frac_digits_end;
1799
/* The sign of the exponent : will be 0 (means no exponent), '+' or '-' */
1800
char expo_sign_char=0;
1801
uint exponent=0; // value of the exponent
1803
Pointers used when digits move from the left of the '.' to the
1804
right of the '.' (explained below)
1806
const uchar *int_digits_tail_from= NULL;
1807
/* Number of 0 that need to be added at the left of the '.' (1E3: 3 zeros) */
1808
uint int_digits_added_zeros= 0;
1810
Pointer used when digits move from the right of the '.' to the left
1813
const uchar *frac_digits_head_end= NULL;
1814
/* Number of 0 that need to be added at the right of the '.' (for 1E-3) */
1815
uint frac_digits_added_zeros= 0;
1816
uchar *pos, *tmp_left_pos, *tmp_right_pos;
1817
/* Pointers that are used as limits (begin and end of the field buffer) */
1818
uchar *left_wall, *right_wall;
1821
To remember if table->in_use->cuted_fields has already been incremented,
1822
to do that only once
1824
bool is_cuted_fields_incr=0;
1827
There are three steps in this function :
1828
- parse the input string
1829
- modify the position of digits around the decimal dot '.'
1830
according to the exponent value (if specified)
1831
- write the formatted number
1837
/* skip pre-space */
1838
while (from != end && my_isspace(&my_charset_bin,*from))
1842
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
1843
is_cuted_fields_incr=1;
1845
else if (*from == '+' || *from == '-') // Found some sign ?
1849
We allow "+" for unsigned decimal unless defined different
1850
Both options allowed as one may wish not to have "+" for unsigned numbers
1851
because of data processing issues
1857
Field_decimal::overflow(1);
1861
Defining this will not store "+" for unsigned decimal type even if
1862
it is passed in numeric string. This will make some tests to fail
1864
#ifdef DONT_ALLOW_UNSIGNED_PLUS
1871
pre_zeros_from= from;
1872
for (; from!=end && *from == '0'; from++) ; // Read prezeros
1873
pre_zeros_end=int_digits_from=from;
1874
/* Read non zero digits at the left of '.'*/
1875
for (; from != end && my_isdigit(&my_charset_bin, *from) ; from++) ;
1876
int_digits_end=from;
1877
if (from!=end && *from == '.') // Some '.' ?
1879
frac_digits_from= from;
1880
/* Read digits at the right of '.' */
1881
for (;from!=end && my_isdigit(&my_charset_bin, *from); from++) ;
1882
frac_digits_end=from;
1883
// Some exponentiation symbol ?
1884
if (from != end && (*from == 'e' || *from == 'E'))
1887
if (from != end && (*from == '+' || *from == '-')) // Some exponent sign ?
1888
expo_sign_char= *from++;
1890
expo_sign_char= '+';
1892
Read digits of the exponent and compute its value. We must care about
1893
'exponent' overflow, because as unsigned arithmetic is "modulo", big
1894
exponents will become small (e.g. 1e4294967296 will become 1e0, and the
1895
field will finally contain 1 instead of its max possible value).
1897
for (;from!=end && my_isdigit(&my_charset_bin, *from); from++)
1899
exponent=10*exponent+(*from-'0');
1900
if (exponent>MAX_EXPONENT)
1906
We only have to generate warnings if count_cuted_fields is set.
1907
This is to avoid extra checks of the number when they are not needed.
1908
Even if this flag is not set, it's OK to increment warnings, if
1909
it makes the code easer to read.
1912
if (table->in_use->count_cuted_fields)
1915
for (;from != end && my_isspace(&my_charset_bin, *from); from++) ;
1916
if (from != end) // If still something left, warn
1918
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1);
1919
is_cuted_fields_incr=1;
1924
Now "move" digits around the decimal dot according to the exponent value,
1925
and add necessary zeros.
1927
- 1E+3 : needs 3 more zeros at the left of '.' (int_digits_added_zeros=3)
1928
- 1E-3 : '1' moves at the right of '.', and 2 more zeros are needed
1930
- 1234.5E-3 : '234' moves at the right of '.'
1931
These moves are implemented with pointers which point at the begin
1932
and end of each moved segment. Examples :
1933
- 1234.5E-3 : before the code below is executed, the int_digits part is
1934
from '1' to '4' and the frac_digits part from '5' to '5'. After the code
1935
below, the int_digits part is from '1' to '1', the frac_digits_head
1936
part is from '2' to '4', and the frac_digits part from '5' to '5'.
1937
- 1234.5E3 : before the code below is executed, the int_digits part is
1938
from '1' to '4' and the frac_digits part from '5' to '5'. After the code
1939
below, the int_digits part is from '1' to '4', the int_digits_tail
1940
part is from '5' to '5', the frac_digits part is empty, and
1941
int_digits_added_zeros=2 (to make 1234500).
1945
Below tmp_uint cannot overflow with small enough MAX_EXPONENT setting,
1946
as int_digits_added_zeros<=exponent<4G and
1947
(int_digits_end-int_digits_from)<=max_allowed_packet<=2G and
1948
(frac_digits_from-int_digits_tail_from)<=max_allowed_packet<=2G
1951
if (!expo_sign_char)
1952
tmp_uint=tmp_dec+(uint)(int_digits_end-int_digits_from);
1953
else if (expo_sign_char == '-')
1955
tmp_uint=min(exponent,(uint)(int_digits_end-int_digits_from));
1956
frac_digits_added_zeros=exponent-tmp_uint;
1957
int_digits_end -= tmp_uint;
1958
frac_digits_head_end=int_digits_end+tmp_uint;
1959
tmp_uint=tmp_dec+(uint)(int_digits_end-int_digits_from);
1961
else // (expo_sign_char=='+')
1963
tmp_uint=min(exponent,(uint)(frac_digits_end-frac_digits_from));
1964
int_digits_added_zeros=exponent-tmp_uint;
1965
int_digits_tail_from=frac_digits_from;
1966
frac_digits_from=frac_digits_from+tmp_uint;
1968
We "eat" the heading zeros of the
1969
int_digits.int_digits_tail.int_digits_added_zeros concatenation
1970
(for example 0.003e3 must become 3 and not 0003)
1972
if (int_digits_from == int_digits_end)
1975
There was nothing in the int_digits part, so continue
1976
eating int_digits_tail zeros
1978
for (; int_digits_tail_from != frac_digits_from &&
1979
*int_digits_tail_from == '0'; int_digits_tail_from++) ;
1980
if (int_digits_tail_from == frac_digits_from)
1982
// there were only zeros in int_digits_tail too
1983
int_digits_added_zeros=0;
1986
tmp_uint= (uint) (tmp_dec+(int_digits_end-int_digits_from)+
1987
(uint)(frac_digits_from-int_digits_tail_from)+
1988
int_digits_added_zeros);
1992
Now write the formated number
1994
First the digits of the int_% parts.
1995
Do we have enough room to write these digits ?
1996
If the sign is defined and '-', we need one position for it
1999
if (field_length < tmp_uint + (int) (sign_char == '-'))
2001
// too big number, change to max or min number
2002
Field_decimal::overflow(sign_char == '-');
2007
Tmp_left_pos is the position where the leftmost digit of
2008
the int_% parts will be written
2010
tmp_left_pos=pos=to+(uint)(field_length-tmp_uint);
2012
// Write all digits of the int_% parts
2013
while (int_digits_from != int_digits_end)
2014
*pos++ = *int_digits_from++ ;
2016
if (expo_sign_char == '+')
2018
while (int_digits_tail_from != frac_digits_from)
2019
*pos++= *int_digits_tail_from++;
2020
while (int_digits_added_zeros-- >0)
2024
Note the position where the rightmost digit of the int_% parts has been
2025
written (this is to later check if the int_% parts contained nothing,
2026
meaning an extra 0 is needed).
2031
Step back to the position of the leftmost digit of the int_% parts,
2032
to write sign and fill with zeros or blanks or prezeros.
2038
while (pos > left_wall) // Fill with zeros
2043
left_wall=to+(sign_char != 0)-1;
2044
if (!expo_sign_char) // If exponent was specified, ignore prezeros
2046
for (;pos > left_wall && pre_zeros_from !=pre_zeros_end;
2050
if (pos == tmp_right_pos-1)
2051
*pos--= '0'; // no 0 has ever been written, so write one
2053
if (sign_char && pos != left_wall)
2055
/* Write sign if possible (it is if sign is '-') */
2058
while (pos != left_wall)
2059
*pos--=' '; //fill with blanks
2063
Write digits of the frac_% parts ;
2064
Depending on table->in_use->count_cutted_fields, we may also want
2065
to know if some non-zero tail of these parts will
2066
be truncated (for example, 0.002->0.00 will generate a warning,
2067
while 0.000->0.00 will not)
2068
(and 0E1000000000 will not, while 1E-1000000000 will)
2071
pos=to+(uint)(field_length-tmp_dec); // Calculate post to '.'
2072
right_wall=to+field_length;
2073
if (pos != right_wall)
2076
if (expo_sign_char == '-')
2078
while (frac_digits_added_zeros-- > 0)
2080
if (pos == right_wall)
2082
if (table->in_use->count_cuted_fields && !is_cuted_fields_incr)
2083
break; // Go on below to see if we lose non zero digits
2088
while (int_digits_end != frac_digits_head_end)
2090
tmp_char= *int_digits_end++;
2091
if (pos == right_wall)
2093
if (tmp_char != '0') // Losing a non zero digit ?
2095
if (!is_cuted_fields_incr)
2096
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
2097
WARN_DATA_TRUNCATED, 1);
2106
for (;frac_digits_from!=frac_digits_end;)
2108
tmp_char= *frac_digits_from++;
2109
if (pos == right_wall)
2111
if (tmp_char != '0') // Losing a non zero digit ?
2113
if (!is_cuted_fields_incr)
2116
This is a note, not a warning, as we don't want to abort
2117
when we cut decimals in strict mode
2119
set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1);
2128
while (pos != right_wall)
2129
*pos++='0'; // Fill with zeros at right of '.'
2134
int Field_decimal::store(double nr)
2136
ASSERT_COLUMN_MARKED_FOR_WRITE;
2137
if (unsigned_flag && nr < 0)
2143
if (!isfinite(nr)) // Handle infinity as special case
2152
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
2154
fyllchar = zerofill ? (char) '0' : (char) ' ';
2155
length= my_fcvt(nr, dec, buff, NULL);
2157
if (length > field_length)
2165
for (i=field_length-length ; i-- > 0 ;)
2167
memcpy(to,buff,length);
2173
int Field_decimal::store(longlong nr, bool unsigned_val)
2175
ASSERT_COLUMN_MARKED_FOR_WRITE;
2177
uint length, int_part;
2181
if (nr < 0 && unsigned_flag && !unsigned_val)
2186
length= (uint) (longlong10_to_str(nr,buff,unsigned_val ? 10 : -10) - buff);
2187
int_part= field_length- (dec ? dec+1 : 0);
2189
if (length > int_part)
2191
overflow(!unsigned_val && nr < 0L); /* purecov: inspected */
2195
fyllchar = zerofill ? (char) '0' : (char) ' ';
2197
for (uint i=int_part-length ; i-- > 0 ;)
2199
memcpy(to,buff,length);
2203
bfill(to+length+1,dec,'0');
2209
double Field_decimal::val_real(void)
2211
ASSERT_COLUMN_MARKED_FOR_READ;
2214
return my_strntod(&my_charset_bin, (char*) ptr, field_length, &end_not_used,
2218
longlong Field_decimal::val_int(void)
2220
ASSERT_COLUMN_MARKED_FOR_READ;
2223
return my_strntoull(&my_charset_bin, (char*) ptr, field_length, 10, NULL,
2225
return my_strntoll(&my_charset_bin, (char*) ptr, field_length, 10, NULL,
2230
String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
2233
ASSERT_COLUMN_MARKED_FOR_READ;
2237
for (str=ptr ; *str == ' ' ; str++) ;
2238
val_ptr->set_charset(&my_charset_bin);
2239
tmp_length= (size_t) (str-ptr);
2240
if (field_length < tmp_length) // Error in data
2243
val_ptr->set_ascii((const char*) str, field_length-tmp_length);
2248
Should be able to handle at least the following fixed decimal formats:
2249
5.00 , -1.0, 05, -05, +5 with optional pre/end space
2252
int Field_decimal::cmp(const uchar *a_ptr,const uchar *b_ptr)
2256
/* First remove prefixes '0', ' ', and '-' */
2257
for (end=a_ptr+field_length;
2259
(*a_ptr == *b_ptr ||
2260
((my_isspace(&my_charset_bin,*a_ptr) || *a_ptr == '+' ||
2262
(my_isspace(&my_charset_bin,*b_ptr) || *b_ptr == '+' ||
2266
if (*a_ptr == '-') // If both numbers are negative
2267
swap= -1 ^ 1; // Swap result
2276
while (a_ptr != end)
2278
if (*a_ptr++ != *b_ptr++)
2279
return swap ^ (a_ptr[-1] < b_ptr[-1] ? -1 : 1); // compare digits
2285
void Field_decimal::sort_string(uchar *to,uint length)
2288
for (str=ptr,end=ptr+length;
2290
((my_isspace(&my_charset_bin,*str) || *str == '+' ||
2295
return; /* purecov: inspected */
2299
*to++=1; // Smaller than any number
2302
if (my_isdigit(&my_charset_bin,*str))
2303
*to++= (char) ('9' - *str++);
2307
else memcpy(to,str,(uint) (end-str));
2311
void Field_decimal::sql_type(String &res) const
2313
CHARSET_INFO *cs=res.charset();
2314
uint tmp=field_length;
2319
res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
2320
"decimal(%d,%d)",tmp,dec));
2321
add_zerofill_and_unsigned(res);
2325
/****************************************************************************
2326
1718
** Field_new_decimal
2327
1719
****************************************************************************/