Commit d146c2ce authored by Sergei Petrunia's avatar Sergei Petrunia

MDEV-9787: Window functions: HAVING and GROUP BY

- Hook window function computation into the right location.
- Add a testcase which shows that HAVING is now checked before
  the window function computation step.
parent e8875833
...@@ -1472,5 +1472,34 @@ EXPLAIN ...@@ -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 t1;
drop table t0; drop table t0;
...@@ -950,7 +950,14 @@ from t1 ...@@ -950,7 +950,14 @@ from t1
group by a group by a
order by null; 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 t1;
drop table t0; drop table t0;
...@@ -2333,14 +2333,6 @@ bool JOIN::make_aggr_tables_info() ...@@ -2333,14 +2333,6 @@ bool JOIN::make_aggr_tables_info()
curr_tab->fields= &tmp_fields_list1; curr_tab->fields= &tmp_fields_list1;
set_postjoin_aggr_write_func(curr_tab); 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.func_count= 0;
tmp_table_param.field_count+= tmp_table_param.func_count; tmp_table_param.field_count+= tmp_table_param.func_count;
if (sort_and_group || curr_tab->table->group) if (sort_and_group || curr_tab->table->group)
...@@ -2652,6 +2644,24 @@ bool JOIN::make_aggr_tables_info() ...@@ -2652,6 +2644,24 @@ bool JOIN::make_aggr_tables_info()
skip_sort_order= true; 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; fields= curr_fields_list;
// Reset before execution // Reset before execution
set_items_ref_array(items0); set_items_ref_array(items0);
......
...@@ -1565,11 +1565,20 @@ bool Window_func_runner::exec(JOIN *join) ...@@ -1565,11 +1565,20 @@ bool Window_func_runner::exec(JOIN *join)
bool Window_funcs_computation::setup(THD *thd, bool Window_funcs_computation::setup(THD *thd,
List<Item_window_func> *window_funcs) List<Item_window_func> *window_funcs,
JOIN_TAB *tab)
{ {
List_iterator_fast<Item_window_func> it(*window_funcs); List_iterator_fast<Item_window_func> it(*window_funcs);
Item_window_func *item_win; Item_window_func *item_win;
Window_func_runner *runner; 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 // for each window function
while ((item_win= it++)) while ((item_win= it++))
{ {
...@@ -1579,6 +1588,8 @@ bool Window_funcs_computation::setup(THD *thd, ...@@ -1579,6 +1588,8 @@ bool Window_funcs_computation::setup(THD *thd,
{ {
return true; return true;
} }
/* Apply the same condition that the subsequent sort will */
runner->filesort->select= sel;
win_func_runners.push_back(runner, thd->mem_root); win_func_runners.push_back(runner, thd->mem_root);
} }
return false; return false;
......
...@@ -171,9 +171,11 @@ class Window_func_runner : public Sql_alloc ...@@ -171,9 +171,11 @@ class Window_func_runner : public Sql_alloc
bool exec(JOIN *join); bool exec(JOIN *join);
void cleanup() { delete filesort; } 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 This is a "window function computation phase": a single object of this class
takes care of computing all window functions in a SELECT. takes care of computing all window functions in a SELECT.
...@@ -187,7 +189,7 @@ class Window_funcs_computation : public Sql_alloc ...@@ -187,7 +189,7 @@ class Window_funcs_computation : public Sql_alloc
{ {
List<Window_func_runner> win_func_runners; List<Window_func_runner> win_func_runners;
public: public:
bool setup(THD *thd, List<Item_window_func> *window_funcs); bool setup(THD *thd, List<Item_window_func> *window_funcs, st_join_table *tab);
bool exec(JOIN *join); bool exec(JOIN *join);
void cleanup(); void cleanup();
}; };
......
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