MXS-1247 Add initial support for window functions
This commit will be followed by more tests.
This commit is contained in:
@ -80,6 +80,7 @@
|
|||||||
|
|
||||||
#if MYSQL_VERSION_MAJOR >= 10 && MYSQL_VERSION_MINOR >= 2
|
#if MYSQL_VERSION_MAJOR >= 10 && MYSQL_VERSION_MINOR >= 2
|
||||||
#define CTE_SUPPORTED
|
#define CTE_SUPPORTED
|
||||||
|
#define WF_SUPPORTED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CTE_SUPPORTED)
|
#if defined(CTE_SUPPORTED)
|
||||||
@ -2542,6 +2543,16 @@ static bool should_function_be_ignored(parsing_info_t* pi, const char* func_name
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WF_SUPPORTED
|
||||||
|
if (!rv)
|
||||||
|
{
|
||||||
|
if (strcasecmp(func_name, "WF") == 0)
|
||||||
|
{
|
||||||
|
rv = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2607,8 +2618,11 @@ static void update_field_infos(parsing_info_t* pi,
|
|||||||
|
|
||||||
case Item::FUNC_ITEM:
|
case Item::FUNC_ITEM:
|
||||||
case Item::SUM_FUNC_ITEM:
|
case Item::SUM_FUNC_ITEM:
|
||||||
|
#ifdef WF_SUPPORTED
|
||||||
|
case Item::WINDOW_FUNC_ITEM:
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
Item_func* func_item = static_cast<Item_func*>(item);
|
Item_func_or_sum* func_item = static_cast<Item_func_or_sum*>(item);
|
||||||
Item** items = func_item->arguments();
|
Item** items = func_item->arguments();
|
||||||
size_t n_items = func_item->argument_count();
|
size_t n_items = func_item->argument_count();
|
||||||
|
|
||||||
|
@ -387,11 +387,11 @@ static const char* BUILTIN_FUNCTIONS[] =
|
|||||||
|
|
||||||
const size_t N_BUILTIN_FUNCTIONS = sizeof(BUILTIN_FUNCTIONS) / sizeof(BUILTIN_FUNCTIONS[0]);
|
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[] =
|
static const char* BUILTIN_10_2_3_FUNCTIONS[] =
|
||||||
{
|
{
|
||||||
|
//
|
||||||
|
// JSON functions: https://mariadb.com/kb/en/mariadb/json-functions
|
||||||
|
//
|
||||||
"json_array",
|
"json_array",
|
||||||
"json_array_append",
|
"json_array_append",
|
||||||
"json_array_insert",
|
"json_array_insert",
|
||||||
@ -417,7 +417,17 @@ static const char* BUILTIN_10_2_3_FUNCTIONS[] =
|
|||||||
"json_type",
|
"json_type",
|
||||||
"json_unquote",
|
"json_unquote",
|
||||||
"json_valid",
|
"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 =
|
const size_t N_BUILTIN_10_2_3_FUNCTIONS =
|
||||||
|
@ -1028,8 +1028,28 @@ multiselect_op(A) ::= UNION ALL. {A = TK_ALL;}
|
|||||||
multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP;}
|
multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP;}
|
||||||
%endif SQLITE_OMIT_COMPOUND_SELECT
|
%endif SQLITE_OMIT_COMPOUND_SELECT
|
||||||
%ifdef MAXSCALE
|
%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)
|
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) {
|
if (!I1) {
|
||||||
I1=I2;
|
I1=I2;
|
||||||
}
|
}
|
||||||
@ -1882,6 +1902,62 @@ func_arg_tail_opt ::= .
|
|||||||
func_arg_tail_opt ::= group_concat_tail.
|
func_arg_tail_opt ::= group_concat_tail.
|
||||||
func_arg_tail_opt ::= convert_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). {
|
expr(A) ::= id(X) LP distinct(D) exprlist(Y) func_arg_tail_opt RP(E). {
|
||||||
%endif
|
%endif
|
||||||
%ifndef MAXSCALE
|
%ifndef MAXSCALE
|
||||||
|
@ -208,6 +208,9 @@ static Keyword aKeywordTable[] = {
|
|||||||
{ "CONSTRAINT", "TK_CONSTRAINT", ALWAYS },
|
{ "CONSTRAINT", "TK_CONSTRAINT", ALWAYS },
|
||||||
{ "CREATE", "TK_CREATE", ALWAYS },
|
{ "CREATE", "TK_CREATE", ALWAYS },
|
||||||
{ "CROSS", "TK_JOIN_KW", ALWAYS },
|
{ "CROSS", "TK_JOIN_KW", ALWAYS },
|
||||||
|
#ifdef MAXSCALE
|
||||||
|
{ "CURRENT", "TK_CURRENT", ALWAYS },
|
||||||
|
#endif
|
||||||
{ "CURRENT_DATE", "TK_CTIME_KW", ALWAYS },
|
{ "CURRENT_DATE", "TK_CTIME_KW", ALWAYS },
|
||||||
{ "CURRENT_TIME", "TK_CTIME_KW", ALWAYS },
|
{ "CURRENT_TIME", "TK_CTIME_KW", ALWAYS },
|
||||||
{ "CURRENT_TIMESTAMP","TK_CTIME_KW", ALWAYS },
|
{ "CURRENT_TIMESTAMP","TK_CTIME_KW", ALWAYS },
|
||||||
@ -254,6 +257,7 @@ static Keyword aKeywordTable[] = {
|
|||||||
{ "EXCLUSIVE", "TK_EXCLUSIVE", ALWAYS },
|
{ "EXCLUSIVE", "TK_EXCLUSIVE", ALWAYS },
|
||||||
#ifdef MAXSCALE
|
#ifdef MAXSCALE
|
||||||
{ "EXECUTE", "TK_EXECUTE", ALWAYS },
|
{ "EXECUTE", "TK_EXECUTE", ALWAYS },
|
||||||
|
{ "EXCLUDE", "TK_EXCLUDE", ALWAYS },
|
||||||
#endif
|
#endif
|
||||||
{ "EXISTS", "TK_EXISTS", ALWAYS },
|
{ "EXISTS", "TK_EXISTS", ALWAYS },
|
||||||
{ "EXPLAIN", "TK_EXPLAIN", EXPLAIN },
|
{ "EXPLAIN", "TK_EXPLAIN", EXPLAIN },
|
||||||
@ -263,6 +267,7 @@ static Keyword aKeywordTable[] = {
|
|||||||
#ifdef MAXSCALE
|
#ifdef MAXSCALE
|
||||||
{ "FIRST", "TK_FIRST", ALWAYS },
|
{ "FIRST", "TK_FIRST", ALWAYS },
|
||||||
{ "FLUSH", "TK_FLUSH", ALWAYS },
|
{ "FLUSH", "TK_FLUSH", ALWAYS },
|
||||||
|
{ "FOLLOWING", "TK_FOLLOWING", ALWAYS },
|
||||||
#endif
|
#endif
|
||||||
{ "FOR", "TK_FOR", TRIGGER },
|
{ "FOR", "TK_FOR", TRIGGER },
|
||||||
#ifdef MAXSCALE
|
#ifdef MAXSCALE
|
||||||
@ -352,11 +357,16 @@ static Keyword aKeywordTable[] = {
|
|||||||
#endif
|
#endif
|
||||||
{ "OR", "TK_OR", ALWAYS },
|
{ "OR", "TK_OR", ALWAYS },
|
||||||
{ "ORDER", "TK_ORDER", ALWAYS },
|
{ "ORDER", "TK_ORDER", ALWAYS },
|
||||||
|
#ifdef MAXSCALE
|
||||||
|
{ "OTHERS", "TK_OTHERS", ALWAYS },
|
||||||
|
#endif
|
||||||
{ "OUTER", "TK_JOIN_KW", ALWAYS },
|
{ "OUTER", "TK_JOIN_KW", ALWAYS },
|
||||||
#ifdef MAXSCALE
|
#ifdef MAXSCALE
|
||||||
{ "OUTFILE", "TK_OUTFILE", ALWAYS },
|
{ "OUTFILE", "TK_OUTFILE", ALWAYS },
|
||||||
|
{ "OVER", "TK_OVER", ALWAYS },
|
||||||
#endif
|
#endif
|
||||||
#ifdef MAXSCALE
|
#ifdef MAXSCALE
|
||||||
|
{ "PARTITION", "TK_PARTITION", ALWAYS },
|
||||||
{ "PERSISTENT", "TK_PERSISTENT", ALWAYS },
|
{ "PERSISTENT", "TK_PERSISTENT", ALWAYS },
|
||||||
#endif
|
#endif
|
||||||
#ifndef MAXSCALE
|
#ifndef MAXSCALE
|
||||||
@ -364,6 +374,7 @@ static Keyword aKeywordTable[] = {
|
|||||||
#endif
|
#endif
|
||||||
{ "PRAGMA", "TK_PRAGMA", PRAGMA },
|
{ "PRAGMA", "TK_PRAGMA", PRAGMA },
|
||||||
#ifdef MAXSCALE
|
#ifdef MAXSCALE
|
||||||
|
{ "PRECEDING", "TK_PRECEDING", ALWAYS },
|
||||||
{ "PREPARE", "TK_PREPARE", ALWAYS },
|
{ "PREPARE", "TK_PREPARE", ALWAYS },
|
||||||
#endif
|
#endif
|
||||||
{ "PRIMARY", "TK_PRIMARY", ALWAYS },
|
{ "PRIMARY", "TK_PRIMARY", ALWAYS },
|
||||||
@ -378,6 +389,7 @@ static Keyword aKeywordTable[] = {
|
|||||||
#endif
|
#endif
|
||||||
{ "RAISE", "TK_RAISE", TRIGGER },
|
{ "RAISE", "TK_RAISE", TRIGGER },
|
||||||
#ifdef MAXSCALE
|
#ifdef MAXSCALE
|
||||||
|
{ "RANGE", "TK_RANGE", ALWAYS },
|
||||||
{ "READ", "TK_READ", ALWAYS },
|
{ "READ", "TK_READ", ALWAYS },
|
||||||
#endif
|
#endif
|
||||||
{ "RECURSIVE", "TK_RECURSIVE", CTE },
|
{ "RECURSIVE", "TK_RECURSIVE", CTE },
|
||||||
@ -397,6 +409,9 @@ static Keyword aKeywordTable[] = {
|
|||||||
{ "ROLLUP", "TK_ROLLUP", ALWAYS },
|
{ "ROLLUP", "TK_ROLLUP", ALWAYS },
|
||||||
#endif
|
#endif
|
||||||
{ "ROW", "TK_ROW", TRIGGER },
|
{ "ROW", "TK_ROW", TRIGGER },
|
||||||
|
#ifdef MAXSCALE
|
||||||
|
{ "ROWS", "TK_ROWS", ALWAYS },
|
||||||
|
#endif
|
||||||
{ "SAVEPOINT", "TK_SAVEPOINT", ALWAYS },
|
{ "SAVEPOINT", "TK_SAVEPOINT", ALWAYS },
|
||||||
#ifdef MAXSCALE
|
#ifdef MAXSCALE
|
||||||
{ "SCHEMAS", "TK_DATABASES_KW", ALWAYS },
|
{ "SCHEMAS", "TK_DATABASES_KW", ALWAYS },
|
||||||
@ -432,11 +447,15 @@ static Keyword aKeywordTable[] = {
|
|||||||
{ "TEMPTABLE", "TK_TEMPTABLE", ANALYZE },
|
{ "TEMPTABLE", "TK_TEMPTABLE", ANALYZE },
|
||||||
#endif
|
#endif
|
||||||
{ "THEN", "TK_THEN", ALWAYS },
|
{ "THEN", "TK_THEN", ALWAYS },
|
||||||
|
#ifdef MAXSCALE
|
||||||
|
{ "TIES", "TK_TIES", ANALYZE },
|
||||||
|
#endif
|
||||||
{ "TO", "TK_TO", ALWAYS },
|
{ "TO", "TK_TO", ALWAYS },
|
||||||
{ "TRANSACTION", "TK_TRANSACTION", ALWAYS },
|
{ "TRANSACTION", "TK_TRANSACTION", ALWAYS },
|
||||||
{ "TRIGGER", "TK_TRIGGER", TRIGGER },
|
{ "TRIGGER", "TK_TRIGGER", TRIGGER },
|
||||||
#ifdef MAXSCALE
|
#ifdef MAXSCALE
|
||||||
{ "TRUNCATE", "TK_TRUNCATE", ALWAYS },
|
{ "TRUNCATE", "TK_TRUNCATE", ALWAYS },
|
||||||
|
{ "UNBOUNDED", "TK_UNBOUNDED", ALWAYS },
|
||||||
#endif
|
#endif
|
||||||
{ "UNION", "TK_UNION", COMPOUND },
|
{ "UNION", "TK_UNION", COMPOUND },
|
||||||
{ "UNSIGNED", "TK_UNSIGNED", ALWAYS },
|
{ "UNSIGNED", "TK_UNSIGNED", ALWAYS },
|
||||||
@ -459,6 +478,7 @@ static Keyword aKeywordTable[] = {
|
|||||||
{ "VIRTUAL", "TK_VIRTUAL", VTAB },
|
{ "VIRTUAL", "TK_VIRTUAL", VTAB },
|
||||||
#ifdef MAXSCALE
|
#ifdef MAXSCALE
|
||||||
{ "WARNINGS", "TK_WARNINGS", ALWAYS },
|
{ "WARNINGS", "TK_WARNINGS", ALWAYS },
|
||||||
|
{ "WINDOW", "TK_WINDOW", ALWAYS },
|
||||||
#endif
|
#endif
|
||||||
{ "WITH", "TK_WITH", CTE },
|
{ "WITH", "TK_WITH", CTE },
|
||||||
#ifndef MAXSCALE
|
#ifndef MAXSCALE
|
||||||
|
@ -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_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_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_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()
|
endif()
|
||||||
|
|
||||||
if(NOT (MYSQL_EMBEDDED_VERSION VERSION_LESS 10.3))
|
if(NOT (MYSQL_EMBEDDED_VERSION VERSION_LESS 10.3))
|
||||||
|
1879
query_classifier/test/win.test
Normal file
1879
query_classifier/test/win.test
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user