diff --git a/mysql-test/r/win.result b/mysql-test/r/win.result index 4692a3f76cc..82b04e17116 100644 --- a/mysql-test/r/win.result +++ b/mysql-test/r/win.result @@ -1401,3 +1401,76 @@ pk c CNT 9 2 4 10 2 3 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 + } + } + } + } +} +drop table t1; +drop table t0; diff --git a/mysql-test/t/win.test b/mysql-test/t/win.test index cc01d5e678e..6469dc1dbe3 100644 --- a/mysql-test/t/win.test +++ b/mysql-test/t/win.test @@ -924,8 +924,33 @@ execute stmt; 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; + +drop table t1; +drop table t0; diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc index f3001d5942a..f3d71e6ce80 100644 --- a/sql/sql_explain.cc +++ b/sql/sql_explain.cc @@ -878,6 +878,9 @@ void Explain_select::print_explain_json(Explain_query *query, case AGGR_OP_REMOVE_DUPLICATES: writer->add_member("duplicate_removal").start_object(); break; + case AGGR_OP_WINDOW_FUNCS: + writer->add_member("window_functions_computation").start_object(); + break; default: DBUG_ASSERT(0); } diff --git a/sql/sql_explain.h b/sql/sql_explain.h index 3f57f7ac937..ba2cc482be1 100644 --- a/sql/sql_explain.h +++ b/sql/sql_explain.h @@ -264,7 +264,8 @@ typedef enum AGGR_OP_TEMP_TABLE, AGGR_OP_FILESORT, //AGGR_OP_READ_SORTED_FILE, // need this? - AGGR_OP_REMOVE_DUPLICATES + AGGR_OP_REMOVE_DUPLICATES, + AGGR_OP_WINDOW_FUNCS //AGGR_OP_JOIN // Need this? } enum_explain_aggr_node_type; @@ -296,6 +297,11 @@ public: 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; } +}; ///////////////////////////////////////////////////////////////////////////// diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 30be455b3d3..b67ecaf492f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2135,7 +2135,6 @@ bool JOIN::make_aggr_tables_info() All optimization is done. Check if we can use the storage engines group by handler to evaluate the group by */ - group_by_handler *gbh= NULL; if (tables_list && (tmp_table_param.sum_func_count || group_list) && !procedure) { @@ -2337,8 +2336,8 @@ bool JOIN::make_aggr_tables_info() // 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)) + curr_tab->window_funcs_step= new Window_funcs_computation; + if (curr_tab->window_funcs_step->setup(thd, &select_lex->window_funcs)) DBUG_RETURN(true); } @@ -19137,7 +19136,10 @@ bool test_if_use_dynamic_range_scan(JOIN_TAB *join_tab) int join_init_read_record(JOIN_TAB *tab) { 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. return 1; if (tab->filesort && tab->sort_table()) // Sort table. @@ -24158,6 +24160,14 @@ void save_agg_explain_data(JOIN *join, Explain_select *xpl_sel) node= new Explain_aggr_tmp_table; 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) { prev_node= node; @@ -25919,9 +25929,10 @@ AGGR_OP::end_send() // Update 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; diff --git a/sql/sql_select.h b/sql/sql_select.h index e85931dcc7c..552ff4686ca 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -428,7 +428,7 @@ typedef struct st_join_table { Non-NULL value means this join_tab must do window function computation 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