Commit 4fe6fbbb authored by Sergei Petrunia's avatar Sergei Petrunia

Merge branch 'bb-10.2-mdev9543' of github.com:MariaDB/server into bb-10.2-mdev9543

parents 2bd4dc38 d146c2ce
...@@ -1401,3 +1401,105 @@ pk c CNT ...@@ -1401,3 +1401,105 @@ pk c CNT
9 2 4 9 2 4
10 2 3 10 2 3
drop table t0,t1; drop table t0,t1;
#
# EXPLAIN FORMAT=JSON support for window functions
#
create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
explain format=json select rank() over (order by a) from t0;
EXPLAIN
{
"query_block": {
"select_id": 1,
"window_functions_computation": {
"temporary_table": {
"table": {
"table_name": "t0",
"access_type": "ALL",
"rows": 10,
"filtered": 100
}
}
}
}
}
create table t1 (a int, b int, c int);
insert into t1 select a,a,a from t0;
explain format=json
select
a,
rank() over (order by sum(b))
from t1
group by a;
EXPLAIN
{
"query_block": {
"select_id": 1,
"filesort": {
"window_functions_computation": {
"temporary_table": {
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100
}
}
}
}
}
}
explain format=json
select
a,
rank() over (order by sum(b))
from t1
group by a
order by null;
EXPLAIN
{
"query_block": {
"select_id": 1,
"window_functions_computation": {
"temporary_table": {
"table": {
"table_name": "t1",
"access_type": "ALL",
"rows": 10,
"filtered": 100
}
}
}
}
}
#
# 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;
...@@ -924,8 +924,40 @@ execute stmt; ...@@ -924,8 +924,40 @@ execute stmt;
drop table t0,t1; drop table t0,t1;
--echo #
--echo # EXPLAIN FORMAT=JSON support for window functions
--echo #
create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
explain format=json select rank() over (order by a) from t0;
create table t1 (a int, b int, c int);
insert into t1 select a,a,a from t0;
explain format=json
select
a,
rank() over (order by sum(b))
from t1
group by a;
explain format=json
select
a,
rank() over (order by sum(b))
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;
...@@ -884,6 +884,9 @@ void Explain_select::print_explain_json(Explain_query *query, ...@@ -884,6 +884,9 @@ void Explain_select::print_explain_json(Explain_query *query,
case AGGR_OP_REMOVE_DUPLICATES: case AGGR_OP_REMOVE_DUPLICATES:
writer->add_member("duplicate_removal").start_object(); writer->add_member("duplicate_removal").start_object();
break; break;
case AGGR_OP_WINDOW_FUNCS:
writer->add_member("window_functions_computation").start_object();
break;
default: default:
DBUG_ASSERT(0); DBUG_ASSERT(0);
} }
......
...@@ -265,7 +265,8 @@ typedef enum ...@@ -265,7 +265,8 @@ typedef enum
AGGR_OP_TEMP_TABLE, AGGR_OP_TEMP_TABLE,
AGGR_OP_FILESORT, AGGR_OP_FILESORT,
//AGGR_OP_READ_SORTED_FILE, // need this? //AGGR_OP_READ_SORTED_FILE, // need this?
AGGR_OP_REMOVE_DUPLICATES AGGR_OP_REMOVE_DUPLICATES,
AGGR_OP_WINDOW_FUNCS
//AGGR_OP_JOIN // Need this? //AGGR_OP_JOIN // Need this?
} enum_explain_aggr_node_type; } enum_explain_aggr_node_type;
...@@ -297,6 +298,11 @@ class Explain_aggr_remove_dups : public Explain_aggr_node ...@@ -297,6 +298,11 @@ class Explain_aggr_remove_dups : public Explain_aggr_node
enum_explain_aggr_node_type get_type() { return AGGR_OP_REMOVE_DUPLICATES; } enum_explain_aggr_node_type get_type() { return AGGR_OP_REMOVE_DUPLICATES; }
}; };
class Explain_aggr_window_funcs : public Explain_aggr_node
{
public:
enum_explain_aggr_node_type get_type() { return AGGR_OP_WINDOW_FUNCS; }
};
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
......
...@@ -2140,7 +2140,6 @@ bool JOIN::make_aggr_tables_info() ...@@ -2140,7 +2140,6 @@ bool JOIN::make_aggr_tables_info()
All optimization is done. Check if we can use the storage engines All optimization is done. Check if we can use the storage engines
group by handler to evaluate the group by group by handler to evaluate the group by
*/ */
group_by_handler *gbh= NULL;
if (tables_list && (tmp_table_param.sum_func_count || group_list) && if (tables_list && (tmp_table_param.sum_func_count || group_list) &&
!procedure) !procedure)
{ {
...@@ -2339,14 +2338,6 @@ bool JOIN::make_aggr_tables_info() ...@@ -2339,14 +2338,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= new Window_funcs_computation;
if (curr_tab->window_funcs->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)
...@@ -2658,6 +2649,24 @@ bool JOIN::make_aggr_tables_info() ...@@ -2658,6 +2649,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);
...@@ -19137,7 +19146,10 @@ bool test_if_use_dynamic_range_scan(JOIN_TAB *join_tab) ...@@ -19137,7 +19146,10 @@ bool test_if_use_dynamic_range_scan(JOIN_TAB *join_tab)
int join_init_read_record(JOIN_TAB *tab) int join_init_read_record(JOIN_TAB *tab)
{ {
int error; int error;
/*
Note: the query plan tree for the below operations is constructed in
save_agg_explain_data.
*/
if (tab->distinct && tab->remove_duplicates()) // Remove duplicates. if (tab->distinct && tab->remove_duplicates()) // Remove duplicates.
return 1; return 1;
if (tab->filesort && tab->sort_table()) // Sort table. if (tab->filesort && tab->sort_table()) // Sort table.
...@@ -24174,6 +24186,14 @@ void save_agg_explain_data(JOIN *join, Explain_select *xpl_sel) ...@@ -24174,6 +24186,14 @@ void save_agg_explain_data(JOIN *join, Explain_select *xpl_sel)
node= new Explain_aggr_tmp_table; node= new Explain_aggr_tmp_table;
node->child= prev_node; node->child= prev_node;
if (join_tab->window_funcs_step)
{
prev_node=node;
node= new Explain_aggr_window_funcs;
node->child= prev_node;
}
/* The below matches execution in join_init_read_record() */
if (join_tab->distinct) if (join_tab->distinct)
{ {
prev_node= node; prev_node= node;
...@@ -25946,9 +25966,10 @@ AGGR_OP::end_send() ...@@ -25946,9 +25966,10 @@ AGGR_OP::end_send()
// Update ref array // Update ref array
join_tab->join->set_items_ref_array(*join_tab->ref_array); join_tab->join->set_items_ref_array(*join_tab->ref_array);
if (join_tab->window_funcs) if (join_tab->window_funcs_step)
{ {
join_tab->window_funcs->exec(join); if (join_tab->window_funcs_step->exec(join))
return NESTED_LOOP_ERROR;
} }
table->reginfo.lock_type= TL_UNLOCK; table->reginfo.lock_type= TL_UNLOCK;
......
...@@ -428,7 +428,7 @@ typedef struct st_join_table { ...@@ -428,7 +428,7 @@ typedef struct st_join_table {
Non-NULL value means this join_tab must do window function computation Non-NULL value means this join_tab must do window function computation
before reading. before reading.
*/ */
Window_funcs_computation* window_funcs; Window_funcs_computation* window_funcs_step;
/** /**
List of topmost expressions in the select list. The *next* JOIN TAB List of topmost expressions in the select list. The *next* JOIN TAB
......
...@@ -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