From 426cd232a7fed0a55403aa9e42c0dd05dedd8b58 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 4 Feb 2016 18:41:50 +0300 Subject: [PATCH] Window functions: moving ahead Disable the code that attempts to group window functions together by their PARTITION BY / ORDER BY clauses, because 1. It doesn't work: when I issue a query with just one window function, and no indexes on the table, filesort is not invoked at all. 2. It is not possible to check that it works currently. Add my own code that does invoke filesort() for each window function. - Hopefully the sort criteria is right - Debugging shows that filesort operates on {sort_key, rowid} pairs (OK) - We can read the filesort rowid result in order. --- sql/sql_select.h | 2 +- sql/sql_window.cc | 101 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 95 insertions(+), 8 deletions(-) diff --git a/sql/sql_select.h b/sql/sql_select.h index 5aa1924adfa..a75662dd1c7 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1519,7 +1519,7 @@ public: int init_execution(); void exec(); - void process_window_functions(List *curr_fields_list); + bool process_window_functions(List *curr_fields_list); void exec_inner(); bool prepare_result(List **columns_list); diff --git a/sql/sql_window.cc b/sql/sql_window.cc index b5be3db15ef..392d17dd8ec 100644 --- a/sql/sql_window.cc +++ b/sql/sql_window.cc @@ -2,7 +2,7 @@ #include "item_windowfunc.h" #include "filesort.h" #include "sql_window.h" - +//TODO: why pass List by value?? bool Window_spec::check_window_names(List_iterator_fast &it) @@ -88,9 +88,13 @@ setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, @detail JOIN::exec calls this after it has filled the temporary table with query output. The temporary table has fields to store window function values. + + @return + false OK + true Error */ -void JOIN::process_window_functions(List *curr_fields_list) +bool JOIN::process_window_functions(List *curr_fields_list) { /* TODO Get this code to set can_compute_window_function during preparation, @@ -125,17 +129,22 @@ void JOIN::process_window_functions(List *curr_fields_list) The rule for having compatible sorting is thus: Each partition order must contain the other window functions partitions prefixes, or be a prefix itself. This must hold true for all partitions. - Analog for the order by clause. - + Analog for the order by clause. */ List window_functions; SQL_I_List largest_partition; SQL_I_List largest_order_by; List_iterator_fast it(*curr_fields_list); - bool can_compute_window_live = !need_tmp; - Item *item; + +#if 0 + bool can_compute_window_live = !need_tmp; + /* + psergey-winfunc: temporarily disabled the below because there is no + way to test it. Enable it back when we can. + */ + // Construct the window_functions item list and check if they can be // computed using only one sorting. // @@ -181,7 +190,6 @@ void JOIN::process_window_functions(List *curr_fields_list) largest_order_by = spec->order_list; } } - if (can_compute_window_live && window_functions.elements && table_count == 1) { ha_rows examined_rows = 0; @@ -215,4 +223,83 @@ void JOIN::process_window_functions(List *curr_fields_list) my_free(s_order); } + else +#endif + { + while ((item= it++)) + { + if (item->type() == Item::WINDOW_FUNC_ITEM) + { + Item_window_func *item_win = (Item_window_func *) item; + Window_spec *spec = item_win->window_spec; + // spec->partition_list + // spec->order_list + ha_rows examined_rows = 0; + ha_rows found_rows = 0; + ha_rows filesort_retval; + /* + psergey: Igor suggests to use create_sort_index() here, but I think + it doesn't make sense: create_sort_index() assumes that it operates + on a base table in the join. + It calls test_if_skip_sort_order, checks for quick_select and what + not. + It also assumes that ordering comes either from ORDER BY or GROUP BY. + todo: check this again. + */ + uint total_size= spec->partition_list.elements + + spec->order_list.elements; + SORT_FIELD *s_order= + (SORT_FIELD *) my_malloc(sizeof(SORT_FIELD) * (total_size+1), + MYF(MY_WME | MY_ZEROFILL | MY_THREAD_SPECIFIC)); + size_t pos= 0; + for (ORDER* curr = spec->partition_list.first; curr; curr=curr->next, pos++) + s_order[pos].item = *curr->item; + + for (ORDER* curr = spec->order_list.first; curr; curr=curr->next, pos++) + s_order[pos].item = *curr->item; + + //psergey-todo: need the below:?? + table[0]->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE), + MYF(MY_WME | MY_ZEROFILL| + MY_THREAD_SPECIFIC)); + Filesort_tracker dummy_tracker(false); + filesort_retval= filesort(thd, table[0], s_order, + total_size, + this->select, HA_POS_ERROR, FALSE, + &examined_rows, &found_rows, + &dummy_tracker); + table[0]->sort.found_records= filesort_retval; + + join_tab->read_first_record = join_init_read_record; + join_tab->records= found_rows; + + my_free(s_order); + //psergey-todo: use the created sorted-index to compute the window + //function we're looking at. + handler *file= table[0]->file; + + // TODO: We should read in sorted order here, not in rnd_next order! + // note: we can use the same approach as filesort uses to compare + // sort_keys.. + READ_RECORD info; + + if (init_read_record(&info, thd, table[0], select, 0, 1, FALSE)) + return true; + + int err; + while (!(error=info.read_record(&info))) + { + //TODO: What happens for "PARTITION BY (item value...) ? + // TODO: Sort keys are available in the record. Can we just check + // them? + // TODO: how does one check only 'PARTITION BY' part? + } + end_read_record(&info); + + // TODO-TODO: also check how the values are read... + } + } + } + return false; } +