diff --git a/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc b/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc index 813859fa6..066096a90 100644 --- a/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc +++ b/query_classifier/qc_mysqlembedded/qc_mysqlembedded.cc @@ -80,6 +80,7 @@ #if MYSQL_VERSION_MAJOR >= 10 && MYSQL_VERSION_MINOR >= 2 #define CTE_SUPPORTED +#define WF_SUPPORTED #endif #if defined(CTE_SUPPORTED) @@ -2542,6 +2543,16 @@ static bool should_function_be_ignored(parsing_info_t* pi, const char* func_name } #endif +#ifdef WF_SUPPORTED + if (!rv) + { + if (strcasecmp(func_name, "WF") == 0) + { + rv = true; + } + } +#endif + return rv; } @@ -2607,8 +2618,11 @@ static void update_field_infos(parsing_info_t* pi, case Item::FUNC_ITEM: case Item::SUM_FUNC_ITEM: +#ifdef WF_SUPPORTED + case Item::WINDOW_FUNC_ITEM: +#endif { - Item_func* func_item = static_cast(item); + Item_func_or_sum* func_item = static_cast(item); Item** items = func_item->arguments(); size_t n_items = func_item->argument_count(); diff --git a/query_classifier/qc_sqlite/builtin_functions.c b/query_classifier/qc_sqlite/builtin_functions.c index 44bace220..ad912c63f 100644 --- a/query_classifier/qc_sqlite/builtin_functions.c +++ b/query_classifier/qc_sqlite/builtin_functions.c @@ -387,11 +387,11 @@ static const char* BUILTIN_FUNCTIONS[] = const size_t N_BUILTIN_FUNCTIONS = sizeof(BUILTIN_FUNCTIONS) / sizeof(BUILTIN_FUNCTIONS[0]); -// The functions have been taken from: -// https://mariadb.com/kb/en/mariadb/json-functions - static const char* BUILTIN_10_2_3_FUNCTIONS[] = { + // + // JSON functions: https://mariadb.com/kb/en/mariadb/json-functions + // "json_array", "json_array_append", "json_array_insert", @@ -417,7 +417,17 @@ static const char* BUILTIN_10_2_3_FUNCTIONS[] = "json_type", "json_unquote", "json_valid", - "json_value" + "json_value", + + // + // Window functions: https://mariadb.com/kb/en/mariadb/window-functions/ + // + "cume_dist", + "dense_rank", + "ntile", + "percent_rank", + "rank", + "row_number", }; const size_t N_BUILTIN_10_2_3_FUNCTIONS = diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y b/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y index 161d53d8b..03957b69e 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y @@ -1028,8 +1028,28 @@ multiselect_op(A) ::= UNION ALL. {A = TK_ALL;} multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP;} %endif SQLITE_OMIT_COMPOUND_SELECT %ifdef MAXSCALE + +wf_window_name ::= id. + +wf_window_ref_opt ::= . +wf_window_ref_opt ::= id. + +wf_window_spec ::= LP wf_window_ref_opt wf_partition_by_opt wf_order_by_opt wf_frame_opt RP. + +wf_window_def ::= wf_window_name AS wf_window_spec. + +wf_window_def_list ::= wf_window_def_list COMMA wf_window_def. +wf_window_def_list ::= wf_window_def. + +wf_window ::= WINDOW wf_window_def_list. +wf_window ::= WINDOW LP RP. + +wf_window_opt ::= . +wf_window_opt ::= wf_window. + oneselect(A) ::= SELECT select_options(D) selcollist(W) select_into_opt(I1) from(X) where_opt(Y) - groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L) select_into_opt(I2). { + groupby_opt(P) having_opt(Q) wf_window_opt orderby_opt(Z) limit_opt(L) + select_into_opt(I2). { if (!I1) { I1=I2; } @@ -1882,6 +1902,62 @@ func_arg_tail_opt ::= . func_arg_tail_opt ::= group_concat_tail. func_arg_tail_opt ::= convert_tail. +wf_partition_by ::= PARTITION BY nexprlist(X). { + sqlite3ExprListDelete(pParse->db, X); +} + +wf_partition_by_opt ::= . +wf_partition_by_opt ::= wf_partition_by. + +wf_order_by ::= ORDER BY nexprlist(X) sortorder. { + sqlite3ExprListDelete(pParse->db, X); +} + +wf_order_by_opt ::= . +wf_order_by_opt ::= wf_order_by. + +wf_frame_units ::= RANGE. +wf_frame_units ::= ROWS. + +wf_frame_start ::= UNBOUNDED PRECEDING. +wf_frame_start ::= CURRENT ROW. +wf_frame_start ::= term PRECEDING. + +wf_frame_bound ::= wf_frame_start. +wf_frame_bound ::= UNBOUNDED FOLLOWING. +wf_frame_bound ::= term FOLLOWING. + +wf_frame_extent ::= wf_frame_start. +wf_frame_extent ::= BETWEEN wf_frame_bound AND wf_frame_bound. + +wf_frame_exclusion_opt ::= . +wf_frame_exclusion_opt ::= EXCLUDE CURRENT ROW. +wf_frame_exclusion_opt ::= EXCLUDE GROUP. +wf_frame_exclusion_opt ::= EXCLUDE TIES. +wf_frame_exclusion_opt ::= EXCLUDE NO OTHERS. + +wf_frame_opt ::= . +wf_frame_opt ::= wf_frame_units wf_frame_extent wf_frame_exclusion_opt . + +wf ::= OVER LP wf_window_ref_opt wf_partition_by_opt wf_order_by_opt wf_frame_opt RP. +wf ::= OVER id. + +expr(A) ::= id(X) LP distinct(D) exprlist(Y) func_arg_tail_opt RP(E) wf. { + if( Y && Y->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){ + sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X); + } + A.pExpr = sqlite3ExprFunction(pParse, Y, &X); + spanSet(&A,&X,&E); + if( D==SF_Distinct && A.pExpr ){ + A.pExpr->flags |= EP_Distinct; + } +} + +expr(A) ::= id(X) LP STAR RP(E) wf. { + A.pExpr = sqlite3ExprFunction(pParse, 0, &X); + spanSet(&A,&X,&E); +} + expr(A) ::= id(X) LP distinct(D) exprlist(Y) func_arg_tail_opt RP(E). { %endif %ifndef MAXSCALE diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/tool/mkkeywordhash.c b/query_classifier/qc_sqlite/sqlite-src-3110100/tool/mkkeywordhash.c index d496ec6be..b30bb9b07 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/tool/mkkeywordhash.c +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/tool/mkkeywordhash.c @@ -208,6 +208,9 @@ static Keyword aKeywordTable[] = { { "CONSTRAINT", "TK_CONSTRAINT", ALWAYS }, { "CREATE", "TK_CREATE", ALWAYS }, { "CROSS", "TK_JOIN_KW", ALWAYS }, +#ifdef MAXSCALE + { "CURRENT", "TK_CURRENT", ALWAYS }, +#endif { "CURRENT_DATE", "TK_CTIME_KW", ALWAYS }, { "CURRENT_TIME", "TK_CTIME_KW", ALWAYS }, { "CURRENT_TIMESTAMP","TK_CTIME_KW", ALWAYS }, @@ -254,6 +257,7 @@ static Keyword aKeywordTable[] = { { "EXCLUSIVE", "TK_EXCLUSIVE", ALWAYS }, #ifdef MAXSCALE { "EXECUTE", "TK_EXECUTE", ALWAYS }, + { "EXCLUDE", "TK_EXCLUDE", ALWAYS }, #endif { "EXISTS", "TK_EXISTS", ALWAYS }, { "EXPLAIN", "TK_EXPLAIN", EXPLAIN }, @@ -263,6 +267,7 @@ static Keyword aKeywordTable[] = { #ifdef MAXSCALE { "FIRST", "TK_FIRST", ALWAYS }, { "FLUSH", "TK_FLUSH", ALWAYS }, + { "FOLLOWING", "TK_FOLLOWING", ALWAYS }, #endif { "FOR", "TK_FOR", TRIGGER }, #ifdef MAXSCALE @@ -352,11 +357,16 @@ static Keyword aKeywordTable[] = { #endif { "OR", "TK_OR", ALWAYS }, { "ORDER", "TK_ORDER", ALWAYS }, +#ifdef MAXSCALE + { "OTHERS", "TK_OTHERS", ALWAYS }, +#endif { "OUTER", "TK_JOIN_KW", ALWAYS }, #ifdef MAXSCALE { "OUTFILE", "TK_OUTFILE", ALWAYS }, + { "OVER", "TK_OVER", ALWAYS }, #endif #ifdef MAXSCALE + { "PARTITION", "TK_PARTITION", ALWAYS }, { "PERSISTENT", "TK_PERSISTENT", ALWAYS }, #endif #ifndef MAXSCALE @@ -364,6 +374,7 @@ static Keyword aKeywordTable[] = { #endif { "PRAGMA", "TK_PRAGMA", PRAGMA }, #ifdef MAXSCALE + { "PRECEDING", "TK_PRECEDING", ALWAYS }, { "PREPARE", "TK_PREPARE", ALWAYS }, #endif { "PRIMARY", "TK_PRIMARY", ALWAYS }, @@ -378,6 +389,7 @@ static Keyword aKeywordTable[] = { #endif { "RAISE", "TK_RAISE", TRIGGER }, #ifdef MAXSCALE + { "RANGE", "TK_RANGE", ALWAYS }, { "READ", "TK_READ", ALWAYS }, #endif { "RECURSIVE", "TK_RECURSIVE", CTE }, @@ -397,6 +409,9 @@ static Keyword aKeywordTable[] = { { "ROLLUP", "TK_ROLLUP", ALWAYS }, #endif { "ROW", "TK_ROW", TRIGGER }, +#ifdef MAXSCALE + { "ROWS", "TK_ROWS", ALWAYS }, +#endif { "SAVEPOINT", "TK_SAVEPOINT", ALWAYS }, #ifdef MAXSCALE { "SCHEMAS", "TK_DATABASES_KW", ALWAYS }, @@ -432,11 +447,15 @@ static Keyword aKeywordTable[] = { { "TEMPTABLE", "TK_TEMPTABLE", ANALYZE }, #endif { "THEN", "TK_THEN", ALWAYS }, +#ifdef MAXSCALE + { "TIES", "TK_TIES", ANALYZE }, +#endif { "TO", "TK_TO", ALWAYS }, { "TRANSACTION", "TK_TRANSACTION", ALWAYS }, { "TRIGGER", "TK_TRIGGER", TRIGGER }, #ifdef MAXSCALE { "TRUNCATE", "TK_TRUNCATE", ALWAYS }, + { "UNBOUNDED", "TK_UNBOUNDED", ALWAYS }, #endif { "UNION", "TK_UNION", COMPOUND }, { "UNSIGNED", "TK_UNSIGNED", ALWAYS }, @@ -459,6 +478,7 @@ static Keyword aKeywordTable[] = { { "VIRTUAL", "TK_VIRTUAL", VTAB }, #ifdef MAXSCALE { "WARNINGS", "TK_WARNINGS", ALWAYS }, + { "WINDOW", "TK_WINDOW", ALWAYS }, #endif { "WITH", "TK_WITH", CTE }, #ifndef MAXSCALE diff --git a/query_classifier/test/CMakeLists.txt b/query_classifier/test/CMakeLists.txt index a44e39981..d7df9ba38 100644 --- a/query_classifier/test/CMakeLists.txt +++ b/query_classifier/test/CMakeLists.txt @@ -52,6 +52,8 @@ if (BUILD_QC_MYSQLEMBEDDED) add_test(TestQC_cte_grant compare -v 2 ${CMAKE_CURRENT_SOURCE_DIR}/cte_grant.test) add_test(TestQC_cte_nonrecursive compare -v 2 ${CMAKE_CURRENT_SOURCE_DIR}/cte_nonrecursive.test) add_test(TestQC_cte_recursive compare -v 2 ${CMAKE_CURRENT_SOURCE_DIR}/cte_recursive.test) + + add_test(TestQC_win compare -v2 ${CMAKE_CURRENT_SOURCE_DIR}/win.test) endif() if(NOT (MYSQL_EMBEDDED_VERSION VERSION_LESS 10.3)) diff --git a/query_classifier/test/win.test b/query_classifier/test/win.test new file mode 100644 index 000000000..95d32c5bd --- /dev/null +++ b/query_classifier/test/win.test @@ -0,0 +1,1879 @@ +# +# Window Functions Tests +# + +--disable_warnings +drop table if exists t1,t2; +drop view if exists v1; +--enable_warnings + +--echo # ######################################################################## +--echo # # Parser tests +--echo # ######################################################################## +--echo # +--echo # Check what happens when one attempts to use window function without OVER clause +create table t1 (a int, b int); +insert into t1 values (1,1),(2,2); + +--error ER_PARSE_ERROR +select row_number() from t1; +--error ER_PARSE_ERROR +select rank() from t1; + +--echo # Attempt to use window function in the WHERE clause +--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION +select * from t1 where 1=rank() over (order by a); +--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION +select * from t1 where 1>row_number() over (partition by b order by a); +drop table t1; + +--echo # ######################################################################## +--echo # # Functionality tests +--echo # ######################################################################## +--echo # +--echo # Check if ROW_NUMBER() works in basic cases +create table t1(a int, b int, x char(32)); +insert into t1 values (2, 10, 'xx'); +insert into t1 values (2, 10, 'zz'); +insert into t1 values (2, 20, 'yy'); +insert into t1 values (3, 10, 'xxx'); +insert into t1 values (3, 20, 'vvv'); + +--sorted_result +select a, row_number() over (partition by a order by b) from t1; + +select a, b, x, row_number() over (partition by a order by x) from t1; + +drop table t1; + +create table t1 (pk int primary key, a int, b int); +insert into t1 values + (1, 10, 22), + (2, 11, 21), + (3, 12, 20), + (4, 13, 19), + (5, 14, 18); + +select + pk, a, b, + row_number() over (order by a), + row_number() over (order by b) +from t1; + +drop table t1; + +--echo # +--echo # Try RANK() function +--echo # +create table t2 ( + pk int primary key, + a int +); + +insert into t2 values +( 1 , 0), +( 2 , 0), +( 3 , 1), +( 4 , 1), +( 8 , 2), +( 5 , 2), +( 6 , 2), +( 7 , 2), +( 9 , 4), +(10 , 4); + +--sorted_result +select pk, a, rank() over (order by a) from t2; +--sorted_result +select pk, a, rank() over (order by a desc) from t2; + +drop table t2; + +--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; + +--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 # +--echo # Resolution of window names +--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 w1 as CNT +from t1 +window w1 as (partition by c order by pk + rows between 2 preceding and 2 following); + +select + pk, c, + count(*) over (w1 rows between 2 preceding and 2 following) as CNT +from t1 +window w1 as (partition by c order by pk); + +select + pk, c, + count(*) over (w1 order by pk rows between 2 preceding and 2 following) as CNT +from t1 +window w1 as (partition by c); + +select + pk, c, + count(*) over (w2 rows between 2 preceding and 2 following) as CNT +from t1 +window w1 as (partition by c), w2 as (w1 order by pk); + +select + pk, c, + count(*) over w3 as CNT +from t1 +window + w1 as (partition by c), + w2 as (w1 order by pk), + w3 as (w2 rows between 2 preceding and 2 following); + +--error ER_WRONG_WINDOW_SPEC_NAME +select + pk, c, + count(*) over w as CNT +from t1 +window w1 as (partition by c order by pk + rows between 2 preceding and 2 following); + +--error ER_DUP_WINDOW_NAME +select + pk, c, + count(*) over (w2 rows between 2 preceding and 2 following) as CNT +from t1 +window w1 as (partition by c), w1 as (order by pk); + +--error ER_WRONG_WINDOW_SPEC_NAME +select + pk, c, + count(*) over (w2 rows between 2 preceding and 2 following) as CNT +from t1 +window w1 as (partition by c), w2 as (w partition by c order by pk); + +--error ER_PARTITION_LIST_IN_REFERENCING_WINDOW_SPEC +select + pk, c, + count(*) over (w2 rows between 2 preceding and 2 following) as CNT +from t1 +window w1 as (partition by c), w2 as (w1 partition by c order by pk); + +--error ER_ORDER_LIST_IN_REFERENCING_WINDOW_SPEC +select + pk, c, + count(*) over (w2 rows between 2 preceding and 2 following) as CNT +from t1 +window w1 as (partition by c order by pk), w2 as (w1 order by pk); + +--error ER_WINDOW_FRAME_IN_REFERENCED_WINDOW_SPEC +select + pk, c, + count(*) over w3 as CNT +from t1 +window + w1 as (partition by c), + w2 as (w1 order by pk rows between 3 preceding and 2 following), + w3 as (w2 rows between 2 preceding and 2 following); + +--error ER_BAD_COMBINATION_OF_WINDOW_FRAME_BOUND_SPECS +select + pk, c, + count(*) over w1 as CNT +from t1 +window w1 as (partition by c order by pk + rows between unbounded following and 2 following); + +--error ER_BAD_COMBINATION_OF_WINDOW_FRAME_BOUND_SPECS +select + pk, c, + count(*) over (w1 rows between 2 preceding and unbounded preceding) as CNT +from t1 +window w1 as (partition by c order by pk); + +--error ER_BAD_COMBINATION_OF_WINDOW_FRAME_BOUND_SPECS +select + pk, c, + count(*) over (w1 order by pk rows between current row and 2 preceding) as CNT +from t1 +window w1 as (partition by c); + +--error ER_BAD_COMBINATION_OF_WINDOW_FRAME_BOUND_SPECS +select + pk, c, + count(*) over (w2 rows between 2 following and current row) as CNT +from t1 +window w1 as (partition by c), w2 as (w1 order by pk); + +--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION +select + pk, c +from t1 where rank() over w1 > 2 +window w1 as (partition by c order by pk); + +--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION +select + c, max(pk) as m +from t1 + group by c + rank() over w1 +window w1 as (order by m); + +--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION +select + c, max(pk) as m, rank() over w1 as r +from t1 + group by c+r +window w1 as (order by m); + +--error ER_WRONG_PLACEMENT_OF_WINDOW_FUNCTION +select + c, max(pk) as m, rank() over w1 as r +from t1 + group by c having c+r > 3 +window w1 as (order by m); + +--error ER_WINDOW_FUNCTION_IN_WINDOW_SPEC +select + c, max(pk) as m, rank() over w1 as r, + rank() over (partition by r+1 order by m) +from t1 + group by c +window w1 as (order by m); + +--error ER_WINDOW_FUNCTION_IN_WINDOW_SPEC +select + c, max(pk) as m, rank() over w1 as r, + rank() over (partition by m order by r) +from t1 + group by c +window w1 as (order by m); + +--error ER_WINDOW_FUNCTION_IN_WINDOW_SPEC +select + c, max(pk) as m, rank() over w1 as r, dense_rank() over w2 as dr +from t1 + group by c +window w1 as (order by m), w2 as (partition by r order by m); + +--error ER_NOT_ALLOWED_WINDOW_FRAME +select + pk, c, + row_number() over (partition by c order by pk + range between unbounded preceding and current row) as r +from t1; + +--error ER_NOT_ALLOWED_WINDOW_FRAME +select + pk, c, + rank() over w1 as r +from t1 +window w1 as (partition by c order by pk + rows between 2 preceding and 2 following); + +--error ER_NOT_ALLOWED_WINDOW_FRAME +select + pk, c, + dense_rank() over (partition by c order by pk + rows between 1 preceding and 1 following) as r +from t1; + +--error ER_NO_ORDER_LIST_IN_WINDOW_SPEC +select + pk, c, + rank() over w1 as r +from t1 +window w1 as (partition by c); + +--error ER_NO_ORDER_LIST_IN_WINDOW_SPEC +select + pk, c, + dense_rank() over (partition by c) as r +from t1; + +drop table t0,t1; + +--echo # +--echo # MDEV-9634: Window function produces incorrect value +--echo # + +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +create table t2 (part_id int, pk int, a int); +insert into t2 select + if(a<5, 0, 1), a, if(a<5, NULL, 1) from t0; +select * from t2; + +select + part_id, pk, a, + count(a) over (partition by part_id order by pk + rows between 1 preceding and 1 following) as CNT +from t2; + +drop table t0, t2; + +--echo # +--echo # RANGE-type bounds +--echo # + +create table t3 ( + pk int, + val int +); + +insert into t3 values +(0, 1), +(1, 1), +(2, 1), +(3, 2), +(4, 2), +(5, 2), +(6, 2); + +select + pk, + val, + count(val) over (order by val + range between current row and + current row) + as CNT +from t3; + +insert into t3 values +(7, 3), +(8, 3); + +select + pk, + val, + count(val) over (order by val + range between current row and + current row) + as CNT +from t3; + +drop table t3; + +--echo # Now, check with PARTITION BY +create table t4 ( + part_id int, + pk int, + val int +); + +insert into t4 values +(1234, 100, 1), +(1234, 101, 1), +(1234, 102, 1), +(1234, 103, 2), +(1234, 104, 2), +(1234, 105, 2), +(1234, 106, 2), +(1234, 107, 3), +(1234, 108, 3), + +(5678, 200, 1), +(5678, 201, 1), +(5678, 202, 1), +(5678, 203, 2), +(5678, 204, 2), +(5678, 205, 2), +(5678, 206, 2), +(5678, 207, 3), +(5678, 208, 3); + +select + part_id, + pk, + val, + count(val) over (partition by part_id + order by val + range between current row and + current row) + as CNT +from t4; + +--echo # +--echo # Try RANGE UNBOUNDED PRECEDING | FOLLOWING +--echo # +select + part_id, + pk, + val, + count(val) over (partition by part_id + order by val + range between unbounded preceding and + current row) + as CNT +from t4; + +select + part_id, + pk, + val, + count(val) over (partition by part_id + order by val + range between current row and + unbounded following) + as CNT +from t4; + +select + part_id, + pk, + val, + count(val) over (partition by part_id + order by val + range between unbounded preceding and + unbounded following) + as CNT +from t4; + +drop table t4; + +--echo # +--echo # MDEV-9695: Wrong window frame when using RANGE BETWEEN N FOLLOWING AND PRECEDING +--echo # +create table t1 (pk int, a int, b int); +insert into t1 values +( 1 , 0, 1), +( 2 , 0, 2), +( 3 , 1, 4), +( 4 , 1, 8), +( 5 , 2, 32), +( 6 , 2, 64), +( 7 , 2, 128), +( 8 , 2, 16); + +select pk, a, b, +bit_or(b) over (partition by a order by pk ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) as bit_or +from t1; + +--echo # Extra ROWS n PRECEDING tests +select pk, a, b, +bit_or(b) over (partition by a order by pk ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) as bit_or +from t1; +drop table t1; + + +create table t2 ( + pk int, + a int, + b int +); + +insert into t2 values +( 1, 0, 1), +( 2, 0, 2), +( 3, 0, 4), +( 4, 0, 8), +( 5, 1, 16), +( 6, 1, 32), +( 7, 1, 64), +( 8, 1, 128), +( 9, 2, 256), +(10, 2, 512), +(11, 2, 1024), +(12, 2, 2048); + +select pk, a, b, +bit_or(b) over (partition by a order by pk ROWS BETWEEN 1 PRECEDING AND 1 PRECEDING) as bit_or +from t2; + +select pk, a, b, +bit_or(b) over (partition by a order by pk ROWS BETWEEN 2 PRECEDING AND 2 PRECEDING) as bit_or +from t2; + +select pk, a, b, +bit_or(b) over (partition by a order by pk ROWS BETWEEN 2 PRECEDING AND 1 PRECEDING) as bit_or +from t2; + +--echo # Check CURRENT ROW + +select pk, a, b, +bit_or(b) over (partition by a order by pk ROWS BETWEEN CURRENT ROW AND CURRENT ROW) as bit_or +from t2; + +drop table t2; + +--echo # +--echo # Try RANGE PRECEDING|FOLLWING n +--echo # +create table t1 ( + part_id int, + pk int, + a int +); + +insert into t1 values +(10, 1, 1), +(10, 2, 2), +(10, 3, 4), +(10, 4, 8), +(10, 5,26), +(10, 6,27), +(10, 7,40), +(10, 8,71), +(10, 9,72); + +select + pk, a, + count(a) over (ORDER BY a + RANGE BETWEEN UNBOUNDED PRECEDING + 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 + RANGE BETWEEN UNBOUNDED PRECEDING + AND 1 FOLLOWING) as cnt +from t1; + +select + pk, a, + count(a) over (ORDER BY a + RANGE BETWEEN UNBOUNDED PRECEDING + 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 + RANGE BETWEEN UNBOUNDED PRECEDING + AND 1 PRECEDING) as cnt +from t1; + +# Try bottom bound +select + pk, a, + count(a) over (ORDER BY a + RANGE BETWEEN 1 PRECEDING + 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 + RANGE BETWEEN 1 FOLLOWING + 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 + part_id, pk, a, + count(a) over (PARTITION BY part_id + ORDER BY a + RANGE BETWEEN UNBOUNDED PRECEDING + AND 10 FOLLOWING) as cnt +from t1; + +select + pk, a, + count(a) over (PARTITION BY part_id + ORDER BY a + RANGE BETWEEN UNBOUNDED PRECEDING + AND 1 PRECEDING) as cnt +from t1; + +drop table t1; + +--echo # Try a RANGE frame over non-integer datatype: + +create table t1 ( + col1 int, + a decimal(5,3) +); + +insert into t1 values (1, 0.45); +insert into t1 values (1, 0.5); +insert into t1 values (1, 0.55); +insert into t1 values (1, 1.21); +insert into t1 values (1, 1.22); +insert into t1 values (1, 3.33); + +select + a, + count(col1) over (order by a + range between 0.1 preceding + and 0.1 following) +from t1; + +drop table t1; + +--echo # +--echo # RANGE-type frames and NULL values +--echo # +create table t1 ( + pk int, + a int, + b int +); + +insert into t1 values (1, NULL,1); +insert into t1 values (2, NULL,1); +insert into t1 values (3, NULL,1); +insert into t1 values (4, 10 ,1); +insert into t1 values (5, 11 ,1); +insert into t1 values (6, 12 ,1); +insert into t1 values (7, 13 ,1); +insert into t1 values (8, 14 ,1); + + +select + pk, a, + count(b) over (order by a + range between 2 preceding + and 2 following) as CNT +from t1; +drop table t1; + +--echo # +--echo # Try ranges that have bound1 > bound2. The standard actually allows them +--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 1 preceding + and 2 preceding) + as cnt +from t1; + +select + pk, c, + sum(c) over (partition by c + order by pk + rows between 1 preceding + and 2 preceding) + as sum +from t1; + +select + pk, c, + sum(c) over (partition by c + order by pk + rows between 2 following + and 1 following) + as sum +from t1; + + +select + pk, c, + count(*) over (partition by c + order by pk + range between 1 preceding + and 2 preceding) + as cnt +from t1; +drop table t0, t1; + +--echo # +--echo # Error checking for frame bounds +--echo # + +create table t1 (a int, b int, c varchar(32)); +insert into t1 values (1,1,'foo'); +insert into t1 values (2,2,'bar'); +--error ER_RANGE_FRAME_NEEDS_SIMPLE_ORDERBY +select + count(*) over (order by a,b + range between unbounded preceding and current row) +from t1; + +--error ER_WRONG_TYPE_FOR_RANGE_FRAME +select + count(*) over (order by c + range between unbounded preceding and current row) +from t1; + +--error ER_WRONG_TYPE_FOR_RANGE_FRAME +select + count(*) over (order by a + range between 'abcd' preceding and current row) +from t1; + +--error ER_WRONG_TYPE_FOR_RANGE_FRAME +select + count(*) over (order by a + range between current row and 'foo' following) +from t1; + +--echo # Try range frame with invalid bounds +--error ER_WRONG_TYPE_FOR_ROWS_FRAME +select + count(*) over (order by a + rows between 0.5 preceding and current row) +from t1; + +--error ER_WRONG_TYPE_FOR_ROWS_FRAME +select + count(*) over (order by a + rows between current row and 3.14 following) +from t1; + +--echo # +--echo # EXCLUDE clause is parsed but not supported +--echo # + +--error ER_FRAME_EXCLUSION_NOT_SUPPORTED +select + count(*) over (order by a + rows between 1 preceding and 1 following + exclude current row) +from t1; + +--error ER_FRAME_EXCLUSION_NOT_SUPPORTED +select + count(*) over (order by a + range between 1 preceding and 1 following + exclude ties) +from t1; + +--error ER_FRAME_EXCLUSION_NOT_SUPPORTED +select + count(*) over (order by a + range between 1 preceding and 1 following + exclude group) +from t1; + +# EXCLUDE NO OTHERS means 'don't exclude anything' +select + count(*) over (order by a + rows between 1 preceding and 1 following + exclude no others) +from t1; + +drop table t1; + +--echo # +--echo # Window function in grouping query +--echo # + +create table t1 ( + username varchar(32), + amount int +); + +insert into t1 values +('user1',1), +('user1',5), +('user1',3), +('user2',10), +('user2',20), +('user2',30); + +select + username, + sum(amount) as s, + rank() over (order by s desc) +from t1 +group by username; + +drop table t1; + +--echo # +--echo # mdev-9719: Window function in prepared statement +--echo # + +create table t1(a int, b int, x char(32)); +insert into t1 values (2, 10, 'xx'); +insert into t1 values (2, 10, 'zz'); +insert into t1 values (2, 20, 'yy'); +insert into t1 values (3, 10, 'xxx'); +insert into t1 values (3, 20, 'vvv'); + +prepare stmt from 'select a, row_number() over (partition by a order by b) from t1'; +--sorted_result +execute stmt; + +drop table t1; + +--echo # +--echo # mdev-9754: Window name resolution in prepared statement +--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; + +prepare stmt from +'select + pk, c, + count(*) over w1 as CNT +from t1 +window w1 as (partition by c order by pk + rows between 2 preceding and 2 following)'; +execute stmt; + +drop table t0,t1; + +--echo # +--echo # EXPLAIN FORMAT=JSON support for window functions +--echo # +create table t0 (a int); +insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +explain format=json select rank() over (order by a) from t0; + +create table t1 (a int, b int, c int); +insert into t1 select a,a,a from t0; + +explain format=json +select + a, + rank() over (order by sum(b)) +from t1 +group by a; + +explain format=json +select + a, + rank() over (order by sum(b)) +from t1 +group by a +order by null; + +--echo # +--echo # Check how window function works together with GROUP BY and HAVING +--echo # + +select b,max(a) as MX, rank() over (order by b) from t1 group by b having MX in (3,5,7); +explain format=json +select b,max(a) as MX, rank() over (order by b) from t1 group by b having MX in (3,5,7); + +drop table t1; +drop table t0; + +--echo # +--echo # Building ordering index for window functions +--echo # + +create table t1 ( + pk int primary key, + a int, + b int, + c int +); + +insert into t1 values +(101 , 0, 10, 1), +(102 , 0, 10, 2), +(103 , 1, 10, 3), +(104 , 1, 10, 4), +(108 , 2, 10, 5), +(105 , 2, 20, 6), +(106 , 2, 20, 7), +(107 , 2, 20, 8), +(109 , 4, 20, 9), +(110 , 4, 20, 10), +(111 , 5, NULL, 11), +(112 , 5, 1, 12), +(113 , 5, NULL, 13), +(114 , 5, NULL, 14), +(115 , 5, NULL, 15), +(116 , 6, 1, NULL), +(117 , 6, 1, 10), +(118 , 6, 1, 1), +(119 , 6, 1, NULL), +(120 , 6, 1, NULL), +(121 , 6, 1, NULL), +(122 , 6, 1, 2), +(123 , 6, 1, 20), +(124 , 6, 1, -10), +(125 , 6, 1, NULL), +(126 , 6, 1, NULL), +(127 , 6, 1, NULL); + +--sorted_result +select sum(b) over (partition by a order by b,pk + rows between unbounded preceding and current row) as c1, + avg(b) over (w1 rows between 1 preceding and 1 following) as c2, + sum(c) over (w2 rows between 1 preceding and 1 following) as c5, + avg(b) over (w1 rows between 5 preceding and 5 following) as c3, + sum(b) over (w1 rows between 1 preceding and 1 following) as c4 +from t1 +window w1 as (partition by a order by b,pk), + w2 as (partition by b order by c,pk); + +drop table t1; + + +--echo # +--echo # MDEV-9848: Window functions: reuse sorting and/or scanning +--echo # + +create table t1 (a int, b int, c int); +insert into t1 values +(1,3,1), +(2,2,1), +(3,1,1); + +--echo # Check using counters +flush status; +select + rank() over (partition by c order by a), + rank() over (partition by c order by b) +from t1; +show status like '%sort%'; + +flush status; +select + rank() over (partition by c order by a), + rank() over (partition by c order by a) +from t1; +show status like '%sort%'; + +# Check using EXPLAIN FORMAT=JSON +explain format=json +select + rank() over (partition by c order by a), + rank() over (partition by c order by a) +from t1; + +explain format=json +select + rank() over (order by a), + row_number() over (order by a) +from t1; + +explain format=json +select + rank() over (partition by c order by a), + count(*) over (partition by c) +from t1; + +explain format=json +select + count(*) over (partition by c), + rank() over (partition by c order by a) +from t1; + +drop table t1; + + +--echo # +--echo # MDEV-9847: Window functions: crash with big_tables=1 +--echo # +create table t1(a int); +insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +set @tmp=@@big_tables; +set big_tables=1; +select rank() over (order by a) from t1; +set big_tables=@tmp; +drop table t1; + +--echo # +--echo # Check if "ORDER BY window_func" works +--echo # + +create table t1 (s1 int, s2 char(5)); +insert into t1 values (1,'a'); +insert into t1 values (null,null); +insert into t1 values (1,null); +insert into t1 values (null,'a'); +insert into t1 values (2,'b'); +insert into t1 values (-1,''); + +explain format=json +select *, row_number() over (order by s1, s2) as X from t1 order by X desc; +select *, row_number() over (order by s1, s2) as X from t1 order by X desc; +drop table t1; + +--echo # +--echo # Try window functions that are not directly present in the select list +--echo # +create table t1 (a int, b int); +insert into t1 values + (1,3), + (2,2), + (3,1); + +select + a, b, + rank() over (order by a), rank() over (order by b), + rank() over (order by a) - rank() over (order by b) as diff +from + t1; + +drop table t1; + +create table t1 (i int); +insert into t1 values (1),(2); +SELECT MAX(i) OVER (PARTITION BY (i)) FROM t1; +drop table t1; + +--echo # +--echo # Check the 0 in ROWS 0 PRECEDING +--echo # + +create table t1 ( + part_id int, + pk int, + a int +); + +insert into t1 values (1, 1, 1); +insert into t1 values (1, 2, 2); +insert into t1 values (1, 3, 4); +insert into t1 values (1, 4, 8); + +select + pk, a, + sum(a) over (order by pk rows between 0 preceding and current row) +from t1; + +select + pk, a, + sum(a) over (order by pk rows between 1 preceding and 0 preceding) +from t1; + +insert into t1 values (200, 1, 1); +insert into t1 values (200, 2, 2); +insert into t1 values (200, 3, 4); +insert into t1 values (200, 4, 8); +select + part_id, pk, a, + sum(a) over (partition by part_id order by pk rows between 0 preceding and current row) +from t1; + +select + part_id, pk, a, + sum(a) over (partition by part_id order by pk rows between 1 preceding and 0 preceding) +from t1; + +drop table t1; +--echo # +--echo # MDEV-9780, The "DISTINCT must not bet converted into GROUP BY when +--echo # window functions are present" part +--echo # + +create table t1 (part_id int, a int); +insert into t1 values +(100, 1), +(100, 2), +(100, 2), +(100, 3), +(2000, 1), +(2000, 2), +(2000, 3), +(2000, 3), +(2000, 3); + +select rank() over (partition by part_id order by a) from t1; +select distinct rank() over (partition by part_id order by a) from t1; +explain format=json +select distinct rank() over (partition by part_id order by a) from t1; + +drop table t1; + +--echo # +--echo # MDEV-9893: Window functions with different ORDER BY lists, +--echo # one of these lists containing an expression +--echo # + +create table t1 (s1 int, s2 char(5)); +insert into t1 values (1,'a'); +insert into t1 values (null,null); +insert into t1 values (3,null); +insert into t1 values (4,'a'); +insert into t1 values (2,'b'); +insert into t1 values (-1,''); + +select + *, + ROW_NUMBER() OVER (order by s1), + CUME_DIST() OVER (order by -s1) +from t1; + +drop table t1; + + +--echo # +--echo # MDEV-9925: Wrong result with aggregate function as a window function +--echo # +create table t1 (i int); +insert into t1 values (1),(2); +select i, sum(i) over (partition by i) from t1; +drop table t1; + +--echo # +--echo # MDEV-9922: Assertion `!join->only_const_tables() && fsort' failed in int create_sort_index +--echo # +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; + +--echo # +--echo # MDEV-10842: window functions with the same order column +--echo # but different directions +--echo # + +create table t1 ( + pk int primary key, + a int, + b int, + c char(10) +); + +insert into t1 values +( 1, 0, 1, 'one'), +( 2, 0, 2, 'two'), +( 3, 0, 3, 'three'), +( 4, 1, 1, 'one'), +( 5, 1, 1, 'two'), +( 6, 1, 2, 'three'), +( 7, 2, NULL, 'n_one'), +( 8, 2, 1, 'n_two'), +( 9, 2, 2, 'n_three'), +(10, 2, 0, 'n_four'), +(11, 2, 10, NULL); + +select pk, + row_number() over (order by pk desc) as r_desc, + row_number() over (order by pk asc) as r_asc +from t1; + +drop table t1; + +--echo # +--echo # MDEV-10874: two window functions with ccompatible sorting +--echo # + +create table t1 ( +pk int primary key, +a int, +b int, +c char(10), +d decimal(10, 3), +e real +); +insert into t1 values +( 1, 0, 1, 'one', 0.1, 0.001), +( 2, 0, 2, 'two', 0.2, 0.002), +( 3, 0, 3, 'three', 0.3, 0.003), +( 4, 1, 2, 'three', 0.4, 0.004), +( 5, 1, 1, 'two', 0.5, 0.005), +( 6, 1, 1, 'one', 0.6, 0.006), +( 7, 2, NULL, 'n_one', 0.5, 0.007), +( 8, 2, 1, 'n_two', NULL, 0.008), +( 9, 2, 2, NULL, 0.7, 0.009), +(10, 2, 0, 'n_four', 0.8, 0.010), +(11, 2, 10, NULL, 0.9, NULL); + +select pk, a, d, + sum(d) over (partition by a order by pk + ROWS between 1 preceding and current row) as sum_1, + sum(d) over (order by a + ROWS BETWEEN 1 preceding and 2 following) as sum_2 +from t1; +explain format=json +select pk, a, d, + sum(d) over (partition by a order by pk + ROWS between 1 preceding and current row) as sum_1, + sum(d) over (order by a + ROWS BETWEEN 1 preceding and 2 following) as sum_2 +from t1; + +select pk, a, d, + sum(d) over (partition by a order by pk desc + ROWS between 1 preceding and current row) as sum_1, + sum(d) over (order by a + ROWS BETWEEN 1 preceding and 2 following) as sum_2 +from t1; + +drop table t1; + +--echo # +--echo # MDEV-9941: two window functions with compatible partitions +--echo # + +create table t1 ( + a int, + b int, + c int +); + +insert into t1 values + (10, 1, 1), + (10, 3, 10), + (10, 1, 10), + (10, 3, 100), + (10, 5, 1000), + (10, 1, 100); + +explain format=json +select + a,b,c, + row_number() over (partition by a), + row_number() over (partition by a, b) +from t1; + +drop table t1; + +--echo # +--echo # MDEV-10815: Window Function Expressions Wrong Results +--echo # +create table t(a decimal(35,10), b int); +insert into t(a,b) values(1,1); +insert into t(a,b) values(2,1); +insert into t(a,b) values(0,1); +insert into t(a,b) values(1, 2); +insert into t(a,b) values(1.5,2); +insert into t(a,b) values(3, 2); +insert into t(a,b) values(4.5,2); +select a, b, + sum(t.a) over (partition by t.b order by a) as simple_sum, + sum(t.a) over (partition by t.b order by a) + 1 as sum_and_const, + sum(t.b) over (partition by t.b order by a) + sum(t.a) over (partition by t.b order by a) as sum_and_sum +from t +order by t.b, t.a; +drop table t; + +--echo # +--echo # MDEV-10669: Crash in SELECT with window function used +--echo # +create table t(a decimal(35,10), b int); +insert into t(a,b) values(1,1); +insert into t(a,b) values(2,1); +insert into t(a,b) values(0,1); +SELECT (CASE WHEN sum(t.a) over (partition by t.b)=0 THEN null ELSE null END) AS a FROM t; +SELECT ifnull(((t.a) / CASE WHEN sum(t.a) over(partition by t.b) =0 then null else null end) ,0) from t; +SELECT sum(t.a) over (partition by t.b order by a), + sqrt(ifnull((sum(t.a) over (partition by t.b order by a)), 0)) +from t; +drop table t; + +--echo # +--echo # MDEV-10868: view definitions with window functions +--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; + +let $q= +select pk, c, c/count(*) over (partition by c order by pk + rows between 1 preceding and 2 following) as CNT +from t1; + +eval $q; +eval create view v1 as $q; +show create view v1; +select * from v1; + +let $q= +select pk, c, c/count(*) over w1 as CNT from t1 + window w1 as (partition by c order by pk rows between 1 preceding and 2 following); + +eval $q; +eval create view v2 as $q; +show create view v2; +select * from v2; + +let $q= +select pk, c, c/count(*) over w1 as CNT from t1 + window w1 as (partition by c order by pk rows unbounded preceding); + +eval $q; +eval create view v3 as $q; +show create view v3; +select * from v3; + +let $q= +select pk, c, c/count(*) over (partition by c order by pk + range between 3 preceding and current row) as CNT +from t1; + +eval $q; +eval create view v4 as $q; +show create view v4; +select * from v4; + +drop view v1,v2,v3,v4; +drop table t0,t1; + +--echo # +--echo # MDEV-10875: window function in subquery +--echo # + +CREATE TABLE t1 (i INT); +INSERT INTO t1 VALUES (3),(1); + +CREATE TABLE t2 (c VARCHAR(8)); +INSERT INTO t2 VALUES ('foo'),('bar'),('foo'); + +SELECT COUNT(*) OVER (PARTITION BY c) FROM t2; + +SELECT * FROM t1 WHERE i IN ( SELECT COUNT(*) OVER (PARTITION BY c) FROM t2 ); + +DROP TABLE t1, t2; + +--echo # +--echo # MDEV-9976: window function without PARTITION BY and ORDER BY +--echo # + +CREATE TABLE t1 (id int, a int); +INSERT INTO t1 VALUES + (1,1000), (2,1100), (3,1800), (4,1500), (5,1700), (6,1200), + (7,2000), (8,2100), (9,1600); + +--sorted_result +SELECT id, sum(a) OVER (PARTITION BY id + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) +FROM t1; + +--sorted_result +SELECT id, sum(a) OVER (ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) +FROM t1; + +DROP TABLE t1; + +--echo # +--echo # MDEV-11867: window function with aggregation +--echo # over the result of grouping +--echo # + +create table t1 ( + username varchar(32), + amount int +); + +insert into t1 values +('user1',1), +('user1',5), +('user1',3), +('user2',10), +('user2',20), +('user2',30); + +select username, sum(amount) as s, avg(sum(amount)) over (order by s desc) + from t1 +group by username; + +select username, sum(amount), avg(sum(amount)) over (order by sum(amount) desc) + from t1 +group by username; + +drop table t1; + +--echo # +--echo # MDEV-11594: window function over implicit grouping +--echo # + +create table t1 (id int); +insert into t1 values (1), (2), (3), (2); + +select sum(id) over (order by sum(id)) from t1; + +select sum(sum(id)) over (order by sum(id)) from t1; + +drop table t1; + +--echo # +--echo # MDEV-9923: integer constant in order by list +--echo # of window specification +--echo # + +create table t1 (id int); +insert into t1 values (1), (2), (3), (2); + +select rank() over (order by 1) from t1; +select rank() over (order by 2) from t1; +select rank() over (partition by id order by 2) from t1; + +drop table t1; + +--echo # +--echo # MDEV-10660: view using a simple window function +--echo # + +create table t1 (id int); +insert into t1 values (1), (2), (3), (2); + +create view v1(id,rnk) as + select id, rank() over (order by id) from t1; + +show create view v1; + +select id, rank() over (order by id) from t1; +select * from v1; + +drop view v1; +drop table t1; + +--echo # +--echo # MDEV-11138: window function in the query without tables +--echo # + +select row_number() over (); +select count(*) over (); +select sum(5) over (); +select row_number() over (), sum(5) over (); +select row_number() over (order by 2); +select row_number() over (partition by 2); +select row_number() over (partition by 4 order by 1+2); + +--echo # +--echo # MDEV-11999: execution of prepared statement for +--echo # tableless query with window functions +--echo # + +prepare stmt from +"select row_number() over (partition by 4 order by 1+2)"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +--echo # +--echo # MDEV-11745: window function with min/max +--echo # + +create table t1 (i int, b int); +insert into t1 values + (1,1),(2,1),(3,1),(4,4),(5,4),(6,4),(7,8),(8,8),(9,8),(10,8); + +select b, min(i) over (partition by b) as f + from t1 as tt +order by i; + +select b, min(i) over (partition by b) as f + from (select * from t1) as tt +order by i; + +select b, min(i+10) over (partition by b) as f + from t1 as tt +order by i; + +select b, min(i) over (partition by b) as f + from (select i+10 as i, b from t1) as tt +order by i; + +select b, min(i+20) over (partition by b) as f + from (select i+10 as i, b from t1) as tt +order by i; + +select b, max(i) over (partition by b) as f + from t1 as tt +order by i; + +select b, max(i) over (partition by b) as f + from (select * from t1) as tt +order by i; + +select b, max(i+10) over (partition by b) as f + from t1 as tt +order by i; + +select b, max(i) over (partition by b) as f + from (select i+10 as i, b from t1) as tt +order by i; + +select b, max(i+20) over (partition by b) as f + from (select i+10 as i, b from t1) as tt +order by i; + +select max(i), max(i), sum(i), count(i) + from t1 as tt +group by b; + +select max(i), min(sum(i)) over (partition by count(i)) f + from t1 as tt +group by b; + +select max(i), min(sum(i)) over (partition by count(i)) f + from (select * from t1) as tt +group by b; + +select max(i+10), min(sum(i)+10) over (partition by count(i)) f + from t1 as tt +group by b; + +select max(i), max(i), sum(i), count(i) + from (select i+10 as i, b from t1) as tt +group by b; + +select max(i), min(sum(i)) over (partition by count(i)) f + from (select i+10 as i, b from t1) as tt +group by b; + +select max(i), min(i), min(max(i)-min(i)) over (partition by count(i)) f + from (select i+10 as i, b from t1) as tt +group by b; + +drop table t1; + +--echo # +--echo # MDEV-12015: window function over select with WHERE +--echo # that is always FALSE +--echo # + +CREATE TABLE t1 (i INT); +INSERT INTO t1 VALUES (3), (1), (2); + +SELECT i, ROW_NUMBER() OVER () FROM t1 WHERE 1 = 2; + +SELECT i, COUNT(*) OVER () FROM t1 WHERE 1 = 2; + +DROP TABLE t1; + +--echo # +--echo # MDEV-12051: window function in query with implicit grouping +--echo # on always empty set +--echo # + +create table t1 (a int, b varchar(8)); +insert into t1 values (1,'foo'),(2,'bar'); + +select max(a), row_number() over () from t1 where a > 10; +select max(a), sum(max(a)) over () from t1 where a > 10; +select max(a), sum(max(a)) over (partition by max(a)) from t1 where a > 10; + +select max(a), row_number() over () from t1 where 1 = 2; +select max(a), sum(max(a)) over () from t1 where 1 = 2; +select max(a), sum(max(a)) over (partition by max(a)) from t1 where 1 = 2; + +select max(a), row_number() over () from t1 where 1 = 2 + having max(a) is not null; +select max(a), sum(max(a)) over () from t1 where 1 = 2 + having max(a) is not null; + +drop table t1; + +--echo # +--echo # MDEV-10885: window function in query with implicit grouping +--echo # with constant condition evaluated to false +--echo # + +CREATE TABLE t1 (a INT, b VARCHAR(8)); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); + +CREATE TABLE t2 (c INT); +INSERT INTO t2 VALUES (3),(4); + +CREATE TABLE t3 (d INT); +INSERT INTO t3 VALUES (5),(6); + +SELECT MAX(a), ROW_NUMBER() OVER (PARTITION BY MAX(a)) FROM t1 +WHERE EXISTS ( SELECT * FROM t2 WHERE c IN ( SELECT MAX(d) FROM t3 ) ); + +SELECT MAX(a), COUNT(MAX(a)) OVER (PARTITION BY MAX(a)) FROM t1 +WHERE EXISTS ( SELECT * FROM t2 WHERE c IN ( SELECT MAX(d) FROM t3 ) ); + +SELECT MAX(a), SUM(MAX(a)) OVER (PARTITION BY MAX(a)) FROM t1 +WHERE EXISTS ( SELECT * FROM t2 WHERE c IN ( SELECT MAX(d) FROM t3 ) ); + +SELECT MAX(a), ROW_NUMBER() OVER (PARTITION BY MAX(a)) FROM t1 +WHERE EXISTS ( SELECT * FROM t2 WHERE c IN ( SELECT MAX(d) FROM t3 ) ) +HAVING MAX(a) IS NOT NULL; + +SELECT a, MAX(a), ROW_NUMBER() OVER (PARTITION BY b) FROM t1 +WHERE EXISTS ( SELECT * FROM t2 WHERE c IN ( SELECT MAX(d) FROM t3 ) ); + +SELECT a, COUNT(a), AVG(a) OVER (PARTITION BY b) FROM t1 +WHERE EXISTS ( SELECT * FROM t2 WHERE c IN ( SELECT MAX(d) FROM t3 ) ); + +SELECT a, MAX(a), AVG(a) OVER (PARTITION BY b) FROM t1 +WHERE EXISTS ( SELECT * FROM t2 WHERE c IN ( SELECT MAX(d) FROM t3 ) ); + +DROP TABLE t1,t2,t3; + +--echo # +--echo # MDEV-10859: Wrong result of aggregate window function in query +--echo # with HAVING and no ORDER BY +--echo # + +create table empsalary (depname varchar(32), empno smallint primary key, salary int); +insert into empsalary values + ('develop', 1, 5000), ('develop', 2, 4000),('sales', 3, '6000'),('sales', 4, 5000); + +--sorted_result +SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary; +--sorted_result +SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary ORDER BY depname; +--echo # +--echo # These last 2 should have the same row results, ignoring order. +--echo # +--sorted_result +SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary HAVING empno > 1; +--sorted_result +SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary HAVING empno > 1 ORDER BY depname; + +drop table empsalary; + +--echo # +--echo # MDEV-11868: min(distinct) over () returns wrong value +--echo # + +create table TDEC (CDEC int, RNUM int); +create view VDEC as select * from TDEC; +insert into TDEC (CDEC) values (null),(-1),(0),(1),(0),(10); +select TDEC.CDEC, min(TDEC.CDEC) over () from TDEC; +select VDEC.CDEC, min(VDEC.CDEC) over () from VDEC; +select TDEC.CDEC, max(TDEC.CDEC) over () from TDEC; +select VDEC.CDEC, max(VDEC.CDEC) over () from VDEC; + +select TDEC.CDEC, min(distinct TDEC.CDEC) over () from TDEC; +select VDEC.CDEC, min(distinct VDEC.CDEC) over () from VDEC; +select TDEC.CDEC, max(distinct TDEC.CDEC) over () from TDEC; +select VDEC.CDEC, max(distinct VDEC.CDEC) over () from VDEC; + +--echo # +--echo # These should be removed once support for them is added. +--echo # +--error ER_NOT_SUPPORTED_YET +select TDEC.CDEC, count(distinct TDEC.CDEC) over () from TDEC; +--error ER_NOT_SUPPORTED_YET +select VDEC.CDEC, count(distinct VDEC.CDEC) over () from VDEC; +--error ER_NOT_SUPPORTED_YET +select TDEC.CDEC, sum(distinct TDEC.CDEC) over () from TDEC; +--error ER_NOT_SUPPORTED_YET +select VDEC.CDEC, sum(distinct VDEC.CDEC) over () from VDEC; +--error ER_NOT_SUPPORTED_YET +select TDEC.CDEC, avg(distinct TDEC.CDEC) over () from TDEC; +--error ER_NOT_SUPPORTED_YET +select VDEC.CDEC, avg(distinct VDEC.CDEC) over () from VDEC; +--error ER_NOT_SUPPORTED_YET +select TDEC.CDEC, GROUP_CONCAT(TDEC.CDEC) over () from TDEC; +--error ER_NOT_SUPPORTED_YET +select VDEC.CDEC, GROUP_CONCAT(distinct VDEC.CDEC) over () from VDEC; + +drop table TDEC; +drop view VDEC; + +--echo # +--echo # MDEV-10700: 10.2.2 windowing function returns incorrect result +--echo # +create table t(a int,b int, c int , d int); +insert into t(a,b,c,d) values(1, rand(10)*1000, rand(10)*1000, rand(10)*1000); +insert into t(a,b,c,d) values(1, rand(10)*1000, rand(10)*1000, rand(10)*1000); +replace into t(a,b,c,d) select 1, rand(10)*1000, rand(10)*1000, rand(10)*1000 from t t1, t t2, t t3, t t4, t t5, t t6, t t7, t t8, t t9, t t10, t t11, t t12, t t13, t t14, t t15, t t16, t t17; + +select count(distinct s) from (select sum(d) over(partition by a,b,c) as s from t) Z where s > 0; +select count(distinct s) from (select sum(d) as s from t group by a,b,c) Z where s > 0; + +select count(distinct s) from (select sum(d) over(partition by a,b) as s from t) Z where s > 0; +select count(distinct s) from (select sum(d) as s from t group by a,b) Z where s > 0; + +select count(distinct s) from (select sum(d) over(partition by a) as s from t) Z where s > 0; +select count(distinct s) from (select sum(d) as s from t group by a) Z where s > 0; + +drop table t; + +--echo # +--echo # MDEV-9924: window function in query with group by optimized away +--echo # + +create table t1 (i int); +insert into t1 values (2),(3),(1); + +select row_number() over () from t1 group by 1+2; +select max(i), row_number() over () from t1 group by 1+2; +select rank() over (order by max(i)) from t1 group by 1+2; + +select i, row_number() over () from t1 group by 1+2; +select i, rank() over (order by i) rnk from t1 group by 1+2; + +drop table t1; + +--echo # +--echo # MDEV-11907: window function as the second operand of division +--echo # + +create table t1 (pk int, c int); +insert into t1 values (1,1),(2,1),(3,1),(4,1),(5,2); + +set @sql_mode_save= @@sql_mode; +set sql_mode='ERROR_FOR_DIVISION_BY_ZERO'; + +select pk, c, c/count(*) over + (partition by c order by pk + rows between 1 preceding and 2 following) as CNT +from t1; +show warnings; + +set sql_mode=@sql_mode_save; + +drop table t1; + +--echo # +--echo # MDEV-12336: several functions over a window function +--echo # + +create table t1 (name varchar(10), cnt int); +insert into t1 values ('Fred', 23), ('Fred', 35), ('Joe', 10); + +select q.name, q.row_cnt, + round( 100 * ( q.row_cnt / + sum(q.row_cnt) over + ( + order by q.name + rows between + unbounded preceding and + unbounded following + ) + ),2 + ) pct_of_total +from +( + select name, count(*) row_cnt, sum(cnt) sum_cnt + from t1 + group by 1 +) q; + +drop table t1; + +--echo # +--echo # MDEV-11990: window function over min/max aggregation +--echo # + +create table t1 (id int); +insert into t1 values (1), (2), (3), (2), (4), (2); + +select sum(max(id)) over (order by max(id)) from t1; +explain +select sum(max(id)) over (order by max(id)) from t1; + +create index idx on t1(id); +select sum(max(id)) over (order by max(id)) from t1; +explain +select sum(max(id)) over (order by max(id)) from t1; +select sum(max(id)) over (order by max(id)) from t1 where id < 3; +select count(max(id)) over (order by max(id)) from t1 where id < 3; +select max(id), rank() over (order by max(id)) from t1 where id < 3; + +drop table t1;