Commit 914e2c9b authored by Igor Babaev's avatar Igor Babaev

Merge branch '10.3' of github.com:MariaDB/server into 10.3

parents 6f1b6061 a607e4e7
#cmakedefine SOURCE_REVISION "@SOURCE_REVISION@" #define SOURCE_REVISION "@SOURCE_REVISION@"
This diff is collapsed.
CREATE TABLE t1 (name CHAR(10), test double, score DECIMAL(19,4));
INSERT INTO t1 VALUES
('Chun', 0, 3), ('Chun', 0, 7),
('Kaolin', 0.5, 3), ('Kaolin', 0.6, 7),
('Kaolin', 0.5, 4),
('Tatiana', 0.8, 4), ('Tata', 0.8, 4);
--echo #
--echo # Test invalid syntax
--echo #
--echo # Order by clause has more than one element
--error ER_PARSE_ERROR
select percentile_disc(0.5) within group(order by score,test) over (partition by name) from t1;
--error ER_PARSE_ERROR
select percentile_cont(0.5) within group(order by score,test) over (partition by name) from t1;
--echo # Order by clause has no element
--error ER_PARSE_ERROR
select percentile_disc(0.5) within group() over (partition by name) from t1;
--error ER_PARSE_ERROR
select percentile_cont(0.5) within group() over (partition by name) from t1;
--echo # No parameters to the percentile functions
--error ER_PARSE_ERROR
select percentile_disc() within group() over (partition by name) from t1;
--error ER_PARSE_ERROR
select percentile_cont() within group() over (partition by name) from t1;
--echo #
--echo # Test simple syntax
--echo #
select name, percentile_cont(0.5) within group(order by score) over (partition by name) as c from t1;
select name, percentile_disc(0.5) within group(order by score) over (partition by name) as c from t1;
--echo # no partition clause
select name, percentile_disc(0.5) within group(order by score) over () from t1;
select name, percentile_cont(0.5) within group(order by score) over () from t1;
--echo # argument set to null
--error ER_WRONG_TYPE_OF_ARGUMENT
select name, percentile_cont(null) within group(order by score) over (partition by name) from t1;
--error ER_WRONG_TYPE_OF_ARGUMENT
select name, percentile_disc(null) within group(order by score) over (partition by name) from t1;
--echo #subqueries having percentile functions
select * from ( select name , percentile_cont(0.5) within group ( order by score) over (partition by name ) from t1 ) as t;
select * from ( select name , percentile_disc(0.5) within group ( order by score) over (partition by name ) from t1 ) as t;
select name from t1 a where (select percentile_disc(0.5) within group (order by score) over (partition by name) from t1 b limit 1) >= 0.5;
--echo #disallowed fields in order by
--error ER_WRONG_TYPE_FOR_PERCENTILE_FUNC
select score, percentile_cont(0.5) within group(order by name) over (partition by score) from t1;
--error ER_WRONG_TYPE_FOR_PERCENTILE_FUNC
select score, percentile_disc(0.5) within group(order by name) over (partition by score) from t1;
--echo #parameter value should be in the range of [0,1]
--error ER_ARGUMENT_OUT_OF_RANGE
select percentile_disc(1.5) within group(order by score) over (partition by name) from t1;
--error ER_ARGUMENT_OUT_OF_RANGE
select percentile_cont(1.5) within group(order by score) over (partition by name) from t1;
--echo #Argument should remain constant for the entire partition
--error ER_ARGUMENT_NOT_CONSTANT
select name,percentile_cont(test) within group(order by score) over (partition by name) from t1;
--error ER_ARGUMENT_NOT_CONSTANT
select name, percentile_disc(test) within group(order by score) over (partition by name) from t1;
--echo #only numerical types are allowed as argument to percentile functions
--error ER_WRONG_TYPE_OF_ARGUMENT
select name, percentile_cont(name) within group(order by score) over (partition by name) from t1;
--error ER_WRONG_TYPE_OF_ARGUMENT
select name, percentile_disc(name) within group(order by score) over (partition by name) from t1;
--echo #complete query with partition column
select name,cume_dist() over (partition by name order by score), percentile_disc(0.5) within group(order by score) over (partition by name) as c from t1;
select name, percentile_cont(0.5) within group(order by score) over (partition by name) as c from t1;
select name,cume_dist() over (partition by name order by score) as b, percentile_disc(0.1) within group(order by score) over (partition by name) as c from t1;
select name,cume_dist() over (partition by name order by score) as b, percentile_disc(0.2) within group(order by score) over (partition by name) as c from t1;
select name,cume_dist() over (partition by name order by score) as b, percentile_disc(0.3) within group(order by score) over (partition by name) as c from t1;
select name,cume_dist() over (partition by name order by score) as b, percentile_disc(0.4) within group(order by score) over (partition by name) as c from t1;
select name,cume_dist() over (partition by name order by score) as b, percentile_disc(0.5) within group(order by score) over (partition by name) as c from t1;
select name,cume_dist() over (partition by name order by score) as b, percentile_disc(0.6) within group(order by score) over (partition by name) as c from t1;
select name,cume_dist() over (partition by name order by score) as b, percentile_disc(0.7) within group(order by score) over (partition by name) as c from t1;
select name,cume_dist() over (partition by name order by score) as b, percentile_disc(0.8) within group(order by score) over (partition by name) as c from t1;
select name,cume_dist() over (partition by name order by score) as b, percentile_disc(0.9) within group(order by score) over (partition by name) as c from t1;
select name,cume_dist() over (partition by name order by score) as b, percentile_disc(1) within group(order by score) over (partition by name) as c from t1;
select median(score) over (partition by name), percentile_cont(0) within group(order by score) over (partition by name) as c from t1;
select median(score) over (partition by name), percentile_cont(0.1) within group(order by score) over (partition by name) as c from t1;
select median(score) over (partition by name), percentile_cont(0.2) within group(order by score) over (partition by name) as c from t1;
select median(score) over (partition by name), percentile_cont(0.3) within group(order by score) over (partition by name) as c from t1;
select median(score) over (partition by name), percentile_cont(0.4) within group(order by score) over (partition by name) as c from t1;
select median(score) over (partition by name), percentile_cont(0.5) within group(order by score) over (partition by name) as c from t1;
select median(score) over (partition by name), percentile_cont(0.6) within group(order by score) over (partition by name) as c from t1;
select median(score) over (partition by name), percentile_cont(0.7) within group(order by score) over (partition by name) as c from t1;
select median(score) over (partition by name), percentile_cont(0.8) within group(order by score) over (partition by name) as c from t1;
select median(score) over (partition by name), percentile_cont(0.9) within group(order by score) over (partition by name) as c from t1;
select median(score) over (partition by name), percentile_cont(1) within group(order by score) over (partition by name) as c from t1;
drop table t1;
...@@ -354,7 +354,8 @@ class Item_sum :public Item_func_or_sum ...@@ -354,7 +354,8 @@ class Item_sum :public Item_func_or_sum
VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC, VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC,
ROW_NUMBER_FUNC, RANK_FUNC, DENSE_RANK_FUNC, PERCENT_RANK_FUNC, ROW_NUMBER_FUNC, RANK_FUNC, DENSE_RANK_FUNC, PERCENT_RANK_FUNC,
CUME_DIST_FUNC, NTILE_FUNC, FIRST_VALUE_FUNC, LAST_VALUE_FUNC, CUME_DIST_FUNC, NTILE_FUNC, FIRST_VALUE_FUNC, LAST_VALUE_FUNC,
NTH_VALUE_FUNC, LEAD_FUNC, LAG_FUNC NTH_VALUE_FUNC, LEAD_FUNC, LAG_FUNC, PERCENTILE_CONT_FUNC,
PERCENTILE_DISC_FUNC
}; };
Item **ref_by; /* pointer to a ref to the object used to register it */ Item **ref_by; /* pointer to a ref to the object used to register it */
......
...@@ -108,6 +108,7 @@ Item_window_func::fix_fields(THD *thd, Item **ref) ...@@ -108,6 +108,7 @@ Item_window_func::fix_fields(THD *thd, Item **ref)
my_error(ER_NO_ORDER_LIST_IN_WINDOW_SPEC, MYF(0), window_func()->func_name()); my_error(ER_NO_ORDER_LIST_IN_WINDOW_SPEC, MYF(0), window_func()->func_name());
return true; return true;
} }
/* /*
TODO: why the last parameter is 'ref' in this call? What if window_func TODO: why the last parameter is 'ref' in this call? What if window_func
decides to substitute itself for something else and does *ref=.... ? decides to substitute itself for something else and does *ref=.... ?
...@@ -168,10 +169,25 @@ void Item_window_func::split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, ...@@ -168,10 +169,25 @@ void Item_window_func::split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
window_func()->setup_caches(thd); window_func()->setup_caches(thd);
} }
bool Item_window_func::check_result_type_of_order_item()
{
if (only_single_element_order_list())
{
Item_result rtype= window_spec->order_list->first->item[0]->cmp_type();
// TODO (varun) : support date type in percentile_cont function
if (rtype != REAL_RESULT && rtype != INT_RESULT &&
rtype != DECIMAL_RESULT && rtype != TIME_RESULT)
{
my_error(ER_WRONG_TYPE_FOR_PERCENTILE_FUNC, MYF(0), window_func()->func_name());
return TRUE;
}
setting_handler_for_percentile_functions(rtype);
}
return FALSE;
}
/* /*
This must be called before attempting to compute the window function values. This must be called before attempting to compute the window function values.
@detail @detail
If we attempt to do it in fix_fields(), partition_fields will refer If we attempt to do it in fix_fields(), partition_fields will refer
to the original window function arguments. to the original window function arguments.
...@@ -194,6 +210,71 @@ void Item_sum_dense_rank::setup_window_func(THD *thd, Window_spec *window_spec) ...@@ -194,6 +210,71 @@ void Item_sum_dense_rank::setup_window_func(THD *thd, Window_spec *window_spec)
clear(); clear();
} }
void Item_sum_percentile_disc::setup_window_func(THD *thd, Window_spec *window_spec)
{
order_item= window_spec->order_list->first->item[0];
if (!(value= order_item->get_cache(thd)))
return;
value->setup(thd, order_item);
value->store(order_item);
}
void Item_sum_percentile_cont::setup_window_func(THD *thd, Window_spec *window_spec)
{
order_item= window_spec->order_list->first->item[0];
/* TODO(varun): need to discuss and finalise what type should we
return for percentile cont functions
*/
if (!(ceil_value= order_item->get_cache(thd)))
return;
ceil_value->setup(thd, order_item);
ceil_value->store(order_item);
if (!(floor_value= order_item->get_cache(thd)))
return;
floor_value->setup(thd, order_item);
floor_value->store(order_item);
}
bool Item_sum_percentile_cont::fix_fields(THD *thd, Item **ref)
{
bool res;
res= Item_sum_num::fix_fields(thd, ref);
if (res)
return res;
switch(args[0]->cmp_type())
{
case DECIMAL_RESULT:
case REAL_RESULT:
case INT_RESULT:
break;
default:
my_error(ER_WRONG_TYPE_OF_ARGUMENT, MYF(0), func_name());
return TRUE;
}
return res;
}
bool Item_sum_percentile_disc::fix_fields(THD *thd, Item **ref)
{
bool res;
res= Item_sum_num::fix_fields(thd, ref);
if (res)
return res;
switch(args[0]->cmp_type())
{
case DECIMAL_RESULT:
case REAL_RESULT:
case INT_RESULT:
break;
default:
my_error(ER_WRONG_TYPE_OF_ARGUMENT, MYF(0), func_name());
return TRUE;
}
return res;
}
bool Item_sum_dense_rank::add() bool Item_sum_dense_rank::add()
{ {
if (peer_tracker->check_if_next_group() || first_add) if (peer_tracker->check_if_next_group() || first_add)
......
...@@ -24,6 +24,7 @@ class Window_spec; ...@@ -24,6 +24,7 @@ class Window_spec;
int test_if_group_changed(List<Cached_item> &list); int test_if_group_changed(List<Cached_item> &list);
/* A wrapper around test_if_group_changed */ /* A wrapper around test_if_group_changed */
class Group_bound_tracker class Group_bound_tracker
{ {
...@@ -572,6 +573,9 @@ class Item_sum_cume_dist: public Item_sum_window_with_row_count ...@@ -572,6 +573,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), Item_sum_cume_dist(THD *thd) : Item_sum_window_with_row_count(thd),
current_row_count_(0) {} 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() double val_real()
{ {
if (get_row_count() == 0) if (get_row_count() == 0)
...@@ -618,6 +622,11 @@ class Item_sum_cume_dist: public Item_sum_window_with_row_count ...@@ -618,6 +622,11 @@ class Item_sum_cume_dist: public Item_sum_window_with_row_count
Item *get_copy(THD *thd, MEM_ROOT *mem_root) Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_sum_cume_dist>(thd, mem_root, this); } { return get_item_copy<Item_sum_cume_dist>(thd, mem_root, this); }
ulonglong get_row_number()
{
return current_row_count_ ;
}
private: private:
ulonglong current_row_count_; ulonglong current_row_count_;
}; };
...@@ -693,6 +702,277 @@ class Item_sum_ntile : public Item_sum_window_with_row_count ...@@ -693,6 +702,277 @@ class Item_sum_ntile : public Item_sum_window_with_row_count
ulong current_row_count_; 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();}
void fix_length_and_dec()
{
decimals = 10; // TODO-cvicentiu find out how many decimals the standard
// requires.
}
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_sum_percentile_disc>(thd, mem_root, 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();}
void fix_length_and_dec()
{
decimals = 10; // TODO-cvicentiu find out how many decimals the standard
// requires.
}
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_sum_percentile_cont>(thd, mem_root, 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 class Item_window_func : public Item_func_or_sum
{ {
...@@ -747,6 +1027,8 @@ class Item_window_func : public Item_func_or_sum ...@@ -747,6 +1027,8 @@ class Item_window_func : public Item_func_or_sum
case Item_sum::PERCENT_RANK_FUNC: case Item_sum::PERCENT_RANK_FUNC:
case Item_sum::CUME_DIST_FUNC: case Item_sum::CUME_DIST_FUNC:
case Item_sum::NTILE_FUNC: case Item_sum::NTILE_FUNC:
case Item_sum::PERCENTILE_CONT_FUNC:
case Item_sum::PERCENTILE_DISC_FUNC:
return true; return true;
default: default:
return false; return false;
...@@ -773,6 +1055,8 @@ class Item_window_func : public Item_func_or_sum ...@@ -773,6 +1055,8 @@ class Item_window_func : public Item_func_or_sum
case Item_sum::PERCENT_RANK_FUNC: case Item_sum::PERCENT_RANK_FUNC:
case Item_sum::CUME_DIST_FUNC: case Item_sum::CUME_DIST_FUNC:
case Item_sum::NTILE_FUNC: case Item_sum::NTILE_FUNC:
case Item_sum::PERCENTILE_CONT_FUNC:
case Item_sum::PERCENTILE_DISC_FUNC:
return true; return true;
default: default:
return false; return false;
...@@ -796,12 +1080,40 @@ class Item_window_func : public Item_func_or_sum ...@@ -796,12 +1080,40 @@ class Item_window_func : public Item_func_or_sum
case Item_sum::DENSE_RANK_FUNC: case Item_sum::DENSE_RANK_FUNC:
case Item_sum::PERCENT_RANK_FUNC: case Item_sum::PERCENT_RANK_FUNC:
case Item_sum::CUME_DIST_FUNC: case Item_sum::CUME_DIST_FUNC:
case Item_sum::PERCENTILE_CONT_FUNC:
case Item_sum::PERCENTILE_DISC_FUNC:
return true; return true;
default: default:
return false; 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. Computation functions.
TODO: consoder merging these with class Group_bound_tracker. TODO: consoder merging these with class Group_bound_tracker.
......
...@@ -701,6 +701,7 @@ static SYMBOL symbols[] = { ...@@ -701,6 +701,7 @@ static SYMBOL symbols[] = {
{ "WHILE", SYM(WHILE_SYM)}, { "WHILE", SYM(WHILE_SYM)},
{ "WINDOW", SYM(WINDOW_SYM)}, { "WINDOW", SYM(WINDOW_SYM)},
{ "WITH", SYM(WITH)}, { "WITH", SYM(WITH)},
{ "WITHIN", SYM(WITHIN)},
{ "WORK", SYM(WORK_SYM)}, { "WORK", SYM(WORK_SYM)},
{ "WRAPPER", SYM(WRAPPER_SYM)}, { "WRAPPER", SYM(WRAPPER_SYM)},
{ "WRITE", SYM(WRITE_SYM)}, { "WRITE", SYM(WRITE_SYM)},
...@@ -736,6 +737,7 @@ static SYMBOL sql_functions[] = { ...@@ -736,6 +737,7 @@ static SYMBOL sql_functions[] = {
{ "LAG", SYM(LAG_SYM)}, { "LAG", SYM(LAG_SYM)},
{ "LEAD", SYM(LEAD_SYM)}, { "LEAD", SYM(LEAD_SYM)},
{ "MAX", SYM(MAX_SYM)}, { "MAX", SYM(MAX_SYM)},
{ "MEDIAN", SYM(MEDIAN_SYM)},
{ "MID", SYM(SUBSTRING)}, /* unireg function */ { "MID", SYM(SUBSTRING)}, /* unireg function */
{ "MIN", SYM(MIN_SYM)}, { "MIN", SYM(MIN_SYM)},
{ "NOW", SYM(NOW_SYM)}, { "NOW", SYM(NOW_SYM)},
...@@ -743,6 +745,8 @@ static SYMBOL sql_functions[] = { ...@@ -743,6 +745,8 @@ static SYMBOL sql_functions[] = {
{ "NTILE", SYM(NTILE_SYM)}, { "NTILE", SYM(NTILE_SYM)},
{ "POSITION", SYM(POSITION_SYM)}, { "POSITION", SYM(POSITION_SYM)},
{ "PERCENT_RANK", SYM(PERCENT_RANK_SYM)}, { "PERCENT_RANK", SYM(PERCENT_RANK_SYM)},
{ "PERCENTILE_CONT", SYM(PERCENTILE_CONT_SYM)},
{ "PERCENTILE_DISC", SYM(PERCENTILE_DISC_SYM)},
{ "RANK", SYM(RANK_SYM)}, { "RANK", SYM(RANK_SYM)},
{ "ROW_NUMBER", SYM(ROW_NUMBER_SYM)}, { "ROW_NUMBER", SYM(ROW_NUMBER_SYM)},
{ "SESSION_USER", SYM(USER_SYM)}, { "SESSION_USER", SYM(USER_SYM)},
......
...@@ -7790,3 +7790,13 @@ ER_WRONG_NUMBER_OF_VALUES_IN_TVC ...@@ -7790,3 +7790,13 @@ ER_WRONG_NUMBER_OF_VALUES_IN_TVC
eng "The used table value constructor has a different number of values" eng "The used table value constructor has a different number of values"
ER_FIELD_REFERENCE_IN_TVC ER_FIELD_REFERENCE_IN_TVC
eng "Field reference '%-.192s' can't be used in table value constructor" eng "Field reference '%-.192s' can't be used in table value constructor"
ER_NOT_SINGLE_ELEMENT_ORDER_LIST
eng "Incorrect number of elements in the order list for '%s'"
ER_WRONG_TYPE_FOR_PERCENTILE_FUNC
eng "Numeric datatype is required for %s function"
ER_ARGUMENT_NOT_CONSTANT
eng "Argument to the %s function is not a constant for a partition"
ER_ARGUMENT_OUT_OF_RANGE
eng "Argument to the %s function does not belong to the range [0,1]"
ER_WRONG_TYPE_OF_ARGUMENT
eng "%s function only accepts arguments that can be converted to numerical types"
...@@ -321,6 +321,12 @@ setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, ...@@ -321,6 +321,12 @@ setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
win_func_item->update_used_tables(); win_func_item->update_used_tables();
} }
li.rewind();
while ((win_func_item= li++))
{
if (win_func_item->check_result_type_of_order_item())
DBUG_RETURN(1);
}
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -968,6 +974,8 @@ class Partition_read_cursor : public Table_read_cursor ...@@ -968,6 +974,8 @@ class Partition_read_cursor : public Table_read_cursor
bool end_of_partition; bool end_of_partition;
}; };
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/* /*
...@@ -1735,7 +1743,17 @@ class Frame_unbounded_following_set_count : public Frame_unbounded_following ...@@ -1735,7 +1743,17 @@ class Frame_unbounded_following_set_count : public Frame_unbounded_following
/* Walk to the end of the partition, find how many rows there are. */ /* Walk to the end of the partition, find how many rows there are. */
while (!cursor.next()) while (!cursor.next())
num_rows_in_partition++; num_rows_in_partition++;
set_win_funcs_row_count(num_rows_in_partition);
}
ha_rows get_curr_rownum() const
{
return cursor.get_rownum();
}
protected:
void set_win_funcs_row_count(ha_rows num_rows_in_partition)
{
List_iterator_fast<Item_sum> it(sum_functions); List_iterator_fast<Item_sum> it(sum_functions);
Item_sum* item; Item_sum* item;
while ((item= it++)) while ((item= it++))
...@@ -1745,11 +1763,43 @@ class Frame_unbounded_following_set_count : public Frame_unbounded_following ...@@ -1745,11 +1763,43 @@ class Frame_unbounded_following_set_count : public Frame_unbounded_following
item_with_row_count->set_row_count(num_rows_in_partition); item_with_row_count->set_row_count(num_rows_in_partition);
} }
} }
};
class Frame_unbounded_following_set_count_no_nulls:
public Frame_unbounded_following_set_count
{
public:
Frame_unbounded_following_set_count_no_nulls(THD *thd,
SQL_I_List<ORDER> *partition_list,
SQL_I_List<ORDER> *order_list) :
Frame_unbounded_following_set_count(thd,partition_list, order_list)
{
order_item= order_list->first->item[0];
}
void next_partition(ha_rows rownum)
{
ha_rows num_rows_in_partition= 0;
if (cursor.fetch())
return;
/* Walk to the end of the partition, find how many rows there are. */
do
{
if (!order_item->is_null())
num_rows_in_partition++;
} while (!cursor.next());
set_win_funcs_row_count(num_rows_in_partition);
}
ha_rows get_curr_rownum() const ha_rows get_curr_rownum() const
{ {
return cursor.get_rownum(); return cursor.get_rownum();
} }
private:
Item* order_item;
}; };
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
...@@ -2490,6 +2540,21 @@ void add_special_frame_cursors(THD *thd, Cursor_manager *cursor_manager, ...@@ -2490,6 +2540,21 @@ void add_special_frame_cursors(THD *thd, Cursor_manager *cursor_manager,
cursor_manager->add_cursor(fc); cursor_manager->add_cursor(fc);
break; break;
} }
case Item_sum::PERCENTILE_CONT_FUNC:
case Item_sum::PERCENTILE_DISC_FUNC:
{
fc= new Frame_unbounded_preceding(thd,
spec->partition_list,
spec->order_list);
fc->add_sum_func(item_sum);
cursor_manager->add_cursor(fc);
fc= new Frame_unbounded_following(thd,
spec->partition_list,
spec->order_list);
fc->add_sum_func(item_sum);
cursor_manager->add_cursor(fc);
break;
}
default: default:
fc= new Frame_unbounded_preceding( fc= new Frame_unbounded_preceding(
thd, spec->partition_list, spec->order_list); thd, spec->partition_list, spec->order_list);
...@@ -2514,6 +2579,8 @@ static bool is_computed_with_remove(Item_sum::Sumfunctype sum_func) ...@@ -2514,6 +2579,8 @@ static bool is_computed_with_remove(Item_sum::Sumfunctype sum_func)
case Item_sum::NTILE_FUNC: case Item_sum::NTILE_FUNC:
case Item_sum::FIRST_VALUE_FUNC: case Item_sum::FIRST_VALUE_FUNC:
case Item_sum::LAST_VALUE_FUNC: case Item_sum::LAST_VALUE_FUNC:
case Item_sum::PERCENTILE_CONT_FUNC:
case Item_sum::PERCENTILE_DISC_FUNC:
return false; return false;
default: default:
return true; return true;
...@@ -2543,10 +2610,19 @@ void get_window_functions_required_cursors( ...@@ -2543,10 +2610,19 @@ void get_window_functions_required_cursors(
Add a cursor that retrieves it as the first one in the list if necessary. Add a cursor that retrieves it as the first one in the list if necessary.
*/ */
if (item_win_func->requires_partition_size()) if (item_win_func->requires_partition_size())
{
if (item_win_func->only_single_element_order_list())
{
fc= new Frame_unbounded_following_set_count_no_nulls(thd,
item_win_func->window_spec->partition_list,
item_win_func->window_spec->order_list);
}
else
{ {
fc= new Frame_unbounded_following_set_count(thd, fc= new Frame_unbounded_following_set_count(thd,
item_win_func->window_spec->partition_list, item_win_func->window_spec->partition_list,
item_win_func->window_spec->order_list); item_win_func->window_spec->order_list);
}
fc->add_sum_func(sum_func); fc->add_sum_func(sum_func);
cursor_manager->add_cursor(fc); cursor_manager->add_cursor(fc);
} }
...@@ -2727,6 +2803,13 @@ bool compute_window_func(THD *thd, ...@@ -2727,6 +2803,13 @@ bool compute_window_func(THD *thd,
{ {
cursor_manager->notify_cursors_next_row(); cursor_manager->notify_cursors_next_row();
} }
/* Check if we found any error in the window function while adding values
through cursors. */
if (thd->is_error() || thd->is_killed())
break;
/* Return to current row after notifying cursors for each window /* Return to current row after notifying cursors for each window
function. */ function. */
tbl->file->ha_rnd_pos(tbl->record[0], rowid_buf); tbl->file->ha_rnd_pos(tbl->record[0], rowid_buf);
......
...@@ -1237,6 +1237,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -1237,6 +1237,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token MAX_STATEMENT_TIME_SYM %token MAX_STATEMENT_TIME_SYM
%token MAX_USER_CONNECTIONS_SYM %token MAX_USER_CONNECTIONS_SYM
%token MAXVALUE_SYM /* SQL-2003-N */ %token MAXVALUE_SYM /* SQL-2003-N */
%token MEDIAN_SYM
%token MEDIUMBLOB %token MEDIUMBLOB
%token MEDIUMINT %token MEDIUMINT
%token MEDIUMTEXT %token MEDIUMTEXT
...@@ -1329,6 +1330,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -1329,6 +1330,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token PARTITIONING_SYM %token PARTITIONING_SYM
%token PASSWORD_SYM %token PASSWORD_SYM
%token PERCENT_RANK_SYM %token PERCENT_RANK_SYM
%token PERCENTILE_CONT_SYM
%token PERCENTILE_DISC_SYM
%token PERSISTENT_SYM %token PERSISTENT_SYM
%token PHASE_SYM %token PHASE_SYM
%token PLUGINS_SYM %token PLUGINS_SYM
...@@ -1577,6 +1580,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -1577,6 +1580,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token WINDOW_SYM %token WINDOW_SYM
%token WHILE_SYM %token WHILE_SYM
%token WITH /* SQL-2003-R */ %token WITH /* SQL-2003-R */
%token WITHIN
%token WITH_CUBE_SYM /* INTERNAL */ %token WITH_CUBE_SYM /* INTERNAL */
%token WITH_ROLLUP_SYM /* INTERNAL */ %token WITH_ROLLUP_SYM /* INTERNAL */
%token WORK_SYM /* SQL-2003-N */ %token WORK_SYM /* SQL-2003-N */
...@@ -1736,6 +1740,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -1736,6 +1740,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
window_func_expr window_func_expr
window_func window_func
simple_window_func simple_window_func
inverse_distribution_function
percentile_function
inverse_distribution_function_def
function_call_keyword function_call_keyword
function_call_nonkeyword function_call_nonkeyword
function_call_generic function_call_generic
...@@ -1958,7 +1965,6 @@ END_OF_INPUT ...@@ -1958,7 +1965,6 @@ END_OF_INPUT
%type <spvar_definition> row_field_name row_field_definition %type <spvar_definition> row_field_name row_field_definition
%type <spvar_definition_list> row_field_definition_list row_type_body %type <spvar_definition_list> row_field_definition_list row_type_body
%type <NONE> opt_window_clause window_def_list window_def window_spec %type <NONE> opt_window_clause window_def_list window_def window_spec
%type <lex_str_ptr> window_name %type <lex_str_ptr> window_name
%type <NONE> opt_window_ref opt_window_frame_clause %type <NONE> opt_window_ref opt_window_frame_clause
...@@ -9411,6 +9417,7 @@ column_default_non_parenthesized_expr: ...@@ -9411,6 +9417,7 @@ column_default_non_parenthesized_expr:
| variable | variable
| sum_expr | sum_expr
| window_func_expr | window_func_expr
| inverse_distribution_function
| ROW_SYM '(' expr ',' expr_list ')' | ROW_SYM '(' expr ',' expr_list ')'
{ {
$5->push_front($3, thd->mem_root); $5->push_front($3, thd->mem_root);
...@@ -10269,6 +10276,11 @@ geometry_function: ...@@ -10269,6 +10276,11 @@ geometry_function:
Geometry::wkb_polygon, Geometry::wkb_polygon,
Geometry::wkb_linestring)); Geometry::wkb_linestring));
} }
| WITHIN '(' expr ',' expr ')'
{
$$= GEOM_NEW(thd, Item_func_spatial_precise_rel(thd, $3, $5,
Item_func::SP_WITHIN_FUNC));
}
; ;
/* /*
...@@ -10730,6 +10742,71 @@ simple_window_func: ...@@ -10730,6 +10742,71 @@ simple_window_func:
} }
; ;
inverse_distribution_function:
percentile_function OVER_SYM
'(' opt_window_partition_clause ')'
{
LEX *lex= Lex;
if (Select->add_window_spec(thd, lex->win_ref,
Select->group_list,
Select->order_list,
NULL))
MYSQL_YYABORT;
$$= new (thd->mem_root) Item_window_func(thd, (Item_sum *) $1,
thd->lex->win_spec);
if ($$ == NULL)
MYSQL_YYABORT;
if (Select->add_window_func((Item_window_func *) $$))
MYSQL_YYABORT;
}
;
percentile_function:
inverse_distribution_function_def WITHIN GROUP_SYM '('
{ Select->prepare_add_window_spec(thd); }
order_by_single_element_list ')'
{
$$= $1;
}
| MEDIAN_SYM '(' expr ')'
{
Item *args= new (thd->mem_root) Item_decimal(thd, "0.5", 3,
thd->charset());
if (($$ == NULL) || (thd->is_error()))
{
MYSQL_YYABORT;
}
if (add_order_to_list(thd, $3,FALSE)) MYSQL_YYABORT;
$$= new (thd->mem_root) Item_sum_percentile_cont(thd, args);
if ($$ == NULL)
MYSQL_YYABORT;
}
;
inverse_distribution_function_def:
PERCENTILE_CONT_SYM '(' expr ')'
{
$$= new (thd->mem_root) Item_sum_percentile_cont(thd, $3);
if ($$ == NULL)
MYSQL_YYABORT;
}
| PERCENTILE_DISC_SYM '(' expr ')'
{
$$= new (thd->mem_root) Item_sum_percentile_disc(thd, $3);
if ($$ == NULL)
MYSQL_YYABORT;
}
;
order_by_single_element_list:
ORDER_SYM BY order_ident order_dir
{ if (add_order_to_list(thd, $3,(bool) $4)) MYSQL_YYABORT; }
;
window_name: window_name:
ident ident
{ {
...@@ -14665,6 +14742,7 @@ keyword: ...@@ -14665,6 +14742,7 @@ keyword:
| UNICODE_SYM {} | UNICODE_SYM {}
| UNINSTALL_SYM {} | UNINSTALL_SYM {}
| UNBOUNDED_SYM {} | UNBOUNDED_SYM {}
| WITHIN {}
| WRAPPER_SYM {} | WRAPPER_SYM {}
| XA_SYM {} | XA_SYM {}
| UPGRADE_SYM {} | UPGRADE_SYM {}
......
...@@ -645,6 +645,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -645,6 +645,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token MAX_STATEMENT_TIME_SYM %token MAX_STATEMENT_TIME_SYM
%token MAX_USER_CONNECTIONS_SYM %token MAX_USER_CONNECTIONS_SYM
%token MAXVALUE_SYM /* SQL-2003-N */ %token MAXVALUE_SYM /* SQL-2003-N */
%token MEDIAN_SYM
%token MEDIUMBLOB %token MEDIUMBLOB
%token MEDIUMINT %token MEDIUMINT
%token MEDIUMTEXT %token MEDIUMTEXT
...@@ -737,6 +738,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -737,6 +738,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token PARTITIONING_SYM %token PARTITIONING_SYM
%token PASSWORD_SYM %token PASSWORD_SYM
%token PERCENT_RANK_SYM %token PERCENT_RANK_SYM
%token PERCENTILE_CONT_SYM
%token PERCENTILE_DISC_SYM
%token PERSISTENT_SYM %token PERSISTENT_SYM
%token PHASE_SYM %token PHASE_SYM
%token PLUGINS_SYM %token PLUGINS_SYM
...@@ -983,6 +986,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -983,6 +986,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token WINDOW_SYM %token WINDOW_SYM
%token WHILE_SYM %token WHILE_SYM
%token WITH /* SQL-2003-R */ %token WITH /* SQL-2003-R */
%token WITHIN
%token WITH_CUBE_SYM /* INTERNAL */ %token WITH_CUBE_SYM /* INTERNAL */
%token WITH_ROLLUP_SYM /* INTERNAL */ %token WITH_ROLLUP_SYM /* INTERNAL */
%token WORK_SYM /* SQL-2003-N */ %token WORK_SYM /* SQL-2003-N */
...@@ -1147,6 +1151,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -1147,6 +1151,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
window_func_expr window_func_expr
window_func window_func
simple_window_func simple_window_func
inverse_distribution_function
percentile_function
inverse_distribution_function_def
explicit_cursor_attr explicit_cursor_attr
function_call_keyword function_call_keyword
function_call_nonkeyword function_call_nonkeyword
...@@ -9389,6 +9396,7 @@ column_default_non_parenthesized_expr: ...@@ -9389,6 +9396,7 @@ column_default_non_parenthesized_expr:
| variable | variable
| sum_expr | sum_expr
| window_func_expr | window_func_expr
| inverse_distribution_function
| ROW_SYM '(' expr ',' expr_list ')' | ROW_SYM '(' expr ',' expr_list ')'
{ {
$5->push_front($3, thd->mem_root); $5->push_front($3, thd->mem_root);
...@@ -10717,6 +10725,67 @@ simple_window_func: ...@@ -10717,6 +10725,67 @@ simple_window_func:
MYSQL_YYABORT; MYSQL_YYABORT;
} }
; ;
inverse_distribution_function:
percentile_function OVER_SYM
'(' opt_window_partition_clause ')'
{
LEX *lex= Lex;
if (Select->add_window_spec(thd, lex->win_ref,
Select->group_list,
Select->order_list,
NULL))
MYSQL_YYABORT;
$$= new (thd->mem_root) Item_window_func(thd, (Item_sum *) $1,
thd->lex->win_spec);
if ($$ == NULL)
MYSQL_YYABORT;
if (Select->add_window_func((Item_window_func *) $$))
MYSQL_YYABORT;
}
;
percentile_function:
inverse_distribution_function_def WITHIN GROUP_SYM '('
{ Select->prepare_add_window_spec(thd); }
order_by_single_element_list ')'
{
$$= $1;
}
| MEDIAN_SYM '(' expr ')'
{
Item *args= new (thd->mem_root) Item_decimal(thd, "0.5", 3,
thd->charset());
if (($$ == NULL) || (thd->is_error()))
{
MYSQL_YYABORT;
}
if (add_order_to_list(thd, $3,FALSE)) MYSQL_YYABORT;
$$= new (thd->mem_root) Item_sum_percentile_cont(thd, args);
if ($$ == NULL)
MYSQL_YYABORT;
}
;
inverse_distribution_function_def:
PERCENTILE_CONT_SYM '(' expr ')'
{
$$= new (thd->mem_root) Item_sum_percentile_cont(thd, $3);
if ($$ == NULL)
MYSQL_YYABORT;
}
| PERCENTILE_DISC_SYM '(' expr ')'
{
$$= new (thd->mem_root) Item_sum_percentile_disc(thd, $3);
if ($$ == NULL)
MYSQL_YYABORT;
}
;
order_by_single_element_list:
ORDER_SYM BY order_ident order_dir
{ if (add_order_to_list(thd, $3,(bool) $4)) MYSQL_YYABORT; }
;
window_name: window_name:
ident ident
...@@ -14703,6 +14772,7 @@ keyword_directly_assignable: ...@@ -14703,6 +14772,7 @@ keyword_directly_assignable:
| UNICODE_SYM {} | UNICODE_SYM {}
| UNINSTALL_SYM {} | UNINSTALL_SYM {}
| UNBOUNDED_SYM {} | UNBOUNDED_SYM {}
| WITHIN {}
| WRAPPER_SYM {} | WRAPPER_SYM {}
| XA_SYM {} | XA_SYM {}
| UPGRADE_SYM {} | UPGRADE_SYM {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment