summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/t/win.test19
-rw-r--r--sql/item_windowfunc.cc36
-rw-r--r--sql/item_windowfunc.h51
-rw-r--r--sql/sql_select.cc2
-rw-r--r--sql/sql_window.cc46
5 files changed, 126 insertions, 28 deletions
diff --git a/mysql-test/t/win.test b/mysql-test/t/win.test
new file mode 100644
index 00000000000..284a12c7cb4
--- /dev/null
+++ b/mysql-test/t/win.test
@@ -0,0 +1,19 @@
+create table t1(a int, b int, x char(32));
+insert into t1 values (2, 10, 'xx');
+insert into t1 values (2, 10, 'zz');
+insert into t1 values (2, 20, 'yy');
+insert into t1 values (3, 10, 'xxx');
+insert into t1 values (3, 20, 'vvv');
+# Uncommenting this line causes a crash in setup_group when executing the second
+# select.
+#select row_number() over (order by b) from t1;
+#select a, b, x, row_number() over (partition by a,b order by x),
+# row_number() over (partition by a),
+# row_number() over (partition by a order by x)
+#from t1;
+# Uncommenting this line causes a crash in filesort during init_for_filesort.
+#select a, b, x, row_number() over (partition by a order by x) from t1;
+
+select a, row_number() over (partition by a order by b) from t1;
+
+drop table t1;
diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc
index b5e77a1f9f7..cdc4e26dfc8 100644
--- a/sql/item_windowfunc.cc
+++ b/sql/item_windowfunc.cc
@@ -1,4 +1,8 @@
#include "item_windowfunc.h"
+#include "my_dbug.h"
+#include "my_global.h"
+#include "sql_select.h" // test if group changed
+
bool
Item_window_func::fix_fields(THD *thd, Item **ref)
@@ -15,5 +19,37 @@ Item_window_func::fix_fields(THD *thd, Item **ref)
return TRUE;
fixed= 1;
+ read_value_from_result_field= false;
return FALSE;
}
+
+
+/*
+ This must be called before advance_window() can be called.
+
+ @detail
+ If we attempt to do it in fix_fields(), partition_fields will refer
+ to the original window function arguments.
+ We need it to refer to temp.table columns.
+*/
+
+void Item_window_func::setup_partition_border_check(THD *thd)
+{
+ for (ORDER * curr = window_spec->partition_list.first; curr; curr=curr->next) {
+ //curr->item_ptr->fix_fields(thd, curr->item);
+ Cached_item *tmp= new_Cached_item(thd, curr->item[0], TRUE);
+ partition_fields.push_back(tmp);
+ }
+}
+
+
+void Item_window_func::advance_window() {
+
+ int changed = test_if_group_changed(partition_fields);
+
+ if (changed > -1) {
+ window_func->clear();
+ }
+ window_func->add();
+}
+
diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h
index e5ba673d8d4..277b36b56f1 100644
--- a/sql/item_windowfunc.h
+++ b/sql/item_windowfunc.h
@@ -147,15 +147,21 @@ private:
public:
Item_window_func(THD *thd, Item_sum *win_func, LEX_STRING *win_name)
: Item_result_field(thd), window_func(win_func),
- window_name(win_name), window_spec(NULL) {}
+ window_name(win_name), window_spec(NULL),
+ read_value_from_result_field(false) {}
Item_window_func(THD *thd, Item_sum *win_func, Window_spec *win_spec)
: Item_result_field(thd), window_func(win_func),
- window_name(NULL), window_spec(win_spec) {}
+ window_name(NULL), window_spec(win_spec),
+ read_value_from_result_field(false) {}
- enum Item::Type type() const { return Item::WINDOW_FUNC_ITEM; }
+ /*
+ Computation functions.
+ */
+ void setup_partition_border_check(THD *thd);
enum_field_types field_type() const { return window_func->field_type(); }
+ enum Item::Type type() const { return Item::WINDOW_FUNC_ITEM; }
/*
TODO: Window functions are very special functions, so val_() methods have
@@ -170,19 +176,42 @@ public:
It calls window_func->val_int() so that current window function value
can be saved and stored in the temp.table.
- - Phase#3: the temporaty table is read and passed to query output. (Do
- I understand correctly that Item_window_func::val_XXX won't be called
- at all in this phase? Need to check)
-
+ - Phase#3: the temporary table is read and passed to query output.
+ However, Item_window_func still remains in the select list, so
+ item_windowfunc->val_int() will be called.
*/
- double val_real() { return window_func->val_real(); }
+private:
+ bool read_value_from_result_field;
+
+public:
+ void set_read_value_from_result_field()
+ {
+ read_value_from_result_field= true;
+ }
+
+ double val_real()
+ {
+ return read_value_from_result_field? result_field->val_real() :
+ window_func->val_real();
+ }
- longlong val_int() { return window_func->val_int(); }
+ longlong val_int()
+ {
+ return read_value_from_result_field? result_field->val_int() :
+ window_func->val_int();
+ }
- String* val_str(String* str) { return window_func->val_str(str); }
+ String* val_str(String* str)
+ {
+ return read_value_from_result_field? result_field->val_str(str) :
+ window_func->val_str(str);
+ }
my_decimal* val_decimal(my_decimal* dec)
- { return window_func->val_decimal(dec); }
+ {
+ return read_value_from_result_field? result_field->val_decimal(dec) :
+ window_func->val_decimal(dec);
+ }
void fix_length_and_dec() { }
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 94d50335eff..103f3aab1a3 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -19304,6 +19304,8 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (!end_of_records)
{
+#if 0
+#endif
if (join->table_count &&
join->join_tab->is_using_loose_index_scan())
{
diff --git a/sql/sql_window.cc b/sql/sql_window.cc
index 392d17dd8ec..eee70786695 100644
--- a/sql/sql_window.cc
+++ b/sql/sql_window.cc
@@ -1,7 +1,9 @@
#include "sql_select.h"
#include "item_windowfunc.h"
#include "filesort.h"
+#include "sql_base.h"
#include "sql_window.h"
+
//TODO: why pass List<Window_spec> by value??
bool
@@ -258,10 +260,11 @@ bool JOIN::process_window_functions(List<Item> *curr_fields_list)
for (ORDER* curr = spec->order_list.first; curr; curr=curr->next, pos++)
s_order[pos].item = *curr->item;
- //psergey-todo: need the below:??
+ /* This is free'd by free_io_cache call 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,
@@ -274,29 +277,38 @@ bool JOIN::process_window_functions(List<Item> *curr_fields_list)
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;
-
+
+ /*
+ Go through the sorted array and compute the window function
+ */
+ READ_RECORD info;
if (init_read_record(&info, thd, table[0], select, 0, 1, FALSE))
return true;
+ item_win->setup_partition_border_check(thd);
+
int err;
- while (!(error=info.read_record(&info)))
+ TABLE *tbl= *table;
+ while (!(err=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?
+ store_record(tbl,record[1]);
+
+ /*
+ This will cause window function to compute its value for the
+ current row :
+ */
+ item_win->advance_window();
+
+ /* Put the new value into temptable's field */
+ item_win->save_in_field(item_win->result_field, true);
+ err= tbl->file->ha_update_row(tbl->record[1], tbl->record[0]);
+ if (err && err != HA_ERR_RECORD_IS_THE_SAME)
+ return true;
}
+ item_win->set_read_value_from_result_field();
end_read_record(&info);
-
- // TODO-TODO: also check how the values are read...
+ filesort_free_buffers(table[0], true);
+ free_io_cache(table[0]);
}
}
}