mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Merge branch 'bb-10.2-mdev9543' of github.com:MariaDB/server into bb-10.2-mdev9543
This commit is contained in:
@ -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;
|
|||||||
|
|
||||||
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,
|
|||||||
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
|
|||||||
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 @@ public:
|
|||||||
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()
|
|||||||
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()
|
|||||||
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()
|
|||||||
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)
|
|||||||
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)
|
|||||||
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()
|
|||||||
|
|
||||||
// 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 {
|
|||||||
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)
|
|||||||
|
|
||||||
|
|
||||||
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,
|
|||||||
{
|
{
|
||||||
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 @@ public:
|
|||||||
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
|
|||||||
{
|
{
|
||||||
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();
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user