Skip to content

Commit 7091b78

Browse files
author
Alexander Barkov
committed
MDEV-8918 Wrong result for CAST(AVG(bigint_column) AS SIGNED)
- Moving Item_xxx_field declarations after Item_sum_xxx declarations, so Item_xxx_field constructors can be defined directly in item_sum.h rather than item_sum.cc. This removes some duplicate code, e.g. initialization of the following members at constructor time: name, decimals, max_length, unsigned_flag, field, maybe_null. - Adding Item_sum_field as a common parent for Item_avg_field and Item_variance_field - Deriving Item_sum_field directly from Item rather that Item_result_field, as Item_sum_field descendants do not need anything from Item_result_field. - Removing hybrid infrastructure from Item_avg_field, adding Item_avg_field_decimal and Item_avg_field_double instead, as desired result type is already known at constructor time (not only at fix_fields time). This simplifies the code. - Changing Item_avg_field_decimal::val_int() to call val_int_from_decimal() instead of doing { return (longlong) rint(val_real()); } This is the fix itself.
1 parent 174a0b9 commit 7091b78

File tree

4 files changed

+148
-129
lines changed

4 files changed

+148
-129
lines changed

mysql-test/r/func_group.result

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2283,3 +2283,20 @@ Warnings:
22832283
Warning 1292 Truncated incorrect INTEGER value: 'x'
22842284
Warning 1292 Truncated incorrect DOUBLE value: 'x'
22852285
Warning 1292 Truncated incorrect DECIMAL value: 'x'
2286+
#
2287+
# MDEV-8918 Wrong result for CAST(AVG(a) AS SIGNED)
2288+
#
2289+
CREATE TABLE t1 (id INT, a BIGINT);
2290+
INSERT INTO t1 VALUES (1,0x7FFFFFFFFFFFFFFF),(2,0x7FFFFFFFFFFFFFFF);
2291+
SELECT id, AVG(a) AS avg, CAST(MIN(a) AS SIGNED) AS cast_min FROM t1 GROUP BY id HAVING avg!=123 ORDER BY id;
2292+
id avg cast_min
2293+
1 9223372036854775807.0000 9223372036854775807
2294+
2 9223372036854775807.0000 9223372036854775807
2295+
SELECT id, AVG(a) AS avg, CAST(AVG(a) AS SIGNED) AS cast_avg FROM t1 GROUP BY id HAVING avg!=123 ORDER BY id;
2296+
id avg cast_avg
2297+
1 9223372036854775807.0000 9223372036854775807
2298+
2 9223372036854775807.0000 9223372036854775807
2299+
DROP TABLE t1;
2300+
#
2301+
# End of 10.1 tests
2302+
#

mysql-test/t/func_group.test

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,3 +1570,17 @@ DROP TABLE t1,t2,t3,t4,t5,t6;
15701570
--echo # MDEV-8852 Implicit or explicit CAST from MAX(string) to INT,DOUBLE,DECIMAL does not produce warnings
15711571
--echo #
15721572
SELECT MAX('x') << 1, CAST(MAX('x') AS DOUBLE), CAST(MAX('x') AS DECIMAL);
1573+
1574+
1575+
--echo #
1576+
--echo # MDEV-8918 Wrong result for CAST(AVG(a) AS SIGNED)
1577+
--echo #
1578+
CREATE TABLE t1 (id INT, a BIGINT);
1579+
INSERT INTO t1 VALUES (1,0x7FFFFFFFFFFFFFFF),(2,0x7FFFFFFFFFFFFFFF);
1580+
SELECT id, AVG(a) AS avg, CAST(MIN(a) AS SIGNED) AS cast_min FROM t1 GROUP BY id HAVING avg!=123 ORDER BY id;
1581+
SELECT id, AVG(a) AS avg, CAST(AVG(a) AS SIGNED) AS cast_avg FROM t1 GROUP BY id HAVING avg!=123 ORDER BY id;
1582+
DROP TABLE t1;
1583+
1584+
--echo #
1585+
--echo # End of 10.1 tests
1586+
--echo #

