2016-02-13 05:33:56 +01:00
|
|
|
#ifndef ITEM_WINDOWFUNC_INCLUDED
|
|
|
|
#define ITEM_WINDOWFUNC_INCLUDED
|
|
|
|
|
|
|
|
#include "my_global.h"
|
|
|
|
#include "item.h"
|
|
|
|
|
|
|
|
class Window_spec;
|
|
|
|
|
2016-02-05 14:50:50 +01:00
|
|
|
/*
|
|
|
|
ROW_NUMBER() OVER (...)
|
|
|
|
|
2016-02-05 23:53:17 +01:00
|
|
|
@detail
|
2016-02-05 14:50:50 +01:00
|
|
|
- This is a Window function (not just an aggregate)
|
|
|
|
- It can be computed by doing one pass over select output, provided
|
|
|
|
the output is sorted according to the window definition.
|
|
|
|
*/
|
2016-02-13 05:33:56 +01:00
|
|
|
|
|
|
|
class Item_sum_row_number: public Item_sum_int
|
|
|
|
{
|
|
|
|
longlong count;
|
|
|
|
|
2016-02-14 19:00:05 +01:00
|
|
|
public:
|
|
|
|
void clear()
|
|
|
|
{
|
|
|
|
count= 0;
|
|
|
|
}
|
|
|
|
bool add()
|
|
|
|
{
|
|
|
|
count++;
|
|
|
|
return false;
|
|
|
|
}
|
2016-02-13 05:33:56 +01:00
|
|
|
void update_field() {}
|
|
|
|
|
|
|
|
Item_sum_row_number(THD *thd)
|
|
|
|
: Item_sum_int(thd), count(0) {}
|
|
|
|
|
2016-02-05 23:53:17 +01:00
|
|
|
enum Sumfunctype sum_func() const
|
2016-02-13 05:33:56 +01:00
|
|
|
{
|
|
|
|
return ROW_NUMBER_FUNC;
|
|
|
|
}
|
|
|
|
|
2016-02-14 19:00:05 +01:00
|
|
|
longlong val_int()
|
|
|
|
{
|
|
|
|
return count;
|
|
|
|
}
|
2016-02-13 05:33:56 +01:00
|
|
|
const char*func_name() const
|
|
|
|
{
|
|
|
|
return "row_number";
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2016-02-05 14:50:50 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
RANK() OVER (...) Windowing function
|
|
|
|
|
2016-02-05 23:53:17 +01:00
|
|
|
@detail
|
2016-02-05 14:50:50 +01:00
|
|
|
- This is a Window function (not just an aggregate)
|
|
|
|
- It can be computed by doing one pass over select output, provided
|
|
|
|
the output is sorted according to the window definition.
|
2016-02-05 23:53:17 +01:00
|
|
|
|
|
|
|
The function is defined as:
|
|
|
|
|
|
|
|
"The rank of row R is defined as 1 (one) plus the number of rows that
|
|
|
|
precede R and are not peers of R"
|
|
|
|
|
|
|
|
"This implies that if two or more rows are not distinct with respect to
|
|
|
|
the window ordering, then there will be one or more"
|
|
|
|
|
|
|
|
@todo: failure to overload val_int() causes infinite mutual recursion like
|
|
|
|
this:
|
|
|
|
|
|
|
|
#7505 0x0000555555cd3a1c in Item::val_int_from_real (this=0x7fff50006460) at sql/item.cc:364
|
|
|
|
#7506 0x0000555555c768d4 in Item_sum_num::val_int (this=0x7fff50006460) at sql/item_sum.h:707
|
|
|
|
#7507 0x0000555555c76a54 in Item_sum_int::val_real (this=0x7fff50006460) at sql/item_sum.h:721
|
|
|
|
#7508 0x0000555555cd3a1c in Item::val_int_from_real (this=0x7fff50006460) at sql/item.cc:364
|
|
|
|
#7509 0x0000555555c768d4 in Item_sum_num::val_int (this=0x7fff50006460) at sql/item_sum.h:707
|
|
|
|
#7510 0x0000555555c76a54 in Item_sum_int::val_real (this=0x7fff50006460) at sql/item_sum.h:721
|
|
|
|
#7511 0x0000555555e6b411 in Item_window_func::val_real (this=0x7fff5000d870) at sql/item_windowfunc.h:291
|
|
|
|
#7512 0x0000555555ce1f40 in Item::save_in_field (this=0x7fff5000d870, field=0x7fff50012be0, no_conversions=true) at sql/item.cc:5843
|
|
|
|
#7513 0x00005555559c2c54 in Item_result_field::save_in_result_field (this=0x7fff5000d870, no_conversions=true) at sql/item.h:2280
|
|
|
|
#7514 0x0000555555aeb6bf in copy_funcs (func_ptr=0x7fff500126c8, thd=0x55555ab77458) at sql/sql_select.cc:23077
|
|
|
|
#7515 0x0000555555ae2d01 in end_write (join=0x7fff5000f230, join_tab=0x7fff50010728, end_of_records=false) at sql/sql_select.cc:19520
|
|
|
|
#7516 0x0000555555adffc1 in evaluate_join_record (join=0x7fff5000f230, join_tab=0x7fff500103e0, error=0) at sql/sql_select.cc:18388
|
|
|
|
#7517 0x0000555555adf8b6 in sub_select (join=0x7fff5000f230, join_tab=0x7fff500103e0, end_of_records=false) at sql/sql_select.cc:18163
|
|
|
|
|
|
|
|
is this normal? Can it happen with other val_XXX functions?
|
|
|
|
Should we use another way to prevent this by forcing
|
|
|
|
Item_window_func::val_real() to return NULL at phase #1?
|
2016-02-05 14:50:50 +01:00
|
|
|
*/
|
|
|
|
|
2016-02-13 05:33:56 +01:00
|
|
|
class Item_sum_rank: public Item_sum_int
|
|
|
|
{
|
2016-02-05 23:53:17 +01:00
|
|
|
longlong row_number; // just ROW_NUMBER()
|
|
|
|
longlong cur_rank; // current value
|
2016-02-05 14:50:50 +01:00
|
|
|
|
2016-02-05 23:53:17 +01:00
|
|
|
List<Cached_item> orderby_fields;
|
|
|
|
public:
|
2016-02-05 14:50:50 +01:00
|
|
|
void clear()
|
|
|
|
{
|
2016-02-05 23:53:17 +01:00
|
|
|
/* This is called on partition start */
|
|
|
|
cur_rank= 1;
|
|
|
|
row_number= 0;
|
2016-02-05 14:50:50 +01:00
|
|
|
}
|
2016-02-05 23:53:17 +01:00
|
|
|
|
|
|
|
bool add();
|
|
|
|
|
|
|
|
longlong val_int()
|
|
|
|
{
|
|
|
|
return cur_rank;
|
2016-02-05 14:50:50 +01:00
|
|
|
}
|
2016-02-05 23:53:17 +01:00
|
|
|
|
2016-02-13 05:33:56 +01:00
|
|
|
void update_field() {}
|
2016-02-05 23:53:17 +01:00
|
|
|
/*
|
|
|
|
void reset_field();
|
|
|
|
TODO: ^^ what does this do ? It is not called ever?
|
|
|
|
*/
|
2016-02-13 05:33:56 +01:00
|
|
|
|
2016-02-05 23:53:17 +01:00
|
|
|
public:
|
2016-02-13 05:33:56 +01:00
|
|
|
Item_sum_rank(THD *thd)
|
2016-02-05 23:53:17 +01:00
|
|
|
: Item_sum_int(thd) {}
|
2016-02-13 05:33:56 +01:00
|
|
|
|
|
|
|
enum Sumfunctype sum_func () const
|
|
|
|
{
|
|
|
|
return RANK_FUNC;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char*func_name() const
|
|
|
|
{
|
|
|
|
return "rank";
|
|
|
|
}
|
|
|
|
|
2016-02-05 23:53:17 +01:00
|
|
|
void setup_window_func(THD *thd, Window_spec *window_spec);
|
2016-02-13 05:33:56 +01:00
|
|
|
};
|
|
|
|
|
2016-02-05 14:50:50 +01:00
|
|
|
|
|
|
|
/*
|
2016-02-15 23:22:12 +01:00
|
|
|
DENSE_RANK() OVER (...) Windowing function
|
2016-02-05 14:50:50 +01:00
|
|
|
|
2016-02-05 23:53:17 +01:00
|
|
|
@detail
|
2016-02-05 14:50:50 +01:00
|
|
|
- This is a Window function (not just an aggregate)
|
|
|
|
- It can be computed by doing one pass over select output, provided
|
|
|
|
the output is sorted according to the window definition.
|
2016-02-05 23:53:17 +01:00
|
|
|
|
|
|
|
The function is defined as:
|
|
|
|
|
|
|
|
"If DENSE_RANK is specified, then the rank of row R is defined as the
|
|
|
|
number of rows preceding and including R that are distinct with respect
|
|
|
|
to the window ordering"
|
|
|
|
|
|
|
|
"This implies that there are no gaps in the sequential rank numbering of
|
|
|
|
rows in each window partition."
|
2016-02-05 14:50:50 +01:00
|
|
|
*/
|
|
|
|
|
2016-02-05 23:53:17 +01:00
|
|
|
|
2016-02-13 05:33:56 +01:00
|
|
|
class Item_sum_dense_rank: public Item_sum_int
|
|
|
|
{
|
|
|
|
longlong dense_rank;
|
2016-02-15 23:22:12 +01:00
|
|
|
List<Cached_item> orderby_fields;
|
2016-02-15 23:33:53 +01:00
|
|
|
/*
|
|
|
|
XXX(cvicentiu) This class could potentially be implemented in the rank
|
|
|
|
class, with a switch for the DENSE case.
|
|
|
|
*/
|
|
|
|
void clear()
|
|
|
|
{
|
2016-02-15 23:22:12 +01:00
|
|
|
dense_rank= 1;
|
|
|
|
}
|
|
|
|
bool add();
|
2016-02-13 05:33:56 +01:00
|
|
|
void update_field() {}
|
2016-02-15 23:33:53 +01:00
|
|
|
longlong val_int()
|
|
|
|
{
|
2016-02-15 23:22:12 +01:00
|
|
|
return dense_rank;
|
|
|
|
}
|
2016-02-13 05:33:56 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
Item_sum_dense_rank(THD *thd)
|
|
|
|
: Item_sum_int(thd), dense_rank(0) {}
|
|
|
|
enum Sumfunctype sum_func () const
|
|
|
|
{
|
|
|
|
return DENSE_RANK_FUNC;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char*func_name() const
|
|
|
|
{
|
|
|
|
return "dense_rank";
|
|
|
|
}
|
2016-02-15 23:22:12 +01:00
|
|
|
|
|
|
|
void setup_window_func(THD *thd, Window_spec *window_spec);
|
|
|
|
|
2016-02-13 05:33:56 +01:00
|
|
|
};
|
|
|
|
|
2016-02-05 23:53:17 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
@detail
|
|
|
|
"The relative rank of a row R is defined as (RK-1)/(NR-1), where RK is
|
|
|
|
defined to be the RANK of R and NR is defined to be the number of rows in
|
|
|
|
the window partition of R."
|
|
|
|
|
|
|
|
Computation of this function requires two passes:
|
|
|
|
- First pass to find #rows in the partition
|
|
|
|
- Second pass to compute rank of current row and the value of the function
|
|
|
|
*/
|
|
|
|
|
2016-02-13 05:33:56 +01:00
|
|
|
class Item_sum_percent_rank: public Item_sum_num
|
|
|
|
{
|
|
|
|
longlong rank;
|
|
|
|
longlong partition_rows;
|
|
|
|
|
|
|
|
void clear() {}
|
|
|
|
bool add() { return false; }
|
|
|
|
void update_field() {}
|
|
|
|
|
|
|
|
public:
|
|
|
|
Item_sum_percent_rank(THD *thd)
|
|
|
|
: Item_sum_num(thd), rank(0), partition_rows(0) {}
|
|
|
|
|
|
|
|
double val_real() { return 0; }
|
|
|
|
|
|
|
|
enum Sumfunctype sum_func () const
|
|
|
|
{
|
|
|
|
return PERCENT_RANK_FUNC;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char*func_name() const
|
|
|
|
{
|
|
|
|
return "percent_rank";
|
|
|
|
}
|
|
|
|
|
|
|
|
enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2016-02-05 23:53:17 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
@detail
|
|
|
|
"The relative rank of a row R is defined as NP/NR, where
|
|
|
|
- NP is defined to be the number of rows preceding or peer with R in the
|
|
|
|
window ordering of the window partition of R
|
|
|
|
- NR is defined to be the number of rows in the window partition of R.
|
|
|
|
|
|
|
|
Just like with Item_sum_percent_rank, compuation of this function requires
|
|
|
|
two passes.
|
|
|
|
*/
|
|
|
|
|
2016-02-13 05:33:56 +01:00
|
|
|
class Item_sum_cume_dist: public Item_sum_num
|
|
|
|
{
|
|
|
|
longlong count;
|
|
|
|
longlong partition_rows;
|
|
|
|
|
|
|
|
void clear() {}
|
|
|
|
bool add() { return false; }
|
|
|
|
void update_field() {}
|
|
|
|
|
|
|
|
public:
|
|
|
|
Item_sum_cume_dist(THD *thd)
|
|
|
|
: Item_sum_num(thd), count(0), partition_rows(0) {}
|
|
|
|
|
|
|
|
double val_real() { return 0; }
|
|
|
|
|
|
|
|
enum Sumfunctype sum_func () const
|
|
|
|
{
|
|
|
|
return CUME_DIST_FUNC;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char*func_name() const
|
|
|
|
{
|
|
|
|
return "cume_dist";
|
|
|
|
}
|
|
|
|
|
|
|
|
enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Item_window_func : public Item_result_field
|
|
|
|
{
|
2016-02-14 19:00:05 +01:00
|
|
|
/* Window function parameters as we've got them from the parser */
|
2016-02-17 23:25:26 +01:00
|
|
|
public:
|
2016-02-13 05:33:56 +01:00
|
|
|
Item_sum *window_func;
|
|
|
|
LEX_STRING *window_name;
|
2016-02-14 19:00:05 +01:00
|
|
|
public:
|
2016-02-13 05:33:56 +01:00
|
|
|
Window_spec *window_spec;
|
2016-02-14 19:00:05 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
This stores the data bout the partition we're currently in.
|
|
|
|
advance_window() uses this to tell when we've left one partition and
|
|
|
|
entered another.
|
|
|
|
*/
|
|
|
|
List<Cached_item> partition_fields;
|
2016-02-13 05:33:56 +01:00
|
|
|
public:
|
|
|
|
Item_window_func(THD *thd, Item_sum *win_func, LEX_STRING *win_name)
|
|
|
|
: Item_result_field(thd), window_func(win_func),
|
2016-02-05 12:12:17 +01:00
|
|
|
window_name(win_name), window_spec(NULL),
|
2016-02-14 19:00:05 +01:00
|
|
|
force_return_blank(true),
|
2016-02-05 12:12:17 +01:00
|
|
|
read_value_from_result_field(false) {}
|
2016-02-13 05:33:56 +01:00
|
|
|
|
|
|
|
Item_window_func(THD *thd, Item_sum *win_func, Window_spec *win_spec)
|
|
|
|
: Item_result_field(thd), window_func(win_func),
|
2016-02-05 12:12:17 +01:00
|
|
|
window_name(NULL), window_spec(win_spec),
|
2016-02-14 19:00:05 +01:00
|
|
|
force_return_blank(true),
|
2016-02-05 12:12:17 +01:00
|
|
|
read_value_from_result_field(false) {}
|
2016-02-13 05:33:56 +01:00
|
|
|
|
2016-02-05 12:12:17 +01:00
|
|
|
/*
|
|
|
|
Computation functions.
|
2016-02-17 23:25:26 +01:00
|
|
|
TODO: consoder merging these with class Group_bound_tracker.
|
2016-02-05 12:12:17 +01:00
|
|
|
*/
|
|
|
|
void setup_partition_border_check(THD *thd);
|
2016-02-13 05:33:56 +01:00
|
|
|
|
2016-02-14 19:00:05 +01:00
|
|
|
void advance_window();
|
2016-02-17 23:25:26 +01:00
|
|
|
int check_partition_bound();
|
2016-02-14 19:00:05 +01:00
|
|
|
|
2016-02-13 05:33:56 +01:00
|
|
|
enum_field_types field_type() const { return window_func->field_type(); }
|
2016-02-05 12:12:17 +01:00
|
|
|
enum Item::Type type() const { return Item::WINDOW_FUNC_ITEM; }
|
2016-02-13 05:33:56 +01:00
|
|
|
|
2016-02-04 22:52:17 +01:00
|
|
|
/*
|
2016-02-05 14:50:50 +01:00
|
|
|
Window functions are very special functions, so val_() methods have
|
2016-02-04 22:52:17 +01:00
|
|
|
special meaning for them:
|
|
|
|
|
|
|
|
- Phase#1: we run the join and put its result into temporary table. For
|
|
|
|
window functions, we write NULL (or some other) values as placeholders.
|
|
|
|
|
|
|
|
- Phase#2: executor does the scan in {PARTITION, ORDER BY} order of this
|
|
|
|
window function. It calls appropriate methods to inform the window
|
|
|
|
function about rows entering/leaving the window.
|
|
|
|
It calls window_func->val_int() so that current window function value
|
|
|
|
can be saved and stored in the temp.table.
|
|
|
|
|
2016-02-05 12:12:17 +01:00
|
|
|
- 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.
|
2016-02-05 14:50:50 +01:00
|
|
|
During Phase#3, read_value_from_result_field= true.
|
2016-02-04 22:52:17 +01:00
|
|
|
*/
|
2016-02-14 19:00:05 +01:00
|
|
|
public:
|
|
|
|
// TODO: how to reset this for subquery re-execution??
|
|
|
|
bool force_return_blank;
|
2016-02-05 12:12:17 +01:00
|
|
|
private:
|
2016-02-14 19:00:05 +01:00
|
|
|
|
2016-02-05 12:12:17 +01:00
|
|
|
bool read_value_from_result_field;
|
|
|
|
|
|
|
|
public:
|
|
|
|
void set_read_value_from_result_field()
|
|
|
|
{
|
|
|
|
read_value_from_result_field= true;
|
|
|
|
}
|
|
|
|
|
|
|
|
double val_real()
|
|
|
|
{
|
2016-02-14 19:00:05 +01:00
|
|
|
if (force_return_blank)
|
|
|
|
return 0.0;
|
2016-02-05 12:12:17 +01:00
|
|
|
return read_value_from_result_field? result_field->val_real() :
|
|
|
|
window_func->val_real();
|
|
|
|
}
|
2016-02-13 05:33:56 +01:00
|
|
|
|
2016-02-05 12:12:17 +01:00
|
|
|
longlong val_int()
|
|
|
|
{
|
2016-02-14 19:00:05 +01:00
|
|
|
if (force_return_blank)
|
|
|
|
return 0;
|
2016-02-05 12:12:17 +01:00
|
|
|
return read_value_from_result_field? result_field->val_int() :
|
|
|
|
window_func->val_int();
|
|
|
|
}
|
2016-02-13 05:33:56 +01:00
|
|
|
|
2016-02-05 12:12:17 +01:00
|
|
|
String* val_str(String* str)
|
|
|
|
{
|
2016-02-14 19:00:05 +01:00
|
|
|
if (force_return_blank)
|
|
|
|
return str;
|
2016-02-05 12:12:17 +01:00
|
|
|
return read_value_from_result_field? result_field->val_str(str) :
|
|
|
|
window_func->val_str(str);
|
|
|
|
}
|
2016-02-13 05:33:56 +01:00
|
|
|
|
|
|
|
my_decimal* val_decimal(my_decimal* dec)
|
2016-02-05 12:12:17 +01:00
|
|
|
{
|
2016-02-14 19:00:05 +01:00
|
|
|
if (force_return_blank)
|
2016-02-17 23:25:26 +01:00
|
|
|
{
|
|
|
|
my_decimal_set_zero(dec);
|
2016-02-14 19:00:05 +01:00
|
|
|
return dec;
|
2016-02-17 23:25:26 +01:00
|
|
|
}
|
2016-02-05 12:12:17 +01:00
|
|
|
return read_value_from_result_field? result_field->val_decimal(dec) :
|
|
|
|
window_func->val_decimal(dec);
|
|
|
|
}
|
2016-02-13 05:33:56 +01:00
|
|
|
|
2016-02-17 23:25:26 +01:00
|
|
|
void fix_length_and_dec()
|
|
|
|
{
|
|
|
|
window_func->fix_length_and_dec();
|
|
|
|
}
|
2016-02-13 05:33:56 +01:00
|
|
|
|
|
|
|
const char* func_name() const { return "WF"; }
|
|
|
|
|
|
|
|
bool fix_fields(THD *thd, Item **ref);
|
2016-02-20 08:20:09 +01:00
|
|
|
|
|
|
|
bool resolve_window_name(THD *thd);
|
|
|
|
|
2016-02-13 05:33:56 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#endif /* ITEM_WINDOWFUNC_INCLUDED */
|