Commit 9d9c60fb authored by Igor Babaev's avatar Igor Babaev

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.
parent 2cfc450b
......@@ -109,6 +109,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/table_cache.cc ../sql/mf_iocache_encr.cc
../sql/item_inetfunc.cc
../sql/wsrep_dummy.cc ../sql/encryption.cc
../sql/item_windowfunc.cc ../sql/sql_window.cc
${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE}
)
......
......@@ -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
......
......@@ -628,7 +628,8 @@ class Item: public Value_source,
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,
......
......@@ -347,7 +347,9 @@ class Item_sum :public Item_func_or_sum
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 @@ class Item_sum_num :public Item_sum
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 @@ class Item_sum_int :public Item_sum_num
class Item_sum_sum :public Item_sum_num,
public Type_handler_hybrid_field_type
public Type_handler_hybrid_field_type
{
protected:
double sum;
......
#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;
}
#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 */
......@@ -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)},
......
......@@ -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"
......@@ -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()
......
......@@ -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 @@ class st_select_lex: public st_select_lex_node
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 @@ struct LEX: public Query_tables_list
}
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());
......
......@@ -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.
......
......@@ -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);
......
#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);
}
#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 */
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment