Commit cfebaf44 authored by Alexey Kopytov's avatar Alexey Kopytov

Automerge.

parents 59d239e1 2d4df13e
......@@ -1524,10 +1524,10 @@ Warnings:
Warning 1264 Out of range value for column 'f1' at row 1
DESC t1;
Field Type Null Key Default Extra
f1 decimal(59,30) NO 0.000000000000000000000000000000
f1 decimal(65,30) NO 0.000000000000000000000000000000
SELECT f1 FROM t1;
f1
99999999999999999999999999999.999999999999999999999999999999
99999999999999999999999999999999999.999999999999999999999999999999
DROP TABLE t1;
select (1.20396873 * 0.89550000 * 0.68000000 * 1.08721696 * 0.99500000 *
1.01500000 * 1.01500000 * 0.99500000);
......@@ -1577,3 +1577,56 @@ Error 1264 Out of range value for column 'cast(-13.4 as decimal(2,1))' at row 1
select cast(98.6 as decimal(2,0));
cast(98.6 as decimal(2,0))
99
#
# Bug #45262: Bad effects with CREATE TABLE and DECIMAL
#
CREATE TABLE t1 SELECT .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
Warnings:
Note 1265 Data truncated for column 'my_col' at row 1
DESCRIBE t1;
Field Type Null Key Default Extra
my_col decimal(30,30) NO 0.000000000000000000000000000000
SELECT my_col FROM t1;
my_col
0.123456789123456789123456789123
DROP TABLE t1;
CREATE TABLE t1 SELECT 1 + .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
Warnings:
Note 1265 Data truncated for column 'my_col' at row 1
DESCRIBE t1;
Field Type Null Key Default Extra
my_col decimal(65,30) NO 0.000000000000000000000000000000
SELECT my_col FROM t1;
my_col
1.123456789123456789123456789123
DROP TABLE t1;
CREATE TABLE t1 SELECT 1 * .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
Warnings:
Note 1265 Data truncated for column 'my_col' at row 1
DESCRIBE t1;
Field Type Null Key Default Extra
my_col decimal(65,30) NO 0.000000000000000000000000000000
SELECT my_col FROM t1;
my_col
0.123456789123456789123456789123
DROP TABLE t1;
CREATE TABLE t1 SELECT 1 / .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
Warnings:
Note 1265 Data truncated for column 'my_col' at row 1
DESCRIBE t1;
Field Type Null Key Default Extra
my_col decimal(65,4) YES NULL
SELECT my_col FROM t1;
my_col
8.1000
DROP TABLE t1;
CREATE TABLE t1 SELECT 1 % .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
Warnings:
Note 1265 Data truncated for column 'my_col' at row 1
DESCRIBE t1;
Field Type Null Key Default Extra
my_col decimal(65,30) YES NULL
SELECT my_col FROM t1;
my_col
0.012345687012345687012345687012
DROP TABLE t1;
......@@ -1257,3 +1257,32 @@ select cast(-3.4 as decimal(2,1));
select cast(99.6 as decimal(2,0));
select cast(-13.4 as decimal(2,1));
select cast(98.6 as decimal(2,0));
--echo #
--echo # Bug #45262: Bad effects with CREATE TABLE and DECIMAL
--echo #
CREATE TABLE t1 SELECT .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
DESCRIBE t1;
SELECT my_col FROM t1;
DROP TABLE t1;
CREATE TABLE t1 SELECT 1 + .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
DESCRIBE t1;
SELECT my_col FROM t1;
DROP TABLE t1;
CREATE TABLE t1 SELECT 1 * .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
DESCRIBE t1;
SELECT my_col FROM t1;
DROP TABLE t1;
CREATE TABLE t1 SELECT 1 / .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
DESCRIBE t1;
SELECT my_col FROM t1;
DROP TABLE t1;
CREATE TABLE t1 SELECT 1 % .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
DESCRIBE t1;
SELECT my_col FROM t1;
DROP TABLE t1;
......@@ -2260,8 +2260,10 @@ Item_decimal::Item_decimal(const char *str_arg, uint length,
name= (char*) str_arg;
decimals= (uint8) decimal_value.frac;
fixed= 1;
max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
decimals, unsigned_flag);
max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg +
decimals,
decimals,
unsigned_flag);
}
Item_decimal::Item_decimal(longlong val, bool unsig)
......@@ -2269,8 +2271,10 @@ Item_decimal::Item_decimal(longlong val, bool unsig)
int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value);
decimals= (uint8) decimal_value.frac;
fixed= 1;
max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
decimals, unsigned_flag);
max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg +
decimals,
decimals,
unsigned_flag);
}
......@@ -2279,8 +2283,10 @@ Item_decimal::Item_decimal(double val, int precision, int scale)
double2my_decimal(E_DEC_FATAL_ERROR, val, &decimal_value);
decimals= (uint8) decimal_value.frac;
fixed= 1;
max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
decimals, unsigned_flag);
max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg +
decimals,
decimals,
unsigned_flag);
}
......@@ -2300,8 +2306,10 @@ Item_decimal::Item_decimal(my_decimal *value_par)
my_decimal2decimal(value_par, &decimal_value);
decimals= (uint8) decimal_value.frac;
fixed= 1;
max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
decimals, unsigned_flag);
max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg +
decimals,
decimals,
unsigned_flag);
}
......@@ -2311,7 +2319,7 @@ Item_decimal::Item_decimal(const uchar *bin, int precision, int scale)
&decimal_value, precision, scale);
decimals= (uint8) decimal_value.frac;
fixed= 1;
max_length= my_decimal_precision_to_length(precision, decimals,
max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
unsigned_flag);
}
......@@ -2367,8 +2375,10 @@ void Item_decimal::set_decimal_value(my_decimal *value_par)
my_decimal2decimal(value_par, &decimal_value);
decimals= (uint8) decimal_value.frac;
unsigned_flag= !decimal_value.sign();
max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
decimals, unsigned_flag);
max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg +
decimals,
decimals,
unsigned_flag);
}
......@@ -2640,7 +2650,8 @@ void Item_param::set_decimal(const char *str, ulong length)
str2my_decimal(E_DEC_FATAL_ERROR, str, &decimal_value, &end);
state= DECIMAL_VALUE;
decimals= decimal_value.frac;
max_length= my_decimal_precision_to_length(decimal_value.precision(),
max_length=
my_decimal_precision_to_length_no_truncation(decimal_value.precision(),
decimals, unsigned_flag);
maybe_null= 0;
DBUG_VOID_RETURN;
......@@ -2797,7 +2808,8 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
my_decimal2decimal(ent_value, &decimal_value);
state= DECIMAL_VALUE;
decimals= ent_value->frac;
max_length= my_decimal_precision_to_length(ent_value->precision(),
max_length=
my_decimal_precision_to_length_no_truncation(ent_value->precision(),
decimals, unsigned_flag);
item_type= Item::DECIMAL_ITEM;
break;
......@@ -7296,7 +7308,8 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
int item_prec = max(prev_decimal_int_part, item_int_part) + decimals;
int precision= min(item_prec, DECIMAL_MAX_PRECISION);
unsigned_flag&= item->unsigned_flag;
max_length= my_decimal_precision_to_length(precision, decimals,
max_length= my_decimal_precision_to_length_no_truncation(precision,
decimals,
unsigned_flag);
}
......
......@@ -2760,7 +2760,8 @@ void Item_func_case::fix_length_and_dec()
agg_num_lengths(args[i + 1]);
if (else_expr_num != -1)
agg_num_lengths(args[else_expr_num]);
max_length= my_decimal_precision_to_length(max_length + decimals, decimals,
max_length= my_decimal_precision_to_length_no_truncation(max_length +
decimals, decimals,
unsigned_flag);
}
}
......
......@@ -452,11 +452,45 @@ Field *Item_func::tmp_table_field(TABLE *table)
return make_string_field(table);
break;
case DECIMAL_RESULT:
field= new Field_new_decimal(my_decimal_precision_to_length(decimal_precision(),
decimals,
unsigned_flag),
maybe_null, name, decimals, unsigned_flag);
{
uint8 dec= decimals;
uint8 intg= decimal_precision() - dec;
uint32 len= max_length;
/*
Trying to put too many digits overall in a DECIMAL(prec,dec)
will always throw a warning. We must limit dec to
DECIMAL_MAX_SCALE however to prevent an assert() later.
*/
if (dec > 0)
{
int overflow;
dec= min(dec, DECIMAL_MAX_SCALE);
/*
If the value still overflows the field with the corrected dec,
we'll throw out decimals rather than integers. This is still
bad and of course throws a truncation warning.
*/
const int required_length=
my_decimal_precision_to_length(intg + dec, dec,
unsigned_flag);
overflow= required_length - len;
if (overflow > 0)
dec= max(0, dec - overflow); // too long, discard fract
else
/* Corrected value fits. */
len= required_length;
}
field= new Field_new_decimal(len, maybe_null, name, dec, unsigned_flag);
break;
}
case ROW_RESULT:
default:
// This case should never be chosen
......@@ -545,7 +579,7 @@ void Item_func::count_decimal_length()
set_if_smaller(unsigned_flag, args[i]->unsigned_flag);
}
int precision= min(max_int_part + decimals, DECIMAL_MAX_PRECISION);
max_length= my_decimal_precision_to_length(precision, decimals,
max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
unsigned_flag);
}
......@@ -1141,15 +1175,14 @@ void Item_func_additive_op::result_precision()
decimals= max(args[0]->decimals, args[1]->decimals);
int arg1_int= args[0]->decimal_precision() - args[0]->decimals;
int arg2_int= args[1]->decimal_precision() - args[1]->decimals;
int est_prec= max(arg1_int, arg2_int) + 1 + decimals;
int precision= min(est_prec, DECIMAL_MAX_PRECISION);
int precision= max(arg1_int, arg2_int) + 1 + decimals;
/* Integer operations keep unsigned_flag if one of arguments is unsigned */
if (result_type() == INT_RESULT)
unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag;
else
unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag;
max_length= my_decimal_precision_to_length(precision, decimals,
max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
unsigned_flag);
}
......@@ -1255,7 +1288,8 @@ void Item_func_mul::result_precision()
decimals= min(args[0]->decimals + args[1]->decimals, DECIMAL_MAX_SCALE);
uint est_prec = args[0]->decimal_precision() + args[1]->decimal_precision();
uint precision= min(est_prec, DECIMAL_MAX_PRECISION);
max_length= my_decimal_precision_to_length(precision, decimals,unsigned_flag);
max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
unsigned_flag);
}
......@@ -1311,7 +1345,7 @@ void Item_func_div::result_precision()
else
unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag;
decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
max_length= my_decimal_precision_to_length(precision, decimals,
max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
unsigned_flag);
}
......@@ -1999,7 +2033,8 @@ void Item_func_round::fix_length_and_dec()
precision-= decimals_delta - length_increase;
decimals= min(decimals_to_set, DECIMAL_MAX_SCALE);
max_length= my_decimal_precision_to_length(precision, decimals,
max_length= my_decimal_precision_to_length_no_truncation(precision,
decimals,
unsigned_flag);
break;
}
......@@ -2243,7 +2278,8 @@ void Item_func_min_max::fix_length_and_dec()
}
}
else if ((cmp_type == DECIMAL_RESULT) || (cmp_type == INT_RESULT))
max_length= my_decimal_precision_to_length(max_int_part+decimals, decimals,
max_length= my_decimal_precision_to_length_no_truncation(max_int_part +
decimals, decimals,
unsigned_flag);
cached_field_type= agg_field_type(args, arg_count);
}
......
......@@ -378,7 +378,8 @@ public:
Item_decimal_typecast(Item *a, int len, int dec) :Item_func(a)
{
decimals= dec;
max_length= my_decimal_precision_to_length(len, dec, unsigned_flag);
max_length= my_decimal_precision_to_length_no_truncation(len, dec,
unsigned_flag);
}
String *val_str(String *str);
double val_real();
......
......@@ -798,7 +798,8 @@ void Item_sum_sum::fix_length_and_dec()
{
/* SUM result can't be longer than length(arg) + length(MAX_ROWS) */
int precision= args[0]->decimal_precision() + DECIMAL_LONGLONG_DIGITS;
max_length= my_decimal_precision_to_length(precision, decimals,
max_length= my_decimal_precision_to_length_no_truncation(precision,
decimals,
unsigned_flag);
curr_dec_buff= 0;
hybrid_type= DECIMAL_RESULT;
......@@ -1233,7 +1234,8 @@ void Item_sum_avg::fix_length_and_dec()
{
int precision= args[0]->decimal_precision() + prec_increment;
decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
max_length= my_decimal_precision_to_length(precision, decimals,
max_length= my_decimal_precision_to_length_no_truncation(precision,
decimals,
unsigned_flag);
f_precision= min(precision+DECIMAL_LONGLONG_DIGITS, DECIMAL_MAX_PRECISION);
f_scale= args[0]->decimals;
......@@ -1439,7 +1441,8 @@ void Item_sum_variance::fix_length_and_dec()
{
int precision= args[0]->decimal_precision()*2 + prec_increment;
decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
max_length= my_decimal_precision_to_length(precision, decimals,
max_length= my_decimal_precision_to_length_no_truncation(precision,
decimals,
unsigned_flag);
break;
......
......@@ -183,6 +183,19 @@ inline uint my_decimal_length_to_precision(uint length, uint scale,
(unsigned_flag || !length ? 0:1));
}
inline uint32 my_decimal_precision_to_length_no_truncation(uint precision,
uint8 scale,
bool unsigned_flag)
{
/*
When precision is 0 it means that original length was also 0. Thus
unsigned_flag is ignored in this case.
*/
DBUG_ASSERT(precision || !scale);
return (uint32)(precision + (scale > 0 ? 1 : 0) +
(unsigned_flag || !precision ? 0 : 1));
}
inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale,
bool unsigned_flag)
{
......@@ -192,8 +205,8 @@ inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale,
*/
DBUG_ASSERT(precision || !scale);
set_if_smaller(precision, DECIMAL_MAX_PRECISION);
return (uint32)(precision + (scale>0 ? 1:0) +
(unsigned_flag || !precision ? 0:1));
return my_decimal_precision_to_length_no_truncation(precision, scale,
unsigned_flag);
}
inline
......
......@@ -9391,13 +9391,17 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
+1: for decimal point
*/
overflow= my_decimal_precision_to_length(intg + dec, dec,
item->unsigned_flag) - len;
const int required_length=
my_decimal_precision_to_length(intg + dec, dec,
item->unsigned_flag);
overflow= required_length - len;
if (overflow > 0)
dec= max(0, dec - overflow); // too long, discard fract
else
len -= item->decimals - dec; // corrected value fits
/* Corrected value fits. */
len= required_length;
}
new_field= new Field_new_decimal(len, maybe_null, item->name,
......
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