diff options
Diffstat (limited to 'sql/item_windowfunc.h')
-rw-r--r-- | sql/item_windowfunc.h | 441 |
1 files changed, 393 insertions, 48 deletions
diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h index b9df1b7482b..144deb18d8c 100644 --- a/sql/item_windowfunc.h +++ b/sql/item_windowfunc.h @@ -1,7 +1,22 @@ +/* + Copyright (c) 2016,2017 MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + #ifndef ITEM_WINDOWFUNC_INCLUDED #define ITEM_WINDOWFUNC_INCLUDED -#include "my_global.h" #include "item.h" class Window_spec; @@ -9,6 +24,7 @@ class Window_spec; int test_if_group_changed(List<Cached_item> &list); + /* A wrapper around test_if_group_changed */ class Group_bound_tracker { @@ -16,10 +32,10 @@ public: Group_bound_tracker(THD *thd, SQL_I_List<ORDER> *list) { - for (ORDER *curr = list->first; curr; curr=curr->next) + for (ORDER *curr = list->first; curr; curr=curr->next) { - Cached_item *tmp= new_Cached_item(thd, curr->item[0], TRUE); - group_fields.push_back(tmp); + Cached_item *tmp= new_Cached_item(thd, curr->item[0], TRUE); + group_fields.push_back(tmp); } } @@ -129,8 +145,8 @@ public: return "row_number"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_sum_row_number>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_row_number>(thd, this); } }; @@ -203,8 +219,8 @@ public: } Item_sum_int::cleanup(); } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_sum_rank>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_rank>(thd, this); } }; @@ -272,8 +288,8 @@ class Item_sum_dense_rank: public Item_sum_int } Item_sum_int::cleanup(); } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_sum_dense_rank>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_dense_rank>(thd, this); } }; class Item_sum_hybrid_simple : public Item_sum, @@ -282,13 +298,13 @@ class Item_sum_hybrid_simple : public Item_sum, public: Item_sum_hybrid_simple(THD *thd, Item *arg): Item_sum(thd, arg), - Type_handler_hybrid_field_type(MYSQL_TYPE_LONGLONG), + Type_handler_hybrid_field_type(&type_handler_longlong), value(NULL) { collation.set(&my_charset_bin); } Item_sum_hybrid_simple(THD *thd, Item *arg1, Item *arg2): Item_sum(thd, arg1, arg2), - Type_handler_hybrid_field_type(MYSQL_TYPE_LONGLONG), + Type_handler_hybrid_field_type(&type_handler_longlong), value(NULL) { collation.set(&my_charset_bin); } @@ -300,14 +316,9 @@ class Item_sum_hybrid_simple : public Item_sum, my_decimal *val_decimal(my_decimal *); void reset_field(); String *val_str(String *); - /* TODO(cvicentiu) copied from Item_sum_hybrid, what does it do? */ - bool keep_field_type(void) const { return 1; } - enum Item_result result_type() const - { return Type_handler_hybrid_field_type::result_type(); } - enum Item_result cmp_type() const - { return Type_handler_hybrid_field_type::cmp_type(); } - enum enum_field_types field_type() const - { return Type_handler_hybrid_field_type::field_type(); } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + const Type_handler *type_handler() const + { return Type_handler_hybrid_field_type::type_handler(); } void update_field(); Field *create_tmp_field(bool group, TABLE *table); void clear() @@ -341,8 +352,8 @@ class Item_sum_first_value : public Item_sum_hybrid_simple return "first_value"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_sum_first_value>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_first_value>(thd, this); } }; /* @@ -367,8 +378,8 @@ class Item_sum_last_value : public Item_sum_hybrid_simple return "last_value"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_sum_last_value>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_last_value>(thd, this); } }; class Item_sum_nth_value : public Item_sum_hybrid_simple @@ -387,8 +398,8 @@ class Item_sum_nth_value : public Item_sum_hybrid_simple return "nth_value"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_sum_nth_value>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_nth_value>(thd, this); } }; class Item_sum_lead : public Item_sum_hybrid_simple @@ -407,8 +418,8 @@ class Item_sum_lead : public Item_sum_hybrid_simple return "lead"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_sum_lead>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_lead>(thd, this); } }; class Item_sum_lag : public Item_sum_hybrid_simple @@ -427,8 +438,8 @@ class Item_sum_lag : public Item_sum_hybrid_simple return "lag"; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_sum_lag>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_lag>(thd, this); } }; /* @@ -510,8 +521,7 @@ class Item_sum_percent_rank: public Item_sum_window_with_row_count row_number= 0; } bool add(); - enum Item_result result_type () const { return REAL_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + const Type_handler *type_handler() const { return &type_handler_double; } bool fix_length_and_dec() { @@ -521,8 +531,8 @@ class Item_sum_percent_rank: public Item_sum_window_with_row_count } void setup_window_func(THD *thd, Window_spec *window_spec); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_sum_percent_rank>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_percent_rank>(thd, this); } private: longlong cur_rank; // Current rank of the current row. @@ -561,6 +571,9 @@ class Item_sum_cume_dist: public Item_sum_window_with_row_count Item_sum_cume_dist(THD *thd) : Item_sum_window_with_row_count(thd), current_row_count_(0) {} + Item_sum_cume_dist(THD *thd, Item *arg) : Item_sum_window_with_row_count(thd,arg), + current_row_count_(0) {} + double val_real() { if (get_row_count() == 0) @@ -596,8 +609,7 @@ class Item_sum_cume_dist: public Item_sum_window_with_row_count } void update_field() {} - enum Item_result result_type () const { return REAL_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + const Type_handler *type_handler() const { return &type_handler_double; } bool fix_length_and_dec() { @@ -606,8 +618,13 @@ class Item_sum_cume_dist: public Item_sum_window_with_row_count return FALSE; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_sum_cume_dist>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_cume_dist>(thd, this); } + + ulonglong get_row_number() + { + return current_row_count_ ; + } private: ulonglong current_row_count_; @@ -674,28 +691,300 @@ class Item_sum_ntile : public Item_sum_window_with_row_count void update_field() {} - enum Item_result result_type () const { return INT_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } + const Type_handler *type_handler() const { return &type_handler_longlong; } - Item *get_copy(THD *thd, MEM_ROOT *mem_root) - { return get_item_copy<Item_sum_ntile>(thd, mem_root, this); } + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_ntile>(thd, this); } private: longlong get_num_quantiles() { return args[0]->val_int(); } ulong current_row_count_; }; +class Item_sum_percentile_disc : public Item_sum_cume_dist, + public Type_handler_hybrid_field_type +{ +public: + Item_sum_percentile_disc(THD *thd, Item* arg) : Item_sum_cume_dist(thd, arg), + Type_handler_hybrid_field_type(&type_handler_longlong), + value(NULL), val_calculated(FALSE), first_call(TRUE), + prev_value(0), order_item(NULL){} + + double val_real() + { + if (get_row_count() == 0 || get_arg(0)->is_null()) + { + null_value= true; + return 0; + } + null_value= false; + return value->val_real(); + } + + longlong val_int() + { + if (get_row_count() == 0 || get_arg(0)->is_null()) + { + null_value= true; + return 0; + } + null_value= false; + return value->val_int(); + } + + my_decimal* val_decimal(my_decimal* dec) + { + if (get_row_count() == 0 || get_arg(0)->is_null()) + { + null_value= true; + return 0; + } + null_value= false; + return value->val_decimal(dec); + } + + String* val_str(String *str) + { + if (get_row_count() == 0 || get_arg(0)->is_null()) + { + null_value= true; + return 0; + } + null_value= false; + return value->val_str(str); + } + + bool add() + { + Item *arg= get_arg(0); + if (arg->is_null()) + return false; + + if (first_call) + { + prev_value= arg->val_real(); + if (prev_value > 1 || prev_value < 0) + { + my_error(ER_ARGUMENT_OUT_OF_RANGE, MYF(0), func_name()); + return true; + } + first_call= false; + } + + double arg_val= arg->val_real(); + + if (prev_value != arg_val) + { + my_error(ER_ARGUMENT_NOT_CONSTANT, MYF(0), func_name()); + return true; + } + + if (val_calculated) + return false; + + value->store(order_item); + value->cache_value(); + if (value->null_value) + return false; + + Item_sum_cume_dist::add(); + double val= Item_sum_cume_dist::val_real(); + + if (val >= prev_value && !val_calculated) + val_calculated= true; + return false; + } + + enum Sumfunctype sum_func() const + { + return PERCENTILE_DISC_FUNC; + } + + void clear() + { + val_calculated= false; + first_call= true; + value->clear(); + Item_sum_cume_dist::clear(); + } + + const char*func_name() const + { + return "percentile_disc"; + } + + void update_field() {} + void set_type_handler(Window_spec *window_spec); + const Type_handler *type_handler() const + {return Type_handler_hybrid_field_type::type_handler();} + + bool fix_length_and_dec() + { + decimals = 10; // TODO-cvicentiu find out how many decimals the standard + // requires. + return FALSE; + } + + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_percentile_disc>(thd, this); } + void setup_window_func(THD *thd, Window_spec *window_spec); + void setup_hybrid(THD *thd, Item *item); + bool fix_fields(THD *thd, Item **ref); + +private: + Item_cache *value; + bool val_calculated; + bool first_call; + double prev_value; + Item *order_item; +}; + +class Item_sum_percentile_cont : public Item_sum_cume_dist, + public Type_handler_hybrid_field_type +{ +public: + Item_sum_percentile_cont(THD *thd, Item* arg) : Item_sum_cume_dist(thd, arg), + Type_handler_hybrid_field_type(&type_handler_double), + floor_value(NULL), ceil_value(NULL), first_call(TRUE),prev_value(0), + ceil_val_calculated(FALSE), floor_val_calculated(FALSE), order_item(NULL){} + + double val_real() + { + if (get_row_count() == 0 || get_arg(0)->is_null()) + { + null_value= true; + return 0; + } + null_value= false; + double val= 1 + prev_value * (get_row_count()-1); + + /* + Applying the formula to get the value + If (CRN = FRN = RN) then the result is (value of expression from row at RN) + Otherwise the result is + (CRN - RN) * (value of expression for row at FRN) + + (RN - FRN) * (value of expression for row at CRN) + */ + + if(ceil(val) == floor(val)) + return floor_value->val_real(); + + double ret_val= ((val - floor(val)) * ceil_value->val_real()) + + ((ceil(val) - val) * floor_value->val_real()); + + return ret_val; + } + + bool add() + { + Item *arg= get_arg(0); + if (arg->is_null()) + return false; + + if (first_call) + { + first_call= false; + prev_value= arg->val_real(); + if (prev_value > 1 || prev_value < 0) + { + my_error(ER_ARGUMENT_OUT_OF_RANGE, MYF(0), func_name()); + return true; + } + } + + double arg_val= arg->val_real(); + if (prev_value != arg_val) + { + my_error(ER_ARGUMENT_NOT_CONSTANT, MYF(0), func_name()); + return true; + } + + if (!floor_val_calculated) + { + floor_value->store(order_item); + floor_value->cache_value(); + if (floor_value->null_value) + return false; + } + if (floor_val_calculated && !ceil_val_calculated) + { + ceil_value->store(order_item); + ceil_value->cache_value(); + if (ceil_value->null_value) + return false; + } + + Item_sum_cume_dist::add(); + double val= 1 + prev_value * (get_row_count()-1); + + if (!floor_val_calculated && get_row_number() == floor(val)) + floor_val_calculated= true; + + if (!ceil_val_calculated && get_row_number() == ceil(val)) + ceil_val_calculated= true; + return false; + } + + enum Sumfunctype sum_func() const + { + return PERCENTILE_CONT_FUNC; + } + + void clear() + { + first_call= true; + floor_value->clear(); + ceil_value->clear(); + floor_val_calculated= false; + ceil_val_calculated= false; + Item_sum_cume_dist::clear(); + } + + const char*func_name() const + { + return "percentile_cont"; + } + void update_field() {} + void set_type_handler(Window_spec *window_spec); + const Type_handler *type_handler() const + {return Type_handler_hybrid_field_type::type_handler();} + + bool fix_length_and_dec() + { + decimals = 10; // TODO-cvicentiu find out how many decimals the standard + // requires. + return FALSE; + } + + Item *get_copy(THD *thd) + { return get_item_copy<Item_sum_percentile_cont>(thd, this); } + void setup_window_func(THD *thd, Window_spec *window_spec); + void setup_hybrid(THD *thd, Item *item); + bool fix_fields(THD *thd, Item **ref); + +private: + Item_cache *floor_value; + Item_cache *ceil_value; + bool first_call; + double prev_value; + bool ceil_val_calculated; + bool floor_val_calculated; + Item *order_item; +}; + + + class Item_window_func : public Item_func_or_sum { /* Window function parameters as we've got them from the parser */ public: - LEX_STRING *window_name; + LEX_CSTRING *window_name; public: Window_spec *window_spec; public: - Item_window_func(THD *thd, Item_sum *win_func, LEX_STRING *win_name) + Item_window_func(THD *thd, Item_sum *win_func, LEX_CSTRING *win_name) : Item_func_or_sum(thd, (Item *) win_func), window_name(win_name), window_spec(NULL), force_return_blank(true), @@ -739,6 +1028,8 @@ public: case Item_sum::PERCENT_RANK_FUNC: case Item_sum::CUME_DIST_FUNC: case Item_sum::NTILE_FUNC: + case Item_sum::PERCENTILE_CONT_FUNC: + case Item_sum::PERCENTILE_DISC_FUNC: return true; default: return false; @@ -765,6 +1056,8 @@ public: case Item_sum::PERCENT_RANK_FUNC: case Item_sum::CUME_DIST_FUNC: case Item_sum::NTILE_FUNC: + case Item_sum::PERCENTILE_CONT_FUNC: + case Item_sum::PERCENTILE_DISC_FUNC: return true; default: return false; @@ -790,21 +1083,49 @@ public: case Item_sum::CUME_DIST_FUNC: case Item_sum::LAG_FUNC: case Item_sum::LEAD_FUNC: + case Item_sum::PERCENTILE_CONT_FUNC: + case Item_sum::PERCENTILE_DISC_FUNC: return true; default: return false; } } + bool only_single_element_order_list() const + { + switch (window_func()->sum_func()){ + case Item_sum::PERCENTILE_CONT_FUNC: + case Item_sum::PERCENTILE_DISC_FUNC: + return true; + default: + return false; + } + } + + void setting_handler_for_percentile_functions(Item_result rtype) const + { + switch (window_func()->sum_func()){ + case Item_sum::PERCENTILE_DISC_FUNC: + ((Item_sum_percentile_disc* ) window_func())->set_handler_by_cmp_type(rtype); + break; + default: + return; + } + } + + bool check_result_type_of_order_item(); + + + /* Computation functions. TODO: consoder merging these with class Group_bound_tracker. */ void setup_partition_border_check(THD *thd); - enum_field_types field_type() const - { - return ((Item_sum *) args[0])->field_type(); + const Type_handler *type_handler() const + { + return ((Item_sum *) args[0])->type_handler(); } enum Item::Type type() const { return Item::WINDOW_FUNC_ITEM; } @@ -830,6 +1151,7 @@ private: */ bool force_return_blank; bool read_value_from_result_field; + void print_for_percentile_functions(String *str, enum_query_type query_type); public: void set_phase_to_initial() @@ -947,6 +1269,29 @@ public: return res; } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { + bool res; + if (force_return_blank) + { + null_value= true; + res= true; + } + else if (read_value_from_result_field) + { + if ((null_value= result_field->is_null())) + res= true; + else + res= result_field->get_date(ltime, fuzzydate); + } + else + { + res= window_func()->get_date(ltime, fuzzydate); + null_value= window_func()->null_value; + } + return res; + } + void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List<Item> &fields, uint flags); @@ -964,7 +1309,7 @@ public: void print(String *str, enum_query_type query_type); - Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } + Item *get_copy(THD *thd) { return 0; } }; |