Loading mysql-test/r/func_group.result +26 −0 Original line number Diff line number Diff line Loading @@ -1029,3 +1029,29 @@ t1 CREATE TABLE `t1` ( `stddev(0)` double(8,4) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; CREATE TABLE t1 (a INT, b INT); INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8); INSERT INTO t1 SELECT a, b+8 FROM t1; INSERT INTO t1 SELECT a, b+16 FROM t1; INSERT INTO t1 SELECT a, b+32 FROM t1; INSERT INTO t1 SELECT a, b+64 FROM t1; INSERT INTO t1 SELECT a, b+128 FROM t1; INSERT INTO t1 SELECT a, b+256 FROM t1; INSERT INTO t1 SELECT a, b+512 FROM t1; INSERT INTO t1 SELECT a, b+1024 FROM t1; INSERT INTO t1 SELECT a, b+2048 FROM t1; INSERT INTO t1 SELECT a, b+4096 FROM t1; INSERT INTO t1 SELECT a, b+8192 FROM t1; INSERT INTO t1 SELECT a, b+16384 FROM t1; INSERT INTO t1 SELECT a, b+32768 FROM t1; SELECT a,COUNT(DISTINCT b) AS cnt FROM t1 GROUP BY a HAVING cnt > 50; a cnt 1 65536 SELECT a,SUM(DISTINCT b) AS sumation FROM t1 GROUP BY a HAVING sumation > 50; a sumation 1 2147516416 SELECT a,AVG(DISTINCT b) AS average FROM t1 GROUP BY a HAVING average > 50; a average 1 32768.5000 DROP TABLE t1; End of 5.0 tests mysql-test/t/func_group.test +25 −0 Original line number Diff line number Diff line Loading @@ -700,3 +700,28 @@ create table t1 select stddev(0); show create table t1; drop table t1; # # Bug #23184: SELECT causes server crash # CREATE TABLE t1 (a INT, b INT); INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8); INSERT INTO t1 SELECT a, b+8 FROM t1; INSERT INTO t1 SELECT a, b+16 FROM t1; INSERT INTO t1 SELECT a, b+32 FROM t1; INSERT INTO t1 SELECT a, b+64 FROM t1; INSERT INTO t1 SELECT a, b+128 FROM t1; INSERT INTO t1 SELECT a, b+256 FROM t1; INSERT INTO t1 SELECT a, b+512 FROM t1; INSERT INTO t1 SELECT a, b+1024 FROM t1; INSERT INTO t1 SELECT a, b+2048 FROM t1; INSERT INTO t1 SELECT a, b+4096 FROM t1; INSERT INTO t1 SELECT a, b+8192 FROM t1; INSERT INTO t1 SELECT a, b+16384 FROM t1; INSERT INTO t1 SELECT a, b+32768 FROM t1; SELECT a,COUNT(DISTINCT b) AS cnt FROM t1 GROUP BY a HAVING cnt > 50; SELECT a,SUM(DISTINCT b) AS sumation FROM t1 GROUP BY a HAVING sumation > 50; SELECT a,AVG(DISTINCT b) AS average FROM t1 GROUP BY a HAVING average > 50; DROP TABLE t1; --echo End of 5.0 tests sql/item_sum.cc +34 −13 Original line number Diff line number Diff line Loading @@ -893,6 +893,7 @@ bool Item_sum_distinct::setup(THD *thd) tree= new Unique(simple_raw_key_cmp, &tree_key_length, tree_key_length, thd->variables.max_heap_table_size); is_evaluated= FALSE; DBUG_RETURN(tree == 0); } Loading @@ -900,6 +901,7 @@ bool Item_sum_distinct::setup(THD *thd) bool Item_sum_distinct::add() { args[0]->save_in_field(table->field[0], FALSE); is_evaluated= FALSE; if (!table->field[0]->is_null()) { DBUG_ASSERT(tree); Loading Loading @@ -929,6 +931,7 @@ void Item_sum_distinct::clear() DBUG_ASSERT(tree != 0); /* we always have a tree */ null_value= 1; tree->reset(); is_evaluated= FALSE; DBUG_VOID_RETURN; } Loading @@ -938,6 +941,7 @@ void Item_sum_distinct::cleanup() delete tree; tree= 0; table= 0; is_evaluated= FALSE; } Item_sum_distinct::~Item_sum_distinct() Loading @@ -948,6 +952,8 @@ Item_sum_distinct::~Item_sum_distinct() void Item_sum_distinct::calculate_val_and_count() { if (!is_evaluated) { count= 0; val.traits->set_zero(&val); Loading @@ -960,6 +966,8 @@ void Item_sum_distinct::calculate_val_and_count() table->field[0]->set_notnull(); tree->walk(item_sum_distinct_walk, (void*) this); } is_evaluated= TRUE; } } Loading Loading @@ -1013,10 +1021,14 @@ Item_sum_avg_distinct::fix_length_and_dec() void Item_sum_avg_distinct::calculate_val_and_count() { if (!is_evaluated) { Item_sum_distinct::calculate_val_and_count(); if (count) val.traits->div(&val, count); is_evaluated= TRUE; } } Loading Loading @@ -2477,6 +2489,7 @@ void Item_sum_count_distinct::cleanup() */ delete tree; tree= 0; is_evaluated= FALSE; if (table) { free_tmp_table(table->in_use, table); Loading @@ -2498,6 +2511,7 @@ void Item_sum_count_distinct::make_unique() original= 0; force_copy_fields= 1; tree= 0; is_evaluated= FALSE; tmp_table_param= 0; always_null= FALSE; } Loading Loading @@ -2617,6 +2631,7 @@ bool Item_sum_count_distinct::setup(THD *thd) but this has to be handled - otherwise someone can crash the server with a DoS attack */ is_evaluated= FALSE; if (! tree) return TRUE; } Loading @@ -2633,8 +2648,11 @@ Item *Item_sum_count_distinct::copy_or_same(THD* thd) void Item_sum_count_distinct::clear() { /* tree and table can be both null only if always_null */ is_evaluated= FALSE; if (tree) { tree->reset(); } else if (table) { table->file->extra(HA_EXTRA_NO_CACHE); Loading @@ -2655,6 +2673,7 @@ bool Item_sum_count_distinct::add() if ((*field)->is_real_null(0)) return 0; // Don't count NULL is_evaluated= FALSE; if (tree) { /* Loading @@ -2680,12 +2699,14 @@ longlong Item_sum_count_distinct::val_int() return LL(0); if (tree) { ulonglong count; if (is_evaluated) return count; if (tree->elements == 0) return (longlong) tree->elements_in_tree(); // everything fits in memory count= 0; tree->walk(count_distinct_walk, (void*) &count); is_evaluated= TRUE; return (longlong) count; } table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); Loading sql/item_sum.h +26 −8 Original line number Diff line number Diff line Loading @@ -321,12 +321,23 @@ class Item_sum :public Item_result_field class Item_sum_num :public Item_sum { protected: /* val_xxx() functions may be called several times during the execution of a query. Derived classes that require extensive calculation in val_xxx() maintain cache of aggregate value. This variable governs the validity of that cache. */ bool is_evaluated; public: Item_sum_num() :Item_sum() {} Item_sum_num(Item *item_par) :Item_sum(item_par) {} Item_sum_num(Item *a, Item* b) :Item_sum(a,b) {} Item_sum_num(List<Item> &list) :Item_sum(list) {} Item_sum_num(THD *thd, Item_sum_num *item) :Item_sum(thd, item) {} Item_sum_num() :Item_sum(),is_evaluated(FALSE) {} Item_sum_num(Item *item_par) :Item_sum(item_par), is_evaluated(FALSE) {} Item_sum_num(Item *a, Item* b) :Item_sum(a,b),is_evaluated(FALSE) {} Item_sum_num(List<Item> &list) :Item_sum(list), is_evaluated(FALSE) {} Item_sum_num(THD *thd, Item_sum_num *item) :Item_sum(thd, item),is_evaluated(item->is_evaluated) {} bool fix_fields(THD *, Item **); longlong val_int() { Loading Loading @@ -508,6 +519,12 @@ class Item_sum_count_distinct :public Item_sum_int to help get things set up, but we insert nothing in it */ Unique *tree; /* Storage for the value of count between calls to val_int() so val_int() will not recalculate on each call. Validitiy of the value is stored in is_evaluated. */ longlong count; /* Following is 0 normal object and pointer to original one for copy (to correctly free resources) Loading @@ -525,14 +542,15 @@ class Item_sum_count_distinct :public Item_sum_int public: Item_sum_count_distinct(List<Item> &list) :Item_sum_int(list), table(0), field_lengths(0), tmp_table_param(0), force_copy_fields(0), tree(0), original(0), always_null(FALSE) force_copy_fields(0), tree(0), count(0), original(0), always_null(FALSE) { quick_group= 0; } Item_sum_count_distinct(THD *thd, Item_sum_count_distinct *item) :Item_sum_int(thd, item), table(item->table), field_lengths(item->field_lengths), tmp_table_param(item->tmp_table_param), force_copy_fields(0), tree(item->tree), original(item), tree_key_length(item->tree_key_length), force_copy_fields(0), tree(item->tree), count(item->count), original(item), tree_key_length(item->tree_key_length), always_null(item->always_null) {} ~Item_sum_count_distinct(); Loading Loading
mysql-test/r/func_group.result +26 −0 Original line number Diff line number Diff line Loading @@ -1029,3 +1029,29 @@ t1 CREATE TABLE `t1` ( `stddev(0)` double(8,4) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; CREATE TABLE t1 (a INT, b INT); INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8); INSERT INTO t1 SELECT a, b+8 FROM t1; INSERT INTO t1 SELECT a, b+16 FROM t1; INSERT INTO t1 SELECT a, b+32 FROM t1; INSERT INTO t1 SELECT a, b+64 FROM t1; INSERT INTO t1 SELECT a, b+128 FROM t1; INSERT INTO t1 SELECT a, b+256 FROM t1; INSERT INTO t1 SELECT a, b+512 FROM t1; INSERT INTO t1 SELECT a, b+1024 FROM t1; INSERT INTO t1 SELECT a, b+2048 FROM t1; INSERT INTO t1 SELECT a, b+4096 FROM t1; INSERT INTO t1 SELECT a, b+8192 FROM t1; INSERT INTO t1 SELECT a, b+16384 FROM t1; INSERT INTO t1 SELECT a, b+32768 FROM t1; SELECT a,COUNT(DISTINCT b) AS cnt FROM t1 GROUP BY a HAVING cnt > 50; a cnt 1 65536 SELECT a,SUM(DISTINCT b) AS sumation FROM t1 GROUP BY a HAVING sumation > 50; a sumation 1 2147516416 SELECT a,AVG(DISTINCT b) AS average FROM t1 GROUP BY a HAVING average > 50; a average 1 32768.5000 DROP TABLE t1; End of 5.0 tests
mysql-test/t/func_group.test +25 −0 Original line number Diff line number Diff line Loading @@ -700,3 +700,28 @@ create table t1 select stddev(0); show create table t1; drop table t1; # # Bug #23184: SELECT causes server crash # CREATE TABLE t1 (a INT, b INT); INSERT INTO t1 VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8); INSERT INTO t1 SELECT a, b+8 FROM t1; INSERT INTO t1 SELECT a, b+16 FROM t1; INSERT INTO t1 SELECT a, b+32 FROM t1; INSERT INTO t1 SELECT a, b+64 FROM t1; INSERT INTO t1 SELECT a, b+128 FROM t1; INSERT INTO t1 SELECT a, b+256 FROM t1; INSERT INTO t1 SELECT a, b+512 FROM t1; INSERT INTO t1 SELECT a, b+1024 FROM t1; INSERT INTO t1 SELECT a, b+2048 FROM t1; INSERT INTO t1 SELECT a, b+4096 FROM t1; INSERT INTO t1 SELECT a, b+8192 FROM t1; INSERT INTO t1 SELECT a, b+16384 FROM t1; INSERT INTO t1 SELECT a, b+32768 FROM t1; SELECT a,COUNT(DISTINCT b) AS cnt FROM t1 GROUP BY a HAVING cnt > 50; SELECT a,SUM(DISTINCT b) AS sumation FROM t1 GROUP BY a HAVING sumation > 50; SELECT a,AVG(DISTINCT b) AS average FROM t1 GROUP BY a HAVING average > 50; DROP TABLE t1; --echo End of 5.0 tests
sql/item_sum.cc +34 −13 Original line number Diff line number Diff line Loading @@ -893,6 +893,7 @@ bool Item_sum_distinct::setup(THD *thd) tree= new Unique(simple_raw_key_cmp, &tree_key_length, tree_key_length, thd->variables.max_heap_table_size); is_evaluated= FALSE; DBUG_RETURN(tree == 0); } Loading @@ -900,6 +901,7 @@ bool Item_sum_distinct::setup(THD *thd) bool Item_sum_distinct::add() { args[0]->save_in_field(table->field[0], FALSE); is_evaluated= FALSE; if (!table->field[0]->is_null()) { DBUG_ASSERT(tree); Loading Loading @@ -929,6 +931,7 @@ void Item_sum_distinct::clear() DBUG_ASSERT(tree != 0); /* we always have a tree */ null_value= 1; tree->reset(); is_evaluated= FALSE; DBUG_VOID_RETURN; } Loading @@ -938,6 +941,7 @@ void Item_sum_distinct::cleanup() delete tree; tree= 0; table= 0; is_evaluated= FALSE; } Item_sum_distinct::~Item_sum_distinct() Loading @@ -948,6 +952,8 @@ Item_sum_distinct::~Item_sum_distinct() void Item_sum_distinct::calculate_val_and_count() { if (!is_evaluated) { count= 0; val.traits->set_zero(&val); Loading @@ -960,6 +966,8 @@ void Item_sum_distinct::calculate_val_and_count() table->field[0]->set_notnull(); tree->walk(item_sum_distinct_walk, (void*) this); } is_evaluated= TRUE; } } Loading Loading @@ -1013,10 +1021,14 @@ Item_sum_avg_distinct::fix_length_and_dec() void Item_sum_avg_distinct::calculate_val_and_count() { if (!is_evaluated) { Item_sum_distinct::calculate_val_and_count(); if (count) val.traits->div(&val, count); is_evaluated= TRUE; } } Loading Loading @@ -2477,6 +2489,7 @@ void Item_sum_count_distinct::cleanup() */ delete tree; tree= 0; is_evaluated= FALSE; if (table) { free_tmp_table(table->in_use, table); Loading @@ -2498,6 +2511,7 @@ void Item_sum_count_distinct::make_unique() original= 0; force_copy_fields= 1; tree= 0; is_evaluated= FALSE; tmp_table_param= 0; always_null= FALSE; } Loading Loading @@ -2617,6 +2631,7 @@ bool Item_sum_count_distinct::setup(THD *thd) but this has to be handled - otherwise someone can crash the server with a DoS attack */ is_evaluated= FALSE; if (! tree) return TRUE; } Loading @@ -2633,8 +2648,11 @@ Item *Item_sum_count_distinct::copy_or_same(THD* thd) void Item_sum_count_distinct::clear() { /* tree and table can be both null only if always_null */ is_evaluated= FALSE; if (tree) { tree->reset(); } else if (table) { table->file->extra(HA_EXTRA_NO_CACHE); Loading @@ -2655,6 +2673,7 @@ bool Item_sum_count_distinct::add() if ((*field)->is_real_null(0)) return 0; // Don't count NULL is_evaluated= FALSE; if (tree) { /* Loading @@ -2680,12 +2699,14 @@ longlong Item_sum_count_distinct::val_int() return LL(0); if (tree) { ulonglong count; if (is_evaluated) return count; if (tree->elements == 0) return (longlong) tree->elements_in_tree(); // everything fits in memory count= 0; tree->walk(count_distinct_walk, (void*) &count); is_evaluated= TRUE; return (longlong) count; } table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); Loading
sql/item_sum.h +26 −8 Original line number Diff line number Diff line Loading @@ -321,12 +321,23 @@ class Item_sum :public Item_result_field class Item_sum_num :public Item_sum { protected: /* val_xxx() functions may be called several times during the execution of a query. Derived classes that require extensive calculation in val_xxx() maintain cache of aggregate value. This variable governs the validity of that cache. */ bool is_evaluated; public: Item_sum_num() :Item_sum() {} Item_sum_num(Item *item_par) :Item_sum(item_par) {} Item_sum_num(Item *a, Item* b) :Item_sum(a,b) {} Item_sum_num(List<Item> &list) :Item_sum(list) {} Item_sum_num(THD *thd, Item_sum_num *item) :Item_sum(thd, item) {} Item_sum_num() :Item_sum(),is_evaluated(FALSE) {} Item_sum_num(Item *item_par) :Item_sum(item_par), is_evaluated(FALSE) {} Item_sum_num(Item *a, Item* b) :Item_sum(a,b),is_evaluated(FALSE) {} Item_sum_num(List<Item> &list) :Item_sum(list), is_evaluated(FALSE) {} Item_sum_num(THD *thd, Item_sum_num *item) :Item_sum(thd, item),is_evaluated(item->is_evaluated) {} bool fix_fields(THD *, Item **); longlong val_int() { Loading Loading @@ -508,6 +519,12 @@ class Item_sum_count_distinct :public Item_sum_int to help get things set up, but we insert nothing in it */ Unique *tree; /* Storage for the value of count between calls to val_int() so val_int() will not recalculate on each call. Validitiy of the value is stored in is_evaluated. */ longlong count; /* Following is 0 normal object and pointer to original one for copy (to correctly free resources) Loading @@ -525,14 +542,15 @@ class Item_sum_count_distinct :public Item_sum_int public: Item_sum_count_distinct(List<Item> &list) :Item_sum_int(list), table(0), field_lengths(0), tmp_table_param(0), force_copy_fields(0), tree(0), original(0), always_null(FALSE) force_copy_fields(0), tree(0), count(0), original(0), always_null(FALSE) { quick_group= 0; } Item_sum_count_distinct(THD *thd, Item_sum_count_distinct *item) :Item_sum_int(thd, item), table(item->table), field_lengths(item->field_lengths), tmp_table_param(item->tmp_table_param), force_copy_fields(0), tree(item->tree), original(item), tree_key_length(item->tree_key_length), force_copy_fields(0), tree(item->tree), count(item->count), original(item), tree_key_length(item->tree_key_length), always_null(item->always_null) {} ~Item_sum_count_distinct(); Loading