diff options
author | unknown <monty@mysql.com> | 2005-02-19 18:58:27 +0200 |
---|---|---|
committer | unknown <monty@mysql.com> | 2005-02-19 18:58:27 +0200 |
commit | 64cc538bda5908e2688a1ba08a9ff156971a102b (patch) | |
tree | 45069dd14961944b02845ab6e42f1993666f63e8 | |
parent | c60b1846293a22ab47c99c7001553e3efc3270a0 (diff) | |
download | mariadb-git-64cc538bda5908e2688a1ba08a9ff156971a102b.tar.gz |
Fixed BUILD script to use --with-berkeley-db instead of --with-bdb
Lots of small fixes to multi-precision-math path
Give Note for '123.4e'
Added helper functions type 'val_string_from_real()
Don't give warnings for end space for string2decimal()
Changed storage of values for SP so that we can detect length of argument without strlen()
Changed interface for str2dec() so that we must supple the pointer to the last character in the buffer
BUILD/SETUP.sh:
with-bdb ->with-berkeley-db
include/decimal.h:
Make string2decimal and string2decimal_fixed inline
mysql-test/r/func_group.result:
More tests (to find bugs in precision math fixes)
mysql-test/r/func_set.result:
Test to cover more Item_func_field::val_xxx() code
mysql-test/r/ps_6bdb.result:
update results
mysql-test/r/type_decimal.result:
New tests
Give note for '123.4e'
mysql-test/r/type_newdecimal.result:
Number of decimal changes (probably right, but hard to verify)
mysql-test/t/func_group.test:
More tests (to find bugs in precision math fixes)
mysql-test/t/func_set.test:
Test to cover more Item_func_field::val_xxx() code
mysql-test/t/type_decimal.test:
New tests to cover more cases in decimal.c
sql/item.cc:
Added helper functions type 'val_string_from_real()'
Use new interfase to str2my_decimal()
Moved nr_of_decimals() here (and made it static)
sql/item.h:
Added helper functions type 'val_string_from_real()'
sql/item_func.cc:
Style fixes
Trivial optimizations
Ensure null_value is set if my_decimal_add/sub/mul/div returns error
Remove not needed Item_func_int_div::val_str()
Join Item_func_signproc and Item_func_neg
Fix that FIELD() works when first argument is NULL or one if it's arguments are NULL
new str2my_decimal interface
sql/item_func.h:
Make Item_func_int_div inherit from Item_int_func (allows us to remove some virtual functions)
Join Item_func_signproc & Item_func_neg
sql/item_strfunc.cc:
Move nr_of_decmails() to Item.cc (as it was only used here)
sql/item_sum.cc:
Style fixes
Change a lot of code to use new helper converter functions in item.cc
Moved Item_sum::val_decimal() to Item_sum_int::val_decimal()
Fixed calls to wrong functions (Item_sum_num::val_int())
Ensure that all hybrid functions checks hybrid_type in val_xxx() (As there is no gurantee that they are called in the right context)
Simplify key_length allocation in Item_sum_sum_distinct()
Simplified create_tmp_field() and reset_field()
Fixed potential error in Item_sum_hybrid::reset_field()
Optimize Item_sum_avg::update_field()
Item_std_field() functions musted be fully coded becasue Item_variance_field::val_xxx functions called helper functions
Coded missing Item_sum_ufd_xxx::val_decimal() functions
sql/item_sum.h:
Moved Item_sum::val_decimal() to Item_sum_int::val_decimal()
Added missing Item_sum_ufd_xxx::val_decimal() functions
Removed not used scale() function.
Fixed that Item_std_field() works with decimal arguments
Fixed that CREATE ... STD() will create a REAL field
sql/log_event.cc:
Ensure that we use same format for all types
sql/my_decimal.cc:
Don't give warnings for end space for string2decimal()
Added dbug_print_decimal()
sql/my_decimal.h:
Style fixes
Prototypes for new functions
New interface for str2my_decimal()
sql/mysql_priv.h:
Made nr_of_decimals() static
sql/protocol.cc:
Simplify code (by assume that decimal can't be bigger than DECIMAL_MAX_STR_LENGTH]
sql/protocol_cursor.cc:
Changed storage of values for SP so that we can detect length of argument without strlen()
sql/sp_head.cc:
Simplify code for decimal handling by letting item handling conversion to decimal
sql/sp_rcontext.cc:
Use new method to get length of arguments
sql/sql_analyse.cc:
if -> switch
Increase 'empty' if decimal value=0
Remove usage of strcat()
sql/sql_base.cc:
Remove unnecessary checks
sql/sql_class.cc:
Remove not needed 'else'
Removed not used variables
sql/sql_select.cc:
remove test for impossible condtion
strings/decimal.c:
Made two trivial functions macros
Changed interface for str2dec() so that we must supple the pointer to the last character in the buffer
This safer than before as we don't require an end \0 anymore (old code gave wrong answers in MySQL for some internals strings that where not \0 terminated)
Detect error numbers of type '12.55e'
str2dec() will now set 'to' to zero in case of errors
-rwxr-xr-x | BUILD/SETUP.sh | 4 | ||||
-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/ps_6bdb.result | 2 | ||||
-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 |
30 files changed, 854 insertions, 687 deletions
diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index b899b9a7d9b..403857f403f 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -48,8 +48,8 @@ global_warnings="-Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wch c_warnings="$global_warnings -Wunused" cxx_warnings="$global_warnings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor" -base_max_configs="--with-innodb --with-bdb --with-ndbcluster --with-archive-storage-engine --with-raid --with-openssl --with-raid --with-vio" -max_leave_isam_configs="--with-innodb --with-bdb --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-raid --with-openssl --with-raid --with-vio --with-embedded-server" +base_max_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-raid --with-openssl --with-raid --with-vio" +max_leave_isam_configs="--with-innodb --with-berkeley-db --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-raid --with-openssl --with-raid --with-vio --with-embedded-server" max_no_es_configs="$max_leave_isam_configs --without-isam" max_configs="$max_no_es_configs --with-embedded-server" 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/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index bf7ef64d052..c02215ad750 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -2674,7 +2674,6 @@ Warning 1265 Data truncated for column 'c4' at row 1 Warning 1265 Data truncated for column 'c5' at row 1 Warning 1265 Data truncated for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 -Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 1 @@ -2725,7 +2724,6 @@ Warning 1265 Data truncated for column 'c4' at row 1 Warning 1265 Data truncated for column 'c5' at row 1 Warning 1265 Data truncated for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 -Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 -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 299bc6c081b..d12da37627d 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 1e61474f412..43481db7b56 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 20f70fce575..d41ea184769 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 d2a0e8642f9..d760445e493 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3281,7 +3281,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 f028b1fa1a1..94b473a8c36 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, byte *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 63d3fb7e2e5..728ac48ce4f 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 byte *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 byte *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 fdcf061ab7a..4f8d31771aa 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 075aef9d286..72b6fb599be 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 eef86921012..34d6782ab52 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3400,8 +3400,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; } } @@ -3413,8 +3412,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 0dae2d37062..cebec316af9 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1366,10 +1366,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() @@ -1380,30 +1379,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() @@ -1420,10 +1412,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"); |