Commit 957c09f6 authored by Guilhem Bichot's avatar Guilhem Bichot

Fix for Bug#57932 "query with avg returns incorrect results":

when there was one NULL value, AVG(DISTINCT) could forget about other values.
See commit comment of item_sum.cc.
parent c872e3db
......@@ -1746,3 +1746,18 @@ MAX(c1) MIN(c1)
-00:00:01 -00:00:01
DROP TABLE t1;
# End of the bug#56120
#
# Bug#57932 "query with AVG(DISTINCT) returns NULL if last
# aggregated value was NULL"
#
CREATE TABLE t1 (col_int_nokey int(11));
INSERT INTO t1 VALUES (7),(8),(NULL);
SELECT AVG(DISTINCT col_int_nokey) FROM t1;
AVG(DISTINCT col_int_nokey)
7.5000
SELECT AVG(DISTINCT outr.col_int_nokey) FROM t1 AS outr LEFT JOIN t1 AS outr2 ON
outr.col_int_nokey = outr2.col_int_nokey;
AVG(DISTINCT outr.col_int_nokey)
7.5000
DROP TABLE t1;
# End of the bug#57932
......@@ -1118,3 +1118,14 @@ SELECT MAX(c1),MIN(c1) FROM t1;
DROP TABLE t1;
--echo # End of the bug#56120
--echo #
--echo # Bug#57932 "query with AVG(DISTINCT) returns NULL if last
--echo # aggregated value was NULL"
--echo #
CREATE TABLE t1 (col_int_nokey int(11));
INSERT INTO t1 VALUES (7),(8),(NULL);
SELECT AVG(DISTINCT col_int_nokey) FROM t1;
SELECT AVG(DISTINCT outr.col_int_nokey) FROM t1 AS outr LEFT JOIN t1 AS outr2 ON
outr.col_int_nokey = outr2.col_int_nokey;
DROP TABLE t1;
--echo # End of the bug#57932
......@@ -1325,27 +1325,11 @@ void Item_sum_sum::fix_length_and_dec()
bool Item_sum_sum::add()
{
DBUG_ENTER("Item_sum_sum::add");
bool arg_is_null;
if (hybrid_type == DECIMAL_RESULT)
{
my_decimal value, *val;
if (aggr->use_distinct_values)
{
/*
We are aggregating distinct rows. Get the value from the distinct
table pointer
*/
Aggregator_distinct *daggr= (Aggregator_distinct *)aggr;
val= daggr->table->field[0]->val_decimal (&value);
arg_is_null= daggr->table->field[0]->is_null();
}
else
{
/* non-distinct aggregation */
val= args[0]->val_decimal(&value);
arg_is_null= args[0]->null_value;
}
if (!arg_is_null)
my_decimal value;
const my_decimal *val= aggr->arg_val_decimal(&value);
if (!aggr->arg_is_null())
{
my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1),
val, dec_buffs + curr_dec_buff);
......@@ -1355,25 +1339,8 @@ bool Item_sum_sum::add()
}
else
{
double val;
if (aggr->use_distinct_values)
{
/*
We are aggregating distinct rows. Get the value from the distinct
table pointer
*/
Aggregator_distinct *daggr= (Aggregator_distinct *)aggr;
val= daggr->table->field[0]->val_real ();
arg_is_null= daggr->table->field[0]->is_null();
}
else
{
/* non-distinct aggregation */
val= args[0]->val_real();
arg_is_null= args[0]->null_value;
}
sum+= val;
if (!arg_is_null)
sum+= aggr->arg_val_real();
if (!aggr->arg_is_null())
null_value= 0;
}
DBUG_RETURN(0);
......@@ -1471,6 +1438,45 @@ Aggregator_distinct::~Aggregator_distinct()
}
my_decimal *Aggregator_simple::arg_val_decimal(my_decimal *value)
{
return item_sum->args[0]->val_decimal(value);
}
double Aggregator_simple::arg_val_real()
{
return item_sum->args[0]->val_real();
}
bool Aggregator_simple::arg_is_null()
{
return item_sum->args[0]->null_value;
}
my_decimal *Aggregator_distinct::arg_val_decimal(my_decimal * value)
{
return use_distinct_values ? table->field[0]->val_decimal(value) :
item_sum->args[0]->val_decimal(value);
}
double Aggregator_distinct::arg_val_real()
{
return use_distinct_values ? table->field[0]->val_real() :
item_sum->args[0]->val_real();
}
bool Aggregator_distinct::arg_is_null()
{
return use_distinct_values ? table->field[0]->is_null() :
item_sum->args[0]->null_value;
}
Item *Item_sum_count::copy_or_same(THD* thd)
{
return new (thd->mem_root) Item_sum_count(thd, this);
......@@ -1576,7 +1582,7 @@ bool Item_sum_avg::add()
{
if (Item_sum_sum::add())
return TRUE;
if (!args[0]->null_value)
if (!aggr->arg_is_null())
count++;
return FALSE;
}
......
......@@ -101,6 +101,15 @@ public:
*/
virtual void endup() = 0;
/** Decimal value of being-aggregated argument */
virtual my_decimal *arg_val_decimal(my_decimal * value) = 0;
/** Floating point value of being-aggregated argument */
virtual double arg_val_real() = 0;
/**
NULLness of being-aggregated argument; can be called only after
arg_val_decimal() or arg_val_real().
*/
virtual bool arg_is_null() = 0;
};
......@@ -304,6 +313,7 @@ class st_select_lex;
class Item_sum :public Item_result_field
{
friend class Aggregator_distinct;
friend class Aggregator_simple;
protected:
/**
......@@ -600,6 +610,9 @@ public:
void clear();
bool add();
void endup();
virtual my_decimal *arg_val_decimal(my_decimal * value);
virtual double arg_val_real();
virtual bool arg_is_null();
bool unique_walk_function(void *element);
static int composite_key_cmp(void* arg, uchar* key1, uchar* key2);
......@@ -623,6 +636,9 @@ public:
void clear() { item_sum->clear(); }
bool add() { return item_sum->add(); }
void endup() {};
virtual my_decimal *arg_val_decimal(my_decimal * value);
virtual double arg_val_real();
virtual bool arg_is_null();
};
......
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