summaryrefslogtreecommitdiff
path: root/sql/item_windowfunc.h
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item_windowfunc.h')
-rw-r--r--sql/item_windowfunc.h441
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; }
};