diff options
author | unknown <monty@mysql.com> | 2005-02-19 19:00:41 +0200 |
---|---|---|
committer | unknown <monty@mysql.com> | 2005-02-19 19:00:41 +0200 |
commit | 6c8ae9d65ec0fe3ee9c8349dd7f8cc7336c958dd (patch) | |
tree | 5a44a1612b30cc4765614c35e5172d824e16bb09 | |
parent | 0bc02450a61180a5827ce4ab2a2b3538c1c1ce91 (diff) | |
parent | 64cc538bda5908e2688a1ba08a9ff156971a102b (diff) | |
download | mariadb-git-6c8ae9d65ec0fe3ee9c8349dd7f8cc7336c958dd.tar.gz |
Merge bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/my/mysql-5.0
BUILD/SETUP.sh:
Auto merged
mysql-test/r/ps_6bdb.result:
Auto merged
sql/item.h:
Auto merged
sql/item_func.cc:
Auto merged
sql/item_func.h:
Auto merged
sql/log_event.cc:
Auto merged
sql/my_decimal.cc:
Auto merged
sql/my_decimal.h:
Auto merged
sql/mysql_priv.h:
Auto merged
sql/sp_head.cc:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_class.cc:
Auto merged
sql/sql_select.cc:
Auto merged
-rw-r--r-- | include/decimal.h | 13 | ||||
-rw-r--r-- | mysql-test/r/func_group.result | 20 | ||||
-rw-r--r-- | mysql-test/r/func_set.result | 6 | ||||
-rw-r--r-- | mysql-test/r/type_decimal.result | 23 | ||||
-rw-r--r-- | mysql-test/r/type_newdecimal.result | 2 | ||||
-rw-r--r-- | mysql-test/t/func_group.test | 5 | ||||
-rw-r--r-- | mysql-test/t/func_set.test | 2 | ||||
-rw-r--r-- | mysql-test/t/type_decimal.test | 3 | ||||
-rw-r--r-- | sql/item.cc | 123 | ||||
-rw-r--r-- | sql/item.h | 10 | ||||
-rw-r--r-- | sql/item_func.cc | 182 | ||||
-rw-r--r-- | sql/item_func.h | 21 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 13 | ||||
-rw-r--r-- | sql/item_sum.cc | 549 | ||||
-rw-r--r-- | sql/item_sum.h | 15 | ||||
-rw-r--r-- | sql/log_event.cc | 2 | ||||
-rw-r--r-- | sql/my_decimal.cc | 35 | ||||
-rw-r--r-- | sql/my_decimal.h | 56 | ||||
-rw-r--r-- | sql/mysql_priv.h | 2 | ||||
-rw-r--r-- | sql/protocol.cc | 24 | ||||
-rw-r--r-- | sql/protocol_cursor.cc | 9 | ||||
-rw-r--r-- | sql/sp_head.cc | 72 | ||||
-rw-r--r-- | sql/sp_rcontext.cc | 27 | ||||
-rw-r--r-- | sql/sql_analyse.cc | 43 | ||||
-rw-r--r-- | sql/sql_base.cc | 7 | ||||
-rw-r--r-- | sql/sql_class.cc | 33 | ||||
-rw-r--r-- | sql/sql_select.cc | 5 | ||||
-rw-r--r-- | strings/decimal.c | 233 |
28 files changed, 852 insertions, 683 deletions
diff --git a/include/decimal.h b/include/decimal.h index 1e0ee97c267..3f4a2122c57 100644 --- a/include/decimal.h +++ b/include/decimal.h @@ -17,7 +17,9 @@ #ifndef _decimal_h #define _decimal_h -typedef enum {TRUNCATE=0, HALF_EVEN, HALF_UP, CEILING, FLOOR} decimal_round_mode; +typedef enum +{TRUNCATE=0, HALF_EVEN, HALF_UP, CEILING, FLOOR} + decimal_round_mode; typedef int32 decimal_digit; typedef struct st_decimal { @@ -26,11 +28,10 @@ typedef struct st_decimal { decimal_digit *buf; } decimal; +int internal_str2dec(const char *from, decimal *to, char **end, my_bool fixed); int decimal2string(decimal *from, char *to, int *to_len, int fixed_precision, int fixed_decimals, char filler); -int string2decimal(char *from, decimal *to, char **end); -int string2decimal_fixed(char *from, decimal *to, char **end); int decimal2ulonglong(decimal *from, ulonglong *to); int ulonglong2decimal(ulonglong from, decimal *to); int decimal2longlong(decimal *from, longlong *to); @@ -51,10 +52,14 @@ int decimal_cmp(decimal *from1, decimal *from2); int decimal_mul(decimal *from1, decimal *from2, decimal *to); int decimal_div(decimal *from1, decimal *from2, decimal *to, int scale_incr); int decimal_mod(decimal *from1, decimal *from2, decimal *to); -int decimal_round(decimal *from, decimal *to, int new_scale, decimal_round_mode mode); +int decimal_round(decimal *from, decimal *to, int new_scale, + decimal_round_mode mode); int decimal_is_zero(decimal *from); void max_decimal(int precision, int frac, decimal *to); +#define string2decimal(A,B,C) internal_str2dec((A), (B), (C), 0) +#define string2decimal_fixed(A,B,C) internal_str2dec((A), (B), (C), 1) + /* set a decimal to zero */ #define decimal_make_zero(dec) do { \ diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index fdadd378ceb..0ad992b87e5 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -90,6 +90,26 @@ id avg(rating) 1 3.0000 2 NULL 3 2.0000 +select sql_small_result t2.id, avg(rating) from t2 group by t2.id; +id avg(rating) +1 3.0000 +2 NULL +3 2.0000 +select sql_big_result t2.id, avg(rating) from t2 group by t2.id; +id avg(rating) +1 3.0000 +2 NULL +3 2.0000 +select sql_small_result t2.id, avg(rating+0.0e0) from t2 group by t2.id; +id avg(rating+0.0e0) +1 3 +2 NULL +3 2 +select sql_big_result t2.id, avg(rating+0.0e0) from t2 group by t2.id; +id avg(rating+0.0e0) +1 3 +2 NULL +3 2 drop table t1,t2; create table t1 (a smallint(6) primary key, c char(10), b text); INSERT INTO t1 VALUES (1,'1','1'); diff --git a/mysql-test/r/func_set.result b/mysql-test/r/func_set.result index ca6e0a8c319..aa71cee0752 100644 --- a/mysql-test/r/func_set.result +++ b/mysql-test/r/func_set.result @@ -30,6 +30,12 @@ Y-N-N-Y-N Y,N,N,Y,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, select elt(2,1),field(NULL,"a","b","c"); elt(2,1) field(NULL,"a","b","c") NULL 0 +select field("b","a",NULL),field(1,0,NULL)+0,field(1.0,0.0,NULL)+0.0,field(1.0e1,0.0e1,NULL)+0.0e1; +field("b","a",NULL) field(1,0,NULL)+0 field(1.0,0.0,NULL)+0.0 field(1.0e1,0.0e1,NULL)+0.0e1 +0 0 0.0 0 +select field(NULL,"a",NULL),field(NULL,0,NULL)+0,field(NULL,0.0,NULL)+0.0,field(NULL,0.0e1,NULL)+0.0e1; +field(NULL,"a",NULL) field(NULL,0,NULL)+0 field(NULL,0.0,NULL)+0.0 field(NULL,0.0e1,NULL)+0.0e1 +0 0 0.0 0 select find_in_set("","a,b,c"),find_in_set("","a,b,c,"),find_in_set("",",a,b,c"); find_in_set("","a,b,c") find_in_set("","a,b,c,") find_in_set("",",a,b,c") 0 4 1 diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index 2045b7e65dd..6c4a1fab857 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -169,8 +169,19 @@ Warnings: Warning 1264 Out of range value adjusted for column 'a' at row 1 Note 1265 Data truncated for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 3 +insert into t1 values ("1e+4294967296"),("1e-4294967296"); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Note 1265 Data truncated for column 'a' at row 2 +insert into t1 values ("1e+18446744073709551615"),("1e+18446744073709551616"),("1e-9223372036854775807"),("1e-9223372036854775809"); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1366 Incorrect decimal value: '1e+18446744073709551616' for column 'a' at row 2 +Note 1265 Data truncated for column 'a' at row 3 +Warning 1366 Incorrect decimal value: '1e-9223372036854775809' for column 'a' at row 4 insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); Warnings: +Note 1265 Data truncated for column 'a' at row 1 Note 1265 Data truncated for column 'a' at row 3 select * from t1; a @@ -195,6 +206,12 @@ a 99999999.99 0.00 -99999999.99 +99999999.99 +0.00 +99999999.99 +0.00 +0.00 +0.00 123.40 12340.00 1.23 @@ -229,6 +246,7 @@ Note 1265 Data truncated for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); Warnings: +Note 1265 Data truncated for column 'a' at row 1 Note 1265 Data truncated for column 'a' at row 3 select * from t1; a @@ -287,6 +305,7 @@ Note 1265 Data truncated for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); Warnings: +Note 1265 Data truncated for column 'a' at row 1 Note 1265 Data truncated for column 'a' at row 3 select * from t1; a @@ -338,6 +357,7 @@ Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values (123.4e0),(123.4e+2),(123.4e-2),(123e1),(123e+0); Warnings: Note 1265 Data truncated for column 'a' at row 3 +insert into t1 values (MID("987",1,2)),("987 "),("987.6e+2 "); select * from t1; a 0.00 @@ -366,6 +386,9 @@ a 1.23 1230.00 123.00 +98.00 +987.00 +98760.00 drop table t1; create table t1 (a decimal); insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+12345678901'),(99999999999999); diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index cf23d4162ae..5b6612572cb 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -696,7 +696,7 @@ end while; select v1, v2, v3 * 0.000000000001, v4 * 0.000000000001; end;// call p1()// # v1 v2 v3 * 0.000000000001 v4 * 0.000000000001 -1.000000100000 1.999999900000 1.000000100000000000 1.999999900000000000 +1.000000100000 1.999999900000 1.000000100000 1.999999900000 drop procedure p1; drop table if exists t1; Warnings: diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index a47218e5c01..60eefe2a104 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -58,6 +58,11 @@ create table t2 (id int not null,rating int null); insert into t1 values(1),(2),(3); insert into t2 values(1, 3),(2, NULL),(2, NULL),(3, 2),(3, NULL); select t1.id, avg(rating) from t1 left join t2 on ( t1.id = t2.id ) group by t1.id; +# Test different types with avg() +select sql_small_result t2.id, avg(rating) from t2 group by t2.id; +select sql_big_result t2.id, avg(rating) from t2 group by t2.id; +select sql_small_result t2.id, avg(rating+0.0e0) from t2 group by t2.id; +select sql_big_result t2.id, avg(rating+0.0e0) from t2 group by t2.id; drop table t1,t2; # diff --git a/mysql-test/t/func_set.test b/mysql-test/t/func_set.test index 98ef1e07bfe..0c79dec7cc2 100644 --- a/mysql-test/t/func_set.test +++ b/mysql-test/t/func_set.test @@ -18,6 +18,8 @@ select export_set(9,"Y","N","-",5),export_set(9,"Y","N"),export_set(9,"Y","N","" # Wrong usage of functions # select elt(2,1),field(NULL,"a","b","c"); +select field("b","a",NULL),field(1,0,NULL)+0,field(1.0,0.0,NULL)+0.0,field(1.0e1,0.0e1,NULL)+0.0e1; +select field(NULL,"a",NULL),field(NULL,0,NULL)+0,field(NULL,0.0,NULL)+0.0,field(NULL,0.0e1,NULL)+0.0e1; select find_in_set("","a,b,c"),find_in_set("","a,b,c,"),find_in_set("",",a,b,c"); select find_in_set("abc","abc"),find_in_set("ab","abc"),find_in_set("abcd","abc"); select interval(null, 1, 10, 100); diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 414a06deaa9..6f170a52700 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -165,6 +165,8 @@ insert into t1 values ("00000000000001"),("+0000000000001"),("-0000000000001"); insert into t1 values ("+111111111.11"),("111111111.11"),("-11111111.11"); insert into t1 values ("-111111111.11"),("+1111111111.11"),("1111111111.11"); insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000"); +insert into t1 values ("1e+4294967296"),("1e-4294967296"); +insert into t1 values ("1e+18446744073709551615"),("1e+18446744073709551616"),("1e-9223372036854775807"),("1e-9223372036854775809"); insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); select * from t1; drop table t1; @@ -201,6 +203,7 @@ insert into t1 values (+111111111.11),(111111111.11),(-11111111.11); insert into t1 values (-111111111.11),(+1111111111.11),(1111111111.11); insert into t1 values (1e+100),(1e-100),(-1e+100); insert into t1 values (123.4e0),(123.4e+2),(123.4e-2),(123e1),(123e+0); +insert into t1 values (MID("987",1,2)),("987 "),("987.6e+2 "); select * from t1; drop table t1; diff --git a/sql/item.cc b/sql/item.cc index 4eb4e017ef2..33e6d7cfc42 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -73,6 +73,99 @@ bool Item::val_bool() } +String *Item::val_string_from_real(String *str) +{ + double nr= val_real(); + if (null_value) + return 0; /* purecov: inspected */ + str->set(nr,decimals, &my_charset_bin); + return str; +} + + +String *Item::val_string_from_int(String *str) +{ + longlong nr= val_int(); + if (null_value) + return 0; + if (unsigned_flag) + str->set((ulonglong) nr, &my_charset_bin); + else + str->set(nr, &my_charset_bin); + return str; +} + + +String *Item::val_string_from_decimal(String *str) +{ + my_decimal dec_buf, *dec= val_decimal(&dec_buf); + if (null_value) + return 0; + 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; +} + + +my_decimal *Item::val_decimal_from_real(my_decimal *decimal_value) +{ + double nr= val_real(); + if (null_value) + return 0; + double2my_decimal(E_DEC_FATAL_ERROR, nr, decimal_value); + return (decimal_value); +} + + +my_decimal *Item::val_decimal_from_int(my_decimal *decimal_value) +{ + longlong nr= val_int(); + if (null_value) + return 0; + int2my_decimal(E_DEC_FATAL_ERROR, nr, unsigned_flag, decimal_value); + return decimal_value; +} + + +my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value) +{ + String *res; + char *end_ptr; + int error; + if (!(res= val_str(&str_value))) + return 0; // NULL or EOM + + end_ptr= (char*) res->ptr()+ res->length(); + str2my_decimal(E_DEC_FATAL_ERROR, res->ptr(), res->length(), res->charset(), + decimal_value); + return decimal_value; +} + + +double Item::val_real_from_decimal() +{ + /* Note that fix_fields may not be called for Item_avg_field items */ + double result; + my_decimal value_buff, *dec_val= val_decimal(&value_buff); + if (null_value) + return 0.0; + my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &result); + return result; +} + + +longlong Item::val_int_from_decimal() +{ + /* Note that fix_fields may not be called for Item_avg_field items */ + longlong result; + my_decimal value, *dec_val= val_decimal(&value); + if (null_value) + return 0; + my_decimal2int(E_DEC_FATAL_ERROR, dec_val, unsigned_flag, &result); + return result; +} + + Item::Item(): name(0), orig_name(0), name_length(0), fixed(0), collation(&my_charset_bin, DERIVATION_COERCIBLE) @@ -1376,11 +1469,14 @@ void Item_param::set_double(double d) binary protocol, we use str2my_decimal to convert it to internal decimal value. */ + void Item_param::set_decimal(const char *str, ulong length) { + char *end; DBUG_ENTER("Item_param::set_decimal"); - str2my_decimal(E_DEC_FATAL_ERROR, str, &decimal_value); + end= (char*) str+length; + str2my_decimal(E_DEC_FATAL_ERROR, str, &decimal_value, &end); state= DECIMAL_VALUE; decimals= decimal_value.frac; max_length= decimal_value.intg + decimals + 2; @@ -3012,6 +3108,29 @@ Item_num *Item_uint::neg() } +static uint nr_of_decimals(const char *str, const char *end) +{ + const char *decimal_point; + + /* Find position for '.' */ + for (;;) + { + if (str == end) + return 0; + if (*str == 'e' || *str == 'E') + return NOT_FIXED_DEC; + if (*str++ == '.') + break; + } + decimal_point= str; + for (; my_isdigit(system_charset_info, *str) ; str++) + ; + if (*str == 'e' || *str == 'E') + return NOT_FIXED_DEC; + return (uint) (str - decimal_point); +} + + /* This function is only called during parsing. We will signal an error if value is not a true double value (overflow) @@ -3033,7 +3152,7 @@ Item_float::Item_float(const char *str_arg, uint length) my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "double", (char*) str_arg); } presentation= name=(char*) str_arg; - decimals=(uint8) nr_of_decimals(str_arg); + decimals=(uint8) nr_of_decimals(str_arg, str_arg+length); max_length=length; fixed= 1; } diff --git a/sql/item.h b/sql/item.h index 3e1844ec76e..2ae223bad3a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -276,6 +276,16 @@ public: TRUE value is true (not equal to 0) */ bool val_bool(); + /* Helper functions, see item_sum.cc */ + String *val_string_from_real(String *str); + String *val_string_from_int(String *str); + String *val_string_from_decimal(String *str); + my_decimal *val_decimal_from_real(my_decimal *decimal_value); + my_decimal *val_decimal_from_int(my_decimal *decimal_value); + my_decimal *val_decimal_from_string(my_decimal *decimal_value); + longlong val_int_from_decimal(); + double val_real_from_decimal(); + virtual Field *get_tmp_table_field() { return 0; } virtual Field *tmp_table_field(TABLE *t_arg) { return 0; } virtual const char *full_name() const { return name ? name : "???"; } diff --git a/sql/item_func.cc b/sql/item_func.cc index 1a3e75821ca..f5ffdb0ffc3 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -714,15 +714,14 @@ void Item_num_op::find_num_type(void) 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()) - { + switch (hybrid_type= args[0]->result_type()) { case INT_RESULT: - unsigned_flag=args[0]->unsigned_flag; - hybrid_type= INT_RESULT; + unsigned_flag= args[0]->unsigned_flag; break; case STRING_RESULT: case REAL_RESULT: @@ -730,7 +729,6 @@ void Item_func_num1::find_num_type() max_length= float_length(decimals); break; case DECIMAL_RESULT: - hybrid_type= DECIMAL_RESULT; break; default: DBUG_ASSERT(0); @@ -761,13 +759,12 @@ void Item_func_numhybrid::fix_length_and_dec() String *Item_func_numhybrid::val_str(String *str) { DBUG_ASSERT(fixed == 1); - switch (hybrid_type) - { + switch (hybrid_type) { case DECIMAL_RESULT: { my_decimal decimal_value, *val; if (!(val= decimal_op(&decimal_value))) - return 0; + 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; @@ -785,7 +782,7 @@ String *Item_func_numhybrid::val_str(String *str) } case REAL_RESULT: { - double nr=real_op(); + double nr= real_op(); if (null_value) return 0; /* purecov: inspected */ str->set(nr,decimals,&my_charset_bin); @@ -801,14 +798,13 @@ String *Item_func_numhybrid::val_str(String *str) double Item_func_numhybrid::val_real() { DBUG_ASSERT(fixed == 1); - switch (hybrid_type) - { + switch (hybrid_type) { case DECIMAL_RESULT: { my_decimal decimal_value, *val; - if (!(val= decimal_op(&decimal_value))) - return 0.0; double result; + if (!(val= decimal_op(&decimal_value))) + return 0.0; // null is set my_decimal2double(E_DEC_FATAL_ERROR, val, &result); return result; } @@ -826,13 +822,12 @@ double Item_func_numhybrid::val_real() longlong Item_func_numhybrid::val_int() { DBUG_ASSERT(fixed == 1); - switch (hybrid_type) - { + switch (hybrid_type) { case DECIMAL_RESULT: { my_decimal decimal_value, *val; if (!(val= decimal_op(&decimal_value))) - return 0; + return 0; // null is set longlong result; my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result); return result; @@ -852,8 +847,7 @@ my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value) { my_decimal *val= decimal_value; DBUG_ASSERT(fixed == 1); - switch (hybrid_type) - { + switch (hybrid_type) { case DECIMAL_RESULT: val= decimal_op(decimal_value); break; @@ -949,14 +943,29 @@ longlong Item_func_plus::int_op() } +/* + 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= args[0]->val_decimal(&value1); + my_decimal value1, *val1; + my_decimal value2, *val2; + val1= args[0]->val_decimal(&value1); if ((null_value= args[0]->null_value)) return 0; - my_decimal value2, *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) + 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; } @@ -1008,14 +1017,20 @@ longlong Item_func_minus::int_op() } +/* See Item_func_plus::decimal_op for comments */ + my_decimal *Item_func_minus::decimal_op(my_decimal *decimal_value) { - my_decimal value1, *val1= args[0]->val_decimal(&value1); + my_decimal value1, *val1; + my_decimal value2, *val2= + + val1= args[0]->val_decimal(&value1); if ((null_value= args[0]->null_value)) return 0; - my_decimal value2, *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) + 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; } @@ -1041,14 +1056,19 @@ longlong Item_func_mul::int_op() } +/* See Item_func_plus::decimal_op for comments */ + my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value) { - my_decimal value1, *val1= args[0]->val_decimal(&value1); + my_decimal value1, *val1; + my_decimal value2, *val2; + val1= args[0]->val_decimal(&value1); if ((null_value= args[0]->null_value)) return 0; - my_decimal value2, *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) + 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; } @@ -1081,21 +1101,24 @@ double Item_func_div::real_op() my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value) { - my_decimal value1, *val1= args[0]->val_decimal(&value1); + my_decimal value1, *val1; + my_decimal value2, *val2; + + val1= args[0]->val_decimal(&value1); if ((null_value= args[0]->null_value)) return 0; - my_decimal value2, *val2= args[1]->val_decimal(&value2); + 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)) - { + 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; } } @@ -1115,8 +1138,7 @@ void Item_func_div::fix_length_and_dec() { DBUG_ENTER("Item_func_div::fix_length_and_dec"); Item_num_op::fix_length_and_dec(); - switch(hybrid_type) - { + switch(hybrid_type) { case REAL_RESULT: { decimals=max(args[0]->decimals,args[1]->decimals)+2; @@ -1148,7 +1170,7 @@ longlong Item_func_int_div::val_int() DBUG_ASSERT(fixed == 1); longlong value=args[0]->val_int(); longlong val2=args[1]->val_int(); - if (args[0]->null_value || args[1]->null_value) + if ((null_value= (args[0]->null_value || args[1]->null_value))) return 0; if (val2 == 0) { @@ -1161,19 +1183,6 @@ longlong Item_func_int_div::val_int() } -String *Item_func_int_div::val_str(String*str) -{ - 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); - return str; -} - - void Item_func_int_div::fix_length_and_dec() { max_length=args[0]->max_length - args[0]->decimals; @@ -1215,21 +1224,24 @@ double Item_func_mod::real_op() my_decimal *Item_func_mod::decimal_op(my_decimal *decimal_value) { - my_decimal value1, *val1= args[0]->val_decimal(&value1); + my_decimal value1, *val1; + my_decimal value2, *val2; + + val1= args[0]->val_decimal(&value1); if ((null_value= args[0]->null_value)) return 0; - my_decimal value2, *val2= args[1]->val_decimal(&value2); + 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)) - { + 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; } } @@ -1279,24 +1291,23 @@ void Item_func_neg::fix_num_length_and_dec() } -void Item_func_signproc::fix_length_and_dec() +void Item_func_neg::fix_length_and_dec() { - DBUG_ENTER("Item_func_signproc::fix_length_and_dec"); + DBUG_ENTER("Item_func_neg::fix_length_and_dec"); Item_func_num1::fix_length_and_dec(); + + /* + If this is in integer context keep the context as integer if possible + (This is how multiplication and other integer functions works) + */ 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 */ hybrid_type= DECIMAL_RESULT; DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT")); @@ -1618,9 +1629,9 @@ double Item_func_ceiling::real_op() 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)) - return 0; - if (my_decimal_ceiling(E_DEC_FATAL_ERROR, value, decimal_value) > 1) + if ((null_value= (args[0]->null_value || + my_decimal_ceiling(E_DEC_FATAL_ERROR, value, + decimal_value) > 1))) return 0; return decimal_value; } @@ -1653,9 +1664,9 @@ double Item_func_floor::real_op() 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)) - return 0; - if (my_decimal_floor(E_DEC_FATAL_ERROR, value, decimal_value) > 1) + if ((null_value= (args[0]->null_value || + my_decimal_floor(E_DEC_FATAL_ERROR, value, + decimal_value) > 1))) return 0; return decimal_value; } @@ -1750,10 +1761,9 @@ my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value) 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)) - return 0; - if (my_decimal_round(E_DEC_FATAL_ERROR, value, dec, truncate, - decimal_value) > 1) + 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; } @@ -2125,9 +2135,11 @@ 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); } } @@ -2140,18 +2152,18 @@ longlong Item_func_field::val_int() for (uint i=1; i < arg_count; i++) { dec_arg= args[i]->val_decimal(&dec_arg_buf); - if (args[i]->is_null()) - continue; - if (!my_decimal_cmp(dec_arg, dec)) + if (!args[i]->is_null() && !my_decimal_cmp(dec_arg, dec)) return (longlong) (i); } } else { 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_real()) + if (val == args[i]->val_real() && ! args[i]->is_null()) return (longlong) (i); } } @@ -2589,6 +2601,10 @@ String *udf_handler::val_str(String *str,String *save_str) } +/* + For the moment, UDF functions are returning DECIMAL values as strings +*/ + my_decimal *udf_handler::val_decimal(my_bool *null_value, my_decimal *dec_buf) { char buf[DECIMAL_MAX_STR_LENGTH+1], *end; @@ -2609,8 +2625,8 @@ my_decimal *udf_handler::val_decimal(my_bool *null_value, my_decimal *dec_buf) *null_value= 1; return 0; } - buf[res_length]= 0; - str2my_decimal(E_DEC_FATAL_ERROR, buf, dec_buf, &end); + end= res+ res_length; + str2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf, &end); return dec_buf; } @@ -2664,9 +2680,9 @@ String *Item_func_udf_int::val_str(String *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; - longlong result; my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result); return result; } @@ -2675,9 +2691,9 @@ longlong Item_func_udf_decimal::val_int() 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; - double result; my_decimal2double(E_DEC_FATAL_ERROR, dec, &result); return result; } diff --git a/sql/item_func.h b/sql/item_func.h index 70ad1a0375f..48fc278ccde 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -357,18 +357,15 @@ public: }; -class Item_func_int_div :public Item_func +class Item_func_int_div :public Item_int_func { public: - Item_func_int_div(Item *a,Item *b) :Item_func(a,b) + Item_func_int_div(Item *a,Item *b) :Item_int_func(a,b) {} - double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); } longlong val_int(); - String *val_str(String*str); const char *func_name() const { return "DIV"; } void fix_length_and_dec(); void print(String *str) { print_op(str); } - enum Item_result result_type () const { return INT_RESULT; } }; @@ -384,23 +381,15 @@ public: }; -class Item_func_signproc :public Item_func_num1 -{ -public: - Item_func_signproc(Item *a) :Item_func_num1(a) {} - Item_func_signproc(Item *a, Item *b) :Item_func_num1(a, b) {} - void fix_length_and_dec(); -}; - - -class Item_func_neg :public Item_func_signproc +class Item_func_neg :public Item_func_num1 { public: - Item_func_neg(Item *a) :Item_func_signproc(a) {} + Item_func_neg(Item *a) :Item_func_num1(a) {} double real_op(); longlong int_op(); my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "-"; } + void fix_length_and_dec(); void fix_num_length_and_dec(); }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 091de8e3a01..9f2da0f7fa1 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -47,19 +47,6 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, fname); } -uint nr_of_decimals(const char *str) -{ - if (strchr(str,'e') || strchr(str,'E')) - return NOT_FIXED_DEC; - if ((str=strchr(str,'.'))) - { - const char *start= ++str; - for (; my_isdigit(system_charset_info,*str) ; str++) ; - return (uint) (str-start); - } - return 0; -} - double Item_str_func::val_real() { diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 2ecc1eb083c..b8da1423871 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -125,15 +125,6 @@ Item *Item_sum::get_tmp_table_item(THD *thd) } -my_decimal *Item_sum::val_decimal(my_decimal *decimal_value) -{ - DBUG_ASSERT(fixed); - DBUG_ASSERT(decimal_value); - int2my_decimal(E_DEC_FATAL_ERROR, val_int(), unsigned_flag, decimal_value); - return decimal_value; -} - - bool Item_sum::walk (Item_processor processor, byte *argument) { if (arg_count) @@ -178,38 +169,26 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table, String * Item_sum_num::val_str(String *str) { - DBUG_ASSERT(fixed == 1); - double nr= val_real(); - if (null_value) - return 0; - str->set(nr,decimals, &my_charset_bin); - return str; + return val_string_from_real(str); } my_decimal *Item_sum_num::val_decimal(my_decimal *decimal_value) { - DBUG_ASSERT(fixed == 1); - double nr= val_real(); - if (null_value) - return 0; - double2my_decimal(E_DEC_FATAL_ERROR, nr, decimal_value); - return (decimal_value); + return val_decimal_from_real(decimal_value); } String * Item_sum_int::val_str(String *str) { - DBUG_ASSERT(fixed == 1); - longlong nr= val_int(); - if (null_value) - return 0; - if (unsigned_flag) - str->set((ulonglong) nr, &my_charset_bin); - else - str->set(nr, &my_charset_bin); - return str; + return val_string_from_int(str); +} + + +my_decimal *Item_sum_int::val_decimal(my_decimal *decimal_value) +{ + return val_decimal_from_int(decimal_value); } @@ -249,8 +228,8 @@ Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item) hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign), used_table_cache(item->used_table_cache), was_values(item->was_values) { - switch (hybrid_type) - { + /* copy results from old value */ + switch (hybrid_type) { case INT_RESULT: sum_int= item->sum_int; break; @@ -288,8 +267,7 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) return TRUE; decimals=item->decimals; - switch (hybrid_type= item->result_type()) - { + switch (hybrid_type= item->result_type()) { case INT_RESULT: max_length= 20; sum_int= 0; @@ -334,6 +312,7 @@ Item_sum_sum::Item_sum_sum(THD *thd, Item_sum_sum *item) :Item_sum_num(thd, item), hybrid_type(item->hybrid_type), curr_dec_buff(item->curr_dec_buff) { + /* TODO: check if the following assignments are really needed */ if (hybrid_type == DECIMAL_RESULT) { my_decimal2decimal(item->dec_buffs, dec_buffs); @@ -369,8 +348,7 @@ void Item_sum_sum::fix_length_and_dec() DBUG_ENTER("Item_sum_sum::fix_length_and_dec"); maybe_null=null_value=1; decimals= args[0]->decimals; - switch (args[0]->result_type()) - { + switch (args[0]->result_type()) { case REAL_RESULT: case STRING_RESULT: hybrid_type= REAL_RESULT; @@ -434,7 +412,7 @@ longlong Item_sum_sum::val_int() &result); return result; } - return Item_sum_num::val_int(); + return (longlong) val_real(); } @@ -447,28 +425,22 @@ double Item_sum_sum::val_real() } -String *Item_sum_sum::val_str(String*str) +String *Item_sum_sum::val_str(String *str) { if (hybrid_type == DECIMAL_RESULT) - { - if (null_value) - return NULL; - my_decimal_round(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, decimals, - FALSE, dec_buffs + curr_dec_buff); - my_decimal2string(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, - 0, 0, 0, str); - return str; - } - return Item_sum_num::val_str(str); + return val_string_from_decimal(str); + return val_string_from_real(str); } my_decimal *Item_sum_sum::val_decimal(my_decimal *val) { - DBUG_ASSERT(hybrid_type == DECIMAL_RESULT); - return(dec_buffs + curr_dec_buff); + if (hybrid_type == DECIMAL_RESULT) + return (dec_buffs + curr_dec_buff); + return val_decimal_from_real(val); } + /* Item_sum_sum_distinct */ Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item) @@ -519,6 +491,7 @@ static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2) C_MODE_END + bool Item_sum_sum_distinct::setup(THD *thd) { DBUG_ENTER("Item_sum_sum_distinct::setup"); @@ -539,15 +512,20 @@ bool Item_sum_sum_distinct::setup(THD *thd) TODO: if underlying item result fits in 4 bytes we can take advantage of it and have tree of long/ulong. It gives 10% performance boost */ - uint *key_length_ptr= (uint *)thd->alloc(sizeof(uint)); - *key_length_ptr= ((hybrid_type == DECIMAL_RESULT) ? - my_decimal_get_binary_size(args[0]->max_length, - args[0]->decimals) : - sizeof(double)); - tree= new Unique(simple_raw_key_cmp, key_length_ptr, *key_length_ptr, + + /* + It's safe to use key_length here as even if we do copy_or_same() + the new item will just share the old items key_length, which will not + change or disappear during the life time of this item. + */ + key_length= ((hybrid_type == DECIMAL_RESULT) ? + my_decimal_get_binary_size(args[0]->max_length, + args[0]->decimals) : + sizeof(double)); + tree= new Unique(simple_raw_key_cmp, &key_length, key_length, thd->variables.max_heap_table_size); DBUG_PRINT("info", ("tree 0x%lx, key length %d", (ulong)tree, - *key_length_ptr)); + key_length)); DBUG_RETURN(tree == 0); } @@ -640,6 +618,7 @@ static int sum_sum_distinct_decimal(void *element, element_count num_of_dups, C_MODE_END + double Item_sum_sum_distinct::val_real() { DBUG_ENTER("Item_sum_sum_distinct::val"); @@ -685,17 +664,17 @@ my_decimal *Item_sum_sum_distinct::val_decimal(my_decimal *fake) longlong Item_sum_sum_distinct::val_int() { - longlong i; + longlong result; if (hybrid_type == DECIMAL_RESULT) { /* Item_sum_sum_distinct::val_decimal do not use argument */ my_decimal *val= val_decimal(0); if (!null_value) - my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &i); + my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result); } else - i= (longlong) val_real(); - return i; + result= (longlong) val_real(); + return result; } @@ -703,22 +682,8 @@ String *Item_sum_sum_distinct::val_str(String *str) { DBUG_ASSERT(fixed == 1); if (hybrid_type == DECIMAL_RESULT) - { - /* Item_sum_sum_distinct::val_decimal do not use argument */ - my_decimal *val= val_decimal(0); - if (null_value) - return 0; - my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val); - my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str); - } - else - { - double nr= val_real(); - if (null_value) - return 0; - str->set(nr, decimals, &my_charset_bin); - } - return str; + return val_string_from_decimal(str); + return val_string_from_real(str); } @@ -792,23 +757,21 @@ Item *Item_sum_avg::copy_or_same(THD* thd) Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table, uint convert_blob_len) { - if (hybrid_type == DECIMAL_RESULT) + if (group) { - if (group) - return new Field_string(dec_bin_size + sizeof(longlong), - 0, name, table, &my_charset_bin); - else - return new Field_new_decimal(f_precision, - maybe_null, name, table, f_scale); - } - else - { - if (group) - return new Field_string(sizeof(double)+sizeof(longlong), - 0, name,table,&my_charset_bin); - else - return new Field_double(max_length, maybe_null, name, table, decimals); + /* + We must store both value and counter in the temporary table in one field. + The easyest way is to do this is to store both value in a string + and unpack on access. + */ + return new Field_string(((hybrid_type == DECIMAL_RESULT) ? + dec_bin_size : sizeof(double)) + sizeof(longlong), + 0, name, table, &my_charset_bin); } + if (hybrid_type == DECIMAL_RESULT) + return new Field_new_decimal(f_precision, + maybe_null, name, table, f_scale); + return new Field_double(max_length, maybe_null, name, table, decimals); } @@ -842,14 +805,15 @@ double Item_sum_avg::val_real() my_decimal *Item_sum_avg::val_decimal(my_decimal *val) { + my_decimal sum, cnt; + const my_decimal *sum_dec; DBUG_ASSERT(fixed == 1); if (!count) { null_value=1; return NULL; } - my_decimal sum, cnt; - const my_decimal *sum_dec= Item_sum_sum::val_decimal(&sum); + sum_dec= Item_sum_sum::val_decimal(&sum); int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt); my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, 4); return val; @@ -859,23 +823,11 @@ my_decimal *Item_sum_avg::val_decimal(my_decimal *val) String *Item_sum_avg::val_str(String *str) { if (hybrid_type == DECIMAL_RESULT) - { - my_decimal value, *dec_val= val_decimal(&value); - if (null_value) - return NULL; - my_decimal_round(E_DEC_FATAL_ERROR, dec_val, decimals, FALSE, &value); - my_decimal2string(E_DEC_FATAL_ERROR, &value, 0, 0, 0, str); - return str; - } - double nr= val_real(); - if (null_value) - return NULL; - str->set(nr, decimals, &my_charset_bin); - return str; + return val_string_from_decimal(str); + return val_string_from_real(str); } - /* Standard deviation */ @@ -922,11 +874,10 @@ Item_sum_variance::Item_sum_variance(THD *thd, Item_sum_variance *item): void Item_sum_variance::fix_length_and_dec() { - DBUG_ENTER("Item_sum_sum::fix_length_and_dec"); - maybe_null=null_value=1; + DBUG_ENTER("Item_sum_variance::fix_length_and_dec"); + maybe_null= null_value= 1; decimals= args[0]->decimals + 4; - switch (args[0]->result_type()) - { + switch (args[0]->result_type()) { case REAL_RESULT: case STRING_RESULT: hybrid_type= REAL_RESULT; @@ -934,12 +885,21 @@ void Item_sum_variance::fix_length_and_dec() break; case INT_RESULT: case DECIMAL_RESULT: - /* SUM result can't be longer than length(arg)*2 + digits_after_the_point_to_add*/ + /* + SUM result can't be longer than length(arg)*2 + + digits_after_the_point_to_add + */ max_length= args[0]->max_length*2 + 4; cur_dec= 0; hybrid_type= DECIMAL_RESULT; my_decimal_set_zero(dec_sum); my_decimal_set_zero(dec_sqr); + + /* + The maxium value to usable for variance is DECIMAL_MAX_LENGTH/2 + becasue we need to be able to calculate in dec_bin_size1 + column_value * column_value + */ f_scale0= args[0]->decimals; f_precision0= DECIMAL_MAX_LENGTH / 2; f_scale1= min(f_scale0 * 2, NOT_FIXED_DEC - 1); @@ -971,23 +931,22 @@ Item *Item_sum_variance::copy_or_same(THD* thd) Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table, uint convert_blob_len) { - if (hybrid_type == DECIMAL_RESULT) + if (group) { - if (group) - return new Field_string(dec_bin_size0+dec_bin_size1+sizeof(longlong), - 0, name,table,&my_charset_bin); - else - return new Field_new_decimal(DECIMAL_MAX_LENGTH, - maybe_null, name, table, f_scale1 + 4); - } - else - { - if (group) - return new Field_string(sizeof(double)*2+sizeof(longlong), - 0, name,table,&my_charset_bin); - else - return new Field_double(max_length, maybe_null,name,table,decimals); + /* + We must store both value and counter in the temporary table in one field. + The easyest way is to do this is to store both value in a string + and unpack on access. + */ + return new Field_string(((hybrid_type == DECIMAL_RESULT) ? + dec_bin_size0 + dec_bin_size1 : + sizeof(double)*2) + sizeof(longlong), + 0, name, table, &my_charset_bin); } + if (hybrid_type == DECIMAL_RESULT) + return new Field_new_decimal(DECIMAL_MAX_LENGTH, + maybe_null, name, table, f_scale1 + 4); + return new Field_double(max_length, maybe_null,name,table,decimals); } @@ -1038,19 +997,15 @@ bool Item_sum_variance::add() double Item_sum_variance::val_real() { DBUG_ASSERT(fixed == 1); + if (hybrid_type == DECIMAL_RESULT) + return val_real_from_decimal(); + if (!count) { null_value=1; return 0.0; } null_value=0; - if (hybrid_type == DECIMAL_RESULT) - { - double result; - my_decimal dec_buf, *dec= Item_sum_variance::val_decimal(&dec_buf); - my_decimal2double(E_DEC_FATAL_ERROR, dec, &result); - return result; - } /* Avoid problems when the precision isn't good enough */ double tmp=ulonglong2double(count); double tmp2=(sum_sqr - sum*sum/tmp)/tmp; @@ -1060,22 +1015,17 @@ double Item_sum_variance::val_real() my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf) { + my_decimal count_buf, sum_sqr_buf; DBUG_ASSERT(fixed ==1 ); if (hybrid_type == REAL_RESULT) - { - double result= Item_sum_variance::val_real(); - if (null_value) - return 0; - double2my_decimal(E_DEC_FATAL_ERROR, result, dec_buf); - return dec_buf; - } + return val_decimal_from_real(dec_buf); + if (!count) { null_value= 1; return 0; } null_value= 0; - my_decimal count_buf, sum_sqr_buf; int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &count_buf); my_decimal_mul(E_DEC_FATAL_ERROR, &sum_sqr_buf, dec_sum+cur_dec, dec_sum+cur_dec); @@ -1085,49 +1035,53 @@ my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf) return dec_buf; } + void Item_sum_variance::reset_field() { - char *res=result_field->ptr; + double nr; + char *res= result_field->ptr; + if (hybrid_type == DECIMAL_RESULT) { - my_decimal value, *arg_dec= args[0]->val_decimal(&value); + my_decimal value, *arg_dec, *arg2_dec; + longlong tmp; + + arg_dec= args[0]->val_decimal(&value); if (args[0]->null_value) { - my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero, - res, f_precision0, f_scale0); - my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero, - res+dec_bin_size0, f_precision1, f_scale1); - res+= dec_bin_size0 + dec_bin_size1; - longlong tmp=0; - int8store(res,tmp); + arg_dec= arg2_dec= &decimal_zero; + tmp= 0; } else { - my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, - res, f_precision0, f_scale0); my_decimal_mul(E_DEC_FATAL_ERROR, dec_sum, arg_dec, arg_dec); - my_decimal2binary(E_DEC_FATAL_ERROR, dec_sum, - res+dec_bin_size0, f_precision1, f_scale1); - res+= dec_bin_size0 + dec_bin_size1; - longlong tmp=1; - int8store(res,tmp); + arg2_dec= dec_sum; + tmp= 1; } + my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, + res, f_precision0, f_scale0); + my_decimal2binary(E_DEC_FATAL_ERROR, arg2_dec, + res+dec_bin_size0, f_precision1, f_scale1); + res+= dec_bin_size0 + dec_bin_size1; + int8store(res,tmp); return; } - double nr= args[0]->val_real(); + nr= args[0]->val_real(); if (args[0]->null_value) bzero(res,sizeof(double)*2+sizeof(longlong)); else { + longlong tmp; float8store(res,nr); nr*=nr; float8store(res+sizeof(double),nr); - longlong tmp=1; + tmp= 1; int8store(res+sizeof(double)*2,tmp); } } + void Item_sum_variance::update_field() { longlong field_count; @@ -1170,15 +1124,16 @@ void Item_sum_variance::update_field() } float8store(res,old_nr); float8store(res+sizeof(double),old_sqr); - int8store(res+sizeof(double)*2,field_count); + res+= sizeof(double)*2; + int8store(res,field_count); } + /* min & max */ void Item_sum_hybrid::clear() { - switch (hybrid_type) - { + switch (hybrid_type) { case INT_RESULT: sum_int= 0; break; @@ -1231,8 +1186,7 @@ longlong Item_sum_hybrid::val_int() DBUG_ASSERT(fixed == 1); if (null_value) return 0; - switch (hybrid_type) - { + switch (hybrid_type) { case INT_RESULT: return sum_int; case DECIMAL_RESULT: @@ -1539,8 +1493,7 @@ void Item_sum_num::reset_field() void Item_sum_hybrid::reset_field() { - switch(hybrid_type) - { + switch(hybrid_type) { case STRING_RESULT: { char buff[MAX_FIELD_WIDTH]; @@ -1604,8 +1557,13 @@ void Item_sum_hybrid::reset_field() else result_field->set_notnull(); } - if (!args[0]->null_value) - result_field->store_decimal(arg_dec); + /* + 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: @@ -1620,10 +1578,9 @@ void Item_sum_sum::reset_field() if (hybrid_type == DECIMAL_RESULT) { my_decimal value, *arg_val= args[0]->val_decimal(&value); - if (args[0]->null_value) - result_field->reset(); - else - result_field->store_decimal(arg_val); + if (!arg_val) // Null + arg_val= &decimal_zero; + result_field->store_decimal(arg_val); } else { @@ -1660,23 +1617,18 @@ void Item_sum_avg::reset_field() char *res=result_field->ptr; if (hybrid_type == DECIMAL_RESULT) { + longlong tmp; my_decimal value, *arg_dec= args[0]->val_decimal(&value); if (args[0]->null_value) { - my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero, - res, f_precision, f_scale); - res+= dec_bin_size; - longlong tmp=0; - int8store(res,tmp); + arg_dec= &decimal_zero; + tmp= 0; } else - { - my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, - res, f_precision, f_scale); - res+= dec_bin_size; - longlong tmp=1; - int8store(res,tmp); - } + tmp= 1; + my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, res, f_precision, f_scale); + res+= dec_bin_size; + int8store(res, tmp); } else { @@ -1686,14 +1638,15 @@ void Item_sum_avg::reset_field() bzero(res,sizeof(double)+sizeof(longlong)); else { + longlong tmp= 1; float8store(res,nr); res+=sizeof(double); - longlong tmp=1; int8store(res,tmp); } } } + void Item_sum_bit::reset_field() { reset(); @@ -1708,6 +1661,7 @@ void Item_sum_bit::update_field() int8store(res, bits); } + /* ** calc next value and merge it with field_value */ @@ -1781,36 +1735,36 @@ void Item_sum_avg::update_field() dec_buffs + 1, f_precision, f_scale); field_count= sint8korr(res + dec_bin_size); my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, dec_buffs + 1); - field_count++; my_decimal2binary(E_DEC_FATAL_ERROR, dec_buffs, res, f_precision, f_scale); res+= dec_bin_size; + field_count++; int8store(res, field_count); } } else { - double nr, old_nr; - - float8get(old_nr, res); - field_count= sint8korr(res + sizeof(double)); + double nr; nr= args[0]->val_real(); if (!args[0]->null_value) { + double old_nr; + float8get(old_nr, res); + field_count= sint8korr(res + sizeof(double)); old_nr+= nr; + float8store(res,old_nr); + res+= sizeof(double); field_count++; + int8store(res, field_count); } - float8store(res,old_nr); - res+= sizeof(double); - int8store(res, field_count); } } + void Item_sum_hybrid::update_field() { - switch (hybrid_type) - { + switch (hybrid_type) { case STRING_RESULT: min_max_update_str_field(); break; @@ -1938,52 +1892,45 @@ Item_avg_field::Item_avg_field(Item_result res_type, Item_sum_avg *item) double Item_avg_field::val_real() { // fix_fields() never calls for this Item + double nr; + longlong count; + char *res; + if (hybrid_type == DECIMAL_RESULT) - { - my_decimal value, *dec_val= val_decimal(&value); - if (null_value) - return 0.0; - double d; - my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &d); - return d; - } - else - { - double nr; - longlong count; - float8get(nr,field->ptr); - char *res=(field->ptr+sizeof(double)); - count=sint8korr(res); + return val_real_from_decimal(); - if (!count) - { - null_value=1; - return 0.0; - } - null_value=0; - return nr/(double) count; - } + float8get(nr,field->ptr); + res= (field->ptr+sizeof(double)); + count= sint8korr(res); + + if ((null_value= !count)) + return 0.0; + return nr/(double) count; } + longlong Item_avg_field::val_int() { - return (longlong)val_real(); + return (longlong) val_real(); } -my_decimal *Item_avg_field::val_decimal(my_decimal * val) +my_decimal *Item_avg_field::val_decimal(my_decimal *dec_buf) { // fix_fields() never calls for this Item + if (hybrid_type == REAL_RESULT) + return val_decimal_from_real(dec_buf); + longlong count= sint8korr(field->ptr + dec_bin_size); if ((null_value= !count)) - return NULL; + return 0; my_decimal dec_count, dec_field; binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr, &dec_field, f_precision, f_scale); int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count); - my_decimal_div(E_DEC_FATAL_ERROR, val, &dec_field, &dec_count, 4); - return val; + my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &dec_field, &dec_count, 4); + return dec_buf; } @@ -1991,35 +1938,64 @@ String *Item_avg_field::val_str(String *str) { // fix_fields() never calls for this Item if (hybrid_type == DECIMAL_RESULT) - { - my_decimal value, *dec_val= val_decimal(&value); - if (null_value) - return NULL; - my_decimal_round(E_DEC_FATAL_ERROR, dec_val, decimals, FALSE, &value); - my_decimal2string(E_DEC_FATAL_ERROR, &value, 0, 0, 0, str); - } - else - { - double nr= Item_avg_field::val_real(); - if (null_value) - return 0; - str->set(nr, decimals, &my_charset_bin); - } - return str; + return val_string_from_decimal(str); + return val_string_from_real(str); } + Item_std_field::Item_std_field(Item_sum_std *item) : Item_variance_field(item) { } + double Item_std_field::val_real() { + double nr; // fix_fields() never calls for this Item - double tmp= Item_variance_field::val_real(); - return tmp <= 0.0 ? 0.0 : sqrt(tmp); + if (hybrid_type == REAL_RESULT) + { + /* + We can't call Item_variance_field::val_real() on a DECIMAL_RESULT + as this would call Item_std_field::val_decimal() and we would + calculate sqrt() twice + */ + nr= Item_variance_field::val_real(); + } + else + { + my_decimal dec_buf,*dec; + dec= Item_variance_field::val_decimal(&dec_buf); + if (!dec) + nr= 0.0; // NULL; Return 0.0 + else + my_decimal2double(E_DEC_FATAL_ERROR, dec, &nr); + } + return nr <= 0.0 ? 0.0 : sqrt(nr); } + +my_decimal *Item_std_field::val_decimal(my_decimal *dec_buf) +{ + /* + We can't call val_decimal_from_real() for DECIMAL_RESULT as + Item_variance_field::val_real() would cause an infinite loop + */ + my_decimal tmp_dec, *dec; + double nr; + if (hybrid_type == REAL_RESULT) + return val_decimal_from_real(dec_buf); + dec= Item_variance_field::val_decimal(dec_buf); + if (!dec) + return 0; + my_decimal2double(E_DEC_FATAL_ERROR, dec, &nr); + nr= nr <= 0.0 ? 0.0 : sqrt(nr); + double2my_decimal(E_DEC_FATAL_ERROR, nr, &tmp_dec); + my_decimal_round(E_DEC_FATAL_ERROR, &tmp_dec, decimals, FALSE, dec_buf); + return dec_buf; +} + + Item_variance_field::Item_variance_field(Item_sum_variance *item) { name=item->name; @@ -2038,49 +2014,42 @@ Item_variance_field::Item_variance_field(Item_sum_variance *item) } } + double Item_variance_field::val_real() { // fix_fields() never calls for this Item if (hybrid_type == DECIMAL_RESULT) - { - my_decimal dec_buf, *dec_val= val_decimal(&dec_buf); - if (null_value) - return 0.0; - double d; - my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &d); - return d; - } + return val_real_from_decimal(); + double sum,sum_sqr; longlong count; float8get(sum,field->ptr); float8get(sum_sqr,(field->ptr+sizeof(double))); count=sint8korr(field->ptr+sizeof(double)*2); - if (!count) - { - null_value=1; + if ((null_value= !count)) return 0.0; - } - null_value=0; + double tmp= (double) count; double tmp2=(sum_sqr - sum*sum/tmp)/tmp; return tmp2 <= 0.0 ? 0.0 : tmp2; } + String *Item_variance_field::val_str(String *str) { - // fix_fields() never calls for this Item - double nr= val_real(); - if (null_value) - return 0; - str->set(nr,decimals, &my_charset_bin); - return str; + if (hybrid_type == DECIMAL_RESULT) + return val_string_from_decimal(str); + return val_string_from_real(str); } my_decimal *Item_variance_field::val_decimal(my_decimal *dec_buf) { // fix_fields() never calls for this Item + if (hybrid_type == REAL_RESULT) + return val_decimal_from_real(dec_buf); + longlong count= sint8korr(field->ptr+dec_bin_size0+dec_bin_size1); if ((null_value= !count)) return 0; @@ -2478,55 +2447,34 @@ double Item_sum_udf_float::val_real() DBUG_RETURN(udf.val(&null_value)); } + String *Item_sum_udf_float::val_str(String *str) { - DBUG_ASSERT(fixed == 1); - double nr= val_real(); - if (null_value) - return 0; /* purecov: inspected */ - str->set(nr,decimals, &my_charset_bin); - return str; + return val_string_from_real(str); } -Item *Item_sum_udf_int::copy_or_same(THD* thd) +my_decimal *Item_sum_udf_float::val_decimal(my_decimal *dec) { - return new (thd->mem_root) Item_sum_udf_int(thd, this); + return val_decimal_from_real(dec); } String *Item_sum_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; + return val_string_from_decimal(str); } double Item_sum_udf_decimal::val_real() { - my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); - if (null_value) - return 0.0; - double result; - my_decimal2double(E_DEC_FATAL_ERROR, dec, &result); - return result; + return val_real_from_decimal(); } longlong Item_sum_udf_decimal::val_int() { - my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); - if (null_value) - return 0; - longlong result; - my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result); - return result; + return val_int_from_decimal(); } @@ -2547,6 +2495,11 @@ Item *Item_sum_udf_decimal::copy_or_same(THD* thd) } +Item *Item_sum_udf_int::copy_or_same(THD* thd) +{ + return new (thd->mem_root) Item_sum_udf_int(thd, this); +} + longlong Item_sum_udf_int::val_int() { DBUG_ASSERT(fixed == 1); @@ -2559,14 +2512,15 @@ longlong Item_sum_udf_int::val_int() String *Item_sum_udf_int::val_str(String *str) { - DBUG_ASSERT(fixed == 1); - longlong nr=val_int(); - if (null_value) - return 0; - str->set(nr, &my_charset_bin); - return str; + return val_string_from_int(str); } +my_decimal *Item_sum_udf_int::val_decimal(my_decimal *dec) +{ + return val_decimal_from_int(dec); +} + + /* Default max_length is max argument length */ void Item_sum_udf_str::fix_length_and_dec() @@ -2585,6 +2539,11 @@ Item *Item_sum_udf_str::copy_or_same(THD* thd) } +my_decimal *Item_sum_udf_str::val_decimal(my_decimal *dec) +{ + return val_decimal_from_string(dec); +} + String *Item_sum_udf_str::val_str(String *str) { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_sum.h b/sql/item_sum.h index d759f5607c3..e284416f0f5 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -78,7 +78,6 @@ public: virtual void update_field()=0; virtual bool keep_field_type(void) const { return 0; } virtual void fix_length_and_dec() { maybe_null=1; null_value=1; } - my_decimal *val_decimal(my_decimal *); virtual const char *func_name() const { return "?"; } virtual Item *result_item(Field *field) { return new Item_field(field);} @@ -93,7 +92,6 @@ public: virtual bool setup(THD *thd) {return 0;} virtual void make_unique() {} Item *get_tmp_table_item(THD *thd); - virtual int scale() { return decimals; } virtual Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); @@ -129,6 +127,7 @@ public: Item_sum_int(THD *thd, Item_sum_int *item) :Item_sum_num(thd, item) {} double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); } String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { decimals=0; max_length=21; maybe_null=null_value=0; } @@ -176,6 +175,7 @@ class Item_sum_sum_distinct :public Item_sum_sum Unique *tree; byte *dec_bin_buff; my_decimal tmp_dec; + uint key_length; private: Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item); public: @@ -451,7 +451,9 @@ public: Item_std_field(Item_sum_std *item); enum Type type() const { return FIELD_STD_ITEM; } double val_real(); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return REAL_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;} }; /* @@ -472,6 +474,7 @@ class Item_sum_std :public Item_sum_variance const char *func_name() const { return "std"; } Item *copy_or_same(THD* thd); enum Item_result result_type () const { return REAL_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE;} }; // This class is a string or number function depending on num_func @@ -650,6 +653,7 @@ class Item_sum_udf_float :public Item_udf_sum } double val_real(); String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); void fix_length_and_dec() { fix_num_length_and_dec(); } Item *copy_or_same(THD* thd); }; @@ -667,6 +671,7 @@ public: double val_real() { DBUG_ASSERT(fixed == 1); return (double) Item_sum_udf_int::val_int(); } String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { decimals=0; max_length=21; } Item *copy_or_same(THD* thd); @@ -697,11 +702,13 @@ public: return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10, (char**) 0, &err_not_used) : (longlong) 0; } + my_decimal *val_decimal(my_decimal *dec); enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec(); Item *copy_or_same(THD* thd); }; + class Item_sum_udf_decimal :public Item_udf_sum { public: @@ -864,6 +871,10 @@ class Item_func_group_concat : public Item_sum end_ptr= (char*) res->ptr()+ res->length(); return my_strtoll10(res->ptr(), &end_ptr, &error); } + my_decimal *val_decimal(my_decimal *decimal_value) + { + return val_decimal_from_string(decimal_value); + } String* val_str(String* str); Item *copy_or_same(THD* thd); void no_rows_in_result() {} diff --git a/sql/log_event.cc b/sql/log_event.cc index d499a3316be..1cdb1652d17 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3355,7 +3355,7 @@ void User_var_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* las bin2decimal(val+2, &dec, precision, scale); decimal2string(&dec, str_buf, &str_len, 0, 0, 0); str_buf[str_len]= 0; - fprintf(file, "%s",str_buf); + fprintf(file, ":=%s;\n",str_buf); break; } case STRING_RESULT: diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index 36229d1c795..3e3538a1da9 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -13,6 +13,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #include "mysql_priv.h" #ifndef MYSQL_CLIENT @@ -154,10 +155,11 @@ int my_decimal2binary(uint mask, const my_decimal *d, char *bin, int prec, E_DEC_BAD_NUM E_DEC_OOM */ + int str2my_decimal(uint mask, const char *from, uint length, CHARSET_INFO *charset, my_decimal *decimal_value) { - char *end; + char *end, *from_end; int err; char buff[STRING_BUFFER_USUAL_SIZE]; String tmp(buff, sizeof(buff), &my_charset_bin); @@ -169,10 +171,20 @@ int str2my_decimal(uint mask, const char *from, uint length, length= tmp.length(); charset= &my_charset_bin; } - my_decimal_set_zero(decimal_value); + from_end= end= (char*) from+length; err= string2decimal((char *)from, (decimal *)decimal_value, &end); - if ((uint) (end-from) != length && !err) - err= E_DEC_TRUNCATED; + if (end != from_end && !err) + { + /* Give warining if there is something other than end space */ + for ( ; end < from_end; end++) + { + if (!my_isspace(&my_charset_latin1, *end)) + { + err= E_DEC_TRUNCATED; + break; + } + } + } check_result(mask, err); return err; } @@ -200,12 +212,25 @@ print_decimal_buff(const my_decimal *dec, const byte* ptr, int length) { print_decimal(dec); fprintf(DBUG_FILE, "Record: "); - for(int i= 0; i < length; i++) + for (int i= 0; i < length; i++) { fprintf(DBUG_FILE, "%02X ", (uint)((uchar *)ptr)[i]); } fprintf(DBUG_FILE, "\n"); } + + +void dbug_print_decimal(const char *tag, const char *format, my_decimal *val) +{ + char buff[DECIMAL_MAX_STR_LENGTH]; + String str(buff, sizeof(buff), &my_charset_bin); + if (!val) + str.set("NULL", 4, &my_charset_bin); + else + my_decimal2string(0, val, 0, 0, 0, &str); + DBUG_PRINT(tag, (format, val)); +} + #endif diff --git a/sql/my_decimal.h b/sql/my_decimal.h index f4841418074..b3d6b6ccde6 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -68,10 +68,13 @@ inline uint my_decimal_size(uint precision, uint scale) } -/* my_decimal class limits 'decimal' type to what we need in MySQL */ -/* It internally all necessary space iside the instance so no extra */ -/* memory is needed. One should call fix_buffer_pointer() function */ -/* when he moves my_decimal objects in memory */ +/* + my_decimal class limits 'decimal' type to what we need in MySQL + It contains internally all necessary space needed by the instance so + no extra memory is needed. One should call fix_buffer_pointer() function + when he moves my_decimal objects in memory +*/ + class my_decimal :public decimal { decimal_digit buffer[DECIMAL_BUFF_LENGTH]; @@ -83,6 +86,7 @@ public: len= DECIMAL_BUFF_LENGTH; buf= buffer; #if !defined(HAVE_purify) && !defined(DBUG_OFF) + /* Set buffer to 'random' value to find wrong buffer usage */ for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++) buffer[i]= i; #endif @@ -101,6 +105,9 @@ public: #ifndef DBUG_OFF void print_decimal(const my_decimal *dec); void print_decimal_buff(const my_decimal *dec, const byte* ptr, int length); +void dbug_print_decimal(const char *tag, const char *format, my_decimal *val); +#else +#define dbug_print_decimal(A,B,C) #endif #ifndef MYSQL_CLIENT @@ -158,7 +165,7 @@ inline int binary2my_decimal(uint mask, const char *bin, my_decimal *d, int prec, int scale) { - return check_result(mask, bin2decimal((char *)bin, (decimal *)d, prec, + return check_result(mask, bin2decimal((char *)bin, (decimal*) d, prec, scale)); } @@ -166,7 +173,7 @@ int binary2my_decimal(uint mask, const char *bin, my_decimal *d, int prec, inline int my_decimal_set_zero(my_decimal *d) { - decimal_make_zero(((decimal *)d)); + decimal_make_zero(((decimal*) d)); return 0; } @@ -174,7 +181,7 @@ int my_decimal_set_zero(my_decimal *d) inline bool my_decimal_is_zero(const my_decimal *decimal_value) { - return decimal_is_zero((decimal *)decimal_value); + return decimal_is_zero((decimal*) decimal_value); } @@ -182,7 +189,7 @@ inline int my_decimal_round(uint mask, const my_decimal *from, int scale, bool truncate, my_decimal *to) { - return check_result(mask, decimal_round((decimal *)from, to, scale, + return check_result(mask, decimal_round((decimal*) from, to, scale, (truncate ? TRUNCATE : HALF_UP))); } @@ -190,14 +197,14 @@ int my_decimal_round(uint mask, const my_decimal *from, int scale, inline int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to) { - return check_result(mask, decimal_round((decimal *)from, to, 0, FLOOR)); + return check_result(mask, decimal_round((decimal*) from, to, 0, FLOOR)); } inline int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to) { - return check_result(mask, decimal_round((decimal *)from, to, 0, CEILING)); + return check_result(mask, decimal_round((decimal*) from, to, 0, CEILING)); } @@ -222,17 +229,15 @@ int my_decimal2int(uint mask, const my_decimal *d, my_bool unsigned_flag, inline int my_decimal2double(uint mask, const my_decimal *d, double *result) { - return check_result(mask, decimal2double((decimal *)d, result)); + /* No need to call check_result as this will always succeed */ + return decimal2double((decimal*) d, result); } inline -int str2my_decimal(uint mask, const char *str, my_decimal *d, - char **end= 0) +int str2my_decimal(uint mask, const char *str, my_decimal *d, char **end) { - /* set it to 0 to avoid junk in value in case of error of conversion */ - my_decimal_set_zero(d); - return check_result(mask, string2decimal((char *)str, (decimal *)d, end)); + return check_result(mask, string2decimal(str, (decimal*) d, end)); } @@ -252,7 +257,7 @@ int string2my_decimal(uint mask, const String *str, my_decimal *d) inline int double2my_decimal(uint mask, double val, my_decimal *d) { - return check_result(mask, double2decimal(val, (decimal *)d)); + return check_result(mask, double2decimal(val, (decimal*) d)); } @@ -266,10 +271,9 @@ int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d) inline -int my_decimal_neg(st_decimal *arg) +void my_decimal_neg(st_decimal *arg) { decimal_neg(arg); - return 0; } @@ -277,7 +281,7 @@ inline int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b) { - return check_result(mask, decimal_add((decimal *)a, (decimal *)b, res)); + return check_result(mask, decimal_add((decimal*) a, (decimal*) b, res)); } @@ -285,7 +289,7 @@ inline int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b) { - return check_result(mask, decimal_sub((decimal *)a, (decimal *)b, res)); + return check_result(mask, decimal_sub((decimal*) a, (decimal*) b, res)); } @@ -293,7 +297,7 @@ inline int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b) { - return check_result(mask, decimal_mul((decimal *)a, (decimal *)b, res)); + return check_result(mask, decimal_mul((decimal*) a, (decimal*) b, res)); } @@ -301,7 +305,7 @@ inline int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b, int div_scale_inc) { - return check_result(mask, decimal_div((decimal *)a, (decimal *)b, res, + return check_result(mask, decimal_div((decimal*) a, (decimal*) b, res, div_scale_inc)); } @@ -310,7 +314,7 @@ inline int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a, const my_decimal *b) { - return check_result(mask, decimal_mod((decimal *)a, (decimal *)b, res)); + return check_result(mask, decimal_mod((decimal*) a, (decimal*) b, res)); } @@ -318,14 +322,14 @@ int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a, inline int my_decimal_cmp(const my_decimal *a, const my_decimal *b) { - return decimal_cmp((decimal *)a, (decimal *)b); + return decimal_cmp((decimal*) a, (decimal*) b); } inline void max_my_decimal(my_decimal *to, int precision, int frac) { DBUG_ASSERT(precision <= DECIMAL_MAX_LENGTH); - max_decimal(precision, frac, (decimal *)to); + max_decimal(precision, frac, (decimal*) to); } #endif /*my_decimal_h*/ diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2e6f86858be..942822c2f12 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -400,8 +400,6 @@ typedef struct st_sql_list { } SQL_LIST; -uint nr_of_decimals(const char *str); /* Neaded by sql_string.h */ - extern pthread_key(THD*, THR_THD); inline THD *_current_thd(void) { diff --git a/sql/protocol.cc b/sql/protocol.cc index 7c56bb3fc7a..657341b8bdc 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -822,15 +822,9 @@ bool Protocol_simple::store_decimal(const my_decimal *d) field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL); field_pos++; #endif - int buf_size= my_decimal_string_length(d); - char *buff= (char *)my_alloca(buf_size); - String str(buff, buf_size, &my_charset_bin); - if (my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str)) - { - my_afree(buff); - return TRUE; - } - my_afree(buff); + char buff[DECIMAL_MAX_STR_LENGTH]; + String str(buff, sizeof(buff), &my_charset_bin); + (void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str); return net_store_data(str.ptr(), str.length()); } @@ -1056,15 +1050,9 @@ bool Protocol_prep::store_decimal(const my_decimal *d) field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL); field_pos++; #endif - int buf_size= my_decimal_string_length(d); - char *buff= (char *)my_alloca(buf_size); - String str(buff, buf_size, &my_charset_bin); - if (my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str)) - { - my_afree(buff); - return TRUE; - } - my_afree(buff); + char buff[DECIMAL_MAX_STR_LENGTH]; + String str(buff, sizeof(buff), &my_charset_bin); + (void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str); return store(str.ptr(), str.length(), str.charset()); } diff --git a/sql/protocol_cursor.cc b/sql/protocol_cursor.cc index a5bf94469e7..5ac03c4d427 100644 --- a/sql/protocol_cursor.cc +++ b/sql/protocol_cursor.cc @@ -104,15 +104,15 @@ bool Protocol_cursor::write() byte *to; new_record= (MYSQL_ROWS *)alloc_root(alloc, - sizeof(MYSQL_ROWS) + (field_count + 1)*sizeof(char *) + packet->length()); + sizeof(MYSQL_ROWS) + (field_count + 2)*sizeof(char *) + packet->length()); if (!new_record) goto err; data_tmp= (byte **)(new_record + 1); new_record->data= (char **)data_tmp; - to= (byte *)data_tmp + (field_count + 1)*sizeof(char *); + to= (byte *)data_tmp + (field_count + 2)*sizeof(char *); - for (; cur_field < fields_end; ++cur_field, ++data_tmp) + for (; cur_field < fields_end; cur_field++, data_tmp++) { if ((len= net_field_length((uchar **)&cp)) == 0 || len == NULL_LENGTH) @@ -135,7 +135,8 @@ bool Protocol_cursor::write() cur_field->max_length=len; } } - *data_tmp= 0; + data_tmp[0]= to; // Pointer to last used byte + data_tmp[1]= 0; *prev_record= new_record; prev_record= &new_record->next; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 4c03e88f33a..cd301106907 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -158,69 +158,12 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type) } case DECIMAL_RESULT: { - switch (it->result_type()) - { - case DECIMAL_RESULT: - { - my_decimal value, *val= it->val_decimal(&value); - if (it->null_value) - it= new Item_null(); - else - it= new Item_decimal(val); - break; - } - case INT_RESULT: - { - longlong val= it->val_int(); - if (it->null_value) - it= new Item_null(); - else - it= new Item_decimal(val, (int)it->max_length, - (bool)it->unsigned_flag); - break; - } - case REAL_RESULT: - { - double val= it->val_real(); - if (it->null_value) - it= new Item_null(); - else - it= new Item_decimal(val, (int)it->max_length, - (int)it->decimals); - break; - } - case STRING_RESULT: - { - char buffer[MAX_FIELD_WIDTH]; - String tmp(buffer, sizeof(buffer), it->collation.collation); - String *val= it->val_str(&tmp); - if (it->null_value) - it= new Item_null(); - else - it= new Item_decimal(val->ptr(), val->length(), val->charset()); - break; - } - case ROW_RESULT: - default: - DBUG_ASSERT(0); - } -#ifndef DBUG_OFF + my_decimal value, *val= it->val_decimal(&value); if (it->null_value) - { - DBUG_PRINT("info", ("DECIMAL_RESULT: null")); - } + it= new Item_null(); else - { - my_decimal value, *val= it->val_decimal(&value); - int len; - char *buff= - (char *)my_alloca(len= my_decimal_string_length(val) + 3); - String str(buff, len, &my_charset_bin); - my_decimal2string(0, val, 0, 0, 0, &str); - DBUG_PRINT("info", ("DECIMAL_RESULT: %s", str.ptr())); - my_afree(buff); - } -#endif + it= new Item_decimal(val); + dbug_print_decimal("info", "DECIMAL_RESULT: %s", val); break; } case STRING_RESULT: @@ -236,8 +179,9 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type) } else { - DBUG_PRINT("info",("default result: %*s",s->length(),s->c_ptr_quick())); - it= new Item_string(thd->strmake(s->c_ptr_quick(), s->length()), + DBUG_PRINT("info",("default result: %*s", + s->length(), s->c_ptr_quick())); + it= new Item_string(thd->strmake(s->ptr(), s->length()), s->length(), it->collation.collation); } break; @@ -811,7 +755,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) suv= new Item_func_set_user_var(guv->get_name(), item); /* - we do not check suv->fixed, bacause it can't be fixed after + we do not check suv->fixed, because it can't be fixed after creation */ suv->fix_fields(thd, NULL, &item); diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 0c6c8c5aa70..5b177650726 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -243,27 +243,36 @@ sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars) if (!s) it= new Item_null(); else - switch (sp_map_result_type(pv->type)) - { + { + /* + Length of data can be calculated as: + pointer_to_next_not_null_object - s -1 + where the last -1 is to remove the end \0 + */ + uint len; + MYSQL_ROW next= row+fldcount+1; + while (!*next) // Skip nulls + next++; + len= (*next -s)-1; + switch (sp_map_result_type(pv->type)) { case INT_RESULT: it= new Item_int(s); break; case REAL_RESULT: - it= new Item_float(s, strlen(s)); + it= new Item_float(s, len); break; case DECIMAL_RESULT: - it= new Item_decimal(s, strlen(s), thd->db_charset); + it= new Item_decimal(s, len, thd->db_charset); break; case STRING_RESULT: - { - uint len= strlen(s); - it= new Item_string(thd->strmake(s, len), len, thd->db_charset); - break; - } + /* TODO: Document why we do an extra copy of the string 's' here */ + it= new Item_string(thd->strmake(s, len), len, thd->db_charset); + break; case ROW_RESULT: default: DBUG_ASSERT(0); } + } thd->spcont->set_item(pv->offset, it); } if (fldcount < m_prot->get_field_count()) diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index c2eea524cac..642de13039e 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -133,22 +133,30 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, Item *item; while ((item = it++)) { - if (item->result_type() == INT_RESULT) - { + field_info *new_field; + switch (item->result_type()) { + case INT_RESULT: // Check if fieldtype is ulonglong if (item->type() == Item::FIELD_ITEM && ((Item_field*) item)->field->type() == FIELD_TYPE_LONGLONG && ((Field_longlong*) ((Item_field*) item)->field)->unsigned_flag) - *f_info++ = new field_ulonglong(item, pc); + new_field= new field_ulonglong(item, pc); else - *f_info++ = new field_longlong(item, pc); + new_field= new field_longlong(item, pc); + break; + case REAL_RESULT: + new_field= new field_real(item, pc); + break; + case DECIMAL_RESULT: + new_field= new field_decimal(item, pc); + break; + case STRING_RESULT: + new_field= new field_str(item, pc); + break; + default: + goto err; } - if (item->result_type() == REAL_RESULT) - *f_info++ = new field_real(item, pc); - if (item->result_type() == DECIMAL_RESULT) - *f_info++= new field_decimal(item, pc); - if (item->result_type() == STRING_RESULT) - *f_info++ = new field_str(item, pc); + *f_info++= new_field; } } DBUG_RETURN(pc); @@ -470,6 +478,9 @@ void field_decimal::add() length= my_decimal_string_length(dec); + if (decimal_is_zero(dec)) + empty++; + if (room_in_tree) { char buf[DECIMAL_MAX_FIELD_SIZE]; @@ -502,7 +513,7 @@ void field_decimal::add() cur_sum= 0; min_length = max_length = length; } - else + else if (!decimal_is_zero(dec)) { int next_cur_sum= cur_sum ^ 1; my_decimal sqr_buf; @@ -972,15 +983,17 @@ void field_decimal::get_opt_type(String *answer, { my_decimal zero; char buff[MAX_FIELD_WIDTH]; + uint length; my_decimal_set_zero(&zero); my_bool is_unsigned= (my_decimal_cmp(&zero, &min_arg) >= 0); - sprintf(buff, "DECIMAL(%d, %d)", - (int)(max_length - (item->decimals ? 1 : 0)), item->decimals); + length= my_sprintf(buff, (buff, "DECIMAL(%d, %d)", + (int) (max_length - (item->decimals ? 1 : 0)), + item->decimals)); if (is_unsigned) - strcat(buff, " UNSIGNED"); - answer->append(buff, (uint) strlen(buff)); + length= (uint) (strmov(buff+length, " UNSIGNED")- buff); + answer->append(buff, length); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 6f8c3efcd69..8628e412d86 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3412,8 +3412,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) thd->restore_backup_item_arena(arena, &backup); if (*conds && !(*conds)->fixed) { - if (!(*conds)->fixed && - (*conds)->fix_fields(thd, tables, conds)) + if ((*conds)->fix_fields(thd, tables, conds)) goto err_no_arena; } } @@ -3425,8 +3424,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) thd->restore_backup_item_arena(arena, &backup); if (embedded->on_expr && !embedded->on_expr->fixed) { - if (!embedded->on_expr->fixed && - embedded->on_expr->fix_fields(thd, tables, &embedded->on_expr)) + if (embedded->on_expr->fix_fields(thd, tables, + &embedded->on_expr)) goto err_no_arena; } } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index fa6db61d2d8..7dfb7a99ab3 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1344,10 +1344,9 @@ bool select_max_min_finder_subselect::cmp_real() return (cache->null_value && !maxmin->null_value) || (!cache->null_value && !maxmin->null_value && val1 > val2); - else - return (maxmin->null_value && !cache->null_value) || - (!cache->null_value && !maxmin->null_value && - val1 < val2); + return (maxmin->null_value && !cache->null_value) || + (!cache->null_value && !maxmin->null_value && + val1 < val2); } bool select_max_min_finder_subselect::cmp_int() @@ -1358,30 +1357,23 @@ bool select_max_min_finder_subselect::cmp_int() return (cache->null_value && !maxmin->null_value) || (!cache->null_value && !maxmin->null_value && val1 > val2); - else - return (maxmin->null_value && !cache->null_value) || - (!cache->null_value && !maxmin->null_value && - val1 < val2); + return (maxmin->null_value && !cache->null_value) || + (!cache->null_value && !maxmin->null_value && + val1 < val2); } bool select_max_min_finder_subselect::cmp_decimal() { - String *val1, *val2, buf1, buf2; Item *maxmin= ((Item_singlerow_subselect *)item)->el(0); - /* - as far as both operand is Item_cache buf1 & buf2 will not be used, - but added for safety - */ my_decimal cval, *cvalue= cache->val_decimal(&cval); my_decimal mval, *mvalue= maxmin->val_decimal(&mval); if (fmax) return (cache->null_value && !maxmin->null_value) || (!cache->null_value && !maxmin->null_value && my_decimal_cmp(cvalue, mvalue) > 0) ; - else - return (maxmin->null_value && !cache->null_value) || - (!cache->null_value && !maxmin->null_value && - my_decimal_cmp(cvalue,mvalue) < 0); + return (maxmin->null_value && !cache->null_value) || + (!cache->null_value && !maxmin->null_value && + my_decimal_cmp(cvalue,mvalue) < 0); } bool select_max_min_finder_subselect::cmp_str() @@ -1398,10 +1390,9 @@ bool select_max_min_finder_subselect::cmp_str() return (cache->null_value && !maxmin->null_value) || (!cache->null_value && !maxmin->null_value && sortcmp(val1, val2, cache->collation.collation) > 0) ; - else - return (maxmin->null_value && !cache->null_value) || - (!cache->null_value && !maxmin->null_value && - sortcmp(val1, val2, cache->collation.collation) < 0); + return (maxmin->null_value && !cache->null_value) || + (!cache->null_value && !maxmin->null_value && + sortcmp(val1, val2, cache->collation.collation) < 0); } bool select_exists_subselect::send_data(List<Item> &items) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index dead6a6e08e..91ced987f6a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7217,8 +7217,9 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top) if (conds) { conds= and_conds(conds, table->on_expr); - if (!conds->fixed) - conds->fix_fields(join->thd, 0, &conds); + /* conds is always a new item as both cond and on_expr existed */ + DBUG_ASSERT(!conds->fixed); + conds->fix_fields(join->thd, 0, &conds); } else conds= table->on_expr; diff --git a/strings/decimal.c b/strings/decimal.c index 16c80158722..212bd7204f6 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -743,12 +743,12 @@ int decimal_shift(decimal *dec, int shift) Convert string to decimal SYNOPSIS - str2decl() - from - value to convert + internal_str2decl() + from - value to convert. Doesn't have to be \0 terminated! to - decimal where where the result will be stored to->buf and to->len must be set. - end - if not NULL, *end will be set to the char where - conversion ended + end - Pointer to pointer to end of string. Will on return be + set to the char after the last used character fixed - use to->intg, to->frac as limits for input number NOTE @@ -757,31 +757,36 @@ int decimal_shift(decimal *dec, int shift) RETURN VALUE E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW/E_DEC_BAD_NUM/E_DEC_OOM + In case of E_DEC_FATAL_ERROR *to is set to decimal zero + (to make error handling easier) */ -static int str2dec(char *from, decimal *to, char **end, my_bool fixed) +int internal_str2dec(const char *from, decimal *to, char **end, my_bool fixed) { - char *s=from, *s1, *endp; + const char *s= from, *s1, *endp, *end_of_string= *end; int i, intg, frac, error, intg1, frac1; dec1 x,*buf; - LINT_INIT(error); sanity(to); - while (my_isspace(&my_charset_latin1, *s)) + error= E_DEC_BAD_NUM; /* In case of bad number */ + while (s < end_of_string && my_isspace(&my_charset_latin1, *s)) s++; + if (s == end_of_string) + goto fatal_error; + if ((to->sign= (*s == '-'))) s++; else if (*s == '+') s++; s1=s; - while (my_isdigit(&my_charset_latin1, *s)) + while (s < end_of_string && my_isdigit(&my_charset_latin1, *s)) s++; intg=s-s1; - if (*s=='.') + if (s < end_of_string && *s=='.') { endp= s+1; - while (my_isdigit(&my_charset_latin1, *endp)) + while (s < end_of_string && my_isdigit(&my_charset_latin1, *endp)) endp++; frac= endp - s - 1; } @@ -791,12 +796,12 @@ static int str2dec(char *from, decimal *to, char **end, my_bool fixed) endp= s; } - if (end) - *end= endp; + *end= (char*) endp; if (frac+intg == 0) - return E_DEC_BAD_NUM; + goto fatal_error; + error= 0; if (fixed) { if (frac > to->frac) @@ -812,7 +817,10 @@ static int str2dec(char *from, decimal *to, char **end, my_bool fixed) intg1=ROUND_UP(intg); frac1=ROUND_UP(frac); if (intg1+frac1 > to->len) - return E_DEC_OOM; + { + error= E_DEC_OOM; + goto fatal_error; + } } else { @@ -861,36 +869,43 @@ static int str2dec(char *from, decimal *to, char **end, my_bool fixed) } if (i) *buf=x*powers10[DIG_PER_DEC1-i]; - if (*endp == 'e' || *endp == 'E') - { - long exp= strtol(endp + 1, &endp, 10); - - if (end) - *end= endp; - if (exp > INT_MAX/2) - return E_DEC_OVERFLOW; - if (exp < INT_MIN/2 && error != E_DEC_OVERFLOW) - return E_DEC_TRUNCATED; + /* Handle exponent */ + if (endp+1 < end_of_string && (*endp == 'e' || *endp == 'E')) + { + int str_error; + longlong exp= my_strtoll10(endp+1, (char**) &end_of_string, &str_error); - if(error != E_DEC_OVERFLOW) - error= decimal_shift(to, exp); + if (end_of_string != endp +1) /* If at least one digit */ + { + *end= (char*) end_of_string; + if (str_error > 0) + { + error= E_DEC_BAD_NUM; + goto fatal_error; + } + if (exp > INT_MAX/2 || (str_error == 0 && exp < 0)) + { + error= E_DEC_OVERFLOW; + goto fatal_error; + } + if (exp < INT_MIN/2 && error != E_DEC_OVERFLOW) + { + error= E_DEC_TRUNCATED; + goto fatal_error; + } + if (error != E_DEC_OVERFLOW) + error= decimal_shift(to, (int) exp); + } } + return error; +fatal_error: + decimal_make_zero(to); return error; } -int string2decimal(char *from, decimal *to, char **end) -{ - return str2dec(from, to, end, 0); -} - -int string2decimal_fixed(char *from, decimal *to, char **end) -{ - return str2dec(from, to, end, 1); -} - /* Convert decimal to double @@ -932,9 +947,10 @@ int decimal2double(decimal *from, double *to) int double2decimal(double from, decimal *to) { /* TODO: fix it, when we'll have dtoa */ - char s[400]; + char s[400], *end; sprintf(s, "%f", from); - return string2decimal(s, to, 0); + end= strend(s); + return string2decimal(s, to, &end); } static int ull2dec(ulonglong from, decimal *to) @@ -2160,13 +2176,13 @@ void check_result_code(int actual, int want) { if (actual != want) { - printf("\n^^^^^^^^^^^^^ mast return %d\n", want); + printf("\n^^^^^^^^^^^^^ must return %d\n", want); exit(1); } } -void print_decimal(decimal *d, char *orig, int actual, int want) +void print_decimal(decimal *d, const char *orig, int actual, int want) { char s[100]; int slen=sizeof(s); @@ -2218,38 +2234,41 @@ void test_d2s() dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); } -void test_s2d(char *s, char *orig, int ex) +void test_s2d(const char *s, const char *orig, int ex) { - char s1[100]; + char s1[100], *end; int res; sprintf(s1, "'%s'", s); + end= strend(s); printf("len=%2d %-30s => res=%d ", a.len, s1, - (res= string2decimal(s, &a, 0))); + (res= string2decimal(s, &a, &end))); print_decimal(&a, orig, res, ex); printf("\n"); } -void test_d2f(char *s, int ex) +void test_d2f(const char *s, int ex) { - char s1[100]; + char s1[100], *end; double x; int res; sprintf(s1, "'%s'", s); - string2decimal(s, &a, 0); + end= strend(s); + string2decimal(s, &a, &end); res=decimal2double(&a, &x); if (full) dump_decimal(&a); printf("%-40s => res=%d %.*g\n", s1, res, a.intg+a.frac, x); check_result_code(res, ex); } -void test_d2b2d(char *str, int p, int s, char *orig, int ex) +void test_d2b2d(const char *str, int p, int s, const char *orig, int ex) { - char s1[100], buf[100]; + char s1[100], buf[100], *end; int res, i, size=decimal_bin_size(p, s); sprintf(s1, "'%s'", str); - string2decimal(str, &a, 0); + end= strend(str); + string2decimal(str, &a, &end); res=decimal2bin(&a, buf, p, s); printf("%-31s {%2d, %2d} => res=%d size=%-2d ", s1, p, s, res, size); if (full) @@ -2263,6 +2282,7 @@ void test_d2b2d(char *str, int p, int s, char *orig, int ex) print_decimal(&a, orig, res, ex); printf("\n"); } + void test_f2d(double from, int ex) { int res; @@ -2273,7 +2293,7 @@ void test_f2d(double from, int ex) printf("\n"); } -void test_ull2d(ulonglong from, char *orig, int ex) +void test_ull2d(ulonglong from, const char *orig, int ex) { char s[100]; int res; @@ -2285,7 +2305,7 @@ void test_ull2d(ulonglong from, char *orig, int ex) printf("\n"); } -void test_ll2d(longlong from, char *orig, int ex) +void test_ll2d(longlong from, const char *orig, int ex) { char s[100]; int res; @@ -2297,13 +2317,14 @@ void test_ll2d(longlong from, char *orig, int ex) printf("\n"); } -void test_d2ull(char *s, char *orig, int ex) +void test_d2ull(const char *s, const char *orig, int ex) { - char s1[100]; + char s1[100], *end; ulonglong x; int res; - string2decimal(s, &a, 0); + end= strend(s); + string2decimal(s, &a, &end); res=decimal2ulonglong(&a, &x); if (full) dump_decimal(&a); longlong10_to_str(x,s1,10); @@ -2316,13 +2337,14 @@ void test_d2ull(char *s, char *orig, int ex) } } -void test_d2ll(char *s, char *orig, int ex) +void test_d2ll(const char *s, const char *orig, int ex) { - char s1[100]; + char s1[100], *end; longlong x; int res; - string2decimal(s, &a, 0); + end= strend(s); + string2decimal(s, &a, &end); res=decimal2longlong(&a, &x); if (full) dump_decimal(&a); longlong10_to_str(x,s1,-10); @@ -2335,39 +2357,45 @@ void test_d2ll(char *s, char *orig, int ex) } } -void test_da(char *s1, char *s2, char *orig, int ex) +void test_da(const char *s1, const char *s2, const char *orig, int ex) { - char s[100]; + char s[100], *end; int res; sprintf(s, "'%s' + '%s'", s1, s2); - string2decimal(s1, &a, 0); - string2decimal(s2, &b, 0); + end= strend(s1); + string2decimal(s1, &a, &end); + end= strend(s2); + string2decimal(s2, &b, &end); res=decimal_add(&a, &b, &c); printf("%-40s => res=%d ", s, res); print_decimal(&c, orig, res, ex); printf("\n"); } -void test_ds(char *s1, char *s2, char *orig, int ex) +void test_ds(const char *s1, const char *s2, const char *orig, int ex) { - char s[100]; + char s[100], *end; int res; sprintf(s, "'%s' - '%s'", s1, s2); - string2decimal(s1, &a, 0); - string2decimal(s2, &b, 0); + end= strend(s1); + string2decimal(s1, &a, &end); + end= strend(s2); + string2decimal(s2, &b, &end); res=decimal_sub(&a, &b, &c); printf("%-40s => res=%d ", s, res); print_decimal(&c, orig, res, ex); printf("\n"); } -void test_dc(char *s1, char *s2, int orig) +void test_dc(const char *s1, const char *s2, int orig) { - char s[100]; + char s[100], *end; int res; sprintf(s, "'%s' <=> '%s'", s1, s2); - string2decimal(s1, &a, 0); - string2decimal(s2, &b, 0); + end= strend(s1); + string2decimal(s1, &a, &end); + end= strend(s2); + string2decimal(s2, &b, &end); res=decimal_cmp(&a, &b); printf("%-40s => res=%d\n", s, res); if (orig != res) @@ -2377,26 +2405,30 @@ void test_dc(char *s1, char *s2, int orig) } } -void test_dm(char *s1, char *s2, char *orig, int ex) +void test_dm(const char *s1, const char *s2, const char *orig, int ex) { - char s[100]; + char s[100], *end; int res; sprintf(s, "'%s' * '%s'", s1, s2); - string2decimal(s1, &a, 0); - string2decimal(s2, &b, 0); + end= strend(s1); + string2decimal(s1, &a, &end); + end= strend(s2); + string2decimal(s2, &b, &end); res=decimal_mul(&a, &b, &c); printf("%-40s => res=%d ", s, res); print_decimal(&c, orig, res, ex); printf("\n"); } -void test_dv(char *s1, char *s2, char *orig, int ex) +void test_dv(const char *s1, const char *s2, const char *orig, int ex) { - char s[100]; + char s[100], *end; int res; sprintf(s, "'%s' / '%s'", s1, s2); - string2decimal(s1, &a, 0); - string2decimal(s2, &b, 0); + end= strend(s1); + string2decimal(s1, &a, &end); + end= strend(s2); + string2decimal(s2, &b, &end); res=decimal_div(&a, &b, &c, 5); printf("%-40s => res=%d ", s, res); check_result_code(res, ex); @@ -2407,13 +2439,15 @@ void test_dv(char *s1, char *s2, char *orig, int ex) printf("\n"); } -void test_md(char *s1, char *s2, char *orig, int ex) +void test_md(const char *s1, const char *s2, const char *orig, int ex) { - char s[100]; + char s[100], *end; int res; sprintf(s, "'%s' %% '%s'", s1, s2); - string2decimal(s1, &a, 0); - string2decimal(s2, &b, 0); + end= strend(s1); + string2decimal(s1, &a, &end); + end= strend(s2); + string2decimal(s2, &b, &end); res=decimal_mod(&a, &b, &c); printf("%-40s => res=%d ", s, res); check_result_code(res, ex); @@ -2424,14 +2458,17 @@ void test_md(char *s1, char *s2, char *orig, int ex) printf("\n"); } -char *round_mode[]={"TRUNCATE", "HALF_EVEN", "HALF_UP", "CEILING", "FLOOR"}; +const char *round_mode[]= +{"TRUNCATE", "HALF_EVEN", "HALF_UP", "CEILING", "FLOOR"}; -void test_ro(char *s1, int n, decimal_round_mode mode, char *orig, int ex) +void test_ro(const char *s1, int n, decimal_round_mode mode, const char *orig, + int ex) { - char s[100]; + char s[100], *end; int res; sprintf(s, "'%s', %d, %s", s1, n, round_mode[mode]); - string2decimal(s1, &a, 0); + end= strend(s1); + string2decimal(s1, &a, &end); res=decimal_round(&a, &b, n, mode); printf("%-40s => res=%d ", s, res); print_decimal(&b, orig, res, ex); @@ -2439,7 +2476,7 @@ void test_ro(char *s1, int n, decimal_round_mode mode, char *orig, int ex) } -void test_mx(int precision, int frac, char *orig) +void test_mx(int precision, int frac, const char *orig) { char s[100]; sprintf(s, "%d, %d", precision, frac); @@ -2450,15 +2487,17 @@ void test_mx(int precision, int frac, char *orig) } -void test_pr(char *s1, int prec, int dec, char filler, char *orig, int ex) +void test_pr(const char *s1, int prec, int dec, char filler, const char *orig, + int ex) { - char s[100]; + char s[100], *end; char s2[100]; int slen= sizeof(s2); int res; sprintf(s, "'%s', %d, %d, '%c'", s1, prec, dec, filler); - string2decimal(s1, &a, 0); + end= strend(s1); + string2decimal(s1, &a, &end); res= decimal2string(&a, s2, &slen, prec, dec, filler); printf("%-40s => res=%d '%s'", s, res, s2); check_result_code(res, ex); @@ -2471,12 +2510,13 @@ void test_pr(char *s1, int prec, int dec, char filler, char *orig, int ex) } -void test_sh(char *s1, int shift, char *orig, int ex) +void test_sh(const char *s1, int shift, const char *orig, int ex) { - char s[100]; + char s[100], *end; int res; sprintf(s, "'%s' %s %d", s1, ((shift < 0) ? ">>" : "<<"), abs(shift)); - string2decimal(s1, &a, 0); + end= strend(s1); + string2decimal(s1, &a, &end); res= decimal_shift(&a, shift); printf("%-40s => res=%d ", s, res); print_decimal(&a, orig, res, ex); @@ -2484,12 +2524,13 @@ void test_sh(char *s1, int shift, char *orig, int ex) } -void test_fr(char *s1, char *orig) +void test_fr(const char *s1, const char *orig) { - char s[100]; + char s[100], *end; sprintf(s, "'%s'", s1); printf("%-40s => ", s); - string2decimal(s1, &a, 0); + end= strend(s1); + string2decimal(s1, &a, &end); decimal_optimize_fraction(&a); print_decimal(&a, orig, 0, 0); printf("\n"); |