From 38172240e3d5736d7d55fa2296facd2fcf84f3f6 Mon Sep 17 00:00:00 2001 From: "gkodinov/kgeorge@magare.gmz" <> Date: Fri, 29 Jun 2007 10:39:17 +0300 Subject: [PATCH] Bug#27333: subquery grouped for aggregate of outer query / no aggregate of subquery The optimizer counts the aggregate functions that appear as top level expressions (in all_fields) in the current subquery. Later it makes a list of these that it uses to actually execute the aggregates in end_send_group(). That count is used in several places as a flag whether there are aggregates functions. While collecting the above info it must not consider aggregates that are not aggregated in the current context. It must treat them as normal expressions instead. Not doing that leads to incorrect data about the query, e.g. running a query that actually has no aggregate functions as if it has some (and hence is expected to return only one row). Fixed by ignoring the aggregates that are not aggregated in the current context. One other smaller omission discovered and fixed in the process : the place of aggregation was not calculated for user defined functions. Fixed by calling Item_sum::init_sum_func_check() and Item_sum::check_sum_func() as it's done for the rest of the aggregate functions. --- mysql-test/r/subselect.result | 33 +++++++++++++++++++++++ mysql-test/t/subselect.test | 42 ++++++++++++++++++++++++++++++ sql/item_subselect.cc | 3 ++- sql/item_sum.cc | 4 +-- sql/item_sum.h | 9 ++++++- sql/sql_select.cc | 49 +++++++++++++++++++++-------------- sql/sql_select.h | 4 +-- 7 files changed, 119 insertions(+), 25 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index efd6a5ab572..be99bdb1afc 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -4106,4 +4106,37 @@ d1 1 1 DROP TABLE t1,t2; +CREATE TABLE t1 (a INTEGER, b INTEGER); +CREATE TABLE t2 (x INTEGER); +INSERT INTO t1 VALUES (1,11), (2,22), (2,22); +INSERT INTO t2 VALUES (1), (2); +SELECT a, COUNT(b), (SELECT COUNT(b) FROM t2) FROM t1 GROUP BY a; +ERROR 21000: Subquery returns more than 1 row +SELECT a, COUNT(b), (SELECT COUNT(b)+0 FROM t2) FROM t1 GROUP BY a; +ERROR 21000: Subquery returns more than 1 row +SELECT (SELECT SUM(t1.a)/AVG(t2.x) FROM t2) FROM t1; +(SELECT SUM(t1.a)/AVG(t2.x) FROM t2) +3.3333 +DROP TABLE t1,t2; +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1, 2), (1,3), (1,4), (2,1), (2,2); +SELECT a1.a, COUNT(*) FROM t1 a1 WHERE a1.a = 1 +AND EXISTS( SELECT a2.a FROM t1 a2 WHERE a2.a = a1.a) +GROUP BY a1.a; +a COUNT(*) +1 3 +DROP TABLE t1; +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1),(2); +SELECT (SELECT SUM(t1.a) FROM t2 WHERE a=0) FROM t1; +(SELECT SUM(t1.a) FROM t2 WHERE a=0) +NULL +SELECT (SELECT SUM(t1.a) FROM t2 WHERE a!=0) FROM t1; +ERROR 21000: Subquery returns more than 1 row +SELECT (SELECT SUM(t1.a) FROM t2 WHERE a=1) FROM t1; +(SELECT SUM(t1.a) FROM t2 WHERE a=1) +3 +DROP TABLE t1,t2; End of 5.0 tests. diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 12688fa4cf4..d076ca6bd33 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2945,4 +2945,46 @@ SELECT (SELECT 1 FROM t1 WHERE t1.a=t2.a ORDER BY t1.b LIMIT 1) AS d1 FROM t2; DROP TABLE t1,t2; + +# +# Bug #27333: subquery grouped for aggregate of outer query / no aggregate +# of subquery +# +CREATE TABLE t1 (a INTEGER, b INTEGER); +CREATE TABLE t2 (x INTEGER); +INSERT INTO t1 VALUES (1,11), (2,22), (2,22); +INSERT INTO t2 VALUES (1), (2); + +# wasn't failing, but should +--error ER_SUBQUERY_NO_1_ROW +SELECT a, COUNT(b), (SELECT COUNT(b) FROM t2) FROM t1 GROUP BY a; + +# fails as it should +--error ER_SUBQUERY_NO_1_ROW +SELECT a, COUNT(b), (SELECT COUNT(b)+0 FROM t2) FROM t1 GROUP BY a; + +SELECT (SELECT SUM(t1.a)/AVG(t2.x) FROM t2) FROM t1; +DROP TABLE t1,t2; + +# second test case from 27333 +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1, 2), (1,3), (1,4), (2,1), (2,2); + +-- returns no rows, when it should +SELECT a1.a, COUNT(*) FROM t1 a1 WHERE a1.a = 1 +AND EXISTS( SELECT a2.a FROM t1 a2 WHERE a2.a = a1.a) +GROUP BY a1.a; +DROP TABLE t1; + +#test cases from 29297 +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (a INT); +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (1),(2); +SELECT (SELECT SUM(t1.a) FROM t2 WHERE a=0) FROM t1; +--error ER_SUBQUERY_NO_1_ROW +SELECT (SELECT SUM(t1.a) FROM t2 WHERE a!=0) FROM t1; +SELECT (SELECT SUM(t1.a) FROM t2 WHERE a=1) FROM t1; +DROP TABLE t1,t2; + --echo End of 5.0 tests. diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 3f4ba16a18d..0020dd35c61 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -942,7 +942,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, DBUG_RETURN(RES_ERROR); thd->lex->allow_sum_func= save_allow_sum_func; /* we added aggregate function => we have to change statistic */ - count_field_types(&join->tmp_table_param, join->all_fields, 0); + count_field_types(select_lex, &join->tmp_table_param, join->all_fields, + 0); subs= new Item_singlerow_subselect(select_lex); } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index ea2a14ffb63..e5b0f2721b1 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2461,7 +2461,7 @@ bool Item_sum_count_distinct::setup(THD *thd) } if (always_null) return FALSE; - count_field_types(tmp_table_param,list,0); + count_field_types(select_lex, tmp_table_param, list, 0); tmp_table_param->force_copy_fields= force_copy_fields; DBUG_ASSERT(table == 0); if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1, @@ -3265,7 +3265,7 @@ bool Item_func_group_concat::setup(THD *thd) setup_order(thd, args, context->table_list, list, all_fields, *order)) DBUG_RETURN(TRUE); - count_field_types(tmp_table_param,all_fields,0); + count_field_types(select_lex, tmp_table_param, all_fields, 0); tmp_table_param->force_copy_fields= force_copy_fields; DBUG_ASSERT(table == 0); /* diff --git a/sql/item_sum.h b/sql/item_sum.h index 66c73e1d416..d18454cc3b8 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -966,8 +966,15 @@ public: bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); + + if (init_sum_func_check(thd)) + return TRUE; + fixed= 1; - return udf.fix_fields(thd, this, this->arg_count, this->args); + if (udf.fix_fields(thd, this, this->arg_count, this->args)) + return TRUE; + + return check_sum_func(thd, ref); } enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } virtual bool have_field_update(void) const { return 0; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c403a50de20..9d27ab4bb4e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -611,7 +611,7 @@ JOIN::prepare(Item ***rref_pointer_array, goto err; /* purecov: inspected */ /* Init join struct */ - count_field_types(&tmp_table_param, all_fields, 0); + count_field_types(select_lex, &tmp_table_param, all_fields, 0); ref_pointer_array_size= all_fields.elements*sizeof(Item*); this->group= group_list != 0; unit= unit_arg; @@ -1766,7 +1766,7 @@ JOIN::exec() if (make_simple_join(curr_join, curr_tmp_table)) DBUG_VOID_RETURN; calc_group_buffer(curr_join, group_list); - count_field_types(&curr_join->tmp_table_param, + count_field_types(select_lex, &curr_join->tmp_table_param, curr_join->tmp_all_fields1, curr_join->select_distinct && !curr_join->group_list); curr_join->tmp_table_param.hidden_field_count= @@ -1886,11 +1886,13 @@ JOIN::exec() if (make_simple_join(curr_join, curr_tmp_table)) DBUG_VOID_RETURN; calc_group_buffer(curr_join, curr_join->group_list); - count_field_types(&curr_join->tmp_table_param, *curr_all_fields, 0); + count_field_types(select_lex, &curr_join->tmp_table_param, + *curr_all_fields, 0); } if (procedure) - count_field_types(&curr_join->tmp_table_param, *curr_all_fields, 0); + count_field_types(select_lex, &curr_join->tmp_table_param, + *curr_all_fields, 0); if (curr_join->group || curr_join->tmp_table_param.sum_func_count || (procedure && (procedure->flags & PROC_GROUP))) @@ -13678,8 +13680,8 @@ next_item: *****************************************************************************/ void -count_field_types(TMP_TABLE_PARAM *param, List &fields, - bool reset_with_sum_func) +count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param, + List &fields, bool reset_with_sum_func) { List_iterator li(fields); Item *field; @@ -13697,18 +13699,22 @@ count_field_types(TMP_TABLE_PARAM *param, List &fields, if (! field->const_item()) { Item_sum *sum_item=(Item_sum*) field->real_item(); - if (!sum_item->quick_group) - param->quick_group=0; // UDF SUM function - param->sum_func_count++; - param->func_count++; + if (!sum_item->depended_from() || + sum_item->depended_from() == select_lex) + { + if (!sum_item->quick_group) + param->quick_group=0; // UDF SUM function + param->sum_func_count++; - for (uint i=0 ; i < sum_item->arg_count ; i++) - { - if (sum_item->args[0]->real_item()->type() == Item::FIELD_ITEM) - param->field_count++; - else - param->func_count++; - } + for (uint i=0 ; i < sum_item->arg_count ; i++) + { + if (sum_item->args[0]->real_item()->type() == Item::FIELD_ITEM) + param->field_count++; + else + param->func_count++; + } + } + param->func_count++; } } else @@ -14170,7 +14176,9 @@ bool JOIN::make_sum_func_list(List &field_list, List &send_fields, func= sum_funcs; while ((item=it++)) { - if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item()) + if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item() && + (!((Item_sum*) item)->depended_from() || + ((Item_sum *)item)->depended_from() == select_lex)) *func++= (Item_sum*) item; } if (before_group_by && rollup.state == ROLLUP::STATE_INITED) @@ -14752,7 +14760,10 @@ bool JOIN::rollup_make_fields(List &fields_arg, List &sel_fields, ref_array= ref_array_start; } - if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item()) + if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item() && + (!((Item_sum*) item)->depended_from() || + ((Item_sum *)item)->depended_from() == select_lex)) + { /* This is a top level summary function that must be replaced with diff --git a/sql/sql_select.h b/sql/sql_select.h index 3cdd265df9a..4f9f6e9ed48 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -470,8 +470,8 @@ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, ulonglong select_options, ha_rows rows_limit, char* alias); void free_tmp_table(THD *thd, TABLE *entry); -void count_field_types(TMP_TABLE_PARAM *param, List &fields, - bool reset_with_sum_func); +void count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param, + List &fields, bool reset_with_sum_func); bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, Item **ref_pointer_array, List &new_list1, List &new_list2,