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
VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC,
ROW_NUMBER_FUNC, RANK_FUNC, DENSE_RANK_FUNC, PERCENT_RANK_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 */
......
......@@ -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());
return true;
}
/*
TODO: why the last parameter is 'ref' in this call? What if window_func
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,
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.
@detail
If we attempt to do it in fix_fields(), partition_fields will refer
to the original window function arguments.
......@@ -194,6 +210,71 @@ void Item_sum_dense_rank::setup_window_func(THD *thd, Window_spec *window_spec)
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()
{
if (peer_tracker->check_if_next_group() || first_add)
......
......@@ -24,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
{
......@@ -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),
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)
......@@ -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)
{ return get_item_copy<Item_sum_cume_dist>(thd, mem_root, this); }
ulonglong get_row_number()
{
return current_row_count_ ;
}
private:
ulonglong current_row_count_;
};
......@@ -693,6 +702,277 @@ class Item_sum_ntile : public Item_sum_window_with_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
{
......@@ -747,6 +1027,8 @@ class Item_window_func : public Item_func_or_sum
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;
......@@ -773,6 +1055,8 @@ class Item_window_func : public Item_func_or_sum
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;
......@@ -796,12 +1080,40 @@ class Item_window_func : public Item_func_or_sum
case Item_sum::DENSE_RANK_FUNC:
case Item_sum::PERCENT_RANK_FUNC:
case Item_sum::CUME_DIST_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.
......
......@@ -701,6 +701,7 @@ static SYMBOL symbols[] = {
{ "WHILE", SYM(WHILE_SYM)},
{ "WINDOW", SYM(WINDOW_SYM)},
{ "WITH", SYM(WITH)},
{ "WITHIN", SYM(WITHIN)},
{ "WORK", SYM(WORK_SYM)},
{ "WRAPPER", SYM(WRAPPER_SYM)},
{ "WRITE", SYM(WRITE_SYM)},
......@@ -736,6 +737,7 @@ static SYMBOL sql_functions[] = {
{ "LAG", SYM(LAG_SYM)},
{ "LEAD", SYM(LEAD_SYM)},
{ "MAX", SYM(MAX_SYM)},
{ "MEDIAN", SYM(MEDIAN_SYM)},
{ "MID", SYM(SUBSTRING)}, /* unireg function */
{ "MIN", SYM(MIN_SYM)},
{ "NOW", SYM(NOW_SYM)},
......@@ -743,6 +745,8 @@ static SYMBOL sql_functions[] = {
{ "NTILE", SYM(NTILE_SYM)},
{ "POSITION", SYM(POSITION_SYM)},
{ "PERCENT_RANK", SYM(PERCENT_RANK_SYM)},
{ "PERCENTILE_CONT", SYM(PERCENTILE_CONT_SYM)},
{ "PERCENTILE_DISC", SYM(PERCENTILE_DISC_SYM)},
{ "RANK", SYM(RANK_SYM)},
{ "ROW_NUMBER", SYM(ROW_NUMBER_SYM)},
{ "SESSION_USER", SYM(USER_SYM)},
......
......@@ -7790,3 +7790,13 @@ ER_WRONG_NUMBER_OF_VALUES_IN_TVC
eng "The used table value constructor has a different number of values"
ER_FIELD_REFERENCE_IN_TVC
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,
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);
}
......@@ -968,6 +974,8 @@ class Partition_read_cursor : public Table_read_cursor
bool end_of_partition;
};
/////////////////////////////////////////////////////////////////////////////
/*
......@@ -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. */
while (!cursor.next())
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);
Item_sum* item;
while ((item= it++))
......@@ -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);
}
}
};
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
{
return cursor.get_rownum();
}
private:
Item* order_item;
};
/////////////////////////////////////////////////////////////////////////////
......@@ -2490,6 +2540,21 @@ void add_special_frame_cursors(THD *thd, Cursor_manager *cursor_manager,
cursor_manager->add_cursor(fc);
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:
fc= new Frame_unbounded_preceding(
thd, spec->partition_list, spec->order_list);
......@@ -2514,6 +2579,8 @@ static bool is_computed_with_remove(Item_sum::Sumfunctype sum_func)
case Item_sum::NTILE_FUNC:
case Item_sum::FIRST_VALUE_FUNC:
case Item_sum::LAST_VALUE_FUNC:
case Item_sum::PERCENTILE_CONT_FUNC:
case Item_sum::PERCENTILE_DISC_FUNC:
return false;
default:
return true;
......@@ -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.
*/
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,
item_win_func->window_spec->partition_list,
item_win_func->window_spec->order_list);
}
fc->add_sum_func(sum_func);
cursor_manager->add_cursor(fc);
}
......@@ -2727,6 +2803,13 @@ bool compute_window_func(THD *thd,
{
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
function. */
tbl->file->ha_rnd_pos(tbl->record[0], rowid_buf);
......
......@@ -1237,6 +1237,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token MAX_STATEMENT_TIME_SYM
%token MAX_USER_CONNECTIONS_SYM
%token MAXVALUE_SYM /* SQL-2003-N */
%token MEDIAN_SYM
%token MEDIUMBLOB
%token MEDIUMINT
%token MEDIUMTEXT
......@@ -1329,6 +1330,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token PARTITIONING_SYM
%token PASSWORD_SYM
%token PERCENT_RANK_SYM
%token PERCENTILE_CONT_SYM
%token PERCENTILE_DISC_SYM
%token PERSISTENT_SYM
%token PHASE_SYM
%token PLUGINS_SYM
......@@ -1577,6 +1580,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token WINDOW_SYM
%token WHILE_SYM
%token WITH /* SQL-2003-R */
%token WITHIN
%token WITH_CUBE_SYM /* INTERNAL */
%token WITH_ROLLUP_SYM /* INTERNAL */
%token WORK_SYM /* SQL-2003-N */
......@@ -1736,6 +1740,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
window_func_expr
window_func
simple_window_func
inverse_distribution_function
percentile_function
inverse_distribution_function_def
function_call_keyword
function_call_nonkeyword
function_call_generic
......@@ -1958,7 +1965,6 @@ END_OF_INPUT
%type <spvar_definition> row_field_name row_field_definition
%type <spvar_definition_list> row_field_definition_list row_type_body
%type <NONE> opt_window_clause window_def_list window_def window_spec
%type <lex_str_ptr> window_name
%type <NONE> opt_window_ref opt_window_frame_clause
......@@ -9411,6 +9417,7 @@ column_default_non_parenthesized_expr:
| variable
| sum_expr
| window_func_expr
| inverse_distribution_function
| ROW_SYM '(' expr ',' expr_list ')'
{
$5->push_front($3, thd->mem_root);
......@@ -10269,6 +10276,11 @@ geometry_function:
Geometry::wkb_polygon,
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:
}
;
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:
ident
{
......@@ -14665,6 +14742,7 @@ keyword:
| UNICODE_SYM {}
| UNINSTALL_SYM {}
| UNBOUNDED_SYM {}
| WITHIN {}
| WRAPPER_SYM {}
| XA_SYM {}
| UPGRADE_SYM {}
......
......@@ -645,6 +645,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token MAX_STATEMENT_TIME_SYM
%token MAX_USER_CONNECTIONS_SYM
%token MAXVALUE_SYM /* SQL-2003-N */
%token MEDIAN_SYM
%token MEDIUMBLOB
%token MEDIUMINT
%token MEDIUMTEXT
......@@ -737,6 +738,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token PARTITIONING_SYM
%token PASSWORD_SYM
%token PERCENT_RANK_SYM
%token PERCENTILE_CONT_SYM
%token PERCENTILE_DISC_SYM
%token PERSISTENT_SYM
%token PHASE_SYM
%token PLUGINS_SYM
......@@ -983,6 +986,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token WINDOW_SYM
%token WHILE_SYM
%token WITH /* SQL-2003-R */
%token WITHIN
%token WITH_CUBE_SYM /* INTERNAL */
%token WITH_ROLLUP_SYM /* INTERNAL */
%token WORK_SYM /* SQL-2003-N */
......@@ -1147,6 +1151,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
window_func_expr
window_func
simple_window_func
inverse_distribution_function
percentile_function
inverse_distribution_function_def
explicit_cursor_attr
function_call_keyword
function_call_nonkeyword
......@@ -9389,6 +9396,7 @@ column_default_non_parenthesized_expr:
| variable
| sum_expr
| window_func_expr
| inverse_distribution_function
| ROW_SYM '(' expr ',' expr_list ')'
{
$5->push_front($3, thd->mem_root);
......@@ -10717,6 +10725,67 @@ simple_window_func:
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:
ident
......@@ -14703,6 +14772,7 @@ keyword_directly_assignable:
| UNICODE_SYM {}
| UNINSTALL_SYM {}
| UNBOUNDED_SYM {}
| WITHIN {}
| WRAPPER_SYM {}
| XA_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