Backport into build-200911241145-5.1.40sp1

> ------------------------------------------------------------
> revno: 3148.8.5
> revision-id: davi.arnaut@sun.com-20091102112139-pztthzy6qj8jzomn
> parent: svoj@sun.com-20091103091902-vwszwwpfi1f4zrpn
> committer: Davi Arnaut <Davi.Arnaut@Sun.COM>
> branch nick: 48370-5.1
> timestamp: Mon 2009-11-02 09:21:39 -0200
> message:
>   Bug#48370: Absolutely wrong calculations with GROUP BY and decimal fields when using IF
>   Bug#45261: Crash, stored procedure + decimal
>   
>   Revert fix for Bug#45261 due to unforeseen bugs.
This commit is contained in:
MySQL Build Team 2009-11-25 18:00:46 +01:00
parent 6d027f4ba6
commit c084d7010b
12 changed files with 110 additions and 483 deletions

View file

@ -1495,9 +1495,9 @@ CREATE TABLE t1 (a int DEFAULT NULL, b int DEFAULT NULL);
INSERT INTO t1 VALUES (3,30), (1,10), (2,10);
SELECT a+CAST(1 AS decimal(65,30)) AS aa, SUM(b) FROM t1 GROUP BY aa;
aa SUM(b)
2.00000000000000000000000000000 10
3.00000000000000000000000000000 10
4.00000000000000000000000000000 30
2.000000000000000000000000000000 10
3.000000000000000000000000000000 10
4.000000000000000000000000000000 30
SELECT a+CAST(1 AS decimal(65,31)) AS aa, SUM(b) FROM t1 GROUP BY aa;
ERROR 42000: Too big scale 31 specified for column '1'. Maximum is 30.
DROP TABLE t1;
@ -1521,13 +1521,13 @@ f1
DROP TABLE t1;
CREATE TABLE t1 SELECT 123451234512345123451234512345123451234512345.678906789067890678906789067890678906789067890 AS f1;
Warnings:
Note 1265 Data truncated for column 'f1' at row 1
Warning 1264 Out of range value for column 'f1' at row 1
DESC t1;
Field Type Null Key Default Extra
f1 decimal(65,20) NO 0.00000000000000000000
f1 decimal(65,30) NO 0.000000000000000000000000000000
SELECT f1 FROM t1;
f1
123451234512345123451234512345123451234512345.67890678906789067891
99999999999999999999999999999999999.999999999999999999999999999999
DROP TABLE t1;
select (1.20396873 * 0.89550000 * 0.68000000 * 1.08721696 * 0.99500000 *
1.01500000 * 1.01500000 * 0.99500000);
@ -1595,7 +1595,7 @@ Warnings:
Note 1265 Data truncated for column 'my_col' at row 1
DESCRIBE t1;
Field Type Null Key Default Extra
my_col decimal(32,30) NO 0.000000000000000000000000000000
my_col decimal(65,30) NO 0.000000000000000000000000000000
SELECT my_col FROM t1;
my_col
1.123456789123456789123456789123
@ -1625,212 +1625,8 @@ 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) YES NULL
my_col decimal(65,30) YES NULL
SELECT my_col FROM t1;
my_col
0.012345687012345687012345687012
DROP TABLE t1;
#
# Bug#45261: Crash, stored procedure + decimal
#
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 SELECT
/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001
AS c1;
Warnings:
Warning 1264 Out of range value for column 'c1' at row 1
DESC t1;
Field Type Null Key Default Extra
c1 decimal(65,0) NO 0
SELECT * FROM t1;
c1
99999999999999999999999999999999999999999999999999999999999999999
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001.
AS c1;
Warnings:
Warning 1264 Out of range value for column 'c1' at row 1
DESC t1;
Field Type Null Key Default Extra
c1 decimal(65,0) NO 0
SELECT * FROM t1;
c1
99999999999999999999999999999999999999999999999999999999999999999
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001.1 /* 1 */
AS c1;
Warnings:
Warning 1264 Out of range value for column 'c1' at row 1
DESC t1;
Field Type Null Key Default Extra
c1 decimal(65,0) NO 0
SELECT * FROM t1;
c1
99999999999999999999999999999999999999999999999999999999999999999
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 82 */ 1000000000000000000000000000000000000000000000000000000000000000000000000000000001
AS c1;
Warnings:
Error 1292 Truncated incorrect DECIMAL value: ''
DESC t1;
Field Type Null Key Default Extra
c1 decimal(65,0) NO 0
SELECT * FROM t1;
c1
99999999999999999999999999999999999999999999999999999999999999999
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 40 */ 1000000000000000000000000000000000000001.1000000000000000000000000000000000000001 /* 40 */
AS c1;
DESC t1;
Field Type Null Key Default Extra
c1 decimal(65,25) NO 0.0000000000000000000000000
SELECT * FROM t1;
c1
1000000000000000000000000000000000000001.1000000000000000000000000
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 1 */ 1.10000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 80 */
AS c1;
DESC t1;
Field Type Null Key Default Extra
c1 decimal(31,30) NO 0.000000000000000000000000000000
SELECT * FROM t1;
c1
1.100000000000000000000000000000
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 1 */ 1.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */
AS c1;
DESC t1;
Field Type Null Key Default Extra
c1 decimal(31,30) NO 0.000000000000000000000000000000
SELECT * FROM t1;
c1
1.100000000000000000000000000000
DROP TABLE t1;
CREATE TABLE t1 SELECT
.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */
AS c1;
Warnings:
Note 1265 Data truncated for column 'c1' at row 1
DESC t1;
Field Type Null Key Default Extra
c1 decimal(30,30) NO 0.000000000000000000000000000000
SELECT * FROM t1;
c1
0.100000000000000000000000000000
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 45 */ 123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345 /* 45 */
AS c1;
Warnings:
Note 1265 Data truncated for column 'c1' at row 1
DESC t1;
Field Type Null Key Default Extra
c1 decimal(65,20) NO 0.00000000000000000000
SELECT * FROM t1;
c1
123456789012345678901234567890123456789012345.12345678901234567890
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 65 */ 12345678901234567890123456789012345678901234567890123456789012345.1 /* 1 */
AS c1;
Warnings:
Note 1265 Data truncated for column 'c1' at row 1
DESC t1;
Field Type Null Key Default Extra
c1 decimal(65,0) NO 0
SELECT * FROM t1;
c1
12345678901234567890123456789012345678901234567890123456789012345
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 66 */ 123456789012345678901234567890123456789012345678901234567890123456.1 /* 1 */
AS c1;
Warnings:
Warning 1264 Out of range value for column 'c1' at row 1
DESC t1;
Field Type Null Key Default Extra
c1 decimal(65,0) NO 0
SELECT * FROM t1;
c1
99999999999999999999999999999999999999999999999999999999999999999
DROP TABLE t1;
CREATE TABLE t1 SELECT
.123456789012345678901234567890123456789012345678901234567890123456 /* 66 */
AS c1;
Warnings:
Note 1265 Data truncated for column 'c1' at row 1
DESC t1;
Field Type Null Key Default Extra
c1 decimal(30,30) NO 0.000000000000000000000000000000
SELECT * FROM t1;
c1
0.123456789012345678901234567890
DROP TABLE t1;
CREATE TABLE t1 AS SELECT 123.1234567890123456789012345678901 /* 31 */ AS c1;
Warnings:
Note 1265 Data truncated for column 'c1' at row 1
DESC t1;
Field Type Null Key Default Extra
c1 decimal(33,30) NO 0.000000000000000000000000000000
SELECT * FROM t1;
c1
123.123456789012345678901234567890
DROP TABLE t1;
CREATE TABLE t1 SELECT 1.1 + CAST(1 AS DECIMAL(65,30)) AS c1;
DESC t1;
Field Type Null Key Default Extra
c1 decimal(65,29) NO 0.00000000000000000000000000000
SELECT * FROM t1;
c1
2.10000000000000000000000000000
DROP TABLE t1;
#
# Test that the integer and decimal parts are properly calculated.
#
CREATE TABLE t1 (a DECIMAL(30,30));
INSERT INTO t1 VALUES (0.1),(0.2),(0.3);
CREATE TABLE t2 SELECT MIN(a + 0.0000000000000000000000000000001) AS c1 FROM t1;
Warnings:
Note 1265 Data truncated for column 'c1' at row 3
DESC t2;
Field Type Null Key Default Extra
c1 decimal(32,30) YES NULL
DROP TABLE t1,t2;
CREATE TABLE t1 (a DECIMAL(30,30));
INSERT INTO t1 VALUES (0.1),(0.2),(0.3);
CREATE TABLE t2 SELECT IFNULL(a + 0.0000000000000000000000000000001, NULL) AS c1 FROM t1;
Warnings:
Note 1265 Data truncated for column 'c1' at row 1
Note 1265 Data truncated for column 'c1' at row 2
Note 1265 Data truncated for column 'c1' at row 3
DESC t2;
Field Type Null Key Default Extra
c1 decimal(32,30) YES NULL
DROP TABLE t1,t2;
CREATE TABLE t1 (a DECIMAL(30,30));
INSERT INTO t1 VALUES (0.1),(0.2),(0.3);
CREATE TABLE t2 SELECT CASE a WHEN 0.1 THEN 0.0000000000000000000000000000000000000000000000000000000000000000001 END AS c1 FROM t1;
Warnings:
Note 1265 Data truncated for column 'c1' at row 1
DESC t2;
Field Type Null Key Default Extra
c1 decimal(31,30) YES NULL
DROP TABLE t1,t2;
#
# Test that variables get maximum precision.
#
SET @decimal= 1.1;
CREATE TABLE t1 SELECT @decimal AS c1;
DESC t1;
Field Type Null Key Default Extra
c1 decimal(65,30) YES NULL
SELECT * FROM t1;
c1
1.100000000000000000000000000000
DROP TABLE t1;

View file

@ -1286,137 +1286,3 @@ CREATE TABLE t1 SELECT 1 % .1234567891234567891234567891234567891234567891234567
DESCRIBE t1;
SELECT my_col FROM t1;
DROP TABLE t1;
--echo #
--echo # Bug#45261: Crash, stored procedure + decimal
--echo #
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
CREATE TABLE t1 SELECT
/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001
AS c1;
DESC t1;
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001.
AS c1;
DESC t1;
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 81 */ 100000000000000000000000000000000000000000000000000000000000000000000000000000001.1 /* 1 */
AS c1;
DESC t1;
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 82 */ 1000000000000000000000000000000000000000000000000000000000000000000000000000000001
AS c1;
DESC t1;
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 40 */ 1000000000000000000000000000000000000001.1000000000000000000000000000000000000001 /* 40 */
AS c1;
DESC t1;
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 1 */ 1.10000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 80 */
AS c1;
DESC t1;
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 1 */ 1.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */
AS c1;
DESC t1;
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1 SELECT
.100000000000000000000000000000000000000000000000000000000000000000000000000000001 /* 81 */
AS c1;
DESC t1;
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 45 */ 123456789012345678901234567890123456789012345.123456789012345678901234567890123456789012345 /* 45 */
AS c1;
DESC t1;
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 65 */ 12345678901234567890123456789012345678901234567890123456789012345.1 /* 1 */
AS c1;
DESC t1;
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1 SELECT
/* 66 */ 123456789012345678901234567890123456789012345678901234567890123456.1 /* 1 */
AS c1;
DESC t1;
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1 SELECT
.123456789012345678901234567890123456789012345678901234567890123456 /* 66 */
AS c1;
DESC t1;
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1 AS SELECT 123.1234567890123456789012345678901 /* 31 */ AS c1;
DESC t1;
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1 SELECT 1.1 + CAST(1 AS DECIMAL(65,30)) AS c1;
DESC t1;
SELECT * FROM t1;
DROP TABLE t1;
--echo #
--echo # Test that the integer and decimal parts are properly calculated.
--echo #
CREATE TABLE t1 (a DECIMAL(30,30));
INSERT INTO t1 VALUES (0.1),(0.2),(0.3);
CREATE TABLE t2 SELECT MIN(a + 0.0000000000000000000000000000001) AS c1 FROM t1;
DESC t2;
DROP TABLE t1,t2;
CREATE TABLE t1 (a DECIMAL(30,30));
INSERT INTO t1 VALUES (0.1),(0.2),(0.3);
CREATE TABLE t2 SELECT IFNULL(a + 0.0000000000000000000000000000001, NULL) AS c1 FROM t1;
DESC t2;
DROP TABLE t1,t2;
CREATE TABLE t1 (a DECIMAL(30,30));
INSERT INTO t1 VALUES (0.1),(0.2),(0.3);
CREATE TABLE t2 SELECT CASE a WHEN 0.1 THEN 0.0000000000000000000000000000000000000000000000000000000000000000001 END AS c1 FROM t1;
DESC t2;
DROP TABLE t1,t2;
--echo #
--echo # Test that variables get maximum precision.
--echo #
SET @decimal= 1.1;
CREATE TABLE t1 SELECT @decimal AS c1;
DESC t1;
SELECT * FROM t1;
DROP TABLE t1;

