diff options
Diffstat (limited to 'sql/item_func.cc')
-rw-r--r-- | sql/item_func.cc | 1868 |
1 files changed, 1531 insertions, 337 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc index 96250522c4a..680f3608d0d 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -28,6 +28,9 @@ #include <time.h> #include <ft_global.h> +#include "sp_head.h" +#include "sp_rcontext.h" +#include "sp.h" bool check_reserved_words(LEX_STRING *name) { @@ -42,10 +45,10 @@ bool check_reserved_words(LEX_STRING *name) static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname) { - my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0), - c1.collation->name,c1.derivation_name(), - c2.collation->name,c2.derivation_name(), - fname); + my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0), + c1.collation->name, c1.derivation_name(), + c2.collation->name, c2.derivation_name(), + fname); } static void my_coll_agg_error(DTCollation &c1, @@ -53,11 +56,11 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c3, const char *fname) { - my_error(ER_CANT_AGGREGATE_3COLLATIONS,MYF(0), - c1.collation->name,c1.derivation_name(), - c2.collation->name,c2.derivation_name(), - c3.collation->name,c3.derivation_name(), - fname); + my_error(ER_CANT_AGGREGATE_3COLLATIONS, MYF(0), + c1.collation->name, c1.derivation_name(), + c2.collation->name, c2.derivation_name(), + c3.collation->name, c3.derivation_name(), + fname); } @@ -71,7 +74,7 @@ static void my_coll_agg_error(Item** args, uint count, const char *fname) args[2]->collation, fname); else - my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),fname); + my_error(ER_CANT_AGGREGATE_NCOLLATIONS, MYF(0), fname); } @@ -187,8 +190,15 @@ bool Item_func::agg_arg_charsets(DTCollation &coll, res= TRUE; break; // we cannot return here, we need to restore "arena". } - conv->fix_fields(thd, 0, &conv); + if ((*arg)->type() == FIELD_ITEM) + ((Item_field *)(*arg))->no_const_subst= 1; + /* + We do not check conv->fixed, because Item_func_conv_charset which can + be return by safe_charset_converter can't be fixed at creation, also + it do not need tables (second argument) for name resolving + */ *arg= conv; + conv->fix_fields(thd, 0, arg); } if (arena) thd->restore_backup_item_arena(arena, &backup); @@ -274,8 +284,8 @@ Item_func::Item_func(THD *thd, Item_func *item) item. RETURN VALUES - 0 ok - 1 Got error. Stored with my_error(). + FALSE ok + TRUE Got error. Stored with my_error(). */ bool @@ -291,7 +301,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) const_item_cache=1; if (check_stack_overrun(thd, buff)) - return 1; // Fatal error if flag is set! + return TRUE; // Fatal error if flag is set! if (arg_count) { // Print purify happy for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++) @@ -302,8 +312,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) We shouldn't call fix_fields() twice, so check 'fixed' field first */ if ((!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg))) - return 1; /* purecov: inspected */ - + return TRUE; /* purecov: inspected */ item= *arg; if (allowed_arg_cols) @@ -329,10 +338,10 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) } } fix_length_and_dec(); - if (thd->net.last_errno) // An error inside fix_length_and_dec occured - return 1; + if (thd->net.report_error) // An error inside fix_length_and_dec occured + return TRUE; fixed= 1; - return 0; + return FALSE; } bool Item_func::walk (Item_processor processor, byte *argument) @@ -349,6 +358,71 @@ bool Item_func::walk (Item_processor processor, byte *argument) return (this->*processor)(argument); } +void Item_func::traverse_cond(Cond_traverser traverser, + void *argument, traverse_order order) +{ + if (arg_count) + { + Item **arg,**arg_end; + + switch (order) { + case(PREFIX): + (*traverser)(this, argument); + for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++) + { + (*arg)->traverse_cond(traverser, argument, order); + } + break; + case (POSTFIX): + for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++) + { + (*arg)->traverse_cond(traverser, argument, order); + } + (*traverser)(this, argument); + } + } +} + + + +/* + Transform an Item_func object with a transformer callback function + + SYNOPSIS + transform() + transformer the transformer callback function to be applied to the nodes + of the tree of the object + argument parameter to be passed to the transformer + + DESCRIPTION + The function recursively applies the transform method with the + same transformer to each argument the function. + If the call of the method for a member item returns a new item + the old item is substituted for a new one. + After this the transform method is applied to the root node + of the Item_func object. + + RETURN VALUES + Item returned as the result of transformation of the root node +*/ + +Item *Item_func::transform(Item_transformer transformer, byte *argument) +{ + if (arg_count) + { + Item **arg,**arg_end; + for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++) + { + Item *new_item= (*arg)->transform(transformer, argument); + if (!new_item) + return 0; + if (*arg != new_item) + current_thd->change_item_tree(arg, new_item); + } + } + return (this->*transformer)(argument); +} + /* See comments in Item_cmp_func::split_sum_func() */ @@ -438,6 +512,7 @@ bool Item_func::eq(const Item *item, bool binary_cmp) const return 1; } + Field *Item_func::tmp_table_field(TABLE *t_arg) { Field *res; @@ -456,25 +531,33 @@ Field *Item_func::tmp_table_field(TABLE *t_arg) res= new Field_double(max_length, maybe_null, name, t_arg, decimals); break; case STRING_RESULT: - if (max_length > 255) - res= new Field_blob(max_length, maybe_null, name, t_arg, collation.collation); - else - res= new Field_string(max_length, maybe_null, name, t_arg, collation.collation); + res= make_string_field(t_arg); + break; + case DECIMAL_RESULT: + res= new Field_new_decimal(max_length + (decimals?1:0), maybe_null, + name, t_arg, decimals); break; case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } return res; } +my_decimal *Item_func::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed); + int2my_decimal(E_DEC_FATAL_ERROR, val_int(), unsigned_flag, decimal_value); + return decimal_value; +} + String *Item_real_func::val_str(String *str) { DBUG_ASSERT(fixed == 1); - double nr=val(); + double nr= val_real(); if (null_value) return 0; /* purecov: inspected */ str->set(nr,decimals, &my_charset_bin); @@ -482,38 +565,107 @@ String *Item_real_func::val_str(String *str) } -String *Item_num_func::val_str(String *str) +void Item_func::fix_num_length_and_dec() { - DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) + decimals= 0; + for (uint i=0 ; i < arg_count ; i++) { - longlong nr=val_int(); - if (null_value) - return 0; /* purecov: inspected */ - if (!unsigned_flag) - str->set(nr,&my_charset_bin); - else - str->set((ulonglong) nr,&my_charset_bin); + set_if_bigger(decimals, args[i]->decimals); } - else + max_length= float_length(decimals); +} + + +void Item_func_numhybrid::fix_num_length_and_dec() +{} + + +/* + Set max_length/decimals of function if function is fixed point and + result length/precision depends on argument ones + + SYNOPSIS + Item_func::count_decimal_length() +*/ + +void Item_func::count_decimal_length() +{ + uint32 length= 0; + decimals= 0; + for (uint i=0 ; i < arg_count ; i++) { - double nr=val(); - if (null_value) - return 0; /* purecov: inspected */ - str->set(nr,decimals,&my_charset_bin); + set_if_bigger(decimals, args[i]->decimals); + set_if_bigger(length, (args[i]->max_length - args[i]->decimals)); } - return str; + max_length= length; + length+= decimals; + if (length < max_length) // If previous operation gave overflow + max_length= UINT_MAX32; + else + max_length= length; } -void Item_func::fix_num_length_and_dec() +/* + Set max_length of if it is maximum length of its arguments + + SYNOPSIS + Item_func::count_only_length() +*/ + +void Item_func::count_only_length() { - decimals=0; + max_length= 0; for (uint i=0 ; i < arg_count ; i++) - set_if_bigger(decimals,args[i]->decimals); - max_length=float_length(decimals); + set_if_bigger(max_length, args[i]->max_length); } + +/* + Set max_length/decimals of function if function is floating point and + result length/precision depends on argument ones + + SYNOPSIS + Item_func::count_real_length() +*/ + +void Item_func::count_real_length() +{ + uint32 length= 0; + decimals= 0; + max_length= 0; + for (uint i=0 ; i < arg_count ; i++) + { + if (decimals != NOT_FIXED_DEC) + { + set_if_bigger(decimals, args[i]->decimals); + set_if_bigger(length, (args[i]->max_length - args[i]->decimals)); + } + set_if_bigger(max_length, args[i]->max_length); + } + if (decimals != NOT_FIXED_DEC) + { + max_length= length; + length+= decimals; + if (length < max_length) // If previous operation gave overflow + max_length= UINT_MAX32; + else + max_length= length; + } +} + + + +void Item_func::signal_divide_by_null() +{ + THD *thd= current_thd; + if (thd->variables.sql_mode & MODE_ERROR_FOR_DIVISION_BY_ZERO) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DIVISION_BY_ZERO, + ER(ER_DIVISION_BY_ZERO)); + null_value= 1; +} + + Item *Item_func::get_tmp_table_item(THD *thd) { if (!with_sum_func && !const_item()) @@ -534,45 +686,215 @@ String *Item_int_func::val_str(String *str) return str; } + /* - Change from REAL_RESULT (default) to INT_RESULT if both arguments are - integers + Check arguments here to determine result's type for function with two + arguments. + + SYNOPSIS + Item_num_op::find_num_type() */ void Item_num_op::find_num_type(void) { - if (args[0]->result_type() == INT_RESULT && - args[1]->result_type() == INT_RESULT) + DBUG_ENTER("Item_num_op::find_num_type"); + DBUG_PRINT("info", ("name %s", func_name())); + DBUG_ASSERT(arg_count == 2); + Item_result r0= args[0]->result_type(); + Item_result r1= args[1]->result_type(); + + if (r0 == REAL_RESULT || r1 == REAL_RESULT || + r0 == STRING_RESULT || r1 ==STRING_RESULT) { + count_real_length(); + max_length= float_length(decimals); + hybrid_type= REAL_RESULT; + } + else if (r0 == DECIMAL_RESULT || r1 == DECIMAL_RESULT) + { + hybrid_type= DECIMAL_RESULT; + result_precision(); + } + else if (r0 == INT_RESULT && r1 == INT_RESULT) + { + decimals= 0; hybrid_type=INT_RESULT; unsigned_flag=args[0]->unsigned_flag | args[1]->unsigned_flag; + result_precision(); + } + DBUG_PRINT("info", ("Type: %s", + (hybrid_type == REAL_RESULT ? "REAL_RESULT" : + hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : + hybrid_type == INT_RESULT ? "INT_RESULT" : + "--ILLEGAL!!!--"))); + DBUG_VOID_RETURN; +} + + +/* + Set result type of function if it (type) is depends only on first argument + + SYNOPSIS + Item_func_num1::find_num_type() +*/ + +void Item_func_num1::find_num_type() +{ + DBUG_ENTER("Item_func_num1::find_num_type"); + DBUG_PRINT("info", ("name %s", func_name())); + switch (hybrid_type= args[0]->result_type()) { + case INT_RESULT: + unsigned_flag= args[0]->unsigned_flag; + break; + case STRING_RESULT: + case REAL_RESULT: + hybrid_type= REAL_RESULT; + max_length= float_length(decimals); + break; + case DECIMAL_RESULT: + break; + default: + DBUG_ASSERT(0); } + DBUG_PRINT("info", ("Type: %s", + (hybrid_type == REAL_RESULT ? "REAL_RESULT" : + hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : + hybrid_type == INT_RESULT ? "INT_RESULT" : + "--ILLEGAL!!!--"))); + DBUG_VOID_RETURN; } -String *Item_num_op::val_str(String *str) + +void Item_func_num1::fix_num_length_and_dec() +{ + decimals= args[0]->decimals; + max_length= args[0]->max_length; +} + + +void Item_func_numhybrid::fix_length_and_dec() +{ + fix_num_length_and_dec(); + find_num_type(); +} + + +String *Item_func_numhybrid::val_str(String *str) { DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) + switch (hybrid_type) { + case DECIMAL_RESULT: { - longlong nr=val_int(); + my_decimal decimal_value, *val; + if (!(val= decimal_op(&decimal_value))) + return 0; // null is set + my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val); + my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str); + break; + } + case INT_RESULT: + { + longlong nr= int_op(); if (null_value) return 0; /* purecov: inspected */ if (!unsigned_flag) str->set(nr,&my_charset_bin); else str->set((ulonglong) nr,&my_charset_bin); + break; } - else + case REAL_RESULT: { - double nr=val(); + double nr= real_op(); if (null_value) return 0; /* purecov: inspected */ str->set(nr,decimals,&my_charset_bin); + break; + } + default: + DBUG_ASSERT(0); } return str; } +double Item_func_numhybrid::val_real() +{ + DBUG_ASSERT(fixed == 1); + switch (hybrid_type) { + case DECIMAL_RESULT: + { + my_decimal decimal_value, *val; + double result; + if (!(val= decimal_op(&decimal_value))) + return 0.0; // null is set + my_decimal2double(E_DEC_FATAL_ERROR, val, &result); + return result; + } + case INT_RESULT: + return (double)int_op(); + case REAL_RESULT: + return real_op(); + default: + DBUG_ASSERT(0); + } + return 0.0; +} + + +longlong Item_func_numhybrid::val_int() +{ + DBUG_ASSERT(fixed == 1); + switch (hybrid_type) { + case DECIMAL_RESULT: + { + my_decimal decimal_value, *val; + if (!(val= decimal_op(&decimal_value))) + return 0; // null is set + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result); + return result; + } + case INT_RESULT: + return int_op(); + case REAL_RESULT: + return (longlong)real_op(); + default: + DBUG_ASSERT(0); + } + return 0; +} + + +my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value) +{ + my_decimal *val= decimal_value; + DBUG_ASSERT(fixed == 1); + switch (hybrid_type) { + case DECIMAL_RESULT: + val= decimal_op(decimal_value); + break; + case INT_RESULT: + { + longlong result= int_op(); + int2my_decimal(E_DEC_FATAL_ERROR, result, unsigned_flag, decimal_value); + break; + } + case REAL_RESULT: + { + double result= int_op(); + double2my_decimal(E_DEC_FATAL_ERROR, result, decimal_value); + break; + } + case STRING_RESULT: + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } + return val; +} + + void Item_func_signed::print(String *str) { str->append("cast(", 5); @@ -591,26 +913,98 @@ void Item_func_unsigned::print(String *str) } -double Item_func_plus::val() +String *Item_decimal_typecast::val_str(String *str) { - DBUG_ASSERT(fixed == 1); - double value=args[0]->val()+args[1]->val(); + my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); + my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, &tmp_buf); + my_decimal2string(E_DEC_FATAL_ERROR, &tmp_buf, 0, 0, 0, str); + return str; +} + + +double Item_decimal_typecast::val_real() +{ + my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); + double res; + my_decimal2double(E_DEC_FATAL_ERROR, tmp, &res); + return res; +} + + +longlong Item_decimal_typecast::val_int() +{ + my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); + longlong res; + my_decimal2int(E_DEC_FATAL_ERROR, tmp, unsigned_flag, &res); + return res; +} + + +my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec) +{ + my_decimal tmp_buf, *tmp= args[0]->val_decimal(&tmp_buf); + my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, dec); + return dec; +} + + +double Item_func_plus::real_op() +{ + double value= args[0]->val_real() + args[1]->val_real(); if ((null_value=args[0]->null_value || args[1]->null_value)) return 0.0; return value; } -longlong Item_func_plus::val_int() + +longlong Item_func_plus::int_op() { - DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) - { - longlong value=args[0]->val_int()+args[1]->val_int(); - if ((null_value=args[0]->null_value || args[1]->null_value)) - return 0; - return value; - } - return (longlong) Item_func_plus::val(); + longlong value=args[0]->val_int()+args[1]->val_int(); + if ((null_value=args[0]->null_value || args[1]->null_value)) + return 0; + return value; +} + + +/* + Calculate plus of two decimail's + + SYNOPSIS + decimal_op() + decimal_value Buffer that can be used to store result + + RETURN + 0 Value was NULL; In this case null_value is set + # Value of operation as a decimal +*/ + +my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value) +{ + my_decimal value1, *val1; + my_decimal value2, *val2; + val1= args[0]->val_decimal(&value1); + if ((null_value= args[0]->null_value)) + return 0; + val2= args[1]->val_decimal(&value2); + if ((null_value= (args[1]->null_value || + my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, val1, + val2) > 1))) + return 0; + return decimal_value; +} + +/* + Set precision of results for additive operations (+ and -) + + SYNOPSIS + Item_func_additive_op::result_precision() +*/ +void Item_func_additive_op::result_precision() +{ + decimals= max(args[0]->decimals, args[1]->decimals); + max_length= (max(args[0]->max_length - args[0]->decimals, + args[1]->max_length - args[1]->decimals) + + decimals + 1); } @@ -628,84 +1022,168 @@ void Item_func_minus::fix_length_and_dec() } -double Item_func_minus::val() +double Item_func_minus::real_op() { - DBUG_ASSERT(fixed == 1); - double value=args[0]->val() - args[1]->val(); + double value= args[0]->val_real() - args[1]->val_real(); if ((null_value=args[0]->null_value || args[1]->null_value)) return 0.0; return value; } -longlong Item_func_minus::val_int() + +longlong Item_func_minus::int_op() { - DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) - { - longlong value=args[0]->val_int() - args[1]->val_int(); - if ((null_value=args[0]->null_value || args[1]->null_value)) - return 0; - return value; - } - return (longlong) Item_func_minus::val(); + longlong value=args[0]->val_int() - args[1]->val_int(); + if ((null_value=args[0]->null_value || args[1]->null_value)) + return 0; + return value; } -double Item_func_mul::val() +/* See Item_func_plus::decimal_op for comments */ + +my_decimal *Item_func_minus::decimal_op(my_decimal *decimal_value) +{ + my_decimal value1, *val1; + my_decimal value2, *val2= + + val1= args[0]->val_decimal(&value1); + if ((null_value= args[0]->null_value)) + return 0; + val2= args[1]->val_decimal(&value2); + if ((null_value= (args[1]->null_value || + my_decimal_sub(E_DEC_FATAL_ERROR, decimal_value, val1, + val2) > 1))) + return 0; + return decimal_value; +} + + +double Item_func_mul::real_op() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val()*args[1]->val(); + double value= args[0]->val_real() * args[1]->val_real(); if ((null_value=args[0]->null_value || args[1]->null_value)) - return 0.0; /* purecov: inspected */ + return 0.0; return value; } -longlong Item_func_mul::val_int() + +longlong Item_func_mul::int_op() { DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) - { - longlong value=args[0]->val_int()*args[1]->val_int(); - if ((null_value=args[0]->null_value || args[1]->null_value)) - return 0; /* purecov: inspected */ - return value; - } - return (longlong) Item_func_mul::val(); + longlong value=args[0]->val_int()*args[1]->val_int(); + if ((null_value=args[0]->null_value || args[1]->null_value)) + return 0; + return value; } -double Item_func_div::val() +/* See Item_func_plus::decimal_op for comments */ + +my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value) +{ + my_decimal value1, *val1; + my_decimal value2, *val2; + val1= args[0]->val_decimal(&value1); + if ((null_value= args[0]->null_value)) + return 0; + val2= args[1]->val_decimal(&value2); + if ((null_value= (args[1]->null_value || + my_decimal_mul(E_DEC_FATAL_ERROR, decimal_value, val1, + val2) > 1))) + return 0; + return decimal_value; +} + + +void Item_func_mul::result_precision() +{ + decimals= args[0]->decimals + args[1]->decimals; + max_length= ((args[0]->max_length - args[0]->decimals) + + (args[1]->max_length - args[1]->decimals) + + decimals); +} + + +double Item_func_div::real_op() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); - double val2=args[1]->val(); - if ((null_value= val2 == 0.0 || args[0]->null_value || args[1]->null_value)) + double value= args[0]->val_real(); + double val2= args[1]->val_real(); + if ((null_value= args[0]->null_value || args[1]->null_value)) + return 0.0; + if (val2 == 0.0) + { + signal_divide_by_null(); return 0.0; + } return value/val2; } -longlong Item_func_div::val_int() + +my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value) { - DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) - { - longlong value=args[0]->val_int(); - longlong val2=args[1]->val_int(); - if ((null_value= val2 == 0 || args[0]->null_value || args[1]->null_value)) - return 0; - return value/val2; + my_decimal value1, *val1; + my_decimal value2, *val2; + + val1= args[0]->val_decimal(&value1); + if ((null_value= args[0]->null_value)) + return 0; + val2= args[1]->val_decimal(&value2); + if ((null_value= args[1]->null_value)) + return 0; + switch (my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value, + val1, val2, DECIMAL_DIV_SCALE_INCREASE)) { + case E_DEC_TRUNCATED: + case E_DEC_OK: + return decimal_value; + case E_DEC_DIV_ZERO: + signal_divide_by_null(); + default: + null_value= 1; // Safety + return 0; } - return (longlong) Item_func_div::val(); } + +void Item_func_div::result_precision() +{ + decimals= (args[0]->decimals + args[0]->decimals + + DECIMAL_DIV_SCALE_INCREASE); + max_length= ((args[0]->max_length - args[0]->decimals) + + (args[1]->max_length - args[1]->decimals) + + decimals); +} + + void Item_func_div::fix_length_and_dec() { - decimals=max(args[0]->decimals,args[1]->decimals)+2; - set_if_smaller(decimals, NOT_FIXED_DEC); - max_length=args[0]->max_length - args[0]->decimals + decimals; - uint tmp=float_length(decimals); - set_if_smaller(max_length,tmp); - maybe_null=1; + DBUG_ENTER("Item_func_div::fix_length_and_dec"); + Item_num_op::fix_length_and_dec(); + switch(hybrid_type) { + case REAL_RESULT: + { + decimals=max(args[0]->decimals,args[1]->decimals)+2; + set_if_smaller(decimals, NOT_FIXED_DEC); + max_length=args[0]->max_length - args[0]->decimals + decimals; + uint tmp=float_length(decimals); + set_if_smaller(max_length,tmp); + break; + } + case INT_RESULT: + hybrid_type= DECIMAL_RESULT; + DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT")); + result_precision(); + break; + case DECIMAL_RESULT: + result_precision(); + break; + default: + DBUG_ASSERT(0); + } + maybe_null= 1; // devision by zero + DBUG_VOID_RETURN; } @@ -715,8 +1193,13 @@ longlong Item_func_int_div::val_int() DBUG_ASSERT(fixed == 1); longlong value=args[0]->val_int(); longlong val2=args[1]->val_int(); - if ((null_value= val2 == 0 || args[0]->null_value || args[1]->null_value)) + if ((null_value= (args[0]->null_value || args[1]->null_value))) + return 0; + if (val2 == 0) + { + signal_divide_by_null(); return 0; + } return (unsigned_flag ? (ulonglong) value / (ulonglong) val2 : value / val2); @@ -725,133 +1208,179 @@ longlong Item_func_int_div::val_int() void Item_func_int_div::fix_length_and_dec() { - find_num_type(); max_length=args[0]->max_length - args[0]->decimals; maybe_null=1; + unsigned_flag=args[0]->unsigned_flag | args[1]->unsigned_flag; } -double Item_func_mod::val() -{ - DBUG_ASSERT(fixed == 1); - double x= args[0]->val(); - double y= args[1]->val(); - if ((null_value= (y == 0.0) || args[0]->null_value || args[1]->null_value)) - return 0.0; /* purecov: inspected */ - return fmod(x, y); -} - -longlong Item_func_mod::val_int() +longlong Item_func_mod::int_op() { DBUG_ASSERT(fixed == 1); longlong value= args[0]->val_int(); longlong val2= args[1]->val_int(); - if ((null_value=val2 == 0 || args[0]->null_value || args[1]->null_value)) + if ((null_value= args[0]->null_value || args[1]->null_value)) return 0; /* purecov: inspected */ + if (val2 == 0) + { + signal_divide_by_null(); + return 0; + } return value % val2; } -void Item_func_mod::fix_length_and_dec() +double Item_func_mod::real_op() { - Item_num_op::fix_length_and_dec(); + DBUG_ASSERT(fixed == 1); + double value= args[0]->val_real(); + double val2= args[1]->val_real(); + if ((null_value= args[0]->null_value || args[1]->null_value)) + return 0.0; /* purecov: inspected */ + if (val2 == 0.0) + { + signal_divide_by_null(); + return 0.0; + } + return fmod(value,val2); } -double Item_func_neg::val() +my_decimal *Item_func_mod::decimal_op(my_decimal *decimal_value) { - DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); - null_value=args[0]->null_value; + my_decimal value1, *val1; + my_decimal value2, *val2; + + val1= args[0]->val_decimal(&value1); + if ((null_value= args[0]->null_value)) + return 0; + val2= args[1]->val_decimal(&value2); + if ((null_value= args[1]->null_value)) + return 0; + switch (my_decimal_mod(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value, + val1, val2)) { + case E_DEC_TRUNCATED: + case E_DEC_OK: + return decimal_value; + case E_DEC_DIV_ZERO: + signal_divide_by_null(); + default: + null_value= 1; + return 0; + } +} + + +void Item_func_mod::result_precision() +{ + decimals= max(args[0]->decimals, args[1]->decimals); + max_length= max(args[0]->max_length, args[1]->max_length); +} + + +double Item_func_neg::real_op() +{ + double value= args[0]->val_real(); + null_value= args[0]->null_value; return -value; } -longlong Item_func_neg::val_int() +longlong Item_func_neg::int_op() { - DBUG_ASSERT(fixed == 1); - longlong value=args[0]->val_int(); - null_value=args[0]->null_value; + longlong value= args[0]->val_int(); + null_value= args[0]->null_value; return -value; } +my_decimal *Item_func_neg::decimal_op(my_decimal *decimal_value) +{ + my_decimal val, *value= args[0]->val_decimal(&val); + if (!(null_value= args[0]->null_value)) + { + my_decimal2decimal(value, decimal_value); + my_decimal_neg(decimal_value); + } + return decimal_value; +} + + +void Item_func_neg::fix_num_length_and_dec() +{ + decimals= args[0]->decimals; + /* 1 add because sign can appear */ + max_length= args[0]->max_length + 1; + unsigned_flag= 0; +} + + void Item_func_neg::fix_length_and_dec() { - enum Item_result arg_result= args[0]->result_type(); - enum Item::Type arg_type= args[0]->type(); - decimals=args[0]->decimals; - max_length=args[0]->max_length; - hybrid_type= REAL_RESULT; - + DBUG_ENTER("Item_func_neg::fix_length_and_dec"); + Item_func_num1::fix_length_and_dec(); + /* - We need to account for added '-' in the following cases: - A) argument is a real or integer positive constant - in this case - argument's max_length is set to actual number of bytes occupied, and not - maximum number of bytes real or integer may require. Note that all - constants are non negative so we don't need to account for removed '-'. - B) argument returns a string. + If this is in integer context keep the context as integer if possible + (This is how multiplication and other integer functions works) */ - if (arg_result == STRING_RESULT || - (arg_type == REAL_ITEM && ((Item_real*)args[0])->value >= 0) || - (arg_type == INT_ITEM && ((Item_int*)args[0])->value > 0)) - max_length++; - - if (args[0]->result_type() == INT_RESULT) + if (hybrid_type == INT_RESULT && + args[0]->type() == INT_ITEM && + ((ulonglong) ((Item_uint*) args[0])->value >= + (ulonglong) LONGLONG_MIN)) { /* - If this is in integer context keep the context as integer - (This is how multiplication and other integer functions works) - - We must however do a special case in the case where the argument - is a unsigned bigint constant as in this case the only safe - number to convert in integer context is 9223372036854775808. - (This is needed because the lex parser doesn't anymore handle - signed integers) + Ensure that result is converted to DECIMAL, as longlong can't hold + the negated number */ - if (args[0]->type() != INT_ITEM || - ((ulonglong) ((Item_uint*) args[0])->value <= - (ulonglong) LONGLONG_MIN)) - hybrid_type= INT_RESULT; + hybrid_type= DECIMAL_RESULT; + DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT")); } + DBUG_VOID_RETURN; } -double Item_func_abs::val() +double Item_func_abs::real_op() { - DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); - null_value=args[0]->null_value; + double value= args[0]->val_real(); + null_value= args[0]->null_value; return fabs(value); } -longlong Item_func_abs::val_int() +longlong Item_func_abs::int_op() { - DBUG_ASSERT(fixed == 1); - longlong value=args[0]->val_int(); - null_value=args[0]->null_value; + longlong value= args[0]->val_int(); + null_value= args[0]->null_value; return value >= 0 ? value : -value; } -void Item_func_abs::fix_length_and_dec() +my_decimal *Item_func_abs::decimal_op(my_decimal *decimal_value) { - decimals=args[0]->decimals; - max_length=args[0]->max_length; - hybrid_type= REAL_RESULT; - if (args[0]->result_type() == INT_RESULT) + my_decimal val, *value= args[0]->val_decimal(&val); + if (!(null_value= args[0]->null_value)) { - hybrid_type= INT_RESULT; - unsigned_flag= 1; + my_decimal2decimal(value, decimal_value); + if (decimal_value->sign()) + my_decimal_neg(decimal_value); } + return decimal_value; +} + + +void Item_func_abs::fix_length_and_dec() +{ + Item_func_num1::fix_length_and_dec(); + if (hybrid_type == INT_RESULT) + unsigned_flag= 1; } /* Gateway to natural LOG function */ -double Item_func_ln::val() +double Item_func_ln::val_real() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); + double value= args[0]->val_real(); if ((null_value=(args[0]->null_value || value <= 0.0))) return 0.0; return log(value); @@ -862,15 +1391,15 @@ double Item_func_ln::val() We have to check if all values are > zero and first one is not one as these are the cases then result is not a number. */ -double Item_func_log::val() +double Item_func_log::val_real() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); + double value= args[0]->val_real(); if ((null_value=(args[0]->null_value || value <= 0.0))) return 0.0; if (arg_count == 2) { - double value2= args[1]->val(); + double value2= args[1]->val_real(); if ((null_value=(args[1]->null_value || value2 <= 0.0 || value == 1.0))) return 0.0; return log(value2) / log(value); @@ -878,47 +1407,47 @@ double Item_func_log::val() return log(value); } -double Item_func_log2::val() +double Item_func_log2::val_real() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); + double value= args[0]->val_real(); if ((null_value=(args[0]->null_value || value <= 0.0))) return 0.0; - return log(value) / log(2.0); + return log(value) / M_LN2; } -double Item_func_log10::val() +double Item_func_log10::val_real() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); + double value= args[0]->val_real(); if ((null_value=(args[0]->null_value || value <= 0.0))) return 0.0; /* purecov: inspected */ return log10(value); } -double Item_func_exp::val() +double Item_func_exp::val_real() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); + double value= args[0]->val_real(); if ((null_value=args[0]->null_value)) return 0.0; /* purecov: inspected */ return exp(value); } -double Item_func_sqrt::val() +double Item_func_sqrt::val_real() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); + double value= args[0]->val_real(); if ((null_value=(args[0]->null_value || value < 0))) return 0.0; /* purecov: inspected */ return sqrt(value); } -double Item_func_pow::val() +double Item_func_pow::val_real() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); - double val2=args[1]->val(); + double value= args[0]->val_real(); + double val2= args[1]->val_real(); if ((null_value=(args[0]->null_value || args[1]->null_value))) return 0.0; /* purecov: inspected */ return pow(value,val2); @@ -926,35 +1455,35 @@ double Item_func_pow::val() // Trigonometric functions -double Item_func_acos::val() +double Item_func_acos::val_real() { DBUG_ASSERT(fixed == 1); // the volatile's for BUG #2338 to calm optimizer down (because of gcc's bug) - volatile double value=args[0]->val(); + volatile double value= args[0]->val_real(); if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0)))) return 0.0; return fix_result(acos(value)); } -double Item_func_asin::val() +double Item_func_asin::val_real() { DBUG_ASSERT(fixed == 1); // the volatile's for BUG #2338 to calm optimizer down (because of gcc's bug) - volatile double value=args[0]->val(); + volatile double value= args[0]->val_real(); if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0)))) return 0.0; return fix_result(asin(value)); } -double Item_func_atan::val() +double Item_func_atan::val_real() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); + double value= args[0]->val_real(); if ((null_value=args[0]->null_value)) return 0.0; if (arg_count == 2) { - double val2= args[1]->val(); + double val2= args[1]->val_real(); if ((null_value=args[1]->null_value)) return 0.0; return fix_result(atan2(value,val2)); @@ -962,28 +1491,28 @@ double Item_func_atan::val() return fix_result(atan(value)); } -double Item_func_cos::val() +double Item_func_cos::val_real() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); + double value= args[0]->val_real(); if ((null_value=args[0]->null_value)) return 0.0; return fix_result(cos(value)); } -double Item_func_sin::val() +double Item_func_sin::val_real() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); + double value= args[0]->val_real(); if ((null_value=args[0]->null_value)) return 0.0; return fix_result(sin(value)); } -double Item_func_tan::val() +double Item_func_tan::val_real() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); + double value= args[0]->val_real(); if ((null_value=args[0]->null_value)) return 0.0; return fix_result(tan(value)); @@ -1044,42 +1573,172 @@ void Item_func_integer::fix_length_and_dec() decimals=0; } -longlong Item_func_ceiling::val_int() +void Item_func_int_val::fix_num_length_and_dec() { - DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); - null_value=args[0]->null_value; - return (longlong) ceil(value); + max_length= args[0]->max_length - (args[0]->decimals ? + args[0]->decimals + 1 : + 0) + 2; + uint tmp= float_length(decimals); + set_if_smaller(max_length,tmp); + decimals= 0; } -longlong Item_func_floor::val_int() + +void Item_func_int_val::find_num_type() { - DBUG_ASSERT(fixed == 1); - // the volatile's for BUG #3051 to calm optimizer down (because of gcc's bug) - volatile double value=args[0]->val(); - null_value=args[0]->null_value; - return (longlong) floor(value); + DBUG_ENTER("Item_func_int_val::find_num_type"); + DBUG_PRINT("info", ("name %s", func_name())); + switch(hybrid_type= args[0]->result_type()) + { + case STRING_RESULT: + case REAL_RESULT: + hybrid_type= REAL_RESULT; + max_length= float_length(decimals); + break; + case INT_RESULT: + case DECIMAL_RESULT: + /* + -2 because in most high position can't be used any digit for longlong + and one position for increasing value during operation + */ + if ((args[0]->max_length - args[0]->decimals) >= + (DECIMAL_LONGLONG_DIGITS - 2)) + { + hybrid_type= DECIMAL_RESULT; + } + else + { + unsigned_flag= args[0]->unsigned_flag; + hybrid_type= INT_RESULT; + } + break; + default: + DBUG_ASSERT(0); + } + DBUG_PRINT("info", ("Type: %s", + (hybrid_type == REAL_RESULT ? "REAL_RESULT" : + hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : + hybrid_type == INT_RESULT ? "INT_RESULT" : + "--ILLEGAL!!!--"))); + + DBUG_VOID_RETURN; } -void Item_func_round::fix_length_and_dec() + +longlong Item_func_ceiling::int_op() { - max_length=args[0]->max_length; - decimals=args[0]->decimals; + longlong result; + switch (args[0]->result_type()) { + case INT_RESULT: + result= args[0]->val_int(); + null_value= args[0]->null_value; + break; + case DECIMAL_RESULT: + { + my_decimal dec_buf, *dec; + if ((dec= Item_func_ceiling::decimal_op(&dec_buf))) + my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result); + else + result= 0; + break; + } + default: + result= (longlong)Item_func_ceiling::real_op(); + }; + return result; +} + + +double Item_func_ceiling::real_op() +{ + /* + the volatile's for BUG #3051 to calm optimizer down (because of gcc's + bug) + */ + volatile double value= args[0]->val_real(); + null_value= args[0]->null_value; + return ceil(value); +} + + +my_decimal *Item_func_ceiling::decimal_op(my_decimal *decimal_value) +{ + my_decimal val, *value= args[0]->val_decimal(&val); + if ((null_value= (args[0]->null_value || + my_decimal_ceiling(E_DEC_FATAL_ERROR, value, + decimal_value) > 1))) + return 0; + return decimal_value; +} + + +longlong Item_func_floor::int_op() +{ + longlong result; + switch (args[0]->result_type()) { + case INT_RESULT: + result= args[0]->val_int(); + null_value= args[0]->null_value; + break; + case DECIMAL_RESULT: + { + my_decimal dec_buf, *dec; + if ((dec= Item_func_floor::decimal_op(&dec_buf))) + my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result); + else + result= 0; + break; + } + default: + result= (longlong)Item_func_floor::real_op(); + }; + return result; +} + + +double Item_func_floor::real_op() +{ + /* + the volatile's for BUG #3051 to calm optimizer down (because of gcc's + bug) + */ + volatile double value= args[0]->val_real(); + null_value= args[0]->null_value; + return floor(value); +} + + +my_decimal *Item_func_floor::decimal_op(my_decimal *decimal_value) +{ + my_decimal val, *value= args[0]->val_decimal(&val); + if ((null_value= (args[0]->null_value || + my_decimal_floor(E_DEC_FATAL_ERROR, value, + decimal_value) > 1))) + return 0; + return decimal_value; +} + + +void Item_func_round::fix_num_length_and_dec() +{ + max_length= args[0]->max_length; + decimals= NOT_FIXED_DEC; if (args[1]->const_item()) { int tmp=(int) args[1]->val_int(); if (tmp < 0) decimals=0; else - decimals=min(tmp,NOT_FIXED_DEC); + decimals=min(tmp, NOT_FIXED_DEC); } } -double Item_func_round::val() +double Item_func_round::real_op() { - DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); + double value= args[0]->val_real(); int dec=(int) args[1]->val_int(); + if (dec > 0) + decimals= dec; // to get correct output uint abs_dec=abs(dec); double tmp; /* @@ -1106,6 +1765,57 @@ double Item_func_round::val() } +longlong Item_func_round::int_op() +{ + longlong value= args[0]->val_int(); + int dec=(int) args[1]->val_int(); + decimals= 0; + uint abs_dec; + if ((null_value= args[0]->null_value || args[1]->null_value)) + return 0; + if (dec >= 0) + return value; // integer have not digits after point + + abs_dec= -dec; + double tmp; + /* + tmp2 is here to avoid return the value with 80 bit precision + This will fix that the test round(0.1,1) = round(0.1,1) is true + */ + volatile double tmp2; + + tmp= (abs_dec < array_elements(log_10) ? + log_10[abs_dec] : pow(10.0, (double) abs_dec)); + + if (truncate) + { + if (unsigned_flag) + tmp2= floor(ulonglong2double(value)/tmp)*tmp; + else if (value >= 0) + tmp2= floor(((double)value)/tmp)*tmp; + else + tmp2= ceil(((double)value)/tmp)*tmp; + } + else + tmp2= rint(((double)value)/tmp)*tmp; + return (longlong)tmp2; +} + + +my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value) +{ + my_decimal val, *value= args[0]->val_decimal(&val); + int dec=(int) args[1]->val_int(); + if (dec > 0) + decimals= dec; // to get correct output + if ((null_value= (args[0]->null_value || args[1]->null_value || + my_decimal_round(E_DEC_FATAL_ERROR, value, dec, truncate, + decimal_value) > 1))) + return 0; + return decimal_value; +} + + bool Item_func_rand::fix_fields(THD *thd, struct st_table_list *tables, Item **ref) { @@ -1162,7 +1872,7 @@ void Item_func_rand::update_used_tables() } -double Item_func_rand::val() +double Item_func_rand::val_real() { DBUG_ASSERT(fixed == 1); return my_rnd(rand); @@ -1171,16 +1881,16 @@ double Item_func_rand::val() longlong Item_func_sign::val_int() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); + double value= args[0]->val_real(); null_value=args[0]->null_value; return value < 0.0 ? -1 : (value > 0 ? 1 : 0); } -double Item_func_units::val() +double Item_func_units::val_real() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); + double value= args[0]->val_real(); if ((null_value=args[0]->null_value)) return 0; return value*mul+add; @@ -1196,10 +1906,8 @@ void Item_func_min_max::fix_length_and_dec() for (uint i=0 ; i < arg_count ; i++) { - if (max_length < args[i]->max_length) - max_length=args[i]->max_length; - if (decimals < args[i]->decimals) - decimals=args[i]->decimals; + set_if_bigger(max_length, args[i]->max_length); + set_if_bigger(decimals, args[i]->decimals); if (!args[i]->maybe_null) maybe_null=0; cmp_type=item_cmp_type(cmp_type,args[i]->result_type()); @@ -1224,9 +1932,17 @@ String *Item_func_min_max::val_str(String *str) str->set((ulonglong) nr,&my_charset_bin); return str; } + case DECIMAL_RESULT: + { + my_decimal dec_buf, *dec_val= val_decimal(&dec_buf); + if (null_value) + return 0; + my_decimal2string(E_DEC_FATAL_ERROR, dec_val, 0, 0, 0, str); + return str; + } case REAL_RESULT: { - double nr=val(); + double nr= val_real(); if (null_value) return 0; /* purecov: inspected */ str->set(nr,decimals,&my_charset_bin); @@ -1262,7 +1978,7 @@ String *Item_func_min_max::val_str(String *str) } case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); return 0; } @@ -1270,7 +1986,7 @@ String *Item_func_min_max::val_str(String *str) } -double Item_func_min_max::val() +double Item_func_min_max::val_real() { DBUG_ASSERT(fixed == 1); double value=0.0; @@ -1279,12 +1995,12 @@ double Item_func_min_max::val() { if (null_value) { - value=args[i]->val(); + value= args[i]->val_real(); null_value=args[i]->null_value; } else { - double tmp=args[i]->val(); + double tmp= args[i]->val_real(); if (!args[i]->null_value && (tmp < value ? cmp_sign : -cmp_sign) > 0) value=tmp; } @@ -1315,6 +2031,40 @@ longlong Item_func_min_max::val_int() return value; } + +my_decimal *Item_func_min_max::val_decimal(my_decimal *dec) +{ + DBUG_ASSERT(fixed == 1); + my_decimal tmp_buf, *tmp, *res= NULL; + null_value=1; + for (uint i=0; i < arg_count ; i++) + { + if (null_value) + { + res= args[i]->val_decimal(dec); + null_value= args[i]->null_value; + } + else + { + tmp= args[i]->val_decimal(&tmp_buf); + if (args[i]->null_value) + continue; + if ((my_decimal_cmp(tmp, res) * cmp_sign) < 0) + { + if (tmp == &tmp_buf) + { + my_decimal2decimal(tmp, dec); + res= dec; + } + else + res= tmp; + } + } + } + return res; +} + + longlong Item_func_length::val_int() { DBUG_ASSERT(fixed == 1); @@ -1432,18 +2182,35 @@ longlong Item_func_field::val_int() else if (cmp_type == INT_RESULT) { longlong val= args[0]->val_int(); + if (args[0]->is_null()) + return 0; for (uint i=1; i < arg_count ; i++) { - if (val == args[i]->val_int()) + if (val == args[i]->val_int() && ! args[i]->is_null()) return (longlong) (i); } } + else if (cmp_type == DECIMAL_RESULT) + { + my_decimal dec_arg_buf, *dec_arg, + dec_buf, *dec= args[0]->val_decimal(&dec_buf); + if (args[0]->is_null()) + return 0; + for (uint i=1; i < arg_count; i++) + { + dec_arg= args[i]->val_decimal(&dec_arg_buf); + if (!args[i]->is_null() && !my_decimal_cmp(dec_arg, dec)) + return (longlong) (i); + } + } else { - double val= args[0]->val(); + double val= args[0]->val_real(); + if (args[0]->is_null()) + return 0; for (uint i=1; i < arg_count ; i++) { - if (val == args[i]->val()) + if (val == args[i]->val_real() && ! args[i]->is_null()) return (longlong) (i); } } @@ -1619,26 +2386,6 @@ longlong Item_func_bit_count::val_int() #ifdef HAVE_DLOPEN -udf_handler::~udf_handler() -{ - if (!not_original) - { - if (initialized) - { - if (u_d->func_deinit != NULL) - { - void (*deinit)(UDF_INIT *) = (void (*)(UDF_INIT*)) - u_d->func_deinit; - (*deinit)(&initid); - } - free_udf(u_d); - } - if (buffers) // Because of bug in ecc - delete [] buffers; - } -} - - bool udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, uint arg_count, Item **arguments) @@ -1649,15 +2396,14 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, DBUG_ENTER("Item_udf_func::fix_fields"); if (check_stack_overrun(thd, buff)) - DBUG_RETURN(1); // Fatal error flag is set! + DBUG_RETURN(TRUE); // Fatal error flag is set! udf_func *tmp_udf=find_udf(u_d->name.str,(uint) u_d->name.length,1); if (!tmp_udf) { - my_printf_error(ER_CANT_FIND_UDF,ER(ER_CANT_FIND_UDF),MYF(0),u_d->name.str, - errno); - DBUG_RETURN(1); + my_error(ER_CANT_FIND_UDF, MYF(0), u_d->name.str, errno); + DBUG_RETURN(TRUE); } u_d=tmp_udf; args=arguments; @@ -1674,7 +2420,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, { free_udf(u_d); - DBUG_RETURN(1); + DBUG_RETURN(TRUE); } uint i; Item **arg,**arg_end; @@ -1682,13 +2428,13 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, arg != arg_end ; arg++,i++) { - if (!(*arg)->fixed && + if (!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg)) DBUG_RETURN(1); // we can't assign 'item' before, because fix_fields() can change arg Item *item= *arg; if (item->check_cols(1)) - DBUG_RETURN(1); + DBUG_RETURN(TRUE); /* TODO: We should think about this. It is not always right way just to set an UDF result to return my_charset_bin @@ -1698,7 +2444,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, Moreover, some arguments can represent a numeric input which doesn't effect the result character set and collation. There is no a general rule for UDF. Everything depends on - the particular user definted function. + the particular user defined function. */ if (item->collation.collation->state & MY_CS_BINSORT) func->collation.set(&my_charset_bin); @@ -1709,14 +2455,19 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, const_item_cache&=item->const_item(); f_args.arg_type[i]=item->result_type(); } + //TODO: why all following memory is not allocated with 1 call of sql_alloc? if (!(buffers=new String[arg_count]) || !(f_args.args= (char**) sql_alloc(arg_count * sizeof(char *))) || - !(f_args.lengths=(ulong*) sql_alloc(arg_count * sizeof(long))) || - !(f_args.maybe_null=(char*) sql_alloc(arg_count * sizeof(char))) || - !(num_buffer= (char*) sql_alloc(ALIGN_SIZE(sizeof(double))*arg_count))) + !(f_args.lengths= (ulong*) sql_alloc(arg_count * sizeof(long))) || + !(f_args.maybe_null= (char*) sql_alloc(arg_count * sizeof(char))) || + !(num_buffer= (char*) sql_alloc(arg_count * + ALIGN_SIZE(sizeof(double)))) || + !(f_args.attributes= (char**) sql_alloc(arg_count * sizeof(char *))) || + !(f_args.attribute_lengths= (ulong*) sql_alloc(arg_count * + sizeof(long)))) { free_udf(u_d); - DBUG_RETURN(1); + DBUG_RETURN(TRUE); } } func->fix_length_and_dec(); @@ -1732,8 +2483,10 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, for (uint i=0; i < arg_count; i++) { f_args.args[i]=0; - f_args.lengths[i]=arguments[i]->max_length; - f_args.maybe_null[i]=(char) arguments[i]->maybe_null; + f_args.lengths[i]= arguments[i]->max_length; + f_args.maybe_null[i]= (char) arguments[i]->maybe_null; + f_args.attributes[i]= arguments[i]->name; + f_args.attribute_lengths[i]= arguments[i]->name_length; switch(arguments[i]->type()) { case Item::STRING_ITEM: // Constant string ! @@ -1753,7 +2506,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, } break; case Item::REAL_ITEM: - *((double*) to) = arguments[i]->val(); + *((double*) to)= arguments[i]->val_real(); if (!arguments[i]->null_value) { f_args.args[i]=to; @@ -1770,10 +2523,10 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, u_d->func_init; if ((error=(uchar) init(&initid, &f_args, thd->net.last_error))) { - my_printf_error(ER_CANT_INITIALIZE_UDF,ER(ER_CANT_INITIALIZE_UDF),MYF(0), - u_d->name.str, thd->net.last_error); + my_error(ER_CANT_INITIALIZE_UDF, MYF(0), + u_d->name.str, thd->net.last_error); free_udf(u_d); - DBUG_RETURN(1); + DBUG_RETURN(TRUE); } func->max_length=min(initid.max_length,MAX_BLOB_WIDTH); func->maybe_null=initid.maybe_null; @@ -1783,11 +2536,11 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, initialized=1; if (error) { - my_printf_error(ER_CANT_INITIALIZE_UDF,ER(ER_CANT_INITIALIZE_UDF),MYF(0), - u_d->name.str, ER(ER_UNKNOWN_ERROR)); - DBUG_RETURN(1); + my_error(ER_CANT_INITIALIZE_UDF, MYF(0), + u_d->name.str, ER(ER_UNKNOWN_ERROR)); + DBUG_RETURN(TRUE); } - DBUG_RETURN(0); + DBUG_RETURN(FALSE); } @@ -1802,6 +2555,7 @@ bool udf_handler::get_arguments() f_args.args[i]=0; switch (f_args.arg_type[i]) { case STRING_RESULT: + case DECIMAL_RESULT: { String *res=args[i]->val_str(&buffers[str_count++]); if (!(args[i]->null_value)) @@ -1820,7 +2574,7 @@ bool udf_handler::get_arguments() } break; case REAL_RESULT: - *((double*) to) = args[i]->val(); + *((double*) to)= args[i]->val_real(); if (!args[i]->null_value) { f_args.args[i]=to; @@ -1829,7 +2583,7 @@ bool udf_handler::get_arguments() break; case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } @@ -1874,8 +2628,37 @@ String *udf_handler::val_str(String *str,String *save_str) } +/* + For the moment, UDF functions are returning DECIMAL values as strings +*/ -double Item_func_udf_float::val() +my_decimal *udf_handler::val_decimal(my_bool *null_value, my_decimal *dec_buf) +{ + char buf[DECIMAL_MAX_STR_LENGTH+1], *end; + ulong res_length= DECIMAL_MAX_STR_LENGTH; + + if (get_arguments()) + { + *null_value=1; + return 0; + } + char *(*func)(UDF_INIT *, UDF_ARGS *, char *, ulong *, uchar *, uchar *)= + (char* (*)(UDF_INIT *, UDF_ARGS *, char *, ulong *, uchar *, uchar *)) + u_d->func; + + char *res= func(&initid, &f_args, buf, &res_length, &is_null, &error); + if (is_null || error) + { + *null_value= 1; + return 0; + } + end= res+ res_length; + str2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf, &end); + return dec_buf; +} + + +double Item_func_udf_float::val_real() { DBUG_ASSERT(fixed == 1); DBUG_ENTER("Item_func_udf_float::val"); @@ -1888,7 +2671,7 @@ double Item_func_udf_float::val() String *Item_func_udf_float::val_str(String *str) { DBUG_ASSERT(fixed == 1); - double nr=val(); + double nr= val_real(); if (null_value) return 0; /* purecov: inspected */ str->set(nr,decimals,&my_charset_bin); @@ -1920,6 +2703,59 @@ String *Item_func_udf_int::val_str(String *str) return str; } + +longlong Item_func_udf_decimal::val_int() +{ + my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); + longlong result; + if (null_value) + return 0; + my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result); + return result; +} + + +double Item_func_udf_decimal::val_real() +{ + my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); + double result; + if (null_value) + return 0.0; + my_decimal2double(E_DEC_FATAL_ERROR, dec, &result); + return result; +} + + +my_decimal *Item_func_udf_decimal::val_decimal(my_decimal *dec_buf) +{ + DBUG_ASSERT(fixed == 1); + DBUG_ENTER("Item_func_udf_decimal::val_decimal"); + DBUG_PRINT("info",("result_type: %d arg_count: %d", + args[0]->result_type(), arg_count)); + + DBUG_RETURN(udf.val_decimal(&null_value, dec_buf)); +} + + +String *Item_func_udf_decimal::val_str(String *str) +{ + my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); + if (null_value) + return 0; + if (str->length() < DECIMAL_MAX_STR_LENGTH) + str->length(DECIMAL_MAX_STR_LENGTH); + my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf); + my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, '0', str); + return str; +} + + +void Item_func_udf_decimal::fix_length_and_dec() +{ + fix_num_length_and_dec(); +} + + /* Default max_length is max argument length */ void Item_func_udf_str::fix_length_and_dec() @@ -1939,6 +2775,31 @@ String *Item_func_udf_str::val_str(String *str) return res; } + +/* + This has to come last in the udf_handler methods, or the compiler for IBM + AIX fails to compile with debugging enabled. (Yes, really.) + */ + +udf_handler::~udf_handler() +{ + if (!not_original) + { + if (initialized) + { + if (u_d->func_deinit != NULL) + { + void (*deinit)(UDF_INIT *) = (void (*)(UDF_INIT*)) + u_d->func_deinit; + (*deinit)(&initid); + } + free_udf(u_d); + } + if (buffers) // Because of bug in ecc + delete [] buffers; + } +} + #else bool udf_handler::get_arguments() { return 0; } #endif /* HAVE_DLOPEN */ @@ -2022,18 +2883,6 @@ void item_user_lock_free(void) void item_user_lock_release(User_level_lock *ull) { ull->locked=0; - if (mysql_bin_log.is_open()) - { - char buf[256]; - const char *command="DO RELEASE_LOCK(\""; - String tmp(buf,sizeof(buf), system_charset_info); - tmp.copy(command, strlen(command), tmp.charset()); - tmp.append(ull->key,ull->key_length); - tmp.append("\")", 2); - Query_log_event qev(current_thd, tmp.ptr(), tmp.length(),1, FALSE); - qev.error_code=0; // this query is always safe to run on slave - mysql_bin_log.write(&qev); - } if (--ull->count) pthread_cond_signal(&ull->cond); else @@ -2157,6 +3006,16 @@ longlong Item_func_get_lock::val_int() User_level_lock *ull; int error=0; + /* + In slave thread no need to get locks, everything is serialized. Anyway + there is no way to make GET_LOCK() work on slave like it did on master + (i.e. make it return exactly the same value) because we don't have the + same other concurrent threads environment. No matter what we return here, + it's not guaranteed to be same as on master. + */ + if (thd->slave_thread) + return 1; + pthread_mutex_lock(&LOCK_user_locks); if (!res || !res->length()) @@ -2280,16 +3139,17 @@ longlong Item_func_release_lock::val_int() longlong Item_func_last_insert_id::val_int() { + THD *thd= current_thd; DBUG_ASSERT(fixed == 1); if (arg_count) { - longlong value=args[0]->val_int(); - current_thd->insert_id(value); - null_value=args[0]->null_value; + longlong value= args[0]->val_int(); + thd->insert_id(value); + null_value= args[0]->null_value; + return value; // Avoid side effect of insert_id() } - else - current_thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); - return current_thd->insert_id(); + thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT); + return thd->insert_id(); } /* This function is just used to test speed of different functions */ @@ -2305,7 +3165,7 @@ longlong Item_func_benchmark::val_int() { switch (args[0]->result_type()) { case REAL_RESULT: - (void) args[0]->val(); + (void) args[0]->val_real(); break; case INT_RESULT: (void) args[0]->val_int(); @@ -2315,7 +3175,7 @@ longlong Item_func_benchmark::val_int() break; case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); return 0; } @@ -2394,7 +3254,7 @@ bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables, /* fix_fields will call Item_func_set_user_var::fix_length_and_dec */ if (Item_func::fix_fields(thd, tables, ref) || !(entry= get_variable(&thd->user_vars, name, 1))) - return 1; + return TRUE; /* Remember the last query which updated it, this way a query can later know if this variable is a constant item in the query (it is if update_query_id @@ -2420,7 +3280,7 @@ bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables, entry->collation.set(args[0]->collation.collation, DERIVATION_IMPLICIT); collation.set(entry->collation.collation, DERIVATION_IMPLICIT); cached_result_type= args[0]->result_type(); - return 0; + return FALSE; } @@ -2481,6 +3341,8 @@ bool Item_func_set_user_var::update_hash(void *ptr, uint length, entry->value[length]= 0; // Store end \0 } memcpy(entry->value,ptr,length); + if (type == DECIMAL_RESULT) + ((my_decimal*)entry->value)->fix_buffer_pointer(); entry->length= length; entry->type=type; entry->collation.set(cs, dv); @@ -2496,7 +3358,7 @@ bool Item_func_set_user_var::update_hash(void *ptr, uint length, /* Get the value of a variable as a double */ -double user_var_entry::val(my_bool *null_value) +double user_var_entry::val_real(my_bool *null_value) { if ((*null_value= (value == 0))) return 0.0; @@ -2506,6 +3368,12 @@ double user_var_entry::val(my_bool *null_value) return *(double*) value; case INT_RESULT: return (double) *(longlong*) value; + case DECIMAL_RESULT: + { + double result; + my_decimal2double(E_DEC_FATAL_ERROR, (my_decimal *)value, &result); + return result; + } case STRING_RESULT: return my_atof(value); // This is null terminated case ROW_RESULT: @@ -2528,6 +3396,12 @@ longlong user_var_entry::val_int(my_bool *null_value) return (longlong) *(double*) value; case INT_RESULT: return *(longlong*) value; + case DECIMAL_RESULT: + { + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, (my_decimal *)value, 1, &result); + return result; + } case STRING_RESULT: { int error; @@ -2556,6 +3430,9 @@ String *user_var_entry::val_str(my_bool *null_value, String *str, case INT_RESULT: str->set(*(longlong*) value, &my_charset_bin); break; + case DECIMAL_RESULT: + my_decimal2string(E_DEC_FATAL_ERROR, (my_decimal *)value, 0, 0, 0, str); + break; case STRING_RESULT: if (str->copy(value, length, collation.collation)) str= 0; // EOM error @@ -2566,19 +3443,46 @@ String *user_var_entry::val_str(my_bool *null_value, String *str, return(str); } +/* Get the value of a variable as a decimal */ + +my_decimal *user_var_entry::val_decimal(my_bool *null_value, my_decimal *val) +{ + if ((*null_value= (value == 0))) + return 0; + + switch (type) { + case REAL_RESULT: + double2my_decimal(E_DEC_FATAL_ERROR, *(double*) value, val); + break; + case INT_RESULT: + int2my_decimal(E_DEC_FATAL_ERROR, *(longlong*) value, 0, val); + break; + case DECIMAL_RESULT: + val= (my_decimal *)value; + break; + case STRING_RESULT: + str2my_decimal(E_DEC_FATAL_ERROR, value, length, collation.collation, val); + break; + case ROW_RESULT: + DBUG_ASSERT(1); // Impossible + break; + } + return(val); +} + /* This functions is invoked on SET @variable or @variable:= expression. - Evaluete (and check expression), store results. + Evaluate (and check expression), store results. SYNOPSYS Item_func_set_user_var::check() NOTES - For now it always return OK. All problem with value evalueting - will be catched by thd->net.report_error check in sql_set_variables(). + For now it always return OK. All problem with value evaluating + will be caught by thd->net.report_error check in sql_set_variables(). RETURN - 0 - OK. + FALSE OK. */ bool @@ -2589,7 +3493,7 @@ Item_func_set_user_var::check() switch (cached_result_type) { case REAL_RESULT: { - save_result.vreal= args[0]->val(); + save_result.vreal= args[0]->val_real(); break; } case INT_RESULT: @@ -2602,13 +3506,18 @@ Item_func_set_user_var::check() save_result.vstr= args[0]->val_str(&value); break; } + case DECIMAL_RESULT: + { + save_result.vdec= args[0]->val_decimal(&decimal_buff); + break; + } case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } - DBUG_RETURN(0); + DBUG_RETURN(FALSE); } @@ -2623,7 +3532,7 @@ Item_func_set_user_var::check() the value method used by the user RETURN - 0 Ok + 0 OK 1 EOM Error */ @@ -2660,9 +3569,20 @@ Item_func_set_user_var::update() DERIVATION_IMPLICIT); break; } + case DECIMAL_RESULT: + { + if (!save_result.vdec) // Null value + res= update_hash((void*) 0, 0, DECIMAL_RESULT, &my_charset_bin, + DERIVATION_NONE); + else + res= update_hash((void*) save_result.vdec, + sizeof(my_decimal), DECIMAL_RESULT, + &my_charset_bin, DERIVATION_NONE); + break; + } case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } @@ -2670,12 +3590,12 @@ Item_func_set_user_var::update() } -double Item_func_set_user_var::val() +double Item_func_set_user_var::val_real() { DBUG_ASSERT(fixed == 1); check(); update(); // Store expression - return entry->val(&null_value); + return entry->val_real(&null_value); } longlong Item_func_set_user_var::val_int() @@ -2695,6 +3615,15 @@ String *Item_func_set_user_var::val_str(String *str) } +my_decimal *Item_func_set_user_var::val_decimal(my_decimal *val) +{ + DBUG_ASSERT(fixed == 1); + check(); + update(); // Store expression + return entry->val_decimal(&null_value, val); +} + + void Item_func_set_user_var::print(String *str) { str->append("(@", 2); @@ -2705,6 +3634,16 @@ void Item_func_set_user_var::print(String *str) } +void Item_func_set_user_var::print_as_stmt(String *str) +{ + str->append("set @", 5); + str->append(name.str, name.length); + str->append(":=", 2); + args[0]->print(str); + str->append(')'); +} + + String * Item_func_get_user_var::val_str(String *str) { @@ -2716,12 +3655,21 @@ Item_func_get_user_var::val_str(String *str) } -double Item_func_get_user_var::val() +double Item_func_get_user_var::val_real() { DBUG_ASSERT(fixed == 1); if (!var_entry) return 0.0; // No such variable - return (var_entry->val(&null_value)); + return (var_entry->val_real(&null_value)); +} + + +my_decimal *Item_func_get_user_var::val_decimal(my_decimal *dec) +{ + DBUG_ASSERT(fixed == 1); + if (!var_entry) + return 0; + return var_entry->val_decimal(&null_value, dec); } @@ -2752,7 +3700,7 @@ longlong Item_func_get_user_var::val_int() RETURN 0 OK - 1 Failed to put appropiate record into binary log + 1 Failed to put appropriate record into binary log */ @@ -2776,8 +3724,8 @@ int get_var_with_binlog(THD *thd, LEX_STRING &name, that it gets into the binlog (if it didn't, the slave could be influenced by a variable of the same name previously set by another thread). - We create it like if it had been explicitely set with SET before. - The 'new' mimicks what sql_yacc.yy does when 'SET @a=10;'. + We create it like if it had been explicitly set with SET before. + The 'new' mimics what sql_yacc.yy does when 'SET @a=10;'. sql_set_variables() is what is called from 'case SQLCOM_SET_OPTION' in dispatch_command()). Instead of building a one-element list to pass to sql_set_variables(), we could instead manually call check() and update(); @@ -2808,7 +3756,7 @@ int get_var_with_binlog(THD *thd, LEX_STRING &name, uint size; /* First we need to store value of var_entry, when the next situation - appers: + appears: > set @a:=1; > insert into t1 values (@a), (@a:=@a+1), (@a:=@a+1); We have to write to binlog value @a= 1; @@ -2870,7 +3818,13 @@ void Item_func_get_user_var::fix_length_and_dec() case STRING_RESULT: max_length= MAX_BLOB_WIDTH; break; + case DECIMAL_RESULT: + max_length= DECIMAL_MAX_LENGTH; + decimals= min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1); + break; case ROW_RESULT: // Keep compiler happy + default: + DBUG_ASSERT(0); break; } } @@ -3059,7 +4013,7 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) !args[0]->const_during_execution()) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"AGAINST"); - return 1; + return TRUE; } const_item_cache=0; @@ -3082,7 +4036,7 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) if (key == NO_SUCH_KEY && !(flags & FT_BOOL)) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH"); - return 1; + return TRUE; } table=((Item_field *)item)->field->table; table->fulltext_searched=1; @@ -3098,7 +4052,7 @@ bool Item_func_match::fix_index() if (key == NO_SUCH_KEY) return 0; - for (keynr=0 ; keynr < table->keys ; keynr++) + for (keynr=0 ; keynr < table->s->keys ; keynr++) { if ((table->key_info[keynr].flags & HA_FULLTEXT) && (table->keys_in_use_for_query.is_set(keynr))) @@ -3164,7 +4118,8 @@ err: key=NO_SUCH_KEY; return 0; } - my_error(ER_FT_MATCHING_KEY_NOT_FOUND,MYF(0)); + my_message(ER_FT_MATCHING_KEY_NOT_FOUND, + ER(ER_FT_MATCHING_KEY_NOT_FOUND), MYF(0)); return 1; } @@ -3185,7 +4140,7 @@ bool Item_func_match::eq(const Item *item, bool binary_cmp) const } -double Item_func_match::val() +double Item_func_match::val_real() { DBUG_ASSERT(fixed == 1); DBUG_ENTER("Item_func_match::val"); @@ -3293,7 +4248,7 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name, { if (!var->is_struct()) { - net_printf(thd, ER_VARIABLE_IS_NOT_STRUCT, base_name->str); + my_error(ER_VARIABLE_IS_NOT_STRUCT, MYF(0), base_name->str); return 0; } } @@ -3401,6 +4356,229 @@ longlong Item_func_is_used_lock::val_int() } +longlong Item_func_row_count::val_int() +{ + DBUG_ASSERT(fixed == 1); + THD *thd= current_thd; + + return thd->row_count_func; +} + + +Item_func_sp::Item_func_sp(sp_name *name) + :Item_func(), m_name(name), m_sp(NULL) +{ + maybe_null= 1; + m_name->init_qname(current_thd); + dummy_table= (TABLE *)sql_alloc(sizeof(TABLE)); + bzero(dummy_table, sizeof(TABLE)); +} + +Item_func_sp::Item_func_sp(sp_name *name, List<Item> &list) + :Item_func(list), m_name(name), m_sp(NULL) +{ + maybe_null= 1; + m_name->init_qname(current_thd); + dummy_table= (TABLE *)sql_alloc(sizeof(TABLE)); + bzero(dummy_table, sizeof(TABLE)); +} + +const char * +Item_func_sp::func_name() const +{ + THD *thd= current_thd; + /* Calculate length to avoid reallocation of string for sure */ + uint len= ((m_name->m_db.length + + m_name->m_name.length)*2 + //characters*quoting + 2 + // ` and ` + 1 + // . + 1 + // end of string + ALIGN_SIZE(1)); // to avoid String reallocation + String qname((char *)alloc_root(thd->mem_root, len), len, + system_charset_info); + + qname.length(0); + append_identifier(thd, &qname, m_name->m_db.str, m_name->m_db.length); + qname.append('.'); + append_identifier(thd, &qname, m_name->m_name.str, m_name->m_name.length); + return qname.ptr(); +} + + +Field * +Item_func_sp::sp_result_field(void) const +{ + Field *field= 0; + THD *thd= current_thd; + DBUG_ENTER("Item_func_sp::sp_result_field"); + if (m_sp) + { + if (dummy_table->s == NULL) + { + char *empty_name= (char *) ""; + TABLE_SHARE *share; + dummy_table->s= share= &dummy_table->share_not_to_be_used; + dummy_table->alias = empty_name; + dummy_table->maybe_null = maybe_null; + dummy_table->in_use= current_thd; + share->table_cache_key = empty_name; + share->table_name = empty_name; + share->table_name = empty_name; + } + field= m_sp->make_field(max_length, name, dummy_table); + } + DBUG_RETURN(field); +} + + +int +Item_func_sp::execute(Item **itp) +{ + DBUG_ENTER("Item_func_sp::execute"); + THD *thd= current_thd; + int res; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + st_sp_security_context save_ctx; +#endif + + if (! m_sp) + m_sp= sp_find_function(thd, m_name, TRUE); // cache only + if (! m_sp) + { + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); + DBUG_RETURN(-1); + } + +#ifndef EMBEDDED_LIBRARY + my_bool nsok= thd->net.no_send_ok; + thd->net.no_send_ok= TRUE; +#endif + +#ifndef NO_EMBEDDED_ACCESS_CHECKS + if (check_procedure_access(thd, EXECUTE_ACL, + m_sp->m_db.str, m_sp->m_name.str, 0)) + DBUG_RETURN(-1); + sp_change_security_context(thd, m_sp, &save_ctx); + if (save_ctx.changed && + check_procedure_access(thd, EXECUTE_ACL, + m_sp->m_db.str, m_sp->m_name.str, 0)) + { + sp_restore_security_context(thd, m_sp, &save_ctx); + DBUG_RETURN(-1); + } +#endif + + res= m_sp->execute_function(thd, args, arg_count, itp); + +#ifndef NO_EMBEDDED_ACCESS_CHECKS + sp_restore_security_context(thd, m_sp, &save_ctx); +#endif + +#ifndef EMBEDDED_LIBRARY + thd->net.no_send_ok= nsok; +#endif + DBUG_RETURN(res); +} + + +void +Item_func_sp::make_field(Send_field *tmp_field) +{ + Field *field; + DBUG_ENTER("Item_func_sp::make_field"); + if (! m_sp) + m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only + if ((field= sp_result_field())) + { + field->make_field(tmp_field); + delete field; + DBUG_VOID_RETURN; + } + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); + init_make_field(tmp_field, MYSQL_TYPE_VARCHAR); + DBUG_VOID_RETURN; +} + + +enum enum_field_types +Item_func_sp::field_type() const +{ + Field *field= 0; + DBUG_ENTER("Item_func_sp::field_type"); + + if (! m_sp) + m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only + if ((field= sp_result_field())) + { + enum_field_types result= field->type(); + delete field; + DBUG_RETURN(result); + } + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); + DBUG_RETURN(MYSQL_TYPE_VARCHAR); +} + + +Item_result +Item_func_sp::result_type() const +{ + Field *field= 0; + DBUG_ENTER("Item_func_sp::result_type"); + DBUG_PRINT("info", ("m_sp = %p", m_sp)); + + if (! m_sp) + m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only + if ((field= sp_result_field())) + { + Item_result result= field->result_type(); + delete field; + DBUG_RETURN(result); + } + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); + DBUG_RETURN(STRING_RESULT); +} + +void +Item_func_sp::fix_length_and_dec() +{ + DBUG_ENTER("Item_func_sp::fix_length_and_dec"); + + if (! m_sp) + m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only + if (! m_sp) + { + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); + } + else + { + switch (result_type()) { + case STRING_RESULT: + maybe_null= 1; + max_length= MAX_BLOB_WIDTH; + break; + case REAL_RESULT: + decimals= NOT_FIXED_DEC; + max_length= float_length(decimals); + break; + case INT_RESULT: + decimals= 0; + max_length= 21; + break; + case DECIMAL_RESULT: + // TODO: where to find real precision and scale? + decimals= min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1); + max_length= DECIMAL_MAX_LENGTH; + case ROW_RESULT: + default: + // This case should never be chosen + DBUG_ASSERT(0); + break; + } + } + DBUG_VOID_RETURN; +} + + longlong Item_func_found_rows::val_int() { DBUG_ASSERT(fixed == 1); @@ -3408,3 +4586,19 @@ longlong Item_func_found_rows::val_int() return thd->found_rows(); } + +Field * +Item_func_sp::tmp_table_field(TABLE *t_arg) +{ + Field *res= 0; + enum_field_types ftype; + DBUG_ENTER("Item_func_sp::tmp_table_field"); + + if (m_sp) + res= m_sp->make_field(max_length, (const char *)name, t_arg); + + if (!res) + res= Item_func::tmp_table_field(t_arg); + + DBUG_RETURN(res); +} |