diff --git a/include/source_revision.h.in b/include/source_revision.h.in index 5b657d0940e..991df992e2f 100644 --- a/include/source_revision.h.in +++ b/include/source_revision.h.in @@ -1 +1 @@ -#cmakedefine SOURCE_REVISION "@SOURCE_REVISION@" +#define SOURCE_REVISION "@SOURCE_REVISION@" diff --git a/mysql-test/r/win_percentile.result b/mysql-test/r/win_percentile.result new file mode 100644 index 00000000000..c51e2e6bd51 --- /dev/null +++ b/mysql-test/r/win_percentile.result @@ -0,0 +1,326 @@ +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); +# +# Test invalid syntax +# +# Order by clause has more than one element +select percentile_disc(0.5) within group(order by score,test) over (partition by name) from t1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'test) over (partition by name) from t1' at line 1 +select percentile_cont(0.5) within group(order by score,test) over (partition by name) from t1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'test) over (partition by name) from t1' at line 1 +# Order by clause has no element +select percentile_disc(0.5) within group() over (partition by name) from t1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ') over (partition by name) from t1' at line 1 +select percentile_cont(0.5) within group() over (partition by name) from t1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ') over (partition by name) from t1' at line 1 +# No parameters to the percentile functions +select percentile_disc() within group() over (partition by name) from t1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ') within group() over (partition by name) from t1' at line 1 +select percentile_cont() within group() over (partition by name) from t1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ') within group() over (partition by name) from t1' at line 1 +# +# Test simple syntax +# +select name, percentile_cont(0.5) within group(order by score) over (partition by name) as c from t1; +name c +Chun 5.0000000000 +Chun 5.0000000000 +Kaolin 4.0000000000 +Kaolin 4.0000000000 +Kaolin 4.0000000000 +Tatiana 4.0000000000 +Tata 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 +Tatiana 4.0000000000 +Tata 4.0000000000 +# 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 +Tatiana 4.0000000000 +Tata 4.0000000000 +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 +Chun 4.0000000000 +Kaolin 4.0000000000 +Kaolin 4.0000000000 +Kaolin 4.0000000000 +Tatiana 4.0000000000 +Tata 4.0000000000 +# argument set to null +select name, percentile_cont(null) within group(order by score) over (partition by name) from t1; +ERROR HY000: percentile_cont function only accepts arguments that can be converted to numerical types +select name, percentile_disc(null) within group(order by score) over (partition by name) from t1; +ERROR HY000: percentile_disc function only accepts arguments that can be converted to numerical types +#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; +name percentile_cont(0.5) within group ( order by score) over (partition by name ) +Chun 5.0000000000 +Chun 5.0000000000 +Kaolin 4.0000000000 +Kaolin 4.0000000000 +Kaolin 4.0000000000 +Tatiana 4.0000000000 +Tata 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 +Tatiana 4.0000000000 +Tata 4.0000000000 +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 +Chun +Kaolin +Kaolin +Kaolin +Tatiana +Tata +#disallowed fields in order by +select score, percentile_cont(0.5) within group(order by name) over (partition by score) from t1; +ERROR HY000: Numeric datatype is required for percentile_cont function +select score, percentile_disc(0.5) within group(order by name) over (partition by score) from t1; +ERROR HY000: Numeric datatype is required for percentile_disc function +#parameter value should be in the range of [0,1] +select percentile_disc(1.5) within group(order by score) over (partition by name) from t1; +ERROR HY000: Argument to the percentile_disc function does not belong to the range [0,1] +select percentile_cont(1.5) within group(order by score) over (partition by name) from t1; +ERROR HY000: Argument to the percentile_cont function does not belong to the range [0,1] +#Argument should remain constant for the entire partition +select name,percentile_cont(test) within group(order by score) over (partition by name) from t1; +ERROR HY000: Argument to the percentile_cont function is not a constant for a partition +select name, percentile_disc(test) within group(order by score) over (partition by name) from t1; +ERROR HY000: Argument to the percentile_disc function is not a constant for a partition +#only numerical types are allowed as argument to percentile functions +select name, percentile_cont(name) within group(order by score) over (partition by name) from t1; +ERROR HY000: percentile_cont function only accepts arguments that can be converted to numerical types +select name, percentile_disc(name) within group(order by score) over (partition by name) from t1; +ERROR HY000: percentile_disc function only accepts arguments that can be converted to numerical types +#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 1.0000000000 4.0000000000 +Kaolin 0.6666666667 4.0000000000 +Tatiana 1.0000000000 4.0000000000 +Tata 1.0000000000 4.0000000000 +select name, percentile_cont(0.5) within group(order by score) over (partition by name) as c from t1; +name c +Chun 5.0000000000 +Chun 5.0000000000 +Kaolin 4.0000000000 +Kaolin 4.0000000000 +Kaolin 4.0000000000 +Tatiana 4.0000000000 +Tata 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 1.0000000000 3.0000000000 +Kaolin 0.6666666667 3.0000000000 +Tatiana 1.0000000000 4.0000000000 +Tata 1.0000000000 4.0000000000 +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 1.0000000000 3.0000000000 +Kaolin 0.6666666667 3.0000000000 +Tatiana 1.0000000000 4.0000000000 +Tata 1.0000000000 4.0000000000 +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 1.0000000000 3.0000000000 +Kaolin 0.6666666667 3.0000000000 +Tatiana 1.0000000000 4.0000000000 +Tata 1.0000000000 4.0000000000 +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 1.0000000000 4.0000000000 +Kaolin 0.6666666667 4.0000000000 +Tatiana 1.0000000000 4.0000000000 +Tata 1.0000000000 4.0000000000 +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 1.0000000000 4.0000000000 +Kaolin 0.6666666667 4.0000000000 +Tatiana 1.0000000000 4.0000000000 +Tata 1.0000000000 4.0000000000 +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 1.0000000000 4.0000000000 +Kaolin 0.6666666667 4.0000000000 +Tatiana 1.0000000000 4.0000000000 +Tata 1.0000000000 4.0000000000 +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 1.0000000000 7.0000000000 +Kaolin 0.6666666667 7.0000000000 +Tatiana 1.0000000000 4.0000000000 +Tata 1.0000000000 4.0000000000 +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 1.0000000000 7.0000000000 +Kaolin 0.6666666667 7.0000000000 +Tatiana 1.0000000000 4.0000000000 +Tata 1.0000000000 4.0000000000 +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 1.0000000000 7.0000000000 +Kaolin 0.6666666667 7.0000000000 +Tatiana 1.0000000000 4.0000000000 +Tata 1.0000000000 4.0000000000 +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 1.0000000000 7.0000000000 +Kaolin 0.6666666667 7.0000000000 +Tatiana 1.0000000000 4.0000000000 +Tata 1.0000000000 4.0000000000 +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 +5.0000000000 3.0000000000 +4.0000000000 3.0000000000 +4.0000000000 3.0000000000 +4.0000000000 3.0000000000 +4.0000000000 4.0000000000 +4.0000000000 4.0000000000 +select median(score) over (partition by name), percentile_cont(0.1) within group(order by score) over (partition by name) as c from t1; +median(score) over (partition by name) c +5.0000000000 3.4000000000 +5.0000000000 3.4000000000 +4.0000000000 3.2000000000 +4.0000000000 3.2000000000 +4.0000000000 3.2000000000 +4.0000000000 4.0000000000 +4.0000000000 4.0000000000 +select median(score) over (partition by name), percentile_cont(0.2) within group(order by score) over (partition by name) as c from t1; +median(score) over (partition by name) c +5.0000000000 3.8000000000 +5.0000000000 3.8000000000 +4.0000000000 3.4000000000 +4.0000000000 3.4000000000 +4.0000000000 3.4000000000 +4.0000000000 4.0000000000 +4.0000000000 4.0000000000 +select median(score) over (partition by name), percentile_cont(0.3) within group(order by score) over (partition by name) as c from t1; +median(score) over (partition by name) c +5.0000000000 4.2000000000 +5.0000000000 4.2000000000 +4.0000000000 3.6000000000 +4.0000000000 3.6000000000 +4.0000000000 3.6000000000 +4.0000000000 4.0000000000 +4.0000000000 4.0000000000 +select median(score) over (partition by name), percentile_cont(0.4) within group(order by score) over (partition by name) as c from t1; +median(score) over (partition by name) c +5.0000000000 4.6000000000 +5.0000000000 4.6000000000 +4.0000000000 3.8000000000 +4.0000000000 3.8000000000 +4.0000000000 3.8000000000 +4.0000000000 4.0000000000 +4.0000000000 4.0000000000 +select median(score) over (partition by name), percentile_cont(0.5) within group(order by score) over (partition by name) as c from t1; +median(score) over (partition by name) c +5.0000000000 5.0000000000 +5.0000000000 5.0000000000 +4.0000000000 4.0000000000 +4.0000000000 4.0000000000 +4.0000000000 4.0000000000 +4.0000000000 4.0000000000 +4.0000000000 4.0000000000 +select median(score) over (partition by name), percentile_cont(0.6) within group(order by score) over (partition by name) as c from t1; +median(score) over (partition by name) c +5.0000000000 5.4000000000 +5.0000000000 5.4000000000 +4.0000000000 4.6000000000 +4.0000000000 4.6000000000 +4.0000000000 4.6000000000 +4.0000000000 4.0000000000 +4.0000000000 4.0000000000 +select median(score) over (partition by name), percentile_cont(0.7) within group(order by score) over (partition by name) as c from t1; +median(score) over (partition by name) c +5.0000000000 5.8000000000 +5.0000000000 5.8000000000 +4.0000000000 5.2000000000 +4.0000000000 5.2000000000 +4.0000000000 5.2000000000 +4.0000000000 4.0000000000 +4.0000000000 4.0000000000 +select median(score) over (partition by name), percentile_cont(0.8) within group(order by score) over (partition by name) as c from t1; +median(score) over (partition by name) c +5.0000000000 6.2000000000 +5.0000000000 6.2000000000 +4.0000000000 5.8000000000 +4.0000000000 5.8000000000 +4.0000000000 5.8000000000 +4.0000000000 4.0000000000 +4.0000000000 4.0000000000 +select median(score) over (partition by name), percentile_cont(0.9) within group(order by score) over (partition by name) as c from t1; +median(score) over (partition by name) c +5.0000000000 6.6000000000 +5.0000000000 6.6000000000 +4.0000000000 6.4000000000 +4.0000000000 6.4000000000 +4.0000000000 6.4000000000 +4.0000000000 4.0000000000 +4.0000000000 4.0000000000 +select median(score) over (partition by name), percentile_cont(1) within group(order by score) over (partition by name) as c from t1; +median(score) over (partition by name) c +5.0000000000 7.0000000000 +5.0000000000 7.0000000000 +4.0000000000 7.0000000000 +4.0000000000 7.0000000000 +4.0000000000 7.0000000000 +4.0000000000 4.0000000000 +4.0000000000 4.0000000000 +drop table t1; diff --git a/mysql-test/t/win_percentile.test b/mysql-test/t/win_percentile.test new file mode 100644 index 00000000000..468d8cff56b --- /dev/null +++ b/mysql-test/t/win_percentile.test @@ -0,0 +1,104 @@ +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; diff --git a/sql/item_sum.h b/sql/item_sum.h index 7845ed3318f..467a77c8983 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -354,7 +354,8 @@ public: 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 */ diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc index 835a3cbfdae..8432ab43ad8 100644 --- a/sql/item_windowfunc.cc +++ b/sql/item_windowfunc.cc @@ -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) diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h index 64a974d55d6..849c298f5aa 100644 --- a/sql/item_windowfunc.h +++ b/sql/item_windowfunc.h @@ -24,6 +24,7 @@ class Window_spec; int test_if_group_changed(List &list); + /* A wrapper around test_if_group_changed */ class Group_bound_tracker { @@ -31,10 +32,10 @@ public: Group_bound_tracker(THD *thd, SQL_I_List *list) { - for (ORDER *curr = list->first; curr; curr=curr->next) + for (ORDER *curr = list->first; curr; curr=curr->next) { - Cached_item *tmp= new_Cached_item(thd, curr->item[0], TRUE); - group_fields.push_back(tmp); + Cached_item *tmp= new_Cached_item(thd, curr->item[0], TRUE); + group_fields.push_back(tmp); } } @@ -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(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(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(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 @@ public: 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 @@ public: 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 @@ public: 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. diff --git a/sql/lex.h b/sql/lex.h index ef03afb7a32..63b0567c5d0 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -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)}, diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 6685b21c1df..76486ae8734 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -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" diff --git a/sql/sql_window.cc b/sql/sql_window.cc index d22fff9d486..4bcdca3ca11 100644 --- a/sql/sql_window.cc +++ b/sql/sql_window.cc @@ -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 @@ private: bool end_of_partition; }; + + ///////////////////////////////////////////////////////////////////////////// /* @@ -1735,7 +1743,17 @@ public: /* 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 it(sum_functions); Item_sum* item; while ((item= it++)) @@ -1745,11 +1763,43 @@ public: 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 *partition_list, + SQL_I_List *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; @@ -2544,9 +2611,18 @@ void get_window_functions_required_cursors( */ if (item_win_func->requires_partition_size()) { - fc= new Frame_unbounded_following_set_count(thd, + 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); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ac1d7de45fb..6ee99a9b29a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -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 row_field_name row_field_definition %type row_field_definition_list row_type_body - %type opt_window_clause window_def_list window_def window_spec %type window_name %type 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 {} diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index db45414fd28..a50a4ad8ccb 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -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 {}