View file

@ -2480,97 +2480,12 @@ Field_new_decimal::Field_new_decimal(uint32 len_arg,
{
precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
set_if_smaller(precision, DECIMAL_MAX_PRECISION);
DBUG_ASSERT(precision >= dec);
DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) &&
(dec <= DECIMAL_MAX_SCALE));
bin_size= my_decimal_get_binary_size(precision, dec);
}
/**
Create a field to hold a decimal value from an item.
@remark The MySQL DECIMAL data type has a characteristic that needs to be
taken into account when deducing the type from a Item_decimal.
But first, let's briefly recap what is the new MySQL DECIMAL type:
The declaration syntax for a decimal is DECIMAL(M,D), where:
* M is the maximum number of digits (the precision).
It has a range of 1 to 65.
* D is the number of digits to the right of the decimal separator (the scale).
It has a range of 0 to 30 and must be no larger than M.
D and M are used to determine the storage requirements for the integer
and fractional parts of each value. The integer part is to the left of
the decimal separator and to the right is the fractional part. Hence:
M is the number of digits for the integer and fractional part.
D is the number of digits for the fractional part.
Consequently, M - D is the number of digits for the integer part. For
example, a DECIMAL(20,10) column has ten digits on either side of
the decimal separator.
The characteristic that needs to be taken into account is that the
backing type for Item_decimal is a my_decimal that has a higher
precision (DECIMAL_MAX_POSSIBLE_PRECISION, see my_decimal.h) than
DECIMAL.
Drawing a comparison between my_decimal and DECIMAL:
* M has a range of 1 to 81.
* D has a range of 0 to 81.
There can be a difference in range if the decimal contains a integer
part. This is because the fractional part must always be on a group
boundary, leaving at least one group for the integer part. Since each
group is 9 (DIG_PER_DEC1) digits and there are 9 (DECIMAL_BUFF_LENGTH)
groups, the fractional part is limited to 72 digits if there is at
least one digit in the integral part.
Although the backing type for a DECIMAL is also my_decimal, every
time a my_decimal is stored in a DECIMAL field, the precision and
scale are explicitly capped at 65 (DECIMAL_MAX_PRECISION) and 30
(DECIMAL_MAX_SCALE) digits, following my_decimal truncation procedure
(FIX_INTG_FRAC_ERROR).
*/
Field_new_decimal *
Field_new_decimal::new_decimal_field(const Item *item)
{
uint32 len;
uint intg= item->decimal_int_part(), scale= item->decimals;
DBUG_ASSERT(item->decimal_precision() >= item->decimals);
/*
Employ a procedure along the lines of the my_decimal truncation process:
- If the integer part is equal to or bigger than the maximum precision:
Truncate integer part to fit and the fractional becomes zero.
- Otherwise:
Truncate fractional part to fit.
*/
if (intg >= DECIMAL_MAX_PRECISION)
{
intg= DECIMAL_MAX_PRECISION;
scale= 0;
}
else
{
uint room= min(DECIMAL_MAX_PRECISION - intg, DECIMAL_MAX_SCALE);
if (scale > room)
scale= room;
}
len= my_decimal_precision_to_length(intg + scale, scale, item->unsigned_flag);
return new Field_new_decimal(len, item->maybe_null, item->name, scale,
item->unsigned_flag);
}
int Field_new_decimal::reset(void)
{
store_value(&decimal_zero);

View file

@ -615,10 +615,6 @@ protected:
class Field_num :public Field {
public:
/**
The scale of the Field's value, i.e. the number of digits to the right
of the decimal point.
*/
const uint8 dec;
bool zerofill,unsigned_flag; // Purify cannot handle bit fields
Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
@ -777,11 +773,6 @@ public:
Field_new_decimal(uint32 len_arg, bool maybe_null_arg,
const char *field_name_arg, uint8 dec_arg,
bool unsigned_arg);
/*
Create a field to hold a decimal value from an item.
Truncates the precision and/or scale if necessary.
*/
static Field_new_decimal *new_decimal_field(const Item *item);
enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
Item_result result_type () const { return DECIMAL_RESULT; }

View file

@ -435,26 +435,17 @@ Item::Item(THD *thd, Item *item):
}
/**
Decimal precision of the item.
@remark The precision must not be capped as it can be used in conjunction
with Item::decimals to determine the size of the integer part when
constructing a decimal data type.
@see Item::decimal_int_part()
@see Item::decimals
*/
uint Item::decimal_precision() const
{
uint precision= max_length;
Item_result restype= result_type();
if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT))
precision= my_decimal_length_to_precision(max_length, decimals, unsigned_flag);
return precision;
{
uint prec=
my_decimal_length_to_precision(max_length, decimals, unsigned_flag);
return min(prec, DECIMAL_MAX_PRECISION);
}
return min(max_length, DECIMAL_MAX_PRECISION);
}
@ -4908,7 +4899,9 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length)
switch (field_type()) {
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_NEWDECIMAL:
field= Field_new_decimal::new_decimal_field(this);
field= new Field_new_decimal((uchar*) 0, max_length, null_ptr, 0,
Field::NONE, name, decimals, 0,
unsigned_flag);
break;
case MYSQL_TYPE_TINY:
field= new Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE,

View file

@ -762,10 +762,9 @@ public:
virtual cond_result eq_cmp_result() const { return COND_OK; }
inline uint float_length(uint decimals_par) const
{ return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;}
/** Returns the uncapped decimal precision of this item. */
virtual uint decimal_precision() const;
inline int decimal_int_part() const
{ return decimal_precision() - decimals; }
{ return my_decimal_int_part(decimal_precision(), decimals); }
/*
Returns true if this is constant (during query execution, i.e. its value
will not change until next fix_fields) and its value is known.

View file

@ -2191,7 +2191,7 @@ uint Item_func_ifnull::decimal_precision() const
int arg1_int_part= args[1]->decimal_int_part();
int max_int_part= max(arg0_int_part, arg1_int_part);
int precision= max_int_part + decimals;
return precision;
return min(precision, DECIMAL_MAX_PRECISION);
}
@ -2375,7 +2375,7 @@ uint Item_func_if::decimal_precision() const
int arg1_prec= args[1]->decimal_int_part();
int arg2_prec= args[2]->decimal_int_part();
int precision=max(arg1_prec,arg2_prec) + decimals;
return precision;
return min(precision, DECIMAL_MAX_PRECISION);
}
@ -2783,7 +2783,7 @@ uint Item_func_case::decimal_precision() const
if (else_expr_num != -1)
set_if_bigger(max_int_part, args[else_expr_num]->decimal_int_part());
return max_int_part + decimals;
return min(max_int_part + decimals, DECIMAL_MAX_PRECISION);
}

View file

@ -451,8 +451,45 @@ Field *Item_func::tmp_table_field(TABLE *table)
return make_string_field(table);
break;
case DECIMAL_RESULT:
field= Field_new_decimal::new_decimal_field(this);
{
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
@ -4739,19 +4776,6 @@ void Item_func_get_user_var::fix_length_and_dec()
}
uint Item_func_get_user_var::decimal_precision() const
{
uint precision= max_length;
Item_result restype= result_type();
/* Default to maximum as the precision is unknown a priori. */
if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT))
precision= DECIMAL_MAX_PRECISION;
return precision;
}
bool Item_func_get_user_var::const_item() const
{
return (!var_entry || current_thd->query_id != var_entry->update_query_id);

View file

@ -1393,7 +1393,6 @@ public:
table_map used_tables() const
{ return const_item() ? 0 : RAND_TABLE_BIT; }
bool eq(const Item *item, bool binary_cmp) const;
uint decimal_precision() const;
private:
bool set_value(THD *thd, sp_rcontext *ctx, Item **it);

View file

@ -517,7 +517,8 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table,
name, table->s, collation.collation);
break;
case DECIMAL_RESULT:
field= Field_new_decimal::new_decimal_field(this);
field= new Field_new_decimal(max_length, maybe_null, name,
decimals, unsigned_flag);
break;
case ROW_RESULT:
default:

