diff --git a/mysql-test/r/win.result b/mysql-test/r/win.result index 82b04e17116..11d1fe9279f 100644 --- a/mysql-test/r/win.result +++ b/mysql-test/r/win.result @@ -1472,5 +1472,34 @@ EXPLAIN } } } +# +# Check how window function works together with GROUP BY and HAVING +# +select b,max(a) as MX, rank() over (order by b) from t1 group by b having MX in (3,5,7); +b MX rank() over (order by b) +3 3 1 +5 5 2 +7 7 3 +explain format=json +select b,max(a) as MX, rank() over (order by b) from t1 group by b having MX in (3,5,7); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "(MX in (3,5,7))", + "filesort": { + "window_functions_computation": { + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 10, + "filtered": 100 + } + } + } + } + } +} drop table t1; drop table t0; diff --git a/mysql-test/t/win.test b/mysql-test/t/win.test index 6469dc1dbe3..35b6c1cbb72 100644 --- a/mysql-test/t/win.test +++ b/mysql-test/t/win.test @@ -950,7 +950,14 @@ from t1 group by a order by null; +--echo # +--echo # Check how window function works together with GROUP BY and HAVING +--echo # + +select b,max(a) as MX, rank() over (order by b) from t1 group by b having MX in (3,5,7); +explain format=json +select b,max(a) as MX, rank() over (order by b) from t1 group by b having MX in (3,5,7); + drop table t1; drop table t0; - diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b67ecaf492f..5ef9cf80ac8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2333,14 +2333,6 @@ bool JOIN::make_aggr_tables_info() curr_tab->fields= &tmp_fields_list1; set_postjoin_aggr_write_func(curr_tab); - // psergey-todo: this is probably an incorrect place: - if (select_lex->window_funcs.elements) - { - curr_tab->window_funcs_step= new Window_funcs_computation; - if (curr_tab->window_funcs_step->setup(thd, &select_lex->window_funcs)) - DBUG_RETURN(true); - } - tmp_table_param.func_count= 0; tmp_table_param.field_count+= tmp_table_param.func_count; if (sort_and_group || curr_tab->table->group) @@ -2652,6 +2644,24 @@ bool JOIN::make_aggr_tables_info() skip_sort_order= true; } } + + /* + Window functions computation step should be attached to the last join_tab + that's doing aggregation. + The last join_tab reads the data from the temp. table. It also may do + - sorting + - duplicate value removal + Both of these operations are done after window function computation step. + */ + curr_tab= join_tab + top_join_tab_count + aggr_tables - 1; + if (select_lex->window_funcs.elements) + { + curr_tab->window_funcs_step= new Window_funcs_computation; + if (curr_tab->window_funcs_step->setup(thd, &select_lex->window_funcs, + curr_tab)) + DBUG_RETURN(true); + } + fields= curr_fields_list; // Reset before execution set_items_ref_array(items0); diff --git a/sql/sql_window.cc b/sql/sql_window.cc index 0352a0dfb5f..f28301c26a4 100644 --- a/sql/sql_window.cc +++ b/sql/sql_window.cc @@ -1565,11 +1565,20 @@ bool Window_func_runner::exec(JOIN *join) bool Window_funcs_computation::setup(THD *thd, - List *window_funcs) + List *window_funcs, + JOIN_TAB *tab) { List_iterator_fast it(*window_funcs); Item_window_func *item_win; Window_func_runner *runner; + + SQL_SELECT *sel= NULL; + if (tab->filesort && tab->filesort->select) + { + sel= tab->filesort->select; + DBUG_ASSERT(!sel->quick); + } + // for each window function while ((item_win= it++)) { @@ -1579,6 +1588,8 @@ bool Window_funcs_computation::setup(THD *thd, { return true; } + /* Apply the same condition that the subsequent sort will */ + runner->filesort->select= sel; win_func_runners.push_back(runner, thd->mem_root); } return false; diff --git a/sql/sql_window.h b/sql/sql_window.h index 4c88a49b6b9..042d978431f 100644 --- a/sql/sql_window.h +++ b/sql/sql_window.h @@ -171,9 +171,11 @@ public: bool exec(JOIN *join); void cleanup() { delete filesort; } + + friend class Window_funcs_computation; }; - +struct st_join_table; /* This is a "window function computation phase": a single object of this class takes care of computing all window functions in a SELECT. @@ -187,7 +189,7 @@ class Window_funcs_computation : public Sql_alloc { List win_func_runners; public: - bool setup(THD *thd, List *window_funcs); + bool setup(THD *thd, List *window_funcs, st_join_table *tab); bool exec(JOIN *join); void cleanup(); };