From d70dac207930ab74add149be692a775bc2952aaa Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 7 Aug 2019 21:01:22 +0400 Subject: [PATCH] MDEV-20278 PERCENTILE_DISC() returns a wrong data type --- mysql-test/main/win_percentile.result | 281 +++++++++++++++++--------- mysql-test/main/win_percentile.test | 63 ++++++ sql/item_windowfunc.cc | 12 +- sql/item_windowfunc.h | 11 - sql/sql_type.h | 4 - 5 files changed, 256 insertions(+), 115 deletions(-) diff --git a/mysql-test/main/win_percentile.result b/mysql-test/main/win_percentile.result index 4a918bad17f..19c400c3f2b 100644 --- a/mysql-test/main/win_percentile.result +++ b/mysql-test/main/win_percentile.result @@ -36,23 +36,23 @@ Tata 4.0000000000 Tatiana 4.0000000000 select name, percentile_disc(0.5) within group(order by score) over (partition by name) as c from t1; name c -Chun 3.0000000000 -Chun 3.0000000000 -Kaolin 4.0000000000 -Kaolin 4.0000000000 -Kaolin 4.0000000000 -Tata 4.0000000000 -Tatiana 4.0000000000 +Chun 3.0000 +Chun 3.0000 +Kaolin 4.0000 +Kaolin 4.0000 +Kaolin 4.0000 +Tata 4.0000 +Tatiana 4.0000 # no partition clause select name, percentile_disc(0.5) within group(order by score) over () from t1; name percentile_disc(0.5) within group(order by score) over () -Chun 4.0000000000 -Chun 4.0000000000 -Kaolin 4.0000000000 -Kaolin 4.0000000000 -Kaolin 4.0000000000 -Tata 4.0000000000 -Tatiana 4.0000000000 +Chun 4.0000 +Chun 4.0000 +Kaolin 4.0000 +Kaolin 4.0000 +Kaolin 4.0000 +Tata 4.0000 +Tatiana 4.0000 select name, percentile_cont(0.5) within group(order by score) over () from t1; name percentile_cont(0.5) within group(order by score) over () Chun 4.0000000000 @@ -79,13 +79,13 @@ Tata 4.0000000000 Tatiana 4.0000000000 select * from ( select name , percentile_disc(0.5) within group ( order by score) over (partition by name ) from t1 ) as t; name percentile_disc(0.5) within group ( order by score) over (partition by name ) -Chun 3.0000000000 -Chun 3.0000000000 -Kaolin 4.0000000000 -Kaolin 4.0000000000 -Kaolin 4.0000000000 -Tata 4.0000000000 -Tatiana 4.0000000000 +Chun 3.0000 +Chun 3.0000 +Kaolin 4.0000 +Kaolin 4.0000 +Kaolin 4.0000 +Tata 4.0000 +Tatiana 4.0000 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; name Chun @@ -118,13 +118,13 @@ ERROR HY000: percentile_disc function only accepts arguments that can be convert #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; name cume_dist() over (partition by name order by score) c -Chun 0.5000000000 3.0000000000 -Chun 1.0000000000 3.0000000000 -Kaolin 0.3333333333 4.0000000000 -Kaolin 0.6666666667 4.0000000000 -Kaolin 1.0000000000 4.0000000000 -Tata 1.0000000000 4.0000000000 -Tatiana 1.0000000000 4.0000000000 +Chun 0.5000000000 3.0000 +Chun 1.0000000000 3.0000 +Kaolin 0.3333333333 4.0000 +Kaolin 0.6666666667 4.0000 +Kaolin 1.0000000000 4.0000 +Tata 1.0000000000 4.0000 +Tatiana 1.0000000000 4.0000 select name, percentile_cont(0.5) within group(order by score) over (partition by name) as c from t1; name c Chun 5.0000000000 @@ -136,94 +136,94 @@ Tata 4.0000000000 Tatiana 4.0000000000 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; name b c -Chun 0.5000000000 3.0000000000 -Chun 1.0000000000 3.0000000000 -Kaolin 0.3333333333 3.0000000000 -Kaolin 0.6666666667 3.0000000000 -Kaolin 1.0000000000 3.0000000000 -Tata 1.0000000000 4.0000000000 -Tatiana 1.0000000000 4.0000000000 +Chun 0.5000000000 3.0000 +Chun 1.0000000000 3.0000 +Kaolin 0.3333333333 3.0000 +Kaolin 0.6666666667 3.0000 +Kaolin 1.0000000000 3.0000 +Tata 1.0000000000 4.0000 +Tatiana 1.0000000000 4.0000 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; name b c -Chun 0.5000000000 3.0000000000 -Chun 1.0000000000 3.0000000000 -Kaolin 0.3333333333 3.0000000000 -Kaolin 0.6666666667 3.0000000000 -Kaolin 1.0000000000 3.0000000000 -Tata 1.0000000000 4.0000000000 -Tatiana 1.0000000000 4.0000000000 +Chun 0.5000000000 3.0000 +Chun 1.0000000000 3.0000 +Kaolin 0.3333333333 3.0000 +Kaolin 0.6666666667 3.0000 +Kaolin 1.0000000000 3.0000 +Tata 1.0000000000 4.0000 +Tatiana 1.0000000000 4.0000 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; name b c -Chun 0.5000000000 3.0000000000 -Chun 1.0000000000 3.0000000000 -Kaolin 0.3333333333 3.0000000000 -Kaolin 0.6666666667 3.0000000000 -Kaolin 1.0000000000 3.0000000000 -Tata 1.0000000000 4.0000000000 -Tatiana 1.0000000000 4.0000000000 +Chun 0.5000000000 3.0000 +Chun 1.0000000000 3.0000 +Kaolin 0.3333333333 3.0000 +Kaolin 0.6666666667 3.0000 +Kaolin 1.0000000000 3.0000 +Tata 1.0000000000 4.0000 +Tatiana 1.0000000000 4.0000 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; name b c -Chun 0.5000000000 3.0000000000 -Chun 1.0000000000 3.0000000000 -Kaolin 0.3333333333 4.0000000000 -Kaolin 0.6666666667 4.0000000000 -Kaolin 1.0000000000 4.0000000000 -Tata 1.0000000000 4.0000000000 -Tatiana 1.0000000000 4.0000000000 +Chun 0.5000000000 3.0000 +Chun 1.0000000000 3.0000 +Kaolin 0.3333333333 4.0000 +Kaolin 0.6666666667 4.0000 +Kaolin 1.0000000000 4.0000 +Tata 1.0000000000 4.0000 +Tatiana 1.0000000000 4.0000 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; name b c -Chun 0.5000000000 3.0000000000 -Chun 1.0000000000 3.0000000000 -Kaolin 0.3333333333 4.0000000000 -Kaolin 0.6666666667 4.0000000000 -Kaolin 1.0000000000 4.0000000000 -Tata 1.0000000000 4.0000000000 -Tatiana 1.0000000000 4.0000000000 +Chun 0.5000000000 3.0000 +Chun 1.0000000000 3.0000 +Kaolin 0.3333333333 4.0000 +Kaolin 0.6666666667 4.0000 +Kaolin 1.0000000000 4.0000 +Tata 1.0000000000 4.0000 +Tatiana 1.0000000000 4.0000 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; name b c -Chun 0.5000000000 7.0000000000 -Chun 1.0000000000 7.0000000000 -Kaolin 0.3333333333 4.0000000000 -Kaolin 0.6666666667 4.0000000000 -Kaolin 1.0000000000 4.0000000000 -Tata 1.0000000000 4.0000000000 -Tatiana 1.0000000000 4.0000000000 +Chun 0.5000000000 7.0000 +Chun 1.0000000000 7.0000 +Kaolin 0.3333333333 4.0000 +Kaolin 0.6666666667 4.0000 +Kaolin 1.0000000000 4.0000 +Tata 1.0000000000 4.0000 +Tatiana 1.0000000000 4.0000 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; name b c -Chun 0.5000000000 7.0000000000 -Chun 1.0000000000 7.0000000000 -Kaolin 0.3333333333 7.0000000000 -Kaolin 0.6666666667 7.0000000000 -Kaolin 1.0000000000 7.0000000000 -Tata 1.0000000000 4.0000000000 -Tatiana 1.0000000000 4.0000000000 +Chun 0.5000000000 7.0000 +Chun 1.0000000000 7.0000 +Kaolin 0.3333333333 7.0000 +Kaolin 0.6666666667 7.0000 +Kaolin 1.0000000000 7.0000 +Tata 1.0000000000 4.0000 +Tatiana 1.0000000000 4.0000 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; name b c -Chun 0.5000000000 7.0000000000 -Chun 1.0000000000 7.0000000000 -Kaolin 0.3333333333 7.0000000000 -Kaolin 0.6666666667 7.0000000000 -Kaolin 1.0000000000 7.0000000000 -Tata 1.0000000000 4.0000000000 -Tatiana 1.0000000000 4.0000000000 +Chun 0.5000000000 7.0000 +Chun 1.0000000000 7.0000 +Kaolin 0.3333333333 7.0000 +Kaolin 0.6666666667 7.0000 +Kaolin 1.0000000000 7.0000 +Tata 1.0000000000 4.0000 +Tatiana 1.0000000000 4.0000 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; name b c -Chun 0.5000000000 7.0000000000 -Chun 1.0000000000 7.0000000000 -Kaolin 0.3333333333 7.0000000000 -Kaolin 0.6666666667 7.0000000000 -Kaolin 1.0000000000 7.0000000000 -Tata 1.0000000000 4.0000000000 -Tatiana 1.0000000000 4.0000000000 +Chun 0.5000000000 7.0000 +Chun 1.0000000000 7.0000 +Kaolin 0.3333333333 7.0000 +Kaolin 0.6666666667 7.0000 +Kaolin 1.0000000000 7.0000 +Tata 1.0000000000 4.0000 +Tatiana 1.0000000000 4.0000 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; name b c -Chun 0.5000000000 7.0000000000 -Chun 1.0000000000 7.0000000000 -Kaolin 0.3333333333 7.0000000000 -Kaolin 0.6666666667 7.0000000000 -Kaolin 1.0000000000 7.0000000000 -Tata 1.0000000000 4.0000000000 -Tatiana 1.0000000000 4.0000000000 +Chun 0.5000000000 7.0000 +Chun 1.0000000000 7.0000 +Kaolin 0.3333333333 7.0000 +Kaolin 0.6666666667 7.0000 +Kaolin 1.0000000000 7.0000 +Tata 1.0000000000 4.0000 +Tatiana 1.0000000000 4.0000 select median(score) over (partition by name), percentile_cont(0) within group(order by score) over (partition by name) as c from t1; median(score) over (partition by name) c 5.0000000000 3.0000000000 @@ -366,3 +366,88 @@ median(val) OVER () 2.0000000000 drop table t1; drop view v1; +# +# MDEV-20278 PERCENTILE_DISC() returns a wrong data type +# +# INT variants +CREATE TABLE t1 (name CHAR(30), star_rating INT); +INSERT INTO t1 VALUES ('Lord of the Ladybirds', 5); +INSERT INTO t1 VALUES ('Lord of the Ladybirds', 3); +INSERT INTO t1 VALUES ('Lady of the Flies', 1); +INSERT INTO t1 VALUES ('Lady of the Flies', 2); +INSERT INTO t1 VALUES ('Lady of the Flies', 5); +CREATE OR REPLACE TABLE t2 AS SELECT name, PERCENTILE_DISC(0.5) +WITHIN GROUP (ORDER BY star_rating) +OVER (PARTITION BY name) AS pc FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `name` char(30) DEFAULT NULL, + `pc` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2, t1; +# UNSIGNED INT variants +CREATE OR REPLACE TABLE t1 (name CHAR(30), star_rating BIGINT UNSIGNED); +INSERT INTO t1 VALUES ('Lord of the Ladybirds', 0x8000000000000005); +INSERT INTO t1 VALUES ('Lord of the Ladybirds', 0x8000000000000003); +INSERT INTO t1 VALUES ('Lady of the Flies', 0x8000000000000001); +INSERT INTO t1 VALUES ('Lady of the Flies', 0x8000000000000002); +INSERT INTO t1 VALUES ('Lady of the Flies', 0x8000000000000003); +CREATE OR REPLACE TABLE t2 AS SELECT name, PERCENTILE_DISC(0.5) +WITHIN GROUP (ORDER BY star_rating) +OVER (PARTITION BY name) AS pc FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `name` char(30) DEFAULT NULL, + `pc` bigint(20) unsigned DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT name, pc, HEX(pc) FROM t2 ORDER BY name, pc; +name pc HEX(pc) +Lady of the Flies 9223372036854775810 8000000000000002 +Lady of the Flies 9223372036854775810 8000000000000002 +Lady of the Flies 9223372036854775810 8000000000000002 +Lord of the Ladybirds 9223372036854775811 8000000000000003 +Lord of the Ladybirds 9223372036854775811 8000000000000003 +DROP TABLE t2, t1; +# FLOAT variants +CREATE TABLE t1 (name CHAR(30), star_rating FLOAT); +INSERT INTO t1 VALUES ('Lord of the Ladybirds', 5); +INSERT INTO t1 VALUES ('Lord of the Ladybirds', 3); +INSERT INTO t1 VALUES ('Lady of the Flies', 1); +INSERT INTO t1 VALUES ('Lady of the Flies', 2); +INSERT INTO t1 VALUES ('Lady of the Flies', 5); +CREATE TABLE t2 AS SELECT name, PERCENTILE_DISC(0.5) +WITHIN GROUP (ORDER BY star_rating) +OVER (PARTITION BY name) AS pc FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `name` char(30) DEFAULT NULL, + `pc` float DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t2, t1; +# DECIMAL variants +CREATE OR REPLACE TABLE t1 (name CHAR(30), star_rating DECIMAL(30,2)); +INSERT INTO t1 VALUES ('Lord of the Ladybirds', 50000000000); +INSERT INTO t1 VALUES ('Lord of the Ladybirds', 30000000000); +INSERT INTO t1 VALUES ('Lady of the Flies', 10000000000); +INSERT INTO t1 VALUES ('Lady of the Flies', 20000000000); +INSERT INTO t1 VALUES ('Lady of the Flies', 50000000000); +CREATE OR REPLACE TABLE t2 AS SELECT name, PERCENTILE_DISC(0.5) +WITHIN GROUP (ORDER BY star_rating) +OVER (PARTITION BY name) AS pc FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `name` char(30) DEFAULT NULL, + `pc` decimal(30,2) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t2 ORDER BY name, pc; +name pc +Lady of the Flies 20000000000.00 +Lady of the Flies 20000000000.00 +Lady of the Flies 20000000000.00 +Lord of the Ladybirds 30000000000.00 +Lord of the Ladybirds 30000000000.00 +DROP TABLE t2, t1; diff --git a/mysql-test/main/win_percentile.test b/mysql-test/main/win_percentile.test index d36b365dd9b..2b3fffc4508 100644 --- a/mysql-test/main/win_percentile.test +++ b/mysql-test/main/win_percentile.test @@ -146,3 +146,66 @@ select * from v1; select median(val) OVER () FROM t1; drop table t1; drop view v1; + + +--echo # +--echo # MDEV-20278 PERCENTILE_DISC() returns a wrong data type +--echo # + +--echo # INT variants + +CREATE TABLE t1 (name CHAR(30), star_rating INT); +INSERT INTO t1 VALUES ('Lord of the Ladybirds', 5); +INSERT INTO t1 VALUES ('Lord of the Ladybirds', 3); +INSERT INTO t1 VALUES ('Lady of the Flies', 1); +INSERT INTO t1 VALUES ('Lady of the Flies', 2); +INSERT INTO t1 VALUES ('Lady of the Flies', 5); +CREATE OR REPLACE TABLE t2 AS SELECT name, PERCENTILE_DISC(0.5) + WITHIN GROUP (ORDER BY star_rating) + OVER (PARTITION BY name) AS pc FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2, t1; + +--echo # UNSIGNED INT variants + +CREATE OR REPLACE TABLE t1 (name CHAR(30), star_rating BIGINT UNSIGNED); +INSERT INTO t1 VALUES ('Lord of the Ladybirds', 0x8000000000000005); +INSERT INTO t1 VALUES ('Lord of the Ladybirds', 0x8000000000000003); +INSERT INTO t1 VALUES ('Lady of the Flies', 0x8000000000000001); +INSERT INTO t1 VALUES ('Lady of the Flies', 0x8000000000000002); +INSERT INTO t1 VALUES ('Lady of the Flies', 0x8000000000000003); +CREATE OR REPLACE TABLE t2 AS SELECT name, PERCENTILE_DISC(0.5) + WITHIN GROUP (ORDER BY star_rating) + OVER (PARTITION BY name) AS pc FROM t1; +SHOW CREATE TABLE t2; +SELECT name, pc, HEX(pc) FROM t2 ORDER BY name, pc; +DROP TABLE t2, t1; + +--echo # FLOAT variants + +CREATE TABLE t1 (name CHAR(30), star_rating FLOAT); +INSERT INTO t1 VALUES ('Lord of the Ladybirds', 5); +INSERT INTO t1 VALUES ('Lord of the Ladybirds', 3); +INSERT INTO t1 VALUES ('Lady of the Flies', 1); +INSERT INTO t1 VALUES ('Lady of the Flies', 2); +INSERT INTO t1 VALUES ('Lady of the Flies', 5); +CREATE TABLE t2 AS SELECT name, PERCENTILE_DISC(0.5) + WITHIN GROUP (ORDER BY star_rating) + OVER (PARTITION BY name) AS pc FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2, t1; + +--echo # DECIMAL variants + +CREATE OR REPLACE TABLE t1 (name CHAR(30), star_rating DECIMAL(30,2)); +INSERT INTO t1 VALUES ('Lord of the Ladybirds', 50000000000); +INSERT INTO t1 VALUES ('Lord of the Ladybirds', 30000000000); +INSERT INTO t1 VALUES ('Lady of the Flies', 10000000000); +INSERT INTO t1 VALUES ('Lady of the Flies', 20000000000); +INSERT INTO t1 VALUES ('Lady of the Flies', 50000000000); +CREATE OR REPLACE TABLE t2 AS SELECT name, PERCENTILE_DISC(0.5) + WITHIN GROUP (ORDER BY star_rating) + OVER (PARTITION BY name) AS pc FROM t1; +SHOW CREATE TABLE t2; +SELECT * FROM t2 ORDER BY name, pc; +DROP TABLE t2, t1; diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc index 2db396d3065..85e5144779e 100644 --- a/sql/item_windowfunc.cc +++ b/sql/item_windowfunc.cc @@ -174,7 +174,8 @@ 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(); + Item *src_item= window_spec->order_list->first->item[0]; + Item_result rtype= src_item->cmp_type(); // TODO (varun) : support date type in percentile_cont function if (rtype != REAL_RESULT && rtype != INT_RESULT && rtype != DECIMAL_RESULT && rtype != TIME_RESULT) @@ -182,7 +183,14 @@ bool Item_window_func::check_result_type_of_order_item() my_error(ER_WRONG_TYPE_FOR_PERCENTILE_FUNC, MYF(0), window_func()->func_name()); return TRUE; } - setting_handler_for_percentile_functions(rtype); + if (window_func()->sum_func() == Item_sum::PERCENTILE_DISC_FUNC) + { + Item_sum_percentile_disc *func= + static_cast(window_func()); + func->set_handler(src_item->type_handler()); + func->Type_std_attributes::set(src_item); + Type_std_attributes::set(src_item); + } } return FALSE; } diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h index 37376501d1f..1432643dfc8 100644 --- a/sql/item_windowfunc.h +++ b/sql/item_windowfunc.h @@ -1097,17 +1097,6 @@ public: } } - 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(); diff --git a/sql/sql_type.h b/sql/sql_type.h index 3ef210efecf..a7915ddc463 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -3506,10 +3506,6 @@ public: { return (m_type_handler= Type_handler::get_handler_by_result_type(type)); } - const Type_handler *set_handler_by_cmp_type(Item_result type) - { - return (m_type_handler= Type_handler::get_handler_by_cmp_type(type)); - } const Type_handler *set_handler_by_result_type(Item_result type, uint max_octet_length, CHARSET_INFO *cs)