Commit be158582 authored by Sergei Petrunia's avatar Sergei Petrunia

MDEV-9526: Compute Aggregate functions as window functions

- Add temporary code: clone_read_record() clones READ_RECORD structure,
  as long as it is used for reading filesort() result that fits into
  memory.
- Add frame bounds for ROWS-type frames. ROWS n PRECEDING|FOLLOWING,
  ROWS UNBOUNDED PRECEDING|FOLLOWING, CURRENT ROW are supported.
- Add Item_sum_count::remove() which allows "streaming" computation
  of COUNT() over a moving frame.
parent 0c223a96
......@@ -136,3 +136,120 @@ pk a b rank() over (partition by b order by a) dense_rank() over (partition by b
9 4 20 4 2
10 4 20 4 2
drop table t3;
#
# Try Aggregates as window functions. With frames.
#
create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (pk int, c int);
insert into t1 select a+1,1 from t0;
update t1 set c=2 where pk not in (1,2,3,4);
select * from t1;
pk c
1 1
2 1
3 1
4 1
5 2
6 2
7 2
8 2
9 2
10 2
select
pk, c,
count(*) over (partition by c order by pk
rows between 2 preceding and 2 following) as CNT
from t1;
pk c CNT
1 1 3
2 1 4
3 1 4
4 1 3
5 2 3
6 2 4
7 2 5
8 2 5
9 2 4
10 2 3
select
pk, c,
count(*) over (partition by c order by pk
rows between 1 preceding and 2 following) as CNT
from t1;
pk c CNT
1 1 3
2 1 4
3 1 3
4 1 2
5 2 3
6 2 4
7 2 4
8 2 4
9 2 3
10 2 2
select
pk, c,
count(*) over (partition by c order by pk
rows between 2 preceding and current row) as CNT
from t1;
pk c CNT
1 1 1
2 1 2
3 1 3
4 1 3
5 2 1
6 2 2
7 2 3
8 2 3
9 2 3
10 2 3
select
pk,c,
count(*) over (partition by c order by pk rows
between 1 following and 2 following) as CNT
from t1;
pk c CNT
1 1 2
2 1 2
3 1 1
4 1 0
5 2 2
6 2 2
7 2 2
8 2 2
9 2 1
10 2 0
select
pk,c,
count(*) over (partition by c order by pk rows
between 2 preceding and 1 preceding) as CNT
from t1;
pk c CNT
1 1 0
2 1 1
3 1 2
4 1 2
5 2 0
6 2 1
7 2 2
8 2 2
9 2 2
10 2 2
select
pk, c,
count(*) over (partition by c order by pk
rows between current row and 1 following) as CNT
from t1;
pk c CNT
1 1 2
2 1 2
3 1 2
4 1 1
5 2 2
6 2 2
7 2 2
8 2 2
9 2 2
10 2 1
drop table t0,t1;
......@@ -110,3 +110,52 @@ select pk, a, b, rank() over (order by a), dense_rank() over (order by a) from t
select pk, a, b, rank() over (partition by b order by a), dense_rank() over (partition by b order by a) from t3;
drop table t3;
--echo #
--echo # Try Aggregates as window functions. With frames.
--echo #
create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (pk int, c int);
insert into t1 select a+1,1 from t0;
update t1 set c=2 where pk not in (1,2,3,4);
select * from t1;
select
pk, c,
count(*) over (partition by c order by pk
rows between 2 preceding and 2 following) as CNT
from t1;
select
pk, c,
count(*) over (partition by c order by pk
rows between 1 preceding and 2 following) as CNT
from t1;
select
pk, c,
count(*) over (partition by c order by pk
rows between 2 preceding and current row) as CNT
from t1;
select
pk,c,
count(*) over (partition by c order by pk rows
between 1 following and 2 following) as CNT
from t1;
select
pk,c,
count(*) over (partition by c order by pk rows
between 2 preceding and 1 preceding) as CNT
from t1;
select
pk, c,
count(*) over (partition by c order by pk
rows between current row and 1 following) as CNT
from t1;
drop table t0,t1;
......@@ -1531,6 +1531,18 @@ bool Item_sum_count::add()
return 0;
}
/*
Remove a row. This is used by window functions.
*/
void Item_sum_count::remove()
{
/* TODO: Handle DECIMAL type */
DBUG_ASSERT(aggr->Aggrtype() == Aggregator::SIMPLE_AGGREGATOR);
count--;
}
longlong Item_sum_count::val_int()
{
DBUG_ASSERT(fixed == 1);
......
......@@ -545,6 +545,9 @@ class Item_sum :public Item_func_or_sum
virtual void clear()= 0;
virtual bool add()= 0;
virtual bool setup(THD *thd) { return false; }
//psergey: for window functions:
virtual void remove() { DBUG_ASSERT(0); }
virtual void cleanup();
bool check_vcol_func_processor(uchar *int_arg)
......@@ -784,6 +787,8 @@ class Item_sum_count :public Item_sum_int
void clear();
bool add();
void cleanup();
// psergey-added:
void remove();
public:
Item_sum_count(THD *thd, Item *item_par):
......
......@@ -18,6 +18,8 @@ Item_window_func::fix_fields(THD *thd, Item **ref)
if (window_func->fix_fields(thd, ref))
return TRUE;
max_length= window_func->max_length;
fixed= 1;
force_return_blank= true;
read_value_from_result_field= false;
......@@ -88,10 +90,14 @@ bool Item_sum_rank::add()
return false;
}
int Item_window_func::check_partition_bound()
{
return test_if_group_changed(partition_fields);
}
void Item_window_func::advance_window() {
int changed = test_if_group_changed(partition_fields);
void Item_window_func::advance_window()
{
int changed= check_partition_bound();
if (changed > -1)
{
......
......@@ -275,6 +275,7 @@ class Item_sum_cume_dist: public Item_sum_num
class Item_window_func : public Item_result_field
{
/* Window function parameters as we've got them from the parser */
public:
Item_sum *window_func;
LEX_STRING *window_name;
public:
......@@ -301,10 +302,12 @@ class Item_window_func : public Item_result_field
/*
Computation functions.
TODO: consoder merging these with class Group_bound_tracker.
*/
void setup_partition_border_check(THD *thd);
void advance_window();
int check_partition_bound();
enum_field_types field_type() const { return window_func->field_type(); }
enum Item::Type type() const { return Item::WINDOW_FUNC_ITEM; }
......@@ -367,12 +370,18 @@ class Item_window_func : public Item_result_field
my_decimal* val_decimal(my_decimal* dec)
{
if (force_return_blank)
{
my_decimal_set_zero(dec);
return dec;
}
return read_value_from_result_field? result_field->val_decimal(dec) :
window_func->val_decimal(dec);
}
void fix_length_and_dec() { }
void fix_length_and_dec()
{
window_func->fix_length_and_dec();
}
const char* func_name() const { return "WF"; }
......
......@@ -39,7 +39,7 @@ int rr_sequential(READ_RECORD *info);
static int rr_from_tempfile(READ_RECORD *info);
static int rr_unpack_from_tempfile(READ_RECORD *info);
static int rr_unpack_from_buffer(READ_RECORD *info);
static int rr_from_pointers(READ_RECORD *info);
int rr_from_pointers(READ_RECORD *info);
static int rr_from_cache(READ_RECORD *info);
static int init_rr_cache(THD *thd, READ_RECORD *info);
static int rr_cmp(uchar *a,uchar *b);
......@@ -531,8 +531,8 @@ static int rr_unpack_from_tempfile(READ_RECORD *info)
return 0;
}
static int rr_from_pointers(READ_RECORD *info)
//psergey: make this 'static' again:
int rr_from_pointers(READ_RECORD *info)
{
int tmp;
uchar *cache_pos;
......
This diff is collapsed.
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