diff options
author | Vicențiu Ciorbaru <vicentiu@mariadb.org> | 2016-09-22 18:26:55 +0200 |
---|---|---|
committer | Vicențiu Ciorbaru <vicentiu@mariadb.org> | 2016-09-24 15:12:34 +0200 |
commit | 53cf265b3b6be949a19294661cb3e0ce25d9c712 (patch) | |
tree | 4d80b82ecc26a88e94c3afb5056fac9b742023ea /sql/item_windowfunc.cc | |
parent | 29b227c33565596f903cc6ef5aa2d8a76324e28c (diff) | |
download | mariadb-git-53cf265b3b6be949a19294661cb3e0ce25d9c712.tar.gz |
Implement LEAD and LAG and NTH_VALUE functions
Refactour out (into a copy for now) the logic of Item_sum_hybrid, to
allow for multiple arguments. It does not contain the comparator
members. The result is the class Item_sum_hybrid_simple.
LEAD and LAG make use of this Item to store previous rows in a chache.
It also helps in specifying the field type. Currently LEAD/LAG do not
support default values.
NTH_VALUE behaves identical to LEAD and LAG, except that the starting
position cursor is placed on the top of the frame instead of the current
row.
Diffstat (limited to 'sql/item_windowfunc.cc')
-rw-r--r-- | sql/item_windowfunc.cc | 218 |
1 files changed, 211 insertions, 7 deletions
diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc index 5a7ee522d44..ccdbdd3294f 100644 --- a/sql/item_windowfunc.cc +++ b/sql/item_windowfunc.cc @@ -229,16 +229,220 @@ bool Item_sum_first_value::add() For this usecase we can actually get rid of arg_cache. arg_cache is just for running a comparison function. */ value_added= true; - arg_cache->cache_value(); - value->store(arg_cache); - null_value= arg_cache->null_value; + Item_sum_hybrid_simple::add(); return false; } -bool Item_sum_last_value::add() +bool Item_sum_hybrid_simple::fix_fields(THD *thd, Item **ref) { - arg_cache->cache_value(); - value->store(arg_cache); - null_value= arg_cache->null_value; + DBUG_ASSERT(fixed == 0); + + if (init_sum_func_check(thd)) + return TRUE; + + for (uint i= 0; i < arg_count; i++) + { + Item *item= args[i]; + // 'item' can be changed during fix_fields + if ((!item->fixed && item->fix_fields(thd, args)) || + (item= args[i])->check_cols(1)) + return TRUE; + } + Type_std_attributes::set(args[0]); + for (uint i= 0; i < arg_count && !with_subselect; i++) + with_subselect= with_subselect || args[i]->with_subselect; + + Item *item2= args[0]->real_item(); + if (item2->type() == Item::FIELD_ITEM) + set_handler_by_field_type(((Item_field*) item2)->field->type()); + else if (args[0]->cmp_type() == TIME_RESULT) + set_handler_by_field_type(item2->field_type()); + else + set_handler_by_result_type(item2->result_type(), + max_length, collation.collation); + + switch (Item_sum_hybrid_simple::result_type()) { + case INT_RESULT: + case DECIMAL_RESULT: + case STRING_RESULT: + break; + case REAL_RESULT: + max_length= float_length(decimals); + break; + case ROW_RESULT: + case TIME_RESULT: + DBUG_ASSERT(0); // XXX(cvicentiu) Should this never happen? + return TRUE; + }; + setup_hybrid(thd, args[0]); + /* MIN/MAX can return NULL for empty set indepedent of the used column */ + maybe_null= 1; + result_field=0; + null_value=1; + fix_length_and_dec(); + + if (check_sum_func(thd, ref)) + return TRUE; + for (uint i= 0; i < arg_count; i++) + { + orig_args[i]= args[i]; + } + fixed= 1; + return FALSE; +} + +bool Item_sum_hybrid_simple::add() +{ + value->store(args[0]); + value->cache_value(); + null_value= value->null_value; return false; } + +void Item_sum_hybrid_simple::setup_hybrid(THD *thd, Item *item) +{ + if (!(value= Item_cache::get_cache(thd, item, item->cmp_type()))) + return; + value->setup(thd, item); + value->store(item); + if (!item->const_item()) + value->set_used_tables(RAND_TABLE_BIT); + collation.set(item->collation); +} + +double Item_sum_hybrid_simple::val_real() +{ + DBUG_ASSERT(fixed == 1); + if (null_value) + return 0.0; + double retval= value->val_real(); + if ((null_value= value->null_value)) + DBUG_ASSERT(retval == 0.0); + return retval; +} + +longlong Item_sum_hybrid_simple::val_int() +{ + DBUG_ASSERT(fixed == 1); + if (null_value) + return 0; + longlong retval= value->val_int(); + if ((null_value= value->null_value)) + DBUG_ASSERT(retval == 0); + return retval; +} + +my_decimal *Item_sum_hybrid_simple::val_decimal(my_decimal *val) +{ + DBUG_ASSERT(fixed == 1); + if (null_value) + return 0; + my_decimal *retval= value->val_decimal(val); + if ((null_value= value->null_value)) + DBUG_ASSERT(retval == NULL); + return retval; +} + +String * +Item_sum_hybrid_simple::val_str(String *str) +{ + DBUG_ASSERT(fixed == 1); + if (null_value) + return 0; + String *retval= value->val_str(str); + if ((null_value= value->null_value)) + DBUG_ASSERT(retval == NULL); + return retval; +} + +Field *Item_sum_hybrid_simple::create_tmp_field(bool group, TABLE *table) +{ + DBUG_ASSERT(0); + return NULL; +} + +void Item_sum_hybrid_simple::reset_field() +{ + switch(Item_sum_hybrid_simple::result_type()) { + case STRING_RESULT: + { + char buff[MAX_FIELD_WIDTH]; + String tmp(buff,sizeof(buff),result_field->charset()),*res; + + res=args[0]->val_str(&tmp); + if (args[0]->null_value) + { + result_field->set_null(); + result_field->reset(); + } + else + { + result_field->set_notnull(); + result_field->store(res->ptr(),res->length(),tmp.charset()); + } + break; + } + case INT_RESULT: + { + longlong nr=args[0]->val_int(); + + if (maybe_null) + { + if (args[0]->null_value) + { + nr=0; + result_field->set_null(); + } + else + result_field->set_notnull(); + } + result_field->store(nr, unsigned_flag); + break; + } + case REAL_RESULT: + { + double nr= args[0]->val_real(); + + if (maybe_null) + { + if (args[0]->null_value) + { + nr=0.0; + result_field->set_null(); + } + else + result_field->set_notnull(); + } + result_field->store(nr); + break; + } + case DECIMAL_RESULT: + { + my_decimal value_buff, *arg_dec= args[0]->val_decimal(&value_buff); + + if (maybe_null) + { + if (args[0]->null_value) + result_field->set_null(); + else + result_field->set_notnull(); + } + /* + We must store zero in the field as we will use the field value in + add() + */ + if (!arg_dec) // Null + arg_dec= &decimal_zero; + result_field->store_decimal(arg_dec); + break; + } + case ROW_RESULT: + case TIME_RESULT: + DBUG_ASSERT(0); + } +} + +void Item_sum_hybrid_simple::update_field() +{ + DBUG_ASSERT(0); +} |