diff options
author | Igor Babaev <igor@askmonty.org> | 2016-02-12 20:33:56 -0800 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2016-02-12 20:33:56 -0800 |
commit | 9d9c60fb12f7443fae9d22e716391ed75cf2b41a (patch) | |
tree | 04388814023be7eb42c185b90c3ba35c4a479b5a /sql | |
parent | 2cfc450bf78c2d951729d1a0e8f731c0d987b1d5 (diff) | |
download | mariadb-git-9d9c60fb12f7443fae9d22e716391ed75cf2b41a.tar.gz |
Initial patch for the implementation of window functions (MDEV-6115):
- All parsing problems look like resolved
- Stub performing name resolution of window functions
in simplest queries has been added.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/CMakeLists.txt | 3 | ||||
-rw-r--r-- | sql/item.h | 3 | ||||
-rw-r--r-- | sql/item_sum.h | 7 | ||||
-rw-r--r-- | sql/item_windowfunc.cc | 13 | ||||
-rw-r--r-- | sql/item_windowfunc.h | 177 | ||||
-rw-r--r-- | sql/lex.h | 13 | ||||
-rw-r--r-- | sql/share/errmsg-utf8.txt | 11 | ||||
-rw-r--r-- | sql/sql_lex.cc | 9 | ||||
-rw-r--r-- | sql/sql_lex.h | 20 | ||||
-rw-r--r-- | sql/sql_parse.cc | 47 | ||||
-rw-r--r-- | sql/sql_select.cc | 5 | ||||
-rw-r--r-- | sql/sql_window.cc | 79 | ||||
-rw-r--r-- | sql/sql_window.h | 124 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 262 |
14 files changed, 767 insertions, 6 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 9b0017c9124..19fbed85737 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -122,7 +122,7 @@ SET (SQL_SOURCE sql_profile.cc event_parse_data.cc sql_alter.cc sql_signal.cc rpl_handler.cc mdl.cc sql_admin.cc transaction.cc sys_vars.cc sql_truncate.cc datadict.cc - sql_reload.cc sql_cmd.h item_inetfunc.cc + sql_reload.cc sql_cmd.h item_inetfunc.cc # added in MariaDB: sql_explain.h sql_explain.cc @@ -137,6 +137,7 @@ SET (SQL_SOURCE my_json_writer.cc my_json_writer.h rpl_gtid.cc rpl_parallel.cc sql_type.cc sql_type.h + item_windowfunc.cc sql_window.cc ${WSREP_SOURCES} table_cache.cc encryption.cc ${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc diff --git a/sql/item.h b/sql/item.h index 4051674358e..46d09c247fe 100644 --- a/sql/item.h +++ b/sql/item.h @@ -628,7 +628,8 @@ public: static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) {} - enum Type {FIELD_ITEM= 0, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM, + enum Type {FIELD_ITEM= 0, FUNC_ITEM, SUM_FUNC_ITEM, + WINDOW_FUNC_ITEM, STRING_ITEM, INT_ITEM, REAL_ITEM, NULL_ITEM, VARBIN_ITEM, COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM, PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, diff --git a/sql/item_sum.h b/sql/item_sum.h index 68b034c9213..bf4a1560d42 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -347,7 +347,9 @@ public: enum Sumfunctype { COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC, AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, STD_FUNC, - VARIANCE_FUNC, SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC + 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 }; Item **ref_by; /* pointer to a ref to the object used to register it */ @@ -712,6 +714,7 @@ public: class Item_sum_int :public Item_sum_num { public: + Item_sum_int(THD *thd): Item_sum_num(thd) {} Item_sum_int(THD *thd, Item *item_par): Item_sum_num(thd, item_par) {} Item_sum_int(THD *thd, List<Item> &list): Item_sum_num(thd, list) {} Item_sum_int(THD *thd, Item_sum_int *item) :Item_sum_num(thd, item) {} @@ -726,7 +729,7 @@ public: class Item_sum_sum :public Item_sum_num, - public Type_handler_hybrid_field_type + public Type_handler_hybrid_field_type { protected: double sum; diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc new file mode 100644 index 00000000000..273a0831116 --- /dev/null +++ b/sql/item_windowfunc.cc @@ -0,0 +1,13 @@ +#include "item_windowfunc.h" + +bool +Item_window_func::fix_fields(THD *thd, Item **ref) +{ + DBUG_ASSERT(fixed == 0); + + if (window_func->fix_fields(thd, ref)) + return TRUE; + + fixed= 1; + return FALSE; +} diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h new file mode 100644 index 00000000000..3653cefaf57 --- /dev/null +++ b/sql/item_windowfunc.h @@ -0,0 +1,177 @@ +#ifndef ITEM_WINDOWFUNC_INCLUDED +#define ITEM_WINDOWFUNC_INCLUDED + +#include "my_global.h" +#include "item.h" + +class Window_spec; + + +class Item_sum_row_number: public Item_sum_int +{ + longlong count; + + void clear() {} + bool add() { return false; } + void update_field() {} + + public: + Item_sum_row_number(THD *thd) + : Item_sum_int(thd), count(0) {} + + enum Sumfunctype sum_func () const + { + return ROW_NUMBER_FUNC; + } + + const char*func_name() const + { + return "row_number"; + } + +}; + +class Item_sum_rank: public Item_sum_int +{ + longlong rank; + + void clear() {} + bool add() { return false; } + void update_field() {} + + public: + Item_sum_rank(THD *thd) + : Item_sum_int(thd), rank(0) {} + + enum Sumfunctype sum_func () const + { + return RANK_FUNC; + } + + const char*func_name() const + { + return "rank"; + } + +}; + +class Item_sum_dense_rank: public Item_sum_int +{ + longlong dense_rank; + + void clear() {} + bool add() { return false; } + void update_field() {} + + public: + Item_sum_dense_rank(THD *thd) + : Item_sum_int(thd), dense_rank(0) {} + enum Sumfunctype sum_func () const + { + return DENSE_RANK_FUNC; + } + + const char*func_name() const + { + return "dense_rank"; + } + +}; + +class Item_sum_percent_rank: public Item_sum_num +{ + longlong rank; + longlong partition_rows; + + void clear() {} + bool add() { return false; } + void update_field() {} + + public: + Item_sum_percent_rank(THD *thd) + : Item_sum_num(thd), rank(0), partition_rows(0) {} + + double val_real() { return 0; } + + enum Sumfunctype sum_func () const + { + return PERCENT_RANK_FUNC; + } + + const char*func_name() const + { + return "percent_rank"; + } + + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + +}; + +class Item_sum_cume_dist: public Item_sum_num +{ + longlong count; + longlong partition_rows; + + void clear() {} + bool add() { return false; } + void update_field() {} + + public: + Item_sum_cume_dist(THD *thd) + : Item_sum_num(thd), count(0), partition_rows(0) {} + + double val_real() { return 0; } + + enum Sumfunctype sum_func () const + { + return CUME_DIST_FUNC; + } + + const char*func_name() const + { + return "cume_dist"; + } + + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + +}; + + +class Item_window_func : public Item_result_field +{ +private: + Item_sum *window_func; + LEX_STRING *window_name; + Window_spec *window_spec; + +public: + Item_window_func(THD *thd, Item_sum *win_func, LEX_STRING *win_name) + : Item_result_field(thd), window_func(win_func), + window_name(win_name), window_spec(NULL) {} + + Item_window_func(THD *thd, Item_sum *win_func, Window_spec *win_spec) + : Item_result_field(thd), window_func(win_func), + window_name(NULL), window_spec(win_spec) {} + + enum Item::Type type() const { return Item::WINDOW_FUNC_ITEM; } + + enum_field_types field_type() const { return window_func->field_type(); } + + double val_real() { return window_func->val_real(); } + + longlong val_int() { return window_func->val_int(); } + + String* val_str(String* str) { return window_func->val_str(str); } + + my_decimal* val_decimal(my_decimal* dec) + { return window_func->val_decimal(dec); } + + void fix_length_and_dec() { } + + const char* func_name() const { return "WF"; } + + bool fix_fields(THD *thd, Item **ref); +}; + + +#endif /* ITEM_WINDOWFUNC_INCLUDED */ diff --git a/sql/lex.h b/sql/lex.h index 22ff4e6d360..05f0050e4f6 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -221,6 +221,7 @@ static SYMBOL symbols[] = { { "EVERY", SYM(EVERY_SYM)}, { "EXAMINED", SYM(EXAMINED_SYM)}, { "EXCHANGE", SYM(EXCHANGE_SYM)}, + { "EXCLUDE", SYM(EXCLUDE_SYM)}, { "EXECUTE", SYM(EXECUTE_SYM)}, { "EXISTS", SYM(EXISTS)}, { "EXIT", SYM(EXIT_SYM)}, @@ -241,6 +242,7 @@ static SYMBOL symbols[] = { { "FLOAT4", SYM(FLOAT_SYM)}, { "FLOAT8", SYM(DOUBLE_SYM)}, { "FLUSH", SYM(FLUSH_SYM)}, + { "FOLLOWING", SYM(FOLLOWING_SYM)}, { "FOR", SYM(FOR_SYM)}, { "FORCE", SYM(FORCE_SYM)}, { "FOREIGN", SYM(FOREIGN)}, @@ -425,9 +427,11 @@ static SYMBOL symbols[] = { { "OPTIONALLY", SYM(OPTIONALLY)}, { "OR", SYM(OR_SYM)}, { "ORDER", SYM(ORDER_SYM)}, + { "OTHERS", SYM(OTHERS_SYM)}, { "OUT", SYM(OUT_SYM)}, { "OUTER", SYM(OUTER)}, { "OUTFILE", SYM(OUTFILE)}, + { "OVER", SYM(OVER_SYM)}, { "OWNER", SYM(OWNER_SYM)}, { "PACK_KEYS", SYM(PACK_KEYS_SYM)}, { "PAGE", SYM(PAGE_SYM)}, @@ -446,6 +450,7 @@ static SYMBOL symbols[] = { { "POINT", SYM(POINT_SYM)}, { "POLYGON", SYM(POLYGON)}, { "PORT", SYM(PORT_SYM)}, + { "PRECEDING", SYM(PRECEDING_SYM)}, { "PRECISION", SYM(PRECISION)}, { "PREPARE", SYM(PREPARE_SYM)}, { "PRESERVE", SYM(PRESERVE_SYM)}, @@ -601,6 +606,7 @@ static SYMBOL symbols[] = { { "TEXT", SYM(TEXT_SYM)}, { "THAN", SYM(THAN_SYM)}, { "THEN", SYM(THEN_SYM)}, + { "TIES", SYM(TIES_SYM)}, { "TIME", SYM(TIME_SYM)}, { "TIMESTAMP", SYM(TIMESTAMP)}, { "TIMESTAMPADD", SYM(TIMESTAMP_ADD)}, @@ -618,6 +624,7 @@ static SYMBOL symbols[] = { { "TRUNCATE", SYM(TRUNCATE_SYM)}, { "TYPE", SYM(TYPE_SYM)}, { "TYPES", SYM(TYPES_SYM)}, + { "UNBOUNDED", SYM(UNBOUNDED_SYM)}, { "UNCOMMITTED", SYM(UNCOMMITTED_SYM)}, { "UNDEFINED", SYM(UNDEFINED_SYM)}, { "UNDO_BUFFER_SIZE", SYM(UNDO_BUFFER_SIZE_SYM)}, @@ -659,6 +666,7 @@ static SYMBOL symbols[] = { { "WHEN", SYM(WHEN_SYM)}, { "WHERE", SYM(WHERE)}, { "WHILE", SYM(WHILE_SYM)}, + { "WINDOW", SYM(WINDOW_SYM)}, { "WITH", SYM(WITH)}, { "WORK", SYM(WORK_SYM)}, { "WRAPPER", SYM(WRAPPER_SYM)}, @@ -681,10 +689,12 @@ static SYMBOL sql_functions[] = { { "BIT_XOR", SYM(BIT_XOR)}, { "CAST", SYM(CAST_SYM)}, { "COUNT", SYM(COUNT_SYM)}, + { "CUME_DIST", SYM(CUME_DIST_SYM)}, { "CURDATE", SYM(CURDATE)}, { "CURTIME", SYM(CURTIME)}, { "DATE_ADD", SYM(DATE_ADD_INTERVAL)}, { "DATE_SUB", SYM(DATE_SUB_INTERVAL)}, + { "DENSE_RANK", SYM(DENSE_RANK_SYM)}, { "EXTRACT", SYM(EXTRACT_SYM)}, { "GROUP_CONCAT", SYM(GROUP_CONCAT_SYM)}, { "MAX", SYM(MAX_SYM)}, @@ -692,6 +702,9 @@ static SYMBOL sql_functions[] = { { "MIN", SYM(MIN_SYM)}, { "NOW", SYM(NOW_SYM)}, { "POSITION", SYM(POSITION_SYM)}, + { "PERCENT_RANK", SYM(PERCENT_RANK_SYM)}, + { "RANK", SYM(RANK_SYM)}, + { "ROW_NUMBER", SYM(ROW_NUMBER_SYM)}, { "SESSION_USER", SYM(USER)}, { "STD", SYM(STD_SYM)}, { "STDDEV", SYM(STD_SYM)}, diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 0afd13eb19b..567be4d5a89 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7136,3 +7136,14 @@ ER_KILL_QUERY_DENIED_ERROR eng "You are not owner of query %lu" ger "Sie sind nicht Eigentümer von Abfrage %lu" rus "Вы не являетесь владельцем запроса %lu" +ER_WRONG_WINDOW_SPEC_NAME + eng "Window specification with name '%s' is not defined" +ER_DUP_WINDOW_NAME + eng "Multiple window specifications with the same name '%s'" +ER_PARTITION_LIST_IN_REFERENCING_WINDOW_SPEC + eng "Window specification referencing another one '%s' cannot contain partition list" +ER_ORDER_LIST_IN_REFERENCING_WINDOW_SPEC + eng "Referenced window specification '%s' already contains order list" +ER_WINDOW_FRAME_IN_REFERENCED_WINDOW_SPEC + eng "Referenced window specification '%s' cannot contain window frame" + diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 0a1ea705a63..deeb757bdf3 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -546,6 +546,14 @@ void lex_start(THD *thd) lex->stmt_var_list.empty(); lex->proc_list.elements=0; + lex->save_group_list.empty(); + lex->save_order_list.empty(); + lex->win_ref= NULL; + lex->win_frame= NULL; + lex->frame_top_bound= NULL; + lex->frame_bottom_bound= NULL; + lex->win_spec= NULL; + lex->is_lex_started= TRUE; DBUG_VOID_RETURN; } @@ -1926,6 +1934,7 @@ void st_select_lex::init_query() select_list_tables= 0; m_non_agg_field_used= false; m_agg_func_used= false; + window_specs.empty(); } void st_select_lex::init_select() diff --git a/sql/sql_lex.h b/sql/sql_lex.h index e87fcb8cd22..29271bc3e12 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -28,6 +28,7 @@ #include "mem_root_array.h" #include "sql_cmd.h" #include "sql_alter.h" // Alter_info +#include "sql_window.h" /* YACC and LEX Definitions */ @@ -1070,6 +1071,17 @@ public: void set_non_agg_field_used(bool val) { m_non_agg_field_used= val; } void set_agg_func_used(bool val) { m_agg_func_used= val; } + List<Window_spec> window_specs; + void prepare_add_window_spec(THD *thd); + bool add_window_def(THD *thd, LEX_STRING *win_name, LEX_STRING *win_ref, + SQL_I_List<ORDER> win_partition_list, + SQL_I_List<ORDER> win_order_list, + Window_frame *win_frame); + bool add_window_spec(THD *thd, LEX_STRING *win_ref, + SQL_I_List<ORDER> win_partition_list, + SQL_I_List<ORDER> win_order_list, + Window_frame *win_frame); + private: bool m_non_agg_field_used; bool m_agg_func_used; @@ -2706,6 +2718,14 @@ public: } + SQL_I_List<ORDER> save_group_list; + SQL_I_List<ORDER> save_order_list; + LEX_STRING *win_ref; + Window_frame *win_frame; + Window_frame_bound *frame_top_bound; + Window_frame_bound *frame_bottom_bound; + Window_spec *win_spec; + inline void free_set_stmt_mem_root() { DBUG_ASSERT(!is_arena_for_set_stmt()); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 6c99873cef3..6bd1c9b639b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -7816,6 +7816,53 @@ TABLE_LIST *st_select_lex::convert_right_join() DBUG_RETURN(tab1); } + +void st_select_lex::prepare_add_window_spec(THD *thd) +{ + LEX *lex= thd->lex; + lex->save_group_list= group_list; + lex->save_order_list= order_list; + lex->win_ref= NULL; + lex->win_frame= NULL; + lex->frame_top_bound= NULL; + lex->frame_bottom_bound= NULL; + group_list.empty(); + order_list.empty(); +} + +bool st_select_lex::add_window_def(THD *thd, + LEX_STRING *win_name, + LEX_STRING *win_ref, + SQL_I_List<ORDER> win_partition_list, + SQL_I_List<ORDER> win_order_list, + Window_frame *win_frame) +{ + Window_def *win_def= new (thd->mem_root) Window_def(win_name, + win_ref, + win_partition_list, + win_order_list, + win_frame); + group_list= thd->lex->save_group_list; + order_list= thd->lex->save_order_list; + return (win_def == NULL || window_specs.push_back(win_def)); +} + +bool st_select_lex::add_window_spec(THD *thd, + LEX_STRING *win_ref, + SQL_I_List<ORDER> win_partition_list, + SQL_I_List<ORDER> win_order_list, + Window_frame *win_frame) +{ + Window_spec *win_spec= new (thd->mem_root) Window_spec(win_ref, + win_partition_list, + win_order_list, + win_frame); + group_list= thd->lex->save_group_list; + order_list= thd->lex->save_order_list; + thd->lex->win_spec= win_spec; + return (win_spec == NULL || window_specs.push_back(win_spec)); +} + /** Set lock for all tables in current select level. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1948d3e98d7..38a03428ee0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -53,6 +53,7 @@ #include "log_slow.h" #include "sql_derived.h" #include "sql_statistics.h" +#include "sql_window.h" #include "debug_sync.h" // DEBUG_SYNC #include <m_ctype.h> @@ -621,6 +622,7 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array, COND **conds, ORDER *order, ORDER *group, + List<Window_spec> &win_specs, bool *hidden_group_fields, uint *reserved) { @@ -654,6 +656,8 @@ setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array, res= res || setup_group(thd, ref_pointer_array, tables, fields, all_fields, group, hidden_group_fields); thd->lex->allow_sum_func= save_allow_sum_func; + res= res || setup_windows(thd, ref_pointer_array, tables, fields, all_fields, + win_specs); DBUG_RETURN(res); } @@ -794,6 +798,7 @@ JOIN::prepare(TABLE_LIST *tables_init, if (setup_without_group(thd, ref_ptrs, tables_list, select_lex->leaf_tables, fields_list, all_fields, &conds, order, group_list, + select_lex->window_specs, &hidden_group_fields, &select_lex->select_n_reserved)) DBUG_RETURN(-1); diff --git a/sql/sql_window.cc b/sql/sql_window.cc new file mode 100644 index 00000000000..493a9686ff8 --- /dev/null +++ b/sql/sql_window.cc @@ -0,0 +1,79 @@ +#include "sql_select.h" +#include "sql_window.h" + + +bool +Window_spec::check_window_names(List_iterator_fast<Window_spec> &it) +{ + char *name= this->name(); + char *ref_name= window_reference(); + bool win_ref_is_resolved= false; + it.rewind(); + Window_spec *win_spec; + while((win_spec= it++) && win_spec != this) + { + char *win_spec_name= win_spec->name(); + if (win_spec_name) + { + if (name && my_strcasecmp(system_charset_info, name, win_spec_name) == 0) + { + my_error(ER_DUP_WINDOW_NAME, MYF(0), name); + return true; + } + if (ref_name && + my_strcasecmp(system_charset_info, ref_name, win_spec_name) == 0) + { + if (win_spec->partition_list.elements) + { + my_error(ER_PARTITION_LIST_IN_REFERENCING_WINDOW_SPEC, MYF(0), + ref_name); + return true; + } + if (win_spec->order_list.elements && order_list.elements) + { + my_error(ER_ORDER_LIST_IN_REFERENCING_WINDOW_SPEC, MYF(0), ref_name); + return true; + } + if (win_spec->window_frame) + { + my_error(ER_WINDOW_FRAME_IN_REFERENCED_WINDOW_SPEC, MYF(0), ref_name); + return true; + } + referenced_win_spec=win_spec; + win_ref_is_resolved= true; + } + } + } + if (ref_name && !win_ref_is_resolved) + { + my_error(ER_WRONG_WINDOW_SPEC_NAME, MYF(0), ref_name); + return true; + } + return false; +} + + +int +setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, + List<Item> &fields, List<Item> &all_fields, + List<Window_spec> win_specs) +{ + Window_spec *win_spec; + DBUG_ENTER("setup_windows"); + List_iterator<Window_spec> it(win_specs); + List_iterator_fast<Window_spec> itp(win_specs); + + while ((win_spec= it++)) + { + bool hidden_group_fields; + if (win_spec->check_window_names(itp) || + setup_group(thd, ref_pointer_array, tables, fields, all_fields, + win_spec->partition_list.first, &hidden_group_fields) || + setup_order(thd, ref_pointer_array, tables, fields, all_fields, + win_spec->order_list.first)) + { + DBUG_RETURN(1); + } + } + DBUG_RETURN(0); +} diff --git a/sql/sql_window.h b/sql/sql_window.h new file mode 100644 index 00000000000..680dbcfd63f --- /dev/null +++ b/sql/sql_window.h @@ -0,0 +1,124 @@ + +#ifndef SQL_WINDOW_INCLUDED +#define SQL_WINDOW_INCLUDED + +#include "my_global.h" +#include "item.h" + +class Window_frame_bound : public Sql_alloc +{ + +public: + + enum Bound_precedence_type + { + PRECEDING, + CURRENT, // Used for CURRENT ROW window frame bounds + FOLLOWING + }; + + Bound_precedence_type precedence_type; + + + /* + For UNBOUNDED PRECEDING / UNBOUNDED FOLLOWING window frame bounds + precedence type is seto to PRECEDING / FOLLOWING and + offset is set to NULL. + The offset is not meaningful with precedence type CURRENT + */ + Item *offset; + + Window_frame_bound(Bound_precedence_type prec_type, + Item *offset_val) + : precedence_type(prec_type), offset(offset_val) {} + +}; + + +class Window_frame : public Sql_alloc +{ + +public: + + enum Frame_units + { + UNITS_ROWS, + UNITS_RANGE + }; + + enum Frame_exclusion + { + EXCL_NONE, + EXCL_CURRENT_ROW, + EXCL_GROUP, + EXCL_TIES + }; + + Frame_units units; + + Window_frame_bound *top_bound; + + Window_frame_bound *bottom_bound; + + Frame_exclusion exclusion; + + Window_frame(Frame_units win_frame_units, + Window_frame_bound *win_frame_top_bound, + Window_frame_bound *win_frame_bottom_bound, + Frame_exclusion win_frame_exclusion) + : units(win_frame_units), top_bound(win_frame_top_bound), + bottom_bound(win_frame_bottom_bound), exclusion(win_frame_exclusion) {} + +}; + +class Window_spec : public Sql_alloc +{ + public: + + LEX_STRING *window_ref; + + SQL_I_List<ORDER> partition_list; + + SQL_I_List<ORDER> order_list; + + Window_frame *window_frame; + + Window_spec *referenced_win_spec; + + Window_spec(LEX_STRING *win_ref, + SQL_I_List<ORDER> part_list, + SQL_I_List<ORDER> ord_list, + Window_frame *win_frame) + : window_ref(win_ref), partition_list(part_list), order_list(ord_list), + window_frame(win_frame), referenced_win_spec(NULL) {} + + virtual char *name() { return NULL; } + + bool check_window_names(List_iterator_fast<Window_spec> &it); + + char *window_reference() { return window_ref ? window_ref->str : NULL; } +}; + +class Window_def : public Window_spec +{ + public: + + LEX_STRING *window_name; + + Window_def(LEX_STRING *win_name, + LEX_STRING *win_ref, + SQL_I_List<ORDER> part_list, + SQL_I_List<ORDER> ord_list, + Window_frame *win_frame) + : Window_spec(win_ref, part_list, ord_list, win_frame), + window_name(win_name) {} + + char *name() { return window_name->str; } + +}; + +int setup_windows(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, + List<Item> &fields, List<Item> &all_fields, + List<Window_spec> win_specs); + +#endif /* SQL_WINDOW_INCLUDED */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 3eb6a99a131..3fa73b72e60 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -54,6 +54,8 @@ #include "sql_handler.h" // Sql_cmd_handler_* #include "sql_signal.h" #include "sql_get_diagnostics.h" // Sql_cmd_get_diagnostics +#include "sql_window.h" +#include "item_windowfunc.h" #include "event_parse_data.h" #include "create_options.h" #include <myisam.h> @@ -962,6 +964,8 @@ bool LEX::set_bincmp(CHARSET_INFO *cs, bool bin) handlerton *db_type; st_select_lex *select_lex; struct p_elem_val *p_elem_value; + class Window_frame *window_frame; + class Window_frame_bound *window_frame_bound; udf_func *udf; /* enums */ @@ -987,6 +991,9 @@ bool LEX::set_bincmp(CHARSET_INFO *cs, bool bin) enum sp_variable::enum_mode spvar_mode; enum thr_lock_type lock_type; enum enum_mysql_timestamp_type date_time_type; + enum Window_frame_bound::Bound_precedence_type bound_precedence_type; + enum Window_frame::Frame_units frame_units; + enum Window_frame::Frame_exclusion frame_exclusion; DDL_options_st object_ddl_options; } @@ -998,10 +1005,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %parse-param { THD *thd } %lex-param { THD *thd } /* - Currently there are 121 shift/reduce conflicts. + Currently there are 124 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 121 +%expect 124 /* Comments for TOKENS. @@ -1124,6 +1131,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token CREATE /* SQL-2003-R */ %token CROSS /* SQL-2003-R */ %token CUBE_SYM /* SQL-2003-R */ +%token CUME_DIST_SYM %token CURDATE /* MYSQL-FUNC */ %token CURRENT_SYM /* SQL-2003-R */ %token CURRENT_USER /* SQL-2003-R */ @@ -1154,6 +1162,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token DELAYED_SYM %token DELAY_KEY_WRITE_SYM %token DELETE_SYM /* SQL-2003-R */ +%token DENSE_RANK_SYM %token DESC /* SQL-2003-N */ %token DESCRIBE /* SQL-2003-R */ %token DES_KEY_FILE @@ -1195,6 +1204,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token EVERY_SYM /* SQL-2003-N */ %token EXCHANGE_SYM %token EXAMINED_SYM +%token EXCLUDE_SYM %token EXECUTE_SYM /* SQL-2003-R */ %token EXISTS /* SQL-2003-R */ %token EXIT_SYM @@ -1213,6 +1223,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token FLOAT_NUM %token FLOAT_SYM /* SQL-2003-R */ %token FLUSH_SYM +%token FOLLOWING_SYM %token FORCE_SYM %token FOREIGN /* SQL-2003-R */ %token FOR_SYM /* SQL-2003-R */ @@ -1409,9 +1420,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token ORDER_SYM /* SQL-2003-R */ %token OR_OR_SYM /* OPERATOR */ %token OR_SYM /* SQL-2003-R */ +%token OTHERS_SYM %token OUTER %token OUTFILE %token OUT_SYM /* SQL-2003-R */ +%token OVER_SYM %token OWNER_SYM %token PACK_KEYS_SYM %token PAGE_SYM @@ -1424,6 +1437,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token PARTITIONS_SYM %token PARTITIONING_SYM %token PASSWORD_SYM +%token PERCENT_RANK_SYM %token PERSISTENT_SYM %token PHASE_SYM %token PLUGINS_SYM @@ -1432,6 +1446,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token POLYGON %token PORT_SYM %token POSITION_SYM /* SQL-2003-N */ +%token PRECEDING_SYM %token PRECISION /* SQL-2003-R */ %token PREPARE_SYM /* SQL-2003-R */ %token PRESERVE_SYM @@ -1449,6 +1464,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token QUERY_SYM %token QUICK %token RANGE_SYM /* SQL-2003-R */ +%token RANK_SYM %token READS_SYM /* SQL-2003-R */ %token READ_ONLY_SYM %token READ_SYM /* SQL-2003-N */ @@ -1498,6 +1514,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token ROW_FORMAT_SYM %token ROW_SYM /* SQL-2003-R */ %token ROW_COUNT_SYM /* SQL-2003-N */ +%token ROW_NUMBER_SYM %token RTREE_SYM %token SAVEPOINT_SYM /* SQL-2003-R */ %token SCHEDULE_SYM @@ -1588,6 +1605,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token TEXT_SYM %token THAN_SYM %token THEN_SYM /* SQL-2003-R */ +%token TIES_SYM %token TIMESTAMP /* SQL-2003-R */ %token TIMESTAMP_ADD %token TIMESTAMP_DIFF @@ -1608,6 +1626,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token TYPE_SYM /* SQL-2003-N */ %token UDF_RETURNS_SYM %token ULONGLONG_NUM +%token UNBOUNDED_SYM %token UNCOMMITTED_SYM /* SQL-2003-N */ %token UNDEFINED_SYM %token UNDERSCORE_CHARSET @@ -1649,6 +1668,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token WEIGHT_STRING_SYM %token WHEN_SYM /* SQL-2003-R */ %token WHERE /* SQL-2003-R */ +%token WINDOW_SYM %token WHILE_SYM %token WITH /* SQL-2003-R */ %token WITH_CUBE_SYM /* INTERNAL */ @@ -1787,6 +1807,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); simple_ident_nospvar simple_ident_q field_or_var limit_option part_func_expr + window_func_expr + window_func + simple_window_func function_call_keyword function_call_nonkeyword function_call_generic @@ -1975,6 +1998,15 @@ END_OF_INPUT %type <cond_info_item_name> condition_information_item_name; %type <cond_info_list> condition_information; +%type <NONE> opt_window_clause window_def_list window_def window_spec +%type <lex_str_ptr> window_name +%type <NONE> opt_window_ref opt_window_frame_clause +%type <frame_units> window_frame_units; +%type <NONE> window_frame_extent; +%type <frame_exclusion> opt_window_frame_exclusion; +%type <window_frame_bound> window_frame_start window_frame_bound; + + %type <NONE> '-' '+' '*' '/' '%' '(' ')' ',' '!' '{' '}' '&' '|' AND_SYM OR_SYM OR_OR_SYM BETWEEN_SYM CASE_SYM @@ -8497,6 +8529,7 @@ table_expression: opt_where_clause opt_group_clause opt_having_clause + opt_window_clause opt_order_clause opt_limit_clause opt_procedure_clause @@ -9221,6 +9254,7 @@ simple_expr: | param_marker { $$= $1; } | variable | sum_expr + | window_func_expr | simple_expr OR_OR_SYM simple_expr { $$= new (thd->mem_root) Item_func_concat(thd, $1, $3); @@ -10356,6 +10390,81 @@ sum_expr: } ; +window_func_expr: + window_func OVER_SYM window_name + { + $$= new (thd->mem_root) Item_window_func(thd, (Item_sum *) $1, $3); + if ($$ == NULL) + MYSQL_YYABORT; + } + | + window_func OVER_SYM window_spec + { + LEX *lex= Lex; + if (Select->add_window_spec(thd, lex->win_ref, + Select->group_list, + Select->order_list, + lex->win_frame)) + MYSQL_YYABORT; + $$= new (thd->mem_root) Item_window_func(thd, (Item_sum *) $1, + thd->lex->win_spec); + if ($$ == NULL) + MYSQL_YYABORT; + } + ; + +window_func: + simple_window_func + | + sum_expr + ; + +simple_window_func: + ROW_NUMBER_SYM '(' ')' + { + $$= new (thd->mem_root) Item_sum_row_number(thd); + if ($$ == NULL) + MYSQL_YYABORT; + } + | + RANK_SYM '(' ')' + { + $$= new (thd->mem_root) Item_sum_rank(thd); + if ($$ == NULL) + MYSQL_YYABORT; + } + | + DENSE_RANK_SYM '(' ')' + { + $$= new (thd->mem_root) Item_sum_dense_rank(thd); + if ($$ == NULL) + MYSQL_YYABORT; + } + | + PERCENT_RANK_SYM '(' ')' + { + $$= new (thd->mem_root) Item_sum_percent_rank(thd); + if ($$ == NULL) + MYSQL_YYABORT; + } + | + CUME_DIST_SYM '(' ')' + { + $$= new (thd->mem_root) Item_sum_cume_dist(thd); + if ($$ == NULL) + MYSQL_YYABORT; + } + ; + +window_name: + ident + { + $$= (LEX_STRING *) thd->memdup(&$1, sizeof(LEX_STRING)); + if ($$ == NULL) + MYSQL_YYABORT; + } + ; + variable: '@' { @@ -11290,6 +11399,155 @@ olap_opt: ; /* + optional window clause in select +*/ + +opt_window_clause: + /* empty */ + {} + | WINDOW_SYM + window_def_list + {} + ; + +window_def_list: + window_def_list ',' window_def + | window_def + ; + +window_def: + window_name AS window_spec + { + LEX *lex= Lex; + if (Select->add_window_def(thd, $1, lex->win_ref, + Select->group_list, + Select->order_list, + lex->win_frame )) + MYSQL_YYABORT; + } + ; + +window_spec: + '(' + { Select->prepare_add_window_spec(thd); } + opt_window_ref opt_window_partition_clause + opt_window_order_clause opt_window_frame_clause + ')' + ; + +opt_window_ref: + /* empty */ {} + | ident + { + thd->lex->win_ref= (LEX_STRING *) thd->memdup(&$1, sizeof(LEX_STRING)); + if (thd->lex->win_ref == NULL) + MYSQL_YYABORT; + } + +opt_window_partition_clause: + /* empty */ { } + | PARTITION_SYM BY group_list + ; + +opt_window_order_clause: + /* empty */ { } + | ORDER_SYM BY order_list + ; + +opt_window_frame_clause: + /* empty */ {} + | window_frame_units window_frame_extent opt_window_frame_exclusion + { + LEX *lex= Lex; + lex->win_frame= + new (thd->mem_root) Window_frame($1, + lex->frame_top_bound, + lex->frame_bottom_bound, + $3); + if (lex->win_frame == NULL) + MYSQL_YYABORT; + } + ; + +window_frame_units: + ROWS_SYM { $$= Window_frame::UNITS_ROWS; } + | RANGE_SYM { $$= Window_frame::UNITS_RANGE; } + ; + +window_frame_extent: + window_frame_start + { + LEX *lex= Lex; + lex->frame_top_bound= $1; + lex->frame_bottom_bound= + new (thd->mem_root) + Window_frame_bound(Window_frame_bound::CURRENT, NULL); + if (lex->frame_bottom_bound == NULL) + MYSQL_YYABORT; + } + | BETWEEN_SYM window_frame_bound AND_SYM window_frame_bound + { + LEX *lex= Lex; + lex->frame_top_bound= $2; + lex->frame_bottom_bound= $4; + } + ; + +window_frame_start: + UNBOUNDED_SYM PRECEDING_SYM + { + $$= new (thd->mem_root) + Window_frame_bound(Window_frame_bound::PRECEDING, NULL); + if ($$ == NULL) + MYSQL_YYABORT; + } + | CURRENT_SYM ROW_SYM + { + $$= new (thd->mem_root) + Window_frame_bound(Window_frame_bound::CURRENT, NULL); + if ($$ == NULL) + MYSQL_YYABORT; + } + | literal PRECEDING_SYM + { + $$= new (thd->mem_root) + Window_frame_bound(Window_frame_bound::PRECEDING, $1); + if ($$ == NULL) + MYSQL_YYABORT; + } + ; + +window_frame_bound: + window_frame_start { $$= $1; } + | UNBOUNDED_SYM FOLLOWING_SYM + { + $$= new (thd->mem_root) + Window_frame_bound(Window_frame_bound::FOLLOWING, NULL); + if ($$ == NULL) + MYSQL_YYABORT; + } + | literal FOLLOWING_SYM + { + $$= new (thd->mem_root) + Window_frame_bound(Window_frame_bound::FOLLOWING, $1); + if ($$ == NULL) + MYSQL_YYABORT; + } + ; + +opt_window_frame_exclusion: + /* empty */ { $$= Window_frame::EXCL_NONE; } + | EXCLUDE_SYM CURRENT_SYM ROW_SYM + { $$= Window_frame::EXCL_CURRENT_ROW; } + | EXCLUDE_SYM GROUP_SYM + { $$= Window_frame::EXCL_GROUP; } + | EXCLUDE_SYM TIES_SYM + { $$= Window_frame::EXCL_TIES; } + | EXCLUDE_SYM NO_SYM OTHERS_SYM + { $$= Window_frame::EXCL_NONE; } + ; + +/* Order by statement in ALTER TABLE */ |