MXS-1247 Add initial support for window functions

This commit will be followed by more tests.
This commit is contained in:
Johan Wikman 2017-08-16 12:33:47 +03:00
parent 27ef5c3048
commit 523e7ed445
6 changed files with 2007 additions and 6 deletions

View File

@ -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();

View File

@ -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 =

View File

@ -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

View File

@ -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

View File

@ -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))

File diff suppressed because it is too large Load Diff