Commit 59ec3973 authored by Alexander Barkov's avatar Alexander Barkov

Removing duplicate code in double-to-longlong conversion.

Adding Converter_double_to_longlong and reusing it in:
1. Field_longlong::store(double nr)
2. Field_double::val_int()
3. Item::val_int_from_real()
4. Item_dyncol_get::val_int()
As a good side efferct, now overflow in conversion in the mentioned
val_xxx() methods return exactly the same warning.
parent b258f911
......@@ -236,7 +236,7 @@ select column_get(column_create(1, 99999999999999999999999999999 AS double), 1 a
column_get(column_create(1, 99999999999999999999999999999 AS double), 1 as unsigned int)
18446744073709551615
Warnings:
Warning 1916 Got overflow when converting '1e+29' to UNSIGNED INT. Value truncated.
Warning 1916 Got overflow when converting '1e29' to UNSIGNED INT. Value truncated.
select column_get(column_create(1, 999.9 AS double), 1 as unsigned int);
column_get(column_create(1, 999.9 AS double), 1 as unsigned int)
1000
......@@ -330,7 +330,7 @@ select column_get(column_create(1, -99999999999999999999999999999 AS double), 1
column_get(column_create(1, -99999999999999999999999999999 AS double), 1 as int)
-9223372036854775808
Warnings:
Warning 1916 Got overflow when converting '-1e+29' to INT. Value truncated.
Warning 1916 Got overflow when converting '-1e29' to INT. Value truncated.
select column_get(column_create(1, "-1212III" AS char), 1 as int);
column_get(column_create(1, "-1212III" AS char), 1 as int)
-1212
......
......@@ -2151,7 +2151,7 @@ CREATE TABLE t1 (a DOUBLE);
INSERT INTO t1 VALUES (9e100);
ALTER TABLE t1 MODIFY a ENUM('9e200','9e100');
Warnings:
Warning 1292 Truncated incorrect INTEGER value: '9e100'
Warning 1916 Got overflow when converting '9e100' to INT. Value truncated.
Warning 1265 Data truncated for column 'a' at row 1
SELECT * FROM t1;
a
......
......@@ -4288,16 +4288,13 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_longlong::store(double nr)
{
ASSERT_COLUMN_MARKED_FOR_WRITE_OR_COMPUTED;
bool error;
longlong res;
Converter_double_to_longlong conv(nr, unsigned_flag);
res= double_to_longlong(nr, unsigned_flag, &error);
if (error)
if (conv.error())
set_warning(ER_WARN_DATA_OUT_OF_RANGE, 1);
int8store(ptr,res);
return error;
int8store(ptr, conv.result());
return conv.error();
}
......@@ -4698,53 +4695,61 @@ int truncate_double(double *nr, uint field_length, uint dec,
/*
Convert double to longlong / ulonglong.
If double is outside of range, adjust return value and set error.
If double is outside of the supported range,
adjust m_result and set m_error.
SYNOPSIS
double_to_longlong()
nr Number to convert
unsigned_flag 1 if result is unsigned
error Will be set to 1 in case of overflow.
@param nr Number to convert
@param unsigned_flag true if result is unsigned
*/
longlong double_to_longlong(double nr, bool unsigned_flag, bool *error)
Value_source::
Converter_double_to_longlong::Converter_double_to_longlong(double nr,
bool unsigned_flag)
:m_error(false)
{
longlong res;
*error= 0;
nr= rint(nr);
if (unsigned_flag)
{
if (nr < 0)
{
res= 0;
*error= 1;
m_result= 0;
m_error= true;
}
else if (nr >= (double) ULONGLONG_MAX)
{
res= ~(longlong) 0;
*error= 1;
m_result= ~(longlong) 0;
m_error= true;
}
else
res= (longlong) double2ulonglong(nr);
m_result= (longlong) double2ulonglong(nr);
}
else
{
if (nr <= (double) LONGLONG_MIN)
{
res= LONGLONG_MIN;
*error= (nr < (double) LONGLONG_MIN);
m_result= LONGLONG_MIN;
m_error= (nr < (double) LONGLONG_MIN);
}
else if (nr >= (double) (ulonglong) LONGLONG_MAX)
{
res= LONGLONG_MAX;
*error= (nr > (double) LONGLONG_MAX);
m_result= LONGLONG_MAX;
m_error= (nr > (double) LONGLONG_MAX);
}
else
res= (longlong) nr;
m_result= (longlong) nr;
}
return res;
}
void Value_source::
Converter_double_to_longlong::push_warning(THD *thd,
double nr,
bool unsigned_flag)
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_DATA_OVERFLOW, ER_THD(thd, ER_DATA_OVERFLOW),
ErrConvDouble(nr).ptr(),
unsigned_flag ? "UNSIGNED INT" : "INT");
}
......@@ -4769,27 +4774,6 @@ double Field_double::val_real(void)
return j;
}
longlong Field_double::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
double j;
longlong res;
bool error;
float8get(j,ptr);
res= double_to_longlong(j, 0, &error);
if (error)
{
THD *thd= get_thd();
ErrConvDouble err(j);
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER_THD(thd, ER_TRUNCATED_WRONG_VALUE), "INTEGER",
err.ptr());
}
return res;
}
my_decimal *Field_real::val_decimal(my_decimal *decimal_value)
{
......
......@@ -80,6 +80,35 @@ class Value_source
Warn_filter_all() :Warn_filter(true, true) { }
};
class Converter_double_to_longlong
{
protected:
bool m_error;
longlong m_result;
public:
Converter_double_to_longlong(double nr, bool unsigned_flag);
longlong result() const { return m_result; }
bool error() const { return m_error; }
void push_warning(THD *thd, double nr, bool unsigned_flag);
};
class Converter_double_to_longlong_with_warn:
public Converter_double_to_longlong
{
public:
Converter_double_to_longlong_with_warn(THD *thd, double nr,
bool unsigned_flag)
:Converter_double_to_longlong(nr, unsigned_flag)
{
if (m_error)
push_warning(thd, nr, unsigned_flag);
}
Converter_double_to_longlong_with_warn(double nr, bool unsigned_flag)
:Converter_double_to_longlong(nr, unsigned_flag)
{
if (m_error)
push_warning(current_thd, nr, unsigned_flag);
}
};
// String-to-number converters
class Converter_string_to_number
......@@ -406,7 +435,6 @@ struct st_cache_field;
int field_conv(Field *to,Field *from);
int truncate_double(double *nr, uint field_length, uint dec,
bool unsigned_flag, double max_value);
longlong double_to_longlong(double nr, bool unsigned_flag, bool *error);
inline uint get_enum_pack_length(int elements)
{
......@@ -2148,7 +2176,13 @@ class Field_double :public Field_real {
int store(longlong nr, bool unsigned_val);
int reset(void) { bzero(ptr,sizeof(double)); return 0; }
double val_real(void);
longlong val_int(void);
longlong val_int(void)
{
Converter_double_to_longlong conv(Field_double::val_real(), false);
if (conv.error())
conv.push_warning(get_thd(), Field_double::val_real(), false);
return conv.result();
}
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
int cmp(const uchar *,const uchar *);
......
......@@ -374,14 +374,6 @@ longlong Item::val_int_from_date()
}
longlong Item::val_int_from_real()
{
DBUG_ASSERT(fixed == 1);
bool error;
return double_to_longlong(val_real(), false /*unsigned_flag*/, &error);
}
double Item::val_real_from_date()
{
DBUG_ASSERT(fixed == 1);
......
......@@ -1041,7 +1041,11 @@ class Item: public Value_source,
my_decimal *val_decimal_from_time(my_decimal *decimal_value);
longlong val_int_from_decimal();
longlong val_int_from_date();
longlong val_int_from_real();
longlong val_int_from_real()
{
DBUG_ASSERT(fixed == 1);
return Converter_double_to_longlong_with_warn(val_real(), false).result();
}
longlong val_int_from_str(int *error);
double val_real_from_decimal();
double val_real_from_date();
......
......@@ -4960,23 +4960,8 @@ longlong Item_dyncol_get::val_int()
unsigned_flag= 0; // Make it possible for caller to detect sign
return val.x.long_value;
case DYN_COL_DOUBLE:
{
bool error;
longlong num;
num= double_to_longlong(val.x.double_value, unsigned_flag, &error);
if (error)
{
char buff[30];
sprintf(buff, "%lg", val.x.double_value);
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_DATA_OVERFLOW,
ER_THD(thd, ER_DATA_OVERFLOW),
buff,
unsigned_flag ? "UNSIGNED INT" : "INT");
}
return num;
}
return Converter_double_to_longlong_with_warn(thd, val.x.double_value,
unsigned_flag).result();
case DYN_COL_STRING:
{
int error;
......
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