MXS-1247 Add initial support for window functions
This commit will be followed by more tests.
This commit is contained in:
parent
27ef5c3048
commit
523e7ed445
@ -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_func*>(item);
|
||||
Item_func_or_sum* func_item = static_cast<Item_func_or_sum*>(item);
|
||||
Item** items = func_item->arguments();
|
||||
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]);
|
||||
|
||||
// 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 =
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
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
Loading…
x
Reference in New Issue
Block a user