sql/item_sum.cc

Lines changed: 6 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2502,7 +2502,10 @@ void Item_sum_avg::update_field()
25022502

25032503
Item *Item_sum_avg::result_item(THD *thd, Field *field)
25042504
{
2505-
return new (thd->mem_root) Item_avg_field(thd, hybrid_type, this);
2505+
return
2506+
hybrid_type == DECIMAL_RESULT ?
2507+
(Item_avg_field*) new (thd->mem_root) Item_avg_field_decimal(thd, this) :
2508+
(Item_avg_field*) new (thd->mem_root) Item_avg_field_double(thd, this);
25062509
}
25072510

25082511

@@ -2620,36 +2623,13 @@ Item_sum_hybrid::min_max_update_decimal_field()
26202623
}
26212624

26222625

2623-
Item_avg_field::Item_avg_field(THD *thd, Item_result res_type,
2624-
Item_sum_avg *item):
2625-
Item_result_field(thd)
2626-
{
2627-
name=item->name;
2628-
decimals=item->decimals;
2629-
max_length= item->max_length;
2630-
unsigned_flag= item->unsigned_flag;
2631-
field=item->result_field;
2632-
maybe_null=1;
2633-
hybrid_type= res_type;
2634-
prec_increment= item->prec_increment;
2635-
if (hybrid_type == DECIMAL_RESULT)
2636-
{
2637-
f_scale= item->f_scale;
2638-
f_precision= item->f_precision;
2639-
dec_bin_size= item->dec_bin_size;
2640-
}
2641-
}
2642-
2643-
double Item_avg_field::val_real()
2626+
double Item_avg_field_double::val_real()
26442627
{
26452628
// fix_fields() never calls for this Item
26462629
double nr;
26472630
longlong count;
26482631
uchar *res;
26492632

2650-
if (hybrid_type == DECIMAL_RESULT)
2651-
return val_real_from_decimal();
2652-
26532633
float8get(nr,field->ptr);
26542634
res= (field->ptr+sizeof(double));
26552635
count= sint8korr(res);
@@ -2660,18 +2640,9 @@ double Item_avg_field::val_real()
26602640
}
26612641

26622642

2663-
longlong Item_avg_field::val_int()
2664-
{
2665-
return (longlong) rint(val_real());
2666-
}
2667-
2668-
2669-
my_decimal *Item_avg_field::val_decimal(my_decimal *dec_buf)
2643+
my_decimal *Item_avg_field_decimal::val_decimal(my_decimal *dec_buf)
26702644
{
26712645
// fix_fields() never calls for this Item
2672-
if (hybrid_type == REAL_RESULT)
2673-
return val_decimal_from_real(dec_buf);
2674-
26752646
longlong count= sint8korr(field->ptr + dec_bin_size);
26762647
if ((null_value= !count))
26772648
return 0;
@@ -2686,21 +2657,6 @@ my_decimal *Item_avg_field::val_decimal(my_decimal *dec_buf)
26862657
}
26872658

26882659

2689-
String *Item_avg_field::val_str(String *str)
2690-
{
2691-
// fix_fields() never calls for this Item
2692-
if (hybrid_type == DECIMAL_RESULT)
2693-
return val_string_from_decimal(str);
2694-
return val_string_from_real(str);
2695-
}
2696-
2697-
2698-
Item_std_field::Item_std_field(THD *thd, Item_sum_std *item):
2699-
Item_variance_field(thd, item)
2700-
{
2701-
}
2702-
2703-
27042660
double Item_std_field::val_real()
27052661
{
27062662
double nr;
@@ -2711,19 +2667,6 @@ double Item_std_field::val_real()
27112667
}
27122668

27132669

