diff --git a/mysql-test/r/win.result b/mysql-test/r/win.result index 67957efe704..caa0ddbdcdb 100644 --- a/mysql-test/r/win.result +++ b/mysql-test/r/win.result @@ -91,6 +91,18 @@ pk a rank() over (order by a) 7 2 5 9 4 9 10 4 9 +select pk, a, rank() over (order by a desc) from t2; +pk a rank() over (order by a desc) +1 0 9 +2 0 9 +3 1 7 +4 1 7 +8 2 3 +5 2 3 +6 2 3 +7 2 3 +9 4 1 +10 4 1 drop table t2; # # Try DENSE_RANK() function @@ -252,6 +264,23 @@ pk c CNT 8 2 2 9 2 2 10 2 1 +# Check ORDER BY DESC +select +pk, c, +count(*) over (partition by c order by pk desc +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 drop table t0,t1; # # Resolution of window names @@ -817,6 +846,22 @@ pk a cnt 9 72 9 select pk, a, +count(a) over (ORDER BY a DESC +RANGE BETWEEN UNBOUNDED PRECEDING +AND 10 FOLLOWING) as cnt +from t1; +pk a cnt +1 1 9 +2 2 9 +3 4 9 +4 8 9 +5 26 5 +6 27 5 +7 40 3 +8 71 2 +9 72 2 +select +pk, a, count(a) over (ORDER BY a RANGE BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING) as cnt @@ -849,6 +894,22 @@ pk a cnt 9 72 7 select pk, a, +count(a) over (ORDER BY a DESC +RANGE BETWEEN UNBOUNDED PRECEDING +AND 10 PRECEDING) as cnt +from t1; +pk a cnt +1 1 5 +2 2 5 +3 4 5 +4 8 5 +5 26 3 +6 27 3 +7 40 2 +8 71 0 +9 72 0 +select +pk, a, count(a) over (ORDER BY a RANGE BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) as cnt @@ -881,6 +942,22 @@ pk a cnt 9 72 2 select pk, a, +count(a) over (ORDER BY a DESC +RANGE BETWEEN 1 PRECEDING +AND CURRENT ROW) as cnt +from t1; +pk a cnt +1 1 2 +2 2 1 +3 4 1 +4 8 1 +5 26 2 +6 27 1 +7 40 1 +8 71 2 +9 72 1 +select +pk, a, count(a) over (ORDER BY a RANGE BETWEEN 1 FOLLOWING AND 3 FOLLOWING) as cnt @@ -895,6 +972,39 @@ pk a cnt 7 40 0 8 71 1 9 72 0 +# Try CURRENT ROW with[out] DESC +select +pk, a, +count(a) over (ORDER BY a +RANGE BETWEEN CURRENT ROW +AND 1 FOLLOWING) as cnt +from t1; +pk a cnt +1 1 2 +2 2 1 +3 4 1 +4 8 1 +5 26 2 +6 27 1 +7 40 1 +8 71 2 +9 72 1 +select +pk, a, +count(a) over (order by a desc +range between current row +and 1 following) as cnt +from t1; +pk a cnt +1 1 1 +2 2 2 +3 4 1 +4 8 1 +5 26 1 +6 27 2 +7 40 1 +8 71 1 +9 72 2 insert into t1 select 22, pk, a from t1; select part_id, pk, a, diff --git a/mysql-test/t/win.test b/mysql-test/t/win.test index d946c83ebc3..875b9bc0f36 100644 --- a/mysql-test/t/win.test +++ b/mysql-test/t/win.test @@ -82,6 +82,7 @@ insert into t2 values (10 , 4); select pk, a, rank() over (order by a) from t2; +select pk, a, rank() over (order by a desc) from t2; drop table t2; @@ -158,6 +159,13 @@ select rows between current row and 1 following) as CNT from t1; +--echo # Check ORDER BY DESC +select + pk, c, + count(*) over (partition by c order by pk desc + rows between 2 preceding and 2 following) as CNT +from t1; + drop table t0,t1; --echo # @@ -514,6 +522,13 @@ select AND 10 FOLLOWING) as cnt from t1; +select + pk, a, + count(a) over (ORDER BY a DESC + RANGE BETWEEN UNBOUNDED PRECEDING + AND 10 FOLLOWING) as cnt +from t1; + select pk, a, count(a) over (ORDER BY a @@ -528,6 +543,13 @@ select AND 10 PRECEDING) as cnt from t1; +select + pk, a, + count(a) over (ORDER BY a DESC + RANGE BETWEEN UNBOUNDED PRECEDING + AND 10 PRECEDING) as cnt +from t1; + select pk, a, count(a) over (ORDER BY a @@ -543,6 +565,13 @@ select AND CURRENT ROW) as cnt from t1; +select + pk, a, + count(a) over (ORDER BY a DESC + RANGE BETWEEN 1 PRECEDING + AND CURRENT ROW) as cnt +from t1; + select pk, a, count(a) over (ORDER BY a @@ -550,6 +579,22 @@ select AND 3 FOLLOWING) as cnt from t1; +--echo # Try CURRENT ROW with[out] DESC +select + pk, a, + count(a) over (ORDER BY a + RANGE BETWEEN CURRENT ROW + AND 1 FOLLOWING) as cnt +from t1; + +select + pk, a, + count(a) over (order by a desc + range between current row + and 1 following) as cnt +from t1; + + # Try with partitions insert into t1 select 22, pk, a from t1; select diff --git a/sql/sql_window.cc b/sql/sql_window.cc index 956f1c28681..df9899e232e 100644 --- a/sql/sql_window.cc +++ b/sql/sql_window.cc @@ -275,9 +275,9 @@ public: { int rc= read_record->table->file->ha_rnd_pos(read_record->record, p); if (!rc) - return true; + return true; // restored ok } - return false; + return false; // didn't restore } // todo: should move_to() also read row here? @@ -409,6 +409,11 @@ class Frame_range_n_top : public Frame_cursor Item *item_add; const bool is_preceding; + /* + 1 when order_list uses ASC ordering + -1 when order_list uses DESC ordering + */ + int order_direction; public: Frame_range_n_top(bool is_preceding_arg, Item *n_val_arg) : n_val(n_val_arg), item_add(NULL), is_preceding(is_preceding_arg) @@ -422,9 +427,18 @@ public: DBUG_ASSERT(order_list->elements == 1); Item *src_expr= order_list->first->item[0]; + if (order_list->first->direction == ORDER::ORDER_ASC) + order_direction= 1; + else + order_direction= -1; range_expr= (Cached_item_item*) new_Cached_item(thd, src_expr, FALSE); - if (is_preceding) + + bool use_minus= is_preceding; + if (order_direction == -1) + use_minus= !use_minus; + + if (use_minus) item_add= new (thd->mem_root) Item_func_minus(thd, src_expr, n_val); else item_add= new (thd->mem_root) Item_func_plus(thd, src_expr, n_val); @@ -458,7 +472,7 @@ public: */ if (cursor.restore_last_row()) { - if (range_expr->cmp_read_only() <= 0) + if (order_direction * range_expr->cmp_read_only() <= 0) return; item->remove(); } @@ -470,7 +484,7 @@ private: { while (!cursor.get_next()) { - if (range_expr->cmp_read_only() <= 0) + if (order_direction * range_expr->cmp_read_only() <= 0) break; item->remove(); } @@ -487,6 +501,8 @@ private: Bottom end moves first so it needs to check for partition end (todo: unless it's PRECEDING and in that case it doesnt) + (todo: factor out common parts with Frame_range_n_top into + a common ancestor) */ class Frame_range_n_bottom: public Frame_cursor @@ -502,6 +518,12 @@ class Frame_range_n_bottom: public Frame_cursor Group_bound_tracker bound_tracker; bool end_of_partition; + + /* + 1 when order_list uses ASC ordering + -1 when order_list uses DESC ordering + */ + int order_direction; public: Frame_range_n_bottom(bool is_preceding_arg, Item *n_val_arg) : n_val(n_val_arg), item_add(NULL), is_preceding(is_preceding_arg) @@ -516,8 +538,18 @@ public: DBUG_ASSERT(order_list->elements == 1); Item *src_expr= order_list->first->item[0]; + if (order_list->first->direction == ORDER::ORDER_ASC) + order_direction= 1; + else + order_direction= -1; + range_expr= (Cached_item_item*) new_Cached_item(thd, src_expr, FALSE); - if (is_preceding) + + bool use_minus= is_preceding; + if (order_direction == -1) + use_minus= !use_minus; + + if (use_minus) item_add= new (thd->mem_root) Item_func_minus(thd, src_expr, n_val); else item_add= new (thd->mem_root) Item_func_plus(thd, src_expr, n_val); @@ -560,7 +592,7 @@ public: */ if (cursor.restore_last_row()) { - if (range_expr->cmp_read_only() < 0) + if (order_direction * range_expr->cmp_read_only() < 0) return; item->add(); } @@ -578,7 +610,7 @@ private: end_of_partition= true; break; } - if (range_expr->cmp_read_only() < 0) + if (order_direction * range_expr->cmp_read_only() < 0) break; item->add(); } @@ -695,7 +727,6 @@ class Frame_range_current_row_top : public Frame_cursor Group_bound_tracker peer_tracker; bool move; - bool at_partition_start; public: void init(THD *thd, READ_RECORD *info, SQL_I_List *partition_list, @@ -709,31 +740,33 @@ public: void pre_next_partition(longlong rownum, Item_sum* item) { - // fetch the value from the first row + // Fetch the value from the first row peer_tracker.check_if_next_group(); - } - - void next_partition(longlong rownum, Item_sum* item) - { - at_partition_start= true; cursor.move_to(rownum+1); } + void next_partition(longlong rownum, Item_sum* item) {} + void pre_next_row(Item_sum* item) { - // Check if our current row is pointing to a peer of the current row. - // If not, move forward until that becomes true. + // Check if the new current_row is a peer of the row that our cursor is + // pointing to. move= peer_tracker.check_if_next_group(); } void next_row(Item_sum* item) { - bool was_at_partition_start= at_partition_start; - at_partition_start= false; if (move) { - if (!was_at_partition_start && cursor.restore_last_row()) + /* + Our cursor is pointing at the first row that was a peer of the previous + current row. Or, it was the first row in the partition. + */ + if (cursor.restore_last_row()) { + // todo: need the following check ? + if (!peer_tracker.compare_with_cache()) + return; item->remove(); }