From 1adc3fab23c76cad3ac246075357228d544c6dd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Sun, 4 Sep 2016 05:51:10 +0300 Subject: [PATCH] MDEV-10097: Assertion `count > 0' failed in Item_sum_sum::add_helper(bool) When specifying a RANGE type frame that exceeds the partition size, both for the top and bottom cursors we end up removing more rows than added to the aggregate function. This happens because our TOP range cursor, which removes values from the aggregate function, would be allowed to breach partition boundaries, while the BOTTOM range cursor would not. To prevent this from happening, force the TOP range cursor to only move within the current partition, as does the BOTTOM range cursor. --- mysql-test/r/win.result | 21 +++++++++++++++++++++ mysql-test/t/win.test | 17 +++++++++++++++++ sql/sql_window.cc | 21 +++++++++++++++++---- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/win.result b/mysql-test/r/win.result index ad99453ea1c..33bf45a6835 100644 --- a/mysql-test/r/win.result +++ b/mysql-test/r/win.result @@ -1959,3 +1959,24 @@ select rank() over (order by i) from v1; rank() over (order by i) 1 drop view v1; +# +# MDEV-10097: Assertion `count > 0' failed in Item_sum_sum::add_helper(bool) +# +CREATE TABLE `orders` ( +`o_orderkey` int(11) NOT NULL, +`o_custkey` int(11) DEFAULT NULL, +PRIMARY KEY (`o_orderkey`) +) DEFAULT CHARSET=latin1; +INSERT INTO `orders` VALUES (59908,242); +INSERT INTO `orders` VALUES (59940,238); +SELECT o_custkey, avg(o_custkey) OVER (PARTITION BY abs(o_custkey) +ORDER BY o_custkey +RANGE BETWEEN 15 FOLLOWING +AND 15 FOLLOWING) from orders; +o_custkey avg(o_custkey) OVER (PARTITION BY abs(o_custkey) +ORDER BY o_custkey +RANGE BETWEEN 15 FOLLOWING +AND 15 FOLLOWING) +242 NULL +238 NULL +DROP table orders; diff --git a/mysql-test/t/win.test b/mysql-test/t/win.test index 09ddf41b4f0..dfe8189e924 100644 --- a/mysql-test/t/win.test +++ b/mysql-test/t/win.test @@ -1201,3 +1201,20 @@ create view v1 as select 1 as i; select rank() over (order by i) from v1; drop view v1; +--echo # +--echo # MDEV-10097: Assertion `count > 0' failed in Item_sum_sum::add_helper(bool) +--echo # +CREATE TABLE `orders` ( + `o_orderkey` int(11) NOT NULL, + `o_custkey` int(11) DEFAULT NULL, + PRIMARY KEY (`o_orderkey`) + ) DEFAULT CHARSET=latin1; + +INSERT INTO `orders` VALUES (59908,242); +INSERT INTO `orders` VALUES (59940,238); + +SELECT o_custkey, avg(o_custkey) OVER (PARTITION BY abs(o_custkey) + ORDER BY o_custkey + RANGE BETWEEN 15 FOLLOWING + AND 15 FOLLOWING) from orders; +DROP table orders; diff --git a/sql/sql_window.cc b/sql/sql_window.cc index a862821bd56..7dec391121c 100644 --- a/sql/sql_window.cc +++ b/sql/sql_window.cc @@ -877,7 +877,7 @@ private: class Frame_range_n_top : public Frame_cursor { - Table_read_cursor cursor; + Partition_read_cursor cursor; Cached_item_item *range_expr; @@ -885,6 +885,9 @@ class Frame_range_n_top : public Frame_cursor Item *item_add; const bool is_preceding; + + bool end_of_partition; + /* 1 when order_list uses ASC ordering -1 when order_list uses DESC ordering @@ -895,7 +898,8 @@ public: SQL_I_List *partition_list, SQL_I_List *order_list, bool is_preceding_arg, Item *n_val_arg) : - n_val(n_val_arg), item_add(NULL), is_preceding(is_preceding_arg) + cursor(thd, partition_list), n_val(n_val_arg), item_add(NULL), + is_preceding(is_preceding_arg) { DBUG_ASSERT(order_list->elements == 1); Item *src_expr= order_list->first->item[0]; @@ -921,13 +925,15 @@ public: void init(READ_RECORD *info) { cursor.init(info); - } void pre_next_partition(ha_rows rownum) { // Save the value of FUNC(current_row) range_expr->fetch_value_from(item_add); + + cursor.on_next_partition(rownum); + end_of_partition= false; } void next_partition(ha_rows rownum) @@ -938,11 +944,15 @@ public: void pre_next_row() { + if (end_of_partition) + return; range_expr->fetch_value_from(item_add); } void next_row() { + if (end_of_partition) + return; /* Ok, our cursor is at the first row R where (prev_row + n) >= R @@ -960,12 +970,15 @@ public: private: void walk_till_non_peer() { - while (!cursor.get_next()) + int res; + while (!(res= cursor.get_next())) { if (order_direction * range_expr->cmp_read_only() <= 0) break; remove_value_from_items(); } + if (res) + end_of_partition= true; } };