2714-
Item_variance_field::Item_variance_field(THD *thd, Item_sum_variance *item):
2715-
Item_result_field(thd)
2716-
{
2717-
name=item->name;
2718-
decimals=item->decimals;
2719-
max_length=item->max_length;
2720-
unsigned_flag= item->unsigned_flag;
2721-
field=item->result_field;
2722-
maybe_null=1;
2723-
sample= item->sample;
2724-
}
2725-
2726-
27272670
double Item_variance_field::val_real()
27282671
{
27292672
// fix_fields() never calls for this Item

sql/item_sum.h

Lines changed: 111 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -820,37 +820,6 @@ class Item_sum_count :public Item_sum_int
820820
};
821821

822822

823-
/* Item to get the value of a stored sum function */
824-
825-
class Item_sum_avg;
826-
827-
class Item_avg_field :public Item_result_field
828-
{
829-
Field *field;
830-
Item_result hybrid_type;
831-
uint f_precision, f_scale, dec_bin_size;
832-
uint prec_increment;
833-
public:
834-
Item_avg_field(THD *thd, Item_result res_type, Item_sum_avg *item);
835-
enum Type type() const { return FIELD_AVG_ITEM; }
836-
double val_real();
837-
longlong val_int();
838-
my_decimal *val_decimal(my_decimal *);
839-
bool is_null() { update_null_value(); return null_value; }
840-
String *val_str(String*);
841-
enum_field_types field_type() const
842-
{
843-
return hybrid_type == DECIMAL_RESULT ?
844-
MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE;
845-
}
846-
enum Item_result result_type () const { return hybrid_type; }
847-
bool check_vcol_func_processor(uchar *int_arg)
848-
{
849-
return trace_unsupported_by_check_vcol_func_processor("avg_field");
850-
}
851-
};
852-
853-
854823
class Item_sum_avg :public Item_sum_sum
855824
{
856825
public:
@@ -894,31 +863,6 @@ class Item_sum_avg :public Item_sum_sum
894863
}
895864
};
896865

897-
class Item_sum_variance;
898-
899-
class Item_variance_field :public Item_result_field
900-
{
901-
Field *field;
902-
uint sample;
903-
public:
904-
Item_variance_field(THD *thd, Item_sum_variance *item);
905-
enum Type type() const {return FIELD_VARIANCE_ITEM; }
906-
double val_real();
907-
longlong val_int()
908-
{ /* can't be fix_fields()ed */ return (longlong) rint(val_real()); }
909-
String *val_str(String *str)
910-
{ return val_string_from_real(str); }
911-
my_decimal *val_decimal(my_decimal *dec_buf)
912-
{ return val_decimal_from_real(dec_buf); }
913-
bool is_null() { update_null_value(); return null_value; }
914-
enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
915-
enum Item_result result_type () const { return REAL_RESULT; }
916-
bool check_vcol_func_processor(uchar *int_arg)
917-
{
918-
return trace_unsupported_by_check_vcol_func_processor("var_field");
919-
}
920-
};
921-
922866

923867
/*
924868
variance(a) =
@@ -977,16 +921,6 @@ class Item_sum_variance : public Item_sum_num
977921
}
978922
};
979923

980-
class Item_sum_std;
981-
982-
class Item_std_field :public Item_variance_field
983-
{
984-
public:
985-
Item_std_field(THD *thd, Item_sum_std *item);
986-
enum Type type() const { return FIELD_STD_ITEM; }
987-
double val_real();
988-
};
989-
990924
/*
991925
standard_deviation(a) = sqrt(variance(a))
992926
*/
@@ -1144,6 +1078,117 @@ class Item_sum_xor :public Item_sum_bit
11441078
};
11451079

11461080