View file

@ -48,12 +48,10 @@ C_MODE_END
digits * number of decimal digits in one our big digit - number of decimal
digits in one our big digit decreased by 1 (because we always put decimal
point on the border of our big digits))
This value is 65 due to historical reasons partly due to it being used
as the maximum allowed precision and not the actual maximum precision.
*/
#define DECIMAL_MAX_PRECISION (DECIMAL_MAX_POSSIBLE_PRECISION - 8*2)
#define DECIMAL_MAX_SCALE 30
#define DECIMAL_NOT_SPECIFIED 31
/**
maximum length of string representation (number of maximum decimal
@ -77,6 +75,12 @@ inline uint my_decimal_size(uint precision, uint scale)
}
inline int my_decimal_int_part(uint precision, uint decimals)
{
return precision - ((decimals == DECIMAL_NOT_SPECIFIED) ? 0 : decimals);
}
/**
my_decimal class limits 'decimal_t' type to what we need in MySQL.
@ -180,7 +184,7 @@ inline uint my_decimal_length_to_precision(uint length, uint scale,
}
inline uint32 my_decimal_precision_to_length_no_truncation(uint precision,
uint scale,
uint8 scale,
bool unsigned_flag)
{
/*
@ -192,7 +196,7 @@ inline uint32 my_decimal_precision_to_length_no_truncation(uint precision,
(unsigned_flag || !precision ? 0 : 1));
}
inline uint32 my_decimal_precision_to_length(uint precision, uint scale,
inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale,
bool unsigned_flag)
{
/*

View file

@ -9409,8 +9409,47 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
new_field->set_derivation(item->collation.derivation);
break;
case DECIMAL_RESULT:
new_field= Field_new_decimal::new_decimal_field(item);
{
uint8 dec= item->decimals;
uint8 intg= ((Item_decimal *) item)->decimal_precision() - dec;
uint32 len= item->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)
{
signed 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.
+1: for decimal point
*/
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
/* Corrected value fits. */
len= required_length;
}
new_field= new Field_new_decimal(len, maybe_null, item->name,
dec, item->unsigned_flag);
break;
}
case ROW_RESULT:
default:
// This case should never be choosen