1081+
/* Items to get the value of a stored sum function */
1082+
1083+
class Item_sum_field :public Item
1084+
{
1085+
protected:
1086+
Field *field;
1087+
public:
1088+
Item_sum_field(THD *thd, Item_sum *item)
1089+
:Item(thd), field(item->result_field)
1090+
{
1091+
name= item->name;
1092+
maybe_null= true;
1093+
decimals= item->decimals;
1094+
max_length= item->max_length;
1095+
unsigned_flag= item->unsigned_flag;
1096+
}
1097+
table_map used_tables() const { return (table_map) 1L; }
1098+
Field *get_tmp_table_field() { DBUG_ASSERT(0); return NULL; }
1099+
Field *tmp_table_field(TABLE *) { DBUG_ASSERT(0); return NULL; }
1100+
void set_result_field(Field *) { DBUG_ASSERT(0); }
1101+
void save_in_result_field(bool no_conversions) { DBUG_ASSERT(0); }
1102+
};
1103+
1104+
1105+
class Item_avg_field :public Item_sum_field
1106+
{
1107+
protected:
1108+
uint prec_increment;
1109+
public:
1110+
Item_avg_field(THD *thd, Item_sum_avg *item)
1111+
:Item_sum_field(thd, item), prec_increment(item->prec_increment)
1112+
{ }
1113+
enum Type type() const { return FIELD_AVG_ITEM; }
1114+
bool is_null() { update_null_value(); return null_value; }
1115+
bool check_vcol_func_processor(uchar *int_arg)
1116+
{
1117+
return trace_unsupported_by_check_vcol_func_processor("avg_field");
1118+
}
1119+
};
1120+
1121+
1122+
class Item_avg_field_double :public Item_avg_field
1123+
{
1124+
public:
1125+
Item_avg_field_double(THD *thd, Item_sum_avg *item)
1126+
:Item_avg_field(thd, item)
1127+
{ }
1128+
enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
1129+
enum Item_result result_type () const { return REAL_RESULT; }
1130+
longlong val_int() { return (longlong) rint(val_real()); }
1131+
my_decimal *val_decimal(my_decimal *dec) { return val_decimal_from_real(dec); }
1132+
String *val_str(String *str) { return val_string_from_real(str); }
1133+
double val_real();
1134+
};
1135+
1136+
1137+
class Item_avg_field_decimal :public Item_avg_field
1138+
{
1139+
uint f_precision, f_scale, dec_bin_size;
1140+
public:
1141+
Item_avg_field_decimal(THD *thd, Item_sum_avg *item)
1142+
:Item_avg_field(thd, item),
1143+
f_precision(item->f_precision),
1144+
f_scale(item->f_scale),
1145+
dec_bin_size(item->dec_bin_size)
1146+
{ }
1147+
enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; }
1148+
enum Item_result result_type () const { return DECIMAL_RESULT; }
1149+
double val_real() { return val_real_from_decimal(); }
1150+
longlong val_int() { return val_int_from_decimal(); }
1151+
String *val_str(String *str) { return val_string_from_decimal(str); }
1152+
my_decimal *val_decimal(my_decimal *);
1153+
};
1154+
1155+
1156+
class Item_variance_field :public Item_sum_field
1157+
{
1158+
uint sample;
1159+
public:
1160+
Item_variance_field(THD *thd, Item_sum_variance *item)
1161+
:Item_sum_field(thd, item), sample(item->sample)
1162+
{ }
1163+
enum Type type() const {return FIELD_VARIANCE_ITEM; }
1164+
double val_real();
1165+
longlong val_int()
1166+
{ /* can't be fix_fields()ed */ return (longlong) rint(val_real()); }
1167+
String *val_str(String *str)
1168+
{ return val_string_from_real(str); }
1169+
my_decimal *val_decimal(my_decimal *dec_buf)
1170+
{ return val_decimal_from_real(dec_buf); }
1171+
bool is_null() { update_null_value(); return null_value; }
1172+
enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
1173+
enum Item_result result_type () const { return REAL_RESULT; }
1174+
bool check_vcol_func_processor(uchar *int_arg)
1175+
{
1176+
return trace_unsupported_by_check_vcol_func_processor("var_field");
1177+
}
1178+
};
1179+
1180+
1181+
class Item_std_field :public Item_variance_field
1182+
{
1183+
public:
1184+
Item_std_field(THD *thd, Item_sum_std *item)
1185+
:Item_variance_field(thd, item)
1186+
{ }
1187+
enum Type type() const { return FIELD_STD_ITEM; }
1188+
double val_real();
1189+
};
1190+
1191+
11471192
/*
11481193
User defined aggregates
11491194
*/

0 commit comments

Comments
 (0)