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
This commit is contained in:
monty@mysql.com 2005-02-19 18:58:27 +02:00
parent 7bc48798fc
commit 218e00ac68
30 changed files with 857 additions and 690 deletions

View File

@ -48,8 +48,8 @@ global_warnings="-Wimplicit -Wreturn-type -Wswitch -Wtrigraphs -Wcomment -W -Wch
c_warnings="$global_warnings -Wunused" c_warnings="$global_warnings -Wunused"
cxx_warnings="$global_warnings -Woverloaded-virtual -Wsign-promo -Wreorder -Wctor-dtor-privacy -Wnon-virtual-dtor" 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" 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-bdb --with-ndbcluster --with-archive-storage-engine --with-federated-storage-engine --with-raid --with-openssl --with-raid --with-vio --with-embedded-server" 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_no_es_configs="$max_leave_isam_configs --without-isam"
max_configs="$max_no_es_configs --with-embedded-server" max_configs="$max_no_es_configs --with-embedded-server"

View File

@ -17,7 +17,9 @@
#ifndef _decimal_h #ifndef _decimal_h
#define _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 int32 decimal_digit;
typedef struct st_decimal { typedef struct st_decimal {
@ -26,11 +28,10 @@ typedef struct st_decimal {
decimal_digit *buf; decimal_digit *buf;
} decimal; } decimal;
int internal_str2dec(const char *from, decimal *to, char **end, my_bool fixed);
int decimal2string(decimal *from, char *to, int *to_len, int decimal2string(decimal *from, char *to, int *to_len,
int fixed_precision, int fixed_decimals, int fixed_precision, int fixed_decimals,
char filler); 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 decimal2ulonglong(decimal *from, ulonglong *to);
int ulonglong2decimal(ulonglong from, decimal *to); int ulonglong2decimal(ulonglong from, decimal *to);
int decimal2longlong(decimal *from, longlong *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_mul(decimal *from1, decimal *from2, decimal *to);
int decimal_div(decimal *from1, decimal *from2, decimal *to, int scale_incr); int decimal_div(decimal *from1, decimal *from2, decimal *to, int scale_incr);
int decimal_mod(decimal *from1, decimal *from2, decimal *to); 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); int decimal_is_zero(decimal *from);
void max_decimal(int precision, int frac, decimal *to); 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 */ /* set a decimal to zero */
#define decimal_make_zero(dec) do { \ #define decimal_make_zero(dec) do { \

View File

@ -90,6 +90,26 @@ id avg(rating)
1 3.0000 1 3.0000
2 NULL 2 NULL
3 2.0000 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; drop table t1,t2;
create table t1 (a smallint(6) primary key, c char(10), b text); create table t1 (a smallint(6) primary key, c char(10), b text);
INSERT INTO t1 VALUES (1,'1','1'); INSERT INTO t1 VALUES (1,'1','1');

View File

@ -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"); select elt(2,1),field(NULL,"a","b","c");
elt(2,1) field(NULL,"a","b","c") elt(2,1) field(NULL,"a","b","c")
NULL 0 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"); 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") find_in_set("","a,b,c") find_in_set("","a,b,c,") find_in_set("",",a,b,c")
0 4 1 0 4 1

View File

@ -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 'c5' at row 1
Warning 1265 Data truncated for column 'c6' 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 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 Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ; execute my_select ;
c1 1 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 'c5' at row 1
Warning 1265 Data truncated for column 'c6' 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 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 Warning 1264 Out of range value adjusted for column 'c12' at row 1
execute my_select ; execute my_select ;
c1 -1 c1 -1

View File

@ -169,8 +169,19 @@ Warnings:
Warning 1264 Out of range value adjusted for column 'a' at row 1 Warning 1264 Out of range value adjusted for column 'a' at row 1
Note 1265 Data truncated for column 'a' at row 2 Note 1265 Data truncated for column 'a' at row 2
Warning 1264 Out of range value adjusted for column 'a' at row 3 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"); insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0");
Warnings: Warnings:
Note 1265 Data truncated for column 'a' at row 1
Note 1265 Data truncated for column 'a' at row 3 Note 1265 Data truncated for column 'a' at row 3
select * from t1; select * from t1;
a a
@ -195,6 +206,12 @@ a
99999999.99 99999999.99
0.00 0.00
-99999999.99 -99999999.99
99999999.99
0.00
99999999.99
0.00
0.00
0.00
123.40 123.40
12340.00 12340.00
1.23 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 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"); insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0");
Warnings: Warnings:
Note 1265 Data truncated for column 'a' at row 1
Note 1265 Data truncated for column 'a' at row 3 Note 1265 Data truncated for column 'a' at row 3
select * from t1; select * from t1;
a 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 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"); insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0");
Warnings: Warnings:
Note 1265 Data truncated for column 'a' at row 1
Note 1265 Data truncated for column 'a' at row 3 Note 1265 Data truncated for column 'a' at row 3
select * from t1; select * from t1;
a 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); insert into t1 values (123.4e0),(123.4e+2),(123.4e-2),(123e1),(123e+0);
Warnings: Warnings:
Note 1265 Data truncated for column 'a' at row 3 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; select * from t1;
a a
0.00 0.00
@ -366,6 +386,9 @@ a
1.23 1.23
1230.00 1230.00
123.00 123.00
98.00
987.00
98760.00
drop table t1; drop table t1;
create table t1 (a decimal); create table t1 (a decimal);
insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+12345678901'),(99999999999999); insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+12345678901'),(99999999999999);

View File

@ -696,7 +696,7 @@ end while; select v1, v2, v3 * 0.000000000001, v4 * 0.000000000001; end;//
call p1()// call p1()//
# #
v1 v2 v3 * 0.000000000001 v4 * 0.000000000001 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 procedure p1;
drop table if exists t1; drop table if exists t1;
Warnings: Warnings:

View File

@ -58,6 +58,11 @@ create table t2 (id int not null,rating int null);
insert into t1 values(1),(2),(3); insert into t1 values(1),(2),(3);
insert into t2 values(1, 3),(2, NULL),(2, NULL),(3, 2),(3, NULL); 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; 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; drop table t1,t2;
# #

View File

@ -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 # Wrong usage of functions
# #
select elt(2,1),field(NULL,"a","b","c"); 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("","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 find_in_set("abc","abc"),find_in_set("ab","abc"),find_in_set("abcd","abc");
select interval(null, 1, 10, 100); select interval(null, 1, 10, 100);

View File

@ -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"),("111111111.11"),("-11111111.11");
insert into t1 values ("-111111111.11"),("+1111111111.11"),("1111111111.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+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"); insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0");
select * from t1; select * from t1;
drop table 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 (-111111111.11),(+1111111111.11),(1111111111.11);
insert into t1 values (1e+100),(1e-100),(-1e+100); 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 (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; select * from t1;
drop table t1; drop table t1;

View File

@ -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(): Item::Item():
name(0), orig_name(0), name_length(0), fixed(0), name(0), orig_name(0), name_length(0), fixed(0),
collation(&my_charset_bin, DERIVATION_COERCIBLE) 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 binary protocol, we use str2my_decimal to convert it to
internal decimal value. internal decimal value.
*/ */
void Item_param::set_decimal(const char *str, ulong length) void Item_param::set_decimal(const char *str, ulong length)
{ {
char *end;
DBUG_ENTER("Item_param::set_decimal"); 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; state= DECIMAL_VALUE;
decimals= decimal_value.frac; decimals= decimal_value.frac;
max_length= decimal_value.intg + decimals + 2; 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 This function is only called during parsing. We will signal an error if
value is not a true double value (overflow) 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); my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "double", (char*) str_arg);
} }
presentation= name=(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; max_length=length;
fixed= 1; fixed= 1;
} }

View File

@ -276,6 +276,16 @@ public:
TRUE value is true (not equal to 0) TRUE value is true (not equal to 0)
*/ */
bool val_bool(); 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 *get_tmp_table_field() { return 0; }
virtual Field *tmp_table_field(TABLE *t_arg) { return 0; } virtual Field *tmp_table_field(TABLE *t_arg) { return 0; }
virtual const char *full_name() const { return name ? name : "???"; } virtual const char *full_name() const { return name ? name : "???"; }

View File

@ -714,15 +714,14 @@ void Item_num_op::find_num_type(void)
SYNOPSIS SYNOPSIS
Item_func_num1::find_num_type() Item_func_num1::find_num_type()
*/ */
void Item_func_num1::find_num_type() void Item_func_num1::find_num_type()
{ {
DBUG_ENTER("Item_func_num1::find_num_type"); DBUG_ENTER("Item_func_num1::find_num_type");
DBUG_PRINT("info", ("name %s", func_name())); DBUG_PRINT("info", ("name %s", func_name()));
switch(hybrid_type= args[0]->result_type()) switch (hybrid_type= args[0]->result_type()) {
{
case INT_RESULT: case INT_RESULT:
unsigned_flag=args[0]->unsigned_flag; unsigned_flag= args[0]->unsigned_flag;
hybrid_type= INT_RESULT;
break; break;
case STRING_RESULT: case STRING_RESULT:
case REAL_RESULT: case REAL_RESULT:
@ -730,7 +729,6 @@ void Item_func_num1::find_num_type()
max_length= float_length(decimals); max_length= float_length(decimals);
break; break;
case DECIMAL_RESULT: case DECIMAL_RESULT:
hybrid_type= DECIMAL_RESULT;
break; break;
default: default:
DBUG_ASSERT(0); DBUG_ASSERT(0);
@ -761,13 +759,12 @@ void Item_func_numhybrid::fix_length_and_dec()
String *Item_func_numhybrid::val_str(String *str) String *Item_func_numhybrid::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
switch (hybrid_type) switch (hybrid_type) {
{
case DECIMAL_RESULT: case DECIMAL_RESULT:
{ {
my_decimal decimal_value, *val; my_decimal decimal_value, *val;
if (!(val= decimal_op(&decimal_value))) 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_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val);
my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str); my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str);
break; break;
@ -785,7 +782,7 @@ String *Item_func_numhybrid::val_str(String *str)
} }
case REAL_RESULT: case REAL_RESULT:
{ {
double nr=real_op(); double nr= real_op();
if (null_value) if (null_value)
return 0; /* purecov: inspected */ return 0; /* purecov: inspected */
str->set(nr,decimals,&my_charset_bin); 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() double Item_func_numhybrid::val_real()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
switch (hybrid_type) switch (hybrid_type) {
{
case DECIMAL_RESULT: case DECIMAL_RESULT:
{ {
my_decimal decimal_value, *val; my_decimal decimal_value, *val;
if (!(val= decimal_op(&decimal_value)))
return 0.0;
double result; double result;
if (!(val= decimal_op(&decimal_value)))
return 0.0; // null is set
my_decimal2double(E_DEC_FATAL_ERROR, val, &result); my_decimal2double(E_DEC_FATAL_ERROR, val, &result);
return result; return result;
} }
@ -826,13 +822,12 @@ double Item_func_numhybrid::val_real()
longlong Item_func_numhybrid::val_int() longlong Item_func_numhybrid::val_int()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
switch (hybrid_type) switch (hybrid_type) {
{
case DECIMAL_RESULT: case DECIMAL_RESULT:
{ {
my_decimal decimal_value, *val; my_decimal decimal_value, *val;
if (!(val= decimal_op(&decimal_value))) if (!(val= decimal_op(&decimal_value)))
return 0; return 0; // null is set
longlong result; longlong result;
my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result); my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result);
return result; return result;
@ -852,8 +847,7 @@ my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value)
{ {
my_decimal *val= decimal_value; my_decimal *val= decimal_value;
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
switch (hybrid_type) switch (hybrid_type) {
{
case DECIMAL_RESULT: case DECIMAL_RESULT:
val= decimal_op(decimal_value); val= decimal_op(decimal_value);
break; 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 *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)) if ((null_value= args[0]->null_value))
return 0; return 0;
my_decimal value2, *val2= args[1]->val_decimal(&value2); val2= args[1]->val_decimal(&value2);
if ((null_value= args[1]->null_value) || if ((null_value= (args[1]->null_value ||
my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, val1, val2) > 1) my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, val1,
val2) > 1)))
return 0; return 0;
return decimal_value; 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 *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)) if ((null_value= args[0]->null_value))
return 0; return 0;
my_decimal value2, *val2= args[1]->val_decimal(&value2); val2= args[1]->val_decimal(&value2);
if ((null_value= args[1]->null_value) || if ((null_value= (args[1]->null_value ||
my_decimal_sub(E_DEC_FATAL_ERROR, decimal_value, val1, val2) > 1) my_decimal_sub(E_DEC_FATAL_ERROR, decimal_value, val1,
val2) > 1)))
return 0; return 0;
return decimal_value; 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 *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)) if ((null_value= args[0]->null_value))
return 0; return 0;
my_decimal value2, *val2= args[1]->val_decimal(&value2); val2= args[1]->val_decimal(&value2);
if ((null_value= args[1]->null_value) || if ((null_value= (args[1]->null_value ||
my_decimal_mul(E_DEC_FATAL_ERROR, decimal_value, val1, val2) > 1) my_decimal_mul(E_DEC_FATAL_ERROR, decimal_value, val1,
val2) > 1)))
return 0; return 0;
return decimal_value; 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 *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)) if ((null_value= args[0]->null_value))
return 0; return 0;
my_decimal value2, *val2= args[1]->val_decimal(&value2); val2= args[1]->val_decimal(&value2);
if ((null_value= args[1]->null_value)) if ((null_value= args[1]->null_value))
return 0; return 0;
switch (my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value, 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_TRUNCATED:
case E_DEC_OK: case E_DEC_OK:
return decimal_value; return decimal_value;
case E_DEC_DIV_ZERO: case E_DEC_DIV_ZERO:
signal_divide_by_null(); signal_divide_by_null();
default: default:
null_value= 1; // Safety
return 0; return 0;
} }
} }
@ -1115,8 +1138,7 @@ void Item_func_div::fix_length_and_dec()
{ {
DBUG_ENTER("Item_func_div::fix_length_and_dec"); DBUG_ENTER("Item_func_div::fix_length_and_dec");
Item_num_op::fix_length_and_dec(); Item_num_op::fix_length_and_dec();
switch(hybrid_type) switch(hybrid_type) {
{
case REAL_RESULT: case REAL_RESULT:
{ {
decimals=max(args[0]->decimals,args[1]->decimals)+2; decimals=max(args[0]->decimals,args[1]->decimals)+2;
@ -1148,7 +1170,7 @@ longlong Item_func_int_div::val_int()
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
longlong value=args[0]->val_int(); longlong value=args[0]->val_int();
longlong val2=args[1]->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; return 0;
if (val2 == 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() void Item_func_int_div::fix_length_and_dec()
{ {
max_length=args[0]->max_length - args[0]->decimals; 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 *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)) if ((null_value= args[0]->null_value))
return 0; return 0;
my_decimal value2, *val2= args[1]->val_decimal(&value2); val2= args[1]->val_decimal(&value2);
if ((null_value= args[1]->null_value)) if ((null_value= args[1]->null_value))
return 0; return 0;
switch (my_decimal_mod(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value, 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_TRUNCATED:
case E_DEC_OK: case E_DEC_OK:
return decimal_value; return decimal_value;
case E_DEC_DIV_ZERO: case E_DEC_DIV_ZERO:
signal_divide_by_null(); signal_divide_by_null();
default: default:
null_value= 1;
return 0; 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(); 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 && if (hybrid_type == INT_RESULT &&
args[0]->type() == INT_ITEM && args[0]->type() == INT_ITEM &&
((ulonglong) ((Item_uint*) args[0])->value >= ((ulonglong) ((Item_uint*) args[0])->value >=
(ulonglong) LONGLONG_MIN)) (ulonglong) LONGLONG_MIN))
{ {
/* /*
If this is in integer context keep the context as integer Ensure that result is converted to DECIMAL, as longlong can't hold
(This is how multiplication and other integer functions works) the negated number
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)
*/ */
hybrid_type= DECIMAL_RESULT; hybrid_type= DECIMAL_RESULT;
DBUG_PRINT("info", ("Type changed: 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 *Item_func_ceiling::decimal_op(my_decimal *decimal_value)
{ {
my_decimal val, *value= args[0]->val_decimal(&val); my_decimal val, *value= args[0]->val_decimal(&val);
if ((null_value= args[0]->null_value)) if ((null_value= (args[0]->null_value ||
return 0; my_decimal_ceiling(E_DEC_FATAL_ERROR, value,
if (my_decimal_ceiling(E_DEC_FATAL_ERROR, value, decimal_value) > 1) decimal_value) > 1)))
return 0; return 0;
return decimal_value; 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 *Item_func_floor::decimal_op(my_decimal *decimal_value)
{ {
my_decimal val, *value= args[0]->val_decimal(&val); my_decimal val, *value= args[0]->val_decimal(&val);
if ((null_value= args[0]->null_value)) if ((null_value= (args[0]->null_value ||
return 0; my_decimal_floor(E_DEC_FATAL_ERROR, value,
if (my_decimal_floor(E_DEC_FATAL_ERROR, value, decimal_value) > 1) decimal_value) > 1)))
return 0; return 0;
return decimal_value; 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(); int dec=(int) args[1]->val_int();
if (dec > 0) if (dec > 0)
decimals= dec; // to get correct output decimals= dec; // to get correct output
if ((null_value= args[0]->null_value || args[1]->null_value)) if ((null_value= (args[0]->null_value || args[1]->null_value ||
return 0; my_decimal_round(E_DEC_FATAL_ERROR, value, dec, truncate,
if (my_decimal_round(E_DEC_FATAL_ERROR, value, dec, truncate, decimal_value) > 1)))
decimal_value) > 1)
return 0; return 0;
return decimal_value; return decimal_value;
} }
@ -2125,9 +2135,11 @@ longlong Item_func_field::val_int()
else if (cmp_type == INT_RESULT) else if (cmp_type == INT_RESULT)
{ {
longlong val= args[0]->val_int(); longlong val= args[0]->val_int();
if (args[0]->is_null())
return 0;
for (uint i=1; i < arg_count ; i++) 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); return (longlong) (i);
} }
} }
@ -2140,18 +2152,18 @@ longlong Item_func_field::val_int()
for (uint i=1; i < arg_count; i++) for (uint i=1; i < arg_count; i++)
{ {
dec_arg= args[i]->val_decimal(&dec_arg_buf); dec_arg= args[i]->val_decimal(&dec_arg_buf);
if (args[i]->is_null()) if (!args[i]->is_null() && !my_decimal_cmp(dec_arg, dec))
continue;
if (!my_decimal_cmp(dec_arg, dec))
return (longlong) (i); return (longlong) (i);
} }
} }
else else
{ {
double val= args[0]->val_real(); double val= args[0]->val_real();
if (args[0]->is_null())
return 0;
for (uint i=1; i < arg_count ; i++) 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); 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) my_decimal *udf_handler::val_decimal(my_bool *null_value, my_decimal *dec_buf)
{ {
char buf[DECIMAL_MAX_STR_LENGTH+1], *end; 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; *null_value= 1;
return 0; return 0;
} }
buf[res_length]= 0; end= res+ res_length;
str2my_decimal(E_DEC_FATAL_ERROR, buf, dec_buf, &end); str2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf, &end);
return dec_buf; return dec_buf;
} }
@ -2664,9 +2680,9 @@ String *Item_func_udf_int::val_str(String *str)
longlong Item_func_udf_decimal::val_int() longlong Item_func_udf_decimal::val_int()
{ {
my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf);
longlong result;
if (null_value) if (null_value)
return 0; return 0;
longlong result;
my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result); my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
return result; return result;
} }
@ -2675,9 +2691,9 @@ longlong Item_func_udf_decimal::val_int()
double Item_func_udf_decimal::val_real() double Item_func_udf_decimal::val_real()
{ {
my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf);
double result;
if (null_value) if (null_value)
return 0.0; return 0.0;
double result;
my_decimal2double(E_DEC_FATAL_ERROR, dec, &result); my_decimal2double(E_DEC_FATAL_ERROR, dec, &result);
return result; return result;
} }

View File

@ -357,18 +357,15 @@ public:
}; };
class Item_func_int_div :public Item_func class Item_func_int_div :public Item_int_func
{ {
public: 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(); longlong val_int();
String *val_str(String*str);
const char *func_name() const { return "DIV"; } const char *func_name() const { return "DIV"; }
void fix_length_and_dec(); void fix_length_and_dec();
void print(String *str) { print_op(str); } 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 class Item_func_neg :public Item_func_num1
{ {
public: public:
Item_func_signproc(Item *a) :Item_func_num1(a) {} Item_func_neg(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
{
public:
Item_func_neg(Item *a) :Item_func_signproc(a) {}
double real_op(); double real_op();
longlong int_op(); longlong int_op();
my_decimal *decimal_op(my_decimal *); my_decimal *decimal_op(my_decimal *);
const char *func_name() const { return "-"; } const char *func_name() const { return "-"; }
void fix_length_and_dec();
void fix_num_length_and_dec(); void fix_num_length_and_dec();
}; };

View File

@ -47,19 +47,6 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
fname); 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() double Item_str_func::val_real()
{ {

View File

@ -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) bool Item_sum::walk (Item_processor processor, byte *argument)
{ {
if (arg_count) if (arg_count)
@ -178,38 +169,26 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table,
String * String *
Item_sum_num::val_str(String *str) Item_sum_num::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1); return val_string_from_real(str);
double nr= val_real();
if (null_value)
return 0;
str->set(nr,decimals, &my_charset_bin);
return str;
} }
my_decimal *Item_sum_num::val_decimal(my_decimal *decimal_value) my_decimal *Item_sum_num::val_decimal(my_decimal *decimal_value)
{ {
DBUG_ASSERT(fixed == 1); return val_decimal_from_real(decimal_value);
double nr= val_real();
if (null_value)
return 0;
double2my_decimal(E_DEC_FATAL_ERROR, nr, decimal_value);
return (decimal_value);
} }
String * String *
Item_sum_int::val_str(String *str) Item_sum_int::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1); return val_string_from_int(str);
longlong nr= val_int(); }
if (null_value)
return 0;
if (unsigned_flag) my_decimal *Item_sum_int::val_decimal(my_decimal *decimal_value)
str->set((ulonglong) nr, &my_charset_bin); {
else return val_decimal_from_int(decimal_value);
str->set(nr, &my_charset_bin);
return str;
} }
@ -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), hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign),
used_table_cache(item->used_table_cache), was_values(item->was_values) 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: case INT_RESULT:
sum_int= item->sum_int; sum_int= item->sum_int;
break; break;
@ -288,8 +267,7 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return TRUE; return TRUE;
decimals=item->decimals; decimals=item->decimals;
switch (hybrid_type= item->result_type()) switch (hybrid_type= item->result_type()) {
{
case INT_RESULT: case INT_RESULT:
max_length= 20; max_length= 20;
sum_int= 0; 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), :Item_sum_num(thd, item), hybrid_type(item->hybrid_type),
curr_dec_buff(item->curr_dec_buff) curr_dec_buff(item->curr_dec_buff)
{ {
/* TODO: check if the following assignments are really needed */
if (hybrid_type == DECIMAL_RESULT) if (hybrid_type == DECIMAL_RESULT)
{ {
my_decimal2decimal(item->dec_buffs, dec_buffs); 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"); DBUG_ENTER("Item_sum_sum::fix_length_and_dec");
maybe_null=null_value=1; maybe_null=null_value=1;
decimals= args[0]->decimals; decimals= args[0]->decimals;
switch (args[0]->result_type()) switch (args[0]->result_type()) {
{
case REAL_RESULT: case REAL_RESULT:
case STRING_RESULT: case STRING_RESULT:
hybrid_type= REAL_RESULT; hybrid_type= REAL_RESULT;
@ -434,7 +412,7 @@ longlong Item_sum_sum::val_int()
&result); &result);
return 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 (hybrid_type == DECIMAL_RESULT)
{ return val_string_from_decimal(str);
if (null_value) return val_string_from_real(str);
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);
} }
my_decimal *Item_sum_sum::val_decimal(my_decimal *val) my_decimal *Item_sum_sum::val_decimal(my_decimal *val)
{ {
DBUG_ASSERT(hybrid_type == DECIMAL_RESULT); if (hybrid_type == DECIMAL_RESULT)
return(dec_buffs + curr_dec_buff); 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_sum_sum_distinct(Item *item) 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 C_MODE_END
bool Item_sum_sum_distinct::setup(THD *thd) bool Item_sum_sum_distinct::setup(THD *thd)
{ {
DBUG_ENTER("Item_sum_sum_distinct::setup"); 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 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 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, It's safe to use key_length here as even if we do copy_or_same()
args[0]->decimals) : the new item will just share the old items key_length, which will not
sizeof(double)); change or disappear during the life time of this item.
tree= new Unique(simple_raw_key_cmp, key_length_ptr, *key_length_ptr, */
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); thd->variables.max_heap_table_size);
DBUG_PRINT("info", ("tree 0x%lx, key length %d", (ulong)tree, DBUG_PRINT("info", ("tree 0x%lx, key length %d", (ulong)tree,
*key_length_ptr)); key_length));
DBUG_RETURN(tree == 0); DBUG_RETURN(tree == 0);
} }
@ -640,6 +618,7 @@ static int sum_sum_distinct_decimal(void *element, element_count num_of_dups,
C_MODE_END C_MODE_END
double Item_sum_sum_distinct::val_real() double Item_sum_sum_distinct::val_real()
{ {
DBUG_ENTER("Item_sum_sum_distinct::val"); 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 Item_sum_sum_distinct::val_int()
{ {
longlong i; longlong result;
if (hybrid_type == DECIMAL_RESULT) if (hybrid_type == DECIMAL_RESULT)
{ {
/* Item_sum_sum_distinct::val_decimal do not use argument */ /* Item_sum_sum_distinct::val_decimal do not use argument */
my_decimal *val= val_decimal(0); my_decimal *val= val_decimal(0);
if (!null_value) if (!null_value)
my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &i); my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result);
} }
else else
i= (longlong) val_real(); result= (longlong) val_real();
return i; return result;
} }
@ -703,22 +682,8 @@ String *Item_sum_sum_distinct::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
if (hybrid_type == DECIMAL_RESULT) if (hybrid_type == DECIMAL_RESULT)
{ return val_string_from_decimal(str);
/* Item_sum_sum_distinct::val_decimal do not use argument */ return val_string_from_real(str);
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;
} }
@ -792,23 +757,21 @@ Item *Item_sum_avg::copy_or_same(THD* thd)
Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table, Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table,
uint convert_blob_len) uint convert_blob_len)
{ {
if (group)
{
/*
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) if (hybrid_type == DECIMAL_RESULT)
{ return new Field_new_decimal(f_precision,
if (group) maybe_null, name, table, f_scale);
return new Field_string(dec_bin_size + sizeof(longlong), return new Field_double(max_length, maybe_null, name, table, decimals);
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);
}
} }
@ -842,14 +805,15 @@ double Item_sum_avg::val_real()
my_decimal *Item_sum_avg::val_decimal(my_decimal *val) my_decimal *Item_sum_avg::val_decimal(my_decimal *val)
{ {
my_decimal sum, cnt;
const my_decimal *sum_dec;
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
if (!count) if (!count)
{ {
null_value=1; null_value=1;
return NULL; return NULL;
} }
my_decimal sum, cnt; sum_dec= Item_sum_sum::val_decimal(&sum);
const my_decimal *sum_dec= Item_sum_sum::val_decimal(&sum);
int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt); int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt);
my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, 4); my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, 4);
return val; return val;
@ -859,23 +823,11 @@ my_decimal *Item_sum_avg::val_decimal(my_decimal *val)
String *Item_sum_avg::val_str(String *str) String *Item_sum_avg::val_str(String *str)
{ {
if (hybrid_type == DECIMAL_RESULT) if (hybrid_type == DECIMAL_RESULT)
{ return val_string_from_decimal(str);
my_decimal value, *dec_val= val_decimal(&value); return val_string_from_real(str);
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;
} }
/* /*
Standard deviation 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() void Item_sum_variance::fix_length_and_dec()
{ {
DBUG_ENTER("Item_sum_sum::fix_length_and_dec"); DBUG_ENTER("Item_sum_variance::fix_length_and_dec");
maybe_null=null_value=1; maybe_null= null_value= 1;
decimals= args[0]->decimals + 4; decimals= args[0]->decimals + 4;
switch (args[0]->result_type()) switch (args[0]->result_type()) {
{
case REAL_RESULT: case REAL_RESULT:
case STRING_RESULT: case STRING_RESULT:
hybrid_type= REAL_RESULT; hybrid_type= REAL_RESULT;
@ -934,12 +885,21 @@ void Item_sum_variance::fix_length_and_dec()
break; break;
case INT_RESULT: case INT_RESULT:
case DECIMAL_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; max_length= args[0]->max_length*2 + 4;
cur_dec= 0; cur_dec= 0;
hybrid_type= DECIMAL_RESULT; hybrid_type= DECIMAL_RESULT;
my_decimal_set_zero(dec_sum); my_decimal_set_zero(dec_sum);
my_decimal_set_zero(dec_sqr); 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_scale0= args[0]->decimals;
f_precision0= DECIMAL_MAX_LENGTH / 2; f_precision0= DECIMAL_MAX_LENGTH / 2;
f_scale1= min(f_scale0 * 2, NOT_FIXED_DEC - 1); 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, Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table,
uint convert_blob_len) uint convert_blob_len)
{ {
if (group)
{
/*
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) if (hybrid_type == DECIMAL_RESULT)
{ return new Field_new_decimal(DECIMAL_MAX_LENGTH,
if (group) maybe_null, name, table, f_scale1 + 4);
return new Field_string(dec_bin_size0+dec_bin_size1+sizeof(longlong), return new Field_double(max_length, maybe_null,name,table,decimals);
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);
}
} }
@ -1038,19 +997,15 @@ bool Item_sum_variance::add()
double Item_sum_variance::val_real() double Item_sum_variance::val_real()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
if (hybrid_type == DECIMAL_RESULT)
return val_real_from_decimal();
if (!count) if (!count)
{ {
null_value=1; null_value=1;
return 0.0; return 0.0;
} }
null_value=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 */ /* Avoid problems when the precision isn't good enough */
double tmp=ulonglong2double(count); double tmp=ulonglong2double(count);
double tmp2=(sum_sqr - sum*sum/tmp)/tmp; 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 *Item_sum_variance::val_decimal(my_decimal *dec_buf)
{ {
my_decimal count_buf, sum_sqr_buf;
DBUG_ASSERT(fixed ==1 ); DBUG_ASSERT(fixed ==1 );
if (hybrid_type == REAL_RESULT) if (hybrid_type == REAL_RESULT)
{ return val_decimal_from_real(dec_buf);
double result= Item_sum_variance::val_real();
if (null_value)
return 0;
double2my_decimal(E_DEC_FATAL_ERROR, result, dec_buf);
return dec_buf;
}
if (!count) if (!count)
{ {
null_value= 1; null_value= 1;
return 0; return 0;
} }
null_value= 0; null_value= 0;
my_decimal count_buf, sum_sqr_buf;
int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &count_buf); int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &count_buf);
my_decimal_mul(E_DEC_FATAL_ERROR, &sum_sqr_buf, my_decimal_mul(E_DEC_FATAL_ERROR, &sum_sqr_buf,
dec_sum+cur_dec, dec_sum+cur_dec); 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; return dec_buf;
} }
void Item_sum_variance::reset_field() void Item_sum_variance::reset_field()
{ {
char *res=result_field->ptr; double nr;
char *res= result_field->ptr;
if (hybrid_type == DECIMAL_RESULT) 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) if (args[0]->null_value)
{ {
my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero, arg_dec= arg2_dec= &decimal_zero;
res, f_precision0, f_scale0); tmp= 0;
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);
} }
else 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_decimal_mul(E_DEC_FATAL_ERROR, dec_sum, arg_dec, arg_dec);
my_decimal2binary(E_DEC_FATAL_ERROR, dec_sum, arg2_dec= dec_sum;
res+dec_bin_size0, f_precision1, f_scale1); tmp= 1;
res+= dec_bin_size0 + dec_bin_size1;
longlong tmp=1;
int8store(res,tmp);
} }
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; return;
} }
double nr= args[0]->val_real(); nr= args[0]->val_real();
if (args[0]->null_value) if (args[0]->null_value)
bzero(res,sizeof(double)*2+sizeof(longlong)); bzero(res,sizeof(double)*2+sizeof(longlong));
else else
{ {
longlong tmp;
float8store(res,nr); float8store(res,nr);
nr*=nr; nr*=nr;
float8store(res+sizeof(double),nr); float8store(res+sizeof(double),nr);
longlong tmp=1; tmp= 1;
int8store(res+sizeof(double)*2,tmp); int8store(res+sizeof(double)*2,tmp);
} }
} }
void Item_sum_variance::update_field() void Item_sum_variance::update_field()
{ {
longlong field_count; longlong field_count;
@ -1170,15 +1124,16 @@ void Item_sum_variance::update_field()
} }
float8store(res,old_nr); float8store(res,old_nr);
float8store(res+sizeof(double),old_sqr); float8store(res+sizeof(double),old_sqr);
int8store(res+sizeof(double)*2,field_count); res+= sizeof(double)*2;
int8store(res,field_count);
} }
/* min & max */ /* min & max */
void Item_sum_hybrid::clear() void Item_sum_hybrid::clear()
{ {
switch (hybrid_type) switch (hybrid_type) {
{
case INT_RESULT: case INT_RESULT:
sum_int= 0; sum_int= 0;
break; break;
@ -1231,8 +1186,7 @@ longlong Item_sum_hybrid::val_int()
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
if (null_value) if (null_value)
return 0; return 0;
switch (hybrid_type) switch (hybrid_type) {
{
case INT_RESULT: case INT_RESULT:
return sum_int; return sum_int;
case DECIMAL_RESULT: case DECIMAL_RESULT:
@ -1539,8 +1493,7 @@ void Item_sum_num::reset_field()
void Item_sum_hybrid::reset_field() void Item_sum_hybrid::reset_field()
{ {
switch(hybrid_type) switch(hybrid_type) {
{
case STRING_RESULT: case STRING_RESULT:
{ {
char buff[MAX_FIELD_WIDTH]; char buff[MAX_FIELD_WIDTH];
@ -1604,8 +1557,13 @@ void Item_sum_hybrid::reset_field()
else else
result_field->set_notnull(); 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; break;
} }
case ROW_RESULT: case ROW_RESULT:
@ -1620,10 +1578,9 @@ void Item_sum_sum::reset_field()
if (hybrid_type == DECIMAL_RESULT) if (hybrid_type == DECIMAL_RESULT)
{ {
my_decimal value, *arg_val= args[0]->val_decimal(&value); my_decimal value, *arg_val= args[0]->val_decimal(&value);
if (args[0]->null_value) if (!arg_val) // Null
result_field->reset(); arg_val= &decimal_zero;
else result_field->store_decimal(arg_val);
result_field->store_decimal(arg_val);
} }
else else
{ {
@ -1660,23 +1617,18 @@ void Item_sum_avg::reset_field()
char *res=result_field->ptr; char *res=result_field->ptr;
if (hybrid_type == DECIMAL_RESULT) if (hybrid_type == DECIMAL_RESULT)
{ {
longlong tmp;
my_decimal value, *arg_dec= args[0]->val_decimal(&value); my_decimal value, *arg_dec= args[0]->val_decimal(&value);
if (args[0]->null_value) if (args[0]->null_value)
{ {
my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero, arg_dec= &decimal_zero;
res, f_precision, f_scale); tmp= 0;
res+= dec_bin_size;
longlong tmp=0;
int8store(res,tmp);
} }
else else
{ tmp= 1;
my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, res, f_precision, f_scale);
res, f_precision, f_scale); res+= dec_bin_size;
res+= dec_bin_size; int8store(res, tmp);
longlong tmp=1;
int8store(res,tmp);
}
} }
else else
{ {
@ -1686,14 +1638,15 @@ void Item_sum_avg::reset_field()
bzero(res,sizeof(double)+sizeof(longlong)); bzero(res,sizeof(double)+sizeof(longlong));
else else
{ {
longlong tmp= 1;
float8store(res,nr); float8store(res,nr);
res+=sizeof(double); res+=sizeof(double);
longlong tmp=1;
int8store(res,tmp); int8store(res,tmp);
} }
} }
} }
void Item_sum_bit::reset_field() void Item_sum_bit::reset_field()
{ {
reset(); reset();
@ -1708,6 +1661,7 @@ void Item_sum_bit::update_field()
int8store(res, bits); int8store(res, bits);
} }
/* /*
** calc next value and merge it with field_value ** 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); dec_buffs + 1, f_precision, f_scale);
field_count= sint8korr(res + dec_bin_size); field_count= sint8korr(res + dec_bin_size);
my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, dec_buffs + 1); my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, dec_buffs + 1);
field_count++;
my_decimal2binary(E_DEC_FATAL_ERROR, dec_buffs, my_decimal2binary(E_DEC_FATAL_ERROR, dec_buffs,
res, f_precision, f_scale); res, f_precision, f_scale);
res+= dec_bin_size; res+= dec_bin_size;
field_count++;
int8store(res, field_count); int8store(res, field_count);
} }
} }
else else
{ {
double nr, old_nr; double nr;
float8get(old_nr, res);
field_count= sint8korr(res + sizeof(double));
nr= args[0]->val_real(); nr= args[0]->val_real();
if (!args[0]->null_value) if (!args[0]->null_value)
{ {
double old_nr;
float8get(old_nr, res);
field_count= sint8korr(res + sizeof(double));
old_nr+= nr; old_nr+= nr;
float8store(res,old_nr);
res+= sizeof(double);
field_count++; field_count++;
int8store(res, field_count);
} }
float8store(res,old_nr);
res+= sizeof(double);
int8store(res, field_count);
} }
} }
void Item_sum_hybrid::update_field() void Item_sum_hybrid::update_field()
{ {
switch (hybrid_type) switch (hybrid_type) {
{
case STRING_RESULT: case STRING_RESULT:
min_max_update_str_field(); min_max_update_str_field();
break; 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() double Item_avg_field::val_real()
{ {
// fix_fields() never calls for this Item // fix_fields() never calls for this Item
if (hybrid_type == DECIMAL_RESULT) double nr;
{ longlong count;
my_decimal value, *dec_val= val_decimal(&value); char *res;
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);
if (!count) if (hybrid_type == DECIMAL_RESULT)
{ return val_real_from_decimal();
null_value=1;
return 0.0; float8get(nr,field->ptr);
} res= (field->ptr+sizeof(double));
null_value=0; count= sint8korr(res);
return nr/(double) count;
} if ((null_value= !count))
return 0.0;
return nr/(double) count;
} }
longlong Item_avg_field::val_int() 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 // 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); longlong count= sint8korr(field->ptr + dec_bin_size);
if ((null_value= !count)) if ((null_value= !count))
return NULL; return 0;
my_decimal dec_count, dec_field; my_decimal dec_count, dec_field;
binary2my_decimal(E_DEC_FATAL_ERROR, binary2my_decimal(E_DEC_FATAL_ERROR,
field->ptr, &dec_field, f_precision, f_scale); field->ptr, &dec_field, f_precision, f_scale);
int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count); int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count);
my_decimal_div(E_DEC_FATAL_ERROR, val, &dec_field, &dec_count, 4); my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &dec_field, &dec_count, 4);
return val; return dec_buf;
} }
@ -1991,35 +1938,64 @@ String *Item_avg_field::val_str(String *str)
{ {
// fix_fields() never calls for this Item // fix_fields() never calls for this Item
if (hybrid_type == DECIMAL_RESULT) if (hybrid_type == DECIMAL_RESULT)
{ return val_string_from_decimal(str);
my_decimal value, *dec_val= val_decimal(&value); return val_string_from_real(str);
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;
} }
Item_std_field::Item_std_field(Item_sum_std *item) Item_std_field::Item_std_field(Item_sum_std *item)
: Item_variance_field(item) : Item_variance_field(item)
{ {
} }
double Item_std_field::val_real() double Item_std_field::val_real()
{ {
double nr;
// fix_fields() never calls for this Item // fix_fields() never calls for this Item
double tmp= Item_variance_field::val_real(); if (hybrid_type == REAL_RESULT)
return tmp <= 0.0 ? 0.0 : sqrt(tmp); {
/*
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) Item_variance_field::Item_variance_field(Item_sum_variance *item)
{ {
name=item->name; name=item->name;
@ -2038,49 +2014,42 @@ Item_variance_field::Item_variance_field(Item_sum_variance *item)
} }
} }
double Item_variance_field::val_real() double Item_variance_field::val_real()
{ {
// fix_fields() never calls for this Item // fix_fields() never calls for this Item
if (hybrid_type == DECIMAL_RESULT) if (hybrid_type == DECIMAL_RESULT)
{ return val_real_from_decimal();
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;
}
double sum,sum_sqr; double sum,sum_sqr;
longlong count; longlong count;
float8get(sum,field->ptr); float8get(sum,field->ptr);
float8get(sum_sqr,(field->ptr+sizeof(double))); float8get(sum_sqr,(field->ptr+sizeof(double)));
count=sint8korr(field->ptr+sizeof(double)*2); count=sint8korr(field->ptr+sizeof(double)*2);
if (!count) if ((null_value= !count))
{
null_value=1;
return 0.0; return 0.0;
}
null_value=0;
double tmp= (double) count; double tmp= (double) count;
double tmp2=(sum_sqr - sum*sum/tmp)/tmp; double tmp2=(sum_sqr - sum*sum/tmp)/tmp;
return tmp2 <= 0.0 ? 0.0 : tmp2; return tmp2 <= 0.0 ? 0.0 : tmp2;
} }
String *Item_variance_field::val_str(String *str) String *Item_variance_field::val_str(String *str)
{ {
// fix_fields() never calls for this Item if (hybrid_type == DECIMAL_RESULT)
double nr= val_real(); return val_string_from_decimal(str);
if (null_value) return val_string_from_real(str);
return 0;
str->set(nr,decimals, &my_charset_bin);
return str;
} }
my_decimal *Item_variance_field::val_decimal(my_decimal *dec_buf) my_decimal *Item_variance_field::val_decimal(my_decimal *dec_buf)
{ {
// fix_fields() never calls for this Item // 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); longlong count= sint8korr(field->ptr+dec_bin_size0+dec_bin_size1);
if ((null_value= !count)) if ((null_value= !count))
return 0; return 0;
@ -2478,55 +2447,34 @@ double Item_sum_udf_float::val_real()
DBUG_RETURN(udf.val(&null_value)); DBUG_RETURN(udf.val(&null_value));
} }
String *Item_sum_udf_float::val_str(String *str) String *Item_sum_udf_float::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1); return val_string_from_real(str);
double nr= val_real();
if (null_value)
return 0; /* purecov: inspected */
str->set(nr,decimals, &my_charset_bin);
return 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) String *Item_sum_udf_decimal::val_str(String *str)
{ {
my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); return val_string_from_decimal(str);
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;
} }
double Item_sum_udf_decimal::val_real() double Item_sum_udf_decimal::val_real()
{ {
my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); return val_real_from_decimal();
if (null_value)
return 0.0;
double result;
my_decimal2double(E_DEC_FATAL_ERROR, dec, &result);
return result;
} }
longlong Item_sum_udf_decimal::val_int() longlong Item_sum_udf_decimal::val_int()
{ {
my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf); return val_int_from_decimal();
if (null_value)
return 0;
longlong result;
my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
return result;
} }
@ -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() longlong Item_sum_udf_int::val_int()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
@ -2559,14 +2512,15 @@ longlong Item_sum_udf_int::val_int()
String *Item_sum_udf_int::val_str(String *str) String *Item_sum_udf_int::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1); return val_string_from_int(str);
longlong nr=val_int();
if (null_value)
return 0;
str->set(nr, &my_charset_bin);
return 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 */ /* Default max_length is max argument length */
void Item_sum_udf_str::fix_length_and_dec() 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) String *Item_sum_udf_str::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);

View File

@ -78,7 +78,6 @@ public:
virtual void update_field()=0; virtual void update_field()=0;
virtual bool keep_field_type(void) const { return 0; } virtual bool keep_field_type(void) const { return 0; }
virtual void fix_length_and_dec() { maybe_null=1; null_value=1; } 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 const char *func_name() const { return "?"; }
virtual Item *result_item(Field *field) virtual Item *result_item(Field *field)
{ return new Item_field(field);} { return new Item_field(field);}
@ -93,7 +92,6 @@ public:
virtual bool setup(THD *thd) {return 0;} virtual bool setup(THD *thd) {return 0;}
virtual void make_unique() {} virtual void make_unique() {}
Item *get_tmp_table_item(THD *thd); Item *get_tmp_table_item(THD *thd);
virtual int scale() { return decimals; }
virtual Field *create_tmp_field(bool group, TABLE *table, virtual Field *create_tmp_field(bool group, TABLE *table,
uint convert_blob_length); uint convert_blob_length);
@ -129,6 +127,7 @@ public:
Item_sum_int(THD *thd, Item_sum_int *item) :Item_sum_num(thd, item) {} 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(); } double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
String *val_str(String*str); String *val_str(String*str);
my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return INT_RESULT; } enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec() void fix_length_and_dec()
{ decimals=0; max_length=21; maybe_null=null_value=0; } { 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; Unique *tree;
byte *dec_bin_buff; byte *dec_bin_buff;
my_decimal tmp_dec; my_decimal tmp_dec;
uint key_length;
private: private:
Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item); Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item);
public: public:
@ -451,7 +451,9 @@ public:
Item_std_field(Item_sum_std *item); Item_std_field(Item_sum_std *item);
enum Type type() const { return FIELD_STD_ITEM; } enum Type type() const { return FIELD_STD_ITEM; }
double val_real(); double val_real();
my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return REAL_RESULT; } 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"; } const char *func_name() const { return "std"; }
Item *copy_or_same(THD* thd); Item *copy_or_same(THD* thd);
enum Item_result result_type () const { return REAL_RESULT; } 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 // 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(); double val_real();
String *val_str(String*str); String *val_str(String*str);
my_decimal *val_decimal(my_decimal *);
void fix_length_and_dec() { fix_num_length_and_dec(); } void fix_length_and_dec() { fix_num_length_and_dec(); }
Item *copy_or_same(THD* thd); Item *copy_or_same(THD* thd);
}; };
@ -667,6 +671,7 @@ public:
double val_real() double val_real()
{ DBUG_ASSERT(fixed == 1); return (double) Item_sum_udf_int::val_int(); } { DBUG_ASSERT(fixed == 1); return (double) Item_sum_udf_int::val_int(); }
String *val_str(String*str); String *val_str(String*str);
my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return INT_RESULT; } enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec() { decimals=0; max_length=21; } void fix_length_and_dec() { decimals=0; max_length=21; }
Item *copy_or_same(THD* thd); Item *copy_or_same(THD* thd);
@ -697,11 +702,13 @@ public:
return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10, return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10,
(char**) 0, &err_not_used) : (longlong) 0; (char**) 0, &err_not_used) : (longlong) 0;
} }
my_decimal *val_decimal(my_decimal *dec);
enum Item_result result_type () const { return STRING_RESULT; } enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec(); void fix_length_and_dec();
Item *copy_or_same(THD* thd); Item *copy_or_same(THD* thd);
}; };
class Item_sum_udf_decimal :public Item_udf_sum class Item_sum_udf_decimal :public Item_udf_sum
{ {
public: public:
@ -864,6 +871,10 @@ class Item_func_group_concat : public Item_sum
end_ptr= (char*) res->ptr()+ res->length(); end_ptr= (char*) res->ptr()+ res->length();
return my_strtoll10(res->ptr(), &end_ptr, &error); 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); String* val_str(String* str);
Item *copy_or_same(THD* thd); Item *copy_or_same(THD* thd);
void no_rows_in_result() {} void no_rows_in_result() {}

View File

@ -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); bin2decimal(val+2, &dec, precision, scale);
decimal2string(&dec, str_buf, &str_len, 0, 0, 0); decimal2string(&dec, str_buf, &str_len, 0, 0, 0);
str_buf[str_len]= 0; str_buf[str_len]= 0;
fprintf(file, "%s",str_buf); fprintf(file, ":=%s;\n",str_buf);
break; break;
} }
case STRING_RESULT: case STRING_RESULT:

View File

@ -13,6 +13,7 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysql_priv.h" #include "mysql_priv.h"
#ifndef MYSQL_CLIENT #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_BAD_NUM
E_DEC_OOM E_DEC_OOM
*/ */
int str2my_decimal(uint mask, const char *from, uint length, int str2my_decimal(uint mask, const char *from, uint length,
CHARSET_INFO *charset, my_decimal *decimal_value) CHARSET_INFO *charset, my_decimal *decimal_value)
{ {
char *end; char *end, *from_end;
int err; int err;
char buff[STRING_BUFFER_USUAL_SIZE]; char buff[STRING_BUFFER_USUAL_SIZE];
String tmp(buff, sizeof(buff), &my_charset_bin); 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(); length= tmp.length();
charset= &my_charset_bin; charset= &my_charset_bin;
} }
my_decimal_set_zero(decimal_value); from_end= end= (char*) from+length;
err= string2decimal((char *)from, (decimal *)decimal_value, &end); err= string2decimal((char *)from, (decimal *)decimal_value, &end);
if ((uint) (end-from) != length && !err) if (end != from_end && !err)
err= E_DEC_TRUNCATED; {
/* 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); check_result(mask, err);
return err; return err;
} }
@ -200,12 +212,25 @@ print_decimal_buff(const my_decimal *dec, const byte* ptr, int length)
{ {
print_decimal(dec); print_decimal(dec);
fprintf(DBUG_FILE, "Record: "); 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, "%02X ", (uint)((uchar *)ptr)[i]);
} }
fprintf(DBUG_FILE, "\n"); 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 #endif

View File

@ -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 */ my_decimal class limits 'decimal' type to what we need in MySQL
/* memory is needed. One should call fix_buffer_pointer() function */ It contains internally all necessary space needed by the instance so
/* when he moves my_decimal objects in memory */ 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 class my_decimal :public decimal
{ {
decimal_digit buffer[DECIMAL_BUFF_LENGTH]; decimal_digit buffer[DECIMAL_BUFF_LENGTH];
@ -83,6 +86,7 @@ public:
len= DECIMAL_BUFF_LENGTH; len= DECIMAL_BUFF_LENGTH;
buf= buffer; buf= buffer;
#if !defined(HAVE_purify) && !defined(DBUG_OFF) #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++) for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++)
buffer[i]= i; buffer[i]= i;
#endif #endif
@ -101,6 +105,9 @@ public:
#ifndef DBUG_OFF #ifndef DBUG_OFF
void print_decimal(const my_decimal *dec); void print_decimal(const my_decimal *dec);
void print_decimal_buff(const my_decimal *dec, const byte* ptr, int length); 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 #endif
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
@ -158,7 +165,7 @@ inline
int binary2my_decimal(uint mask, const byte *bin, my_decimal *d, int prec, int binary2my_decimal(uint mask, const byte *bin, my_decimal *d, int prec,
int scale) int scale)
{ {
return check_result(mask, bin2decimal((char *)bin, (decimal *)d, prec, return check_result(mask, bin2decimal((char *)bin, (decimal*) d, prec,
scale)); scale));
} }
@ -166,7 +173,7 @@ int binary2my_decimal(uint mask, const byte *bin, my_decimal *d, int prec,
inline inline
int my_decimal_set_zero(my_decimal *d) int my_decimal_set_zero(my_decimal *d)
{ {
decimal_make_zero(((decimal *)d)); decimal_make_zero(((decimal*) d));
return 0; return 0;
} }
@ -174,7 +181,7 @@ int my_decimal_set_zero(my_decimal *d)
inline inline
bool my_decimal_is_zero(const my_decimal *decimal_value) 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, int my_decimal_round(uint mask, const my_decimal *from, int scale,
bool truncate, my_decimal *to) 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))); (truncate ? TRUNCATE : HALF_UP)));
} }
@ -190,14 +197,14 @@ int my_decimal_round(uint mask, const my_decimal *from, int scale,
inline inline
int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to) 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 inline
int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to) 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 inline
int my_decimal2double(uint mask, const my_decimal *d, double *result) 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 inline
int str2my_decimal(uint mask, const char *str, my_decimal *d, int str2my_decimal(uint mask, const char *str, my_decimal *d, char **end)
char **end= 0)
{ {
/* set it to 0 to avoid junk in value in case of error of conversion */ return check_result(mask, string2decimal(str, (decimal*) d, end));
my_decimal_set_zero(d);
return check_result(mask, string2decimal((char *)str, (decimal *)d, end));
} }
@ -252,7 +257,7 @@ int string2my_decimal(uint mask, const String *str, my_decimal *d)
inline inline
int double2my_decimal(uint mask, double val, my_decimal *d) 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 inline
int my_decimal_neg(st_decimal *arg) void my_decimal_neg(st_decimal *arg)
{ {
decimal_neg(arg); decimal_neg(arg);
return 0;
} }
@ -277,7 +281,7 @@ inline
int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a, int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a,
const my_decimal *b) 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, int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a,
const my_decimal *b) 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, int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a,
const my_decimal *b) 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, int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a,
const my_decimal *b, int div_scale_inc) 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)); div_scale_inc));
} }
@ -310,7 +314,7 @@ inline
int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a, int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a,
const my_decimal *b) 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 inline
int my_decimal_cmp(const my_decimal *a, const my_decimal *b) 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 inline
void max_my_decimal(my_decimal *to, int precision, int frac) void max_my_decimal(my_decimal *to, int precision, int frac)
{ {
DBUG_ASSERT(precision <= DECIMAL_MAX_LENGTH); DBUG_ASSERT(precision <= DECIMAL_MAX_LENGTH);
max_decimal(precision, frac, (decimal *)to); max_decimal(precision, frac, (decimal*) to);
} }
#endif /*my_decimal_h*/ #endif /*my_decimal_h*/

View File

@ -400,8 +400,6 @@ typedef struct st_sql_list {
} SQL_LIST; } SQL_LIST;
uint nr_of_decimals(const char *str); /* Neaded by sql_string.h */
extern pthread_key(THD*, THR_THD); extern pthread_key(THD*, THR_THD);
inline THD *_current_thd(void) inline THD *_current_thd(void)
{ {

View File

@ -822,15 +822,9 @@ bool Protocol_simple::store_decimal(const my_decimal *d)
field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL); field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL);
field_pos++; field_pos++;
#endif #endif
int buf_size= my_decimal_string_length(d); char buff[DECIMAL_MAX_STR_LENGTH];
char *buff= (char *)my_alloca(buf_size); String str(buff, sizeof(buff), &my_charset_bin);
String str(buff, buf_size, &my_charset_bin); (void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
if (my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str))
{
my_afree(buff);
return TRUE;
}
my_afree(buff);
return net_store_data(str.ptr(), str.length()); 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_types[field_pos] == MYSQL_TYPE_NEWDECIMAL);
field_pos++; field_pos++;
#endif #endif
int buf_size= my_decimal_string_length(d); char buff[DECIMAL_MAX_STR_LENGTH];
char *buff= (char *)my_alloca(buf_size); String str(buff, sizeof(buff), &my_charset_bin);
String str(buff, buf_size, &my_charset_bin); (void) my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
if (my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str))
{
my_afree(buff);
return TRUE;
}
my_afree(buff);
return store(str.ptr(), str.length(), str.charset()); return store(str.ptr(), str.length(), str.charset());
} }

View File

@ -104,15 +104,15 @@ bool Protocol_cursor::write()
byte *to; byte *to;
new_record= (MYSQL_ROWS *)alloc_root(alloc, 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) if (!new_record)
goto err; goto err;
data_tmp= (byte **)(new_record + 1); data_tmp= (byte **)(new_record + 1);
new_record->data= (char **)data_tmp; 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 || if ((len= net_field_length((uchar **)&cp)) == 0 ||
len == NULL_LENGTH) len == NULL_LENGTH)
@ -135,7 +135,8 @@ bool Protocol_cursor::write()
cur_field->max_length=len; 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;
prev_record= &new_record->next; prev_record= &new_record->next;

View File

@ -158,69 +158,12 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
} }
case DECIMAL_RESULT: case DECIMAL_RESULT:
{ {
switch (it->result_type()) my_decimal value, *val= it->val_decimal(&value);
{
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
if (it->null_value) if (it->null_value)
{ it= new Item_null();
DBUG_PRINT("info", ("DECIMAL_RESULT: null"));
}
else else
{ it= new Item_decimal(val);
my_decimal value, *val= it->val_decimal(&value); dbug_print_decimal("info", "DECIMAL_RESULT: %s", val);
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
break; break;
} }
case STRING_RESULT: case STRING_RESULT:
@ -236,8 +179,9 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
} }
else else
{ {
DBUG_PRINT("info",("default result: %*s",s->length(),s->c_ptr_quick())); DBUG_PRINT("info",("default result: %*s",
it= new Item_string(thd->strmake(s->c_ptr_quick(), s->length()), s->length(), s->c_ptr_quick()));
it= new Item_string(thd->strmake(s->ptr(), s->length()),
s->length(), it->collation.collation); s->length(), it->collation.collation);
} }
break; 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); 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 creation
*/ */
suv->fix_fields(thd, NULL, &item); suv->fix_fields(thd, NULL, &item);

View File

@ -243,27 +243,36 @@ sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars)
if (!s) if (!s)
it= new Item_null(); it= new Item_null();
else 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: case INT_RESULT:
it= new Item_int(s); it= new Item_int(s);
break; break;
case REAL_RESULT: case REAL_RESULT:
it= new Item_float(s, strlen(s)); it= new Item_float(s, len);
break; break;
case DECIMAL_RESULT: case DECIMAL_RESULT:
it= new Item_decimal(s, strlen(s), thd->db_charset); it= new Item_decimal(s, len, thd->db_charset);
break; break;
case STRING_RESULT: case STRING_RESULT:
{ /* TODO: Document why we do an extra copy of the string 's' here */
uint len= strlen(s); it= new Item_string(thd->strmake(s, len), len, thd->db_charset);
it= new Item_string(thd->strmake(s, len), len, thd->db_charset); break;
break;
}
case ROW_RESULT: case ROW_RESULT:
default: default:
DBUG_ASSERT(0); DBUG_ASSERT(0);
} }
}
thd->spcont->set_item(pv->offset, it); thd->spcont->set_item(pv->offset, it);
} }
if (fldcount < m_prot->get_field_count()) if (fldcount < m_prot->get_field_count())

View File

@ -133,22 +133,30 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
Item *item; Item *item;
while ((item = it++)) 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 // Check if fieldtype is ulonglong
if (item->type() == Item::FIELD_ITEM && if (item->type() == Item::FIELD_ITEM &&
((Item_field*) item)->field->type() == FIELD_TYPE_LONGLONG && ((Item_field*) item)->field->type() == FIELD_TYPE_LONGLONG &&
((Field_longlong*) ((Item_field*) item)->field)->unsigned_flag) ((Field_longlong*) ((Item_field*) item)->field)->unsigned_flag)
*f_info++ = new field_ulonglong(item, pc); new_field= new field_ulonglong(item, pc);
else 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;
*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);
} }
} }
DBUG_RETURN(pc); DBUG_RETURN(pc);
@ -470,6 +478,9 @@ void field_decimal::add()
length= my_decimal_string_length(dec); length= my_decimal_string_length(dec);
if (decimal_is_zero(dec))
empty++;
if (room_in_tree) if (room_in_tree)
{ {
char buf[DECIMAL_MAX_FIELD_SIZE]; char buf[DECIMAL_MAX_FIELD_SIZE];
@ -502,7 +513,7 @@ void field_decimal::add()
cur_sum= 0; cur_sum= 0;
min_length = max_length = length; min_length = max_length = length;
} }
else else if (!decimal_is_zero(dec))
{ {
int next_cur_sum= cur_sum ^ 1; int next_cur_sum= cur_sum ^ 1;
my_decimal sqr_buf; my_decimal sqr_buf;
@ -972,15 +983,17 @@ void field_decimal::get_opt_type(String *answer,
{ {
my_decimal zero; my_decimal zero;
char buff[MAX_FIELD_WIDTH]; char buff[MAX_FIELD_WIDTH];
uint length;
my_decimal_set_zero(&zero); my_decimal_set_zero(&zero);
my_bool is_unsigned= (my_decimal_cmp(&zero, &min_arg) >= 0); my_bool is_unsigned= (my_decimal_cmp(&zero, &min_arg) >= 0);
sprintf(buff, "DECIMAL(%d, %d)", length= my_sprintf(buff, (buff, "DECIMAL(%d, %d)",
(int)(max_length - (item->decimals ? 1 : 0)), item->decimals); (int) (max_length - (item->decimals ? 1 : 0)),
item->decimals));
if (is_unsigned) if (is_unsigned)
strcat(buff, " UNSIGNED"); length= (uint) (strmov(buff+length, " UNSIGNED")- buff);
answer->append(buff, (uint) strlen(buff)); answer->append(buff, length);
} }

View File

@ -3400,8 +3400,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
thd->restore_backup_item_arena(arena, &backup); thd->restore_backup_item_arena(arena, &backup);
if (*conds && !(*conds)->fixed) if (*conds && !(*conds)->fixed)
{ {
if (!(*conds)->fixed && if ((*conds)->fix_fields(thd, tables, conds))
(*conds)->fix_fields(thd, tables, conds))
goto err_no_arena; 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); thd->restore_backup_item_arena(arena, &backup);
if (embedded->on_expr && !embedded->on_expr->fixed) if (embedded->on_expr && !embedded->on_expr->fixed)
{ {
if (!embedded->on_expr->fixed && if (embedded->on_expr->fix_fields(thd, tables,
embedded->on_expr->fix_fields(thd, tables, &embedded->on_expr)) &embedded->on_expr))
goto err_no_arena; goto err_no_arena;
} }
} }

View File

@ -1366,10 +1366,9 @@ bool select_max_min_finder_subselect::cmp_real()
return (cache->null_value && !maxmin->null_value) || return (cache->null_value && !maxmin->null_value) ||
(!cache->null_value && !maxmin->null_value && (!cache->null_value && !maxmin->null_value &&
val1 > val2); val1 > val2);
else return (maxmin->null_value && !cache->null_value) ||
return (maxmin->null_value && !cache->null_value) || (!cache->null_value && !maxmin->null_value &&
(!cache->null_value && !maxmin->null_value && val1 < val2);
val1 < val2);
} }
bool select_max_min_finder_subselect::cmp_int() 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) || return (cache->null_value && !maxmin->null_value) ||
(!cache->null_value && !maxmin->null_value && (!cache->null_value && !maxmin->null_value &&
val1 > val2); val1 > val2);
else return (maxmin->null_value && !cache->null_value) ||
return (maxmin->null_value && !cache->null_value) || (!cache->null_value && !maxmin->null_value &&
(!cache->null_value && !maxmin->null_value && val1 < val2);
val1 < val2);
} }
bool select_max_min_finder_subselect::cmp_decimal() bool select_max_min_finder_subselect::cmp_decimal()
{ {
String *val1, *val2, buf1, buf2;
Item *maxmin= ((Item_singlerow_subselect *)item)->el(0); 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 cval, *cvalue= cache->val_decimal(&cval);
my_decimal mval, *mvalue= maxmin->val_decimal(&mval); my_decimal mval, *mvalue= maxmin->val_decimal(&mval);
if (fmax) if (fmax)
return (cache->null_value && !maxmin->null_value) || return (cache->null_value && !maxmin->null_value) ||
(!cache->null_value && !maxmin->null_value && (!cache->null_value && !maxmin->null_value &&
my_decimal_cmp(cvalue, mvalue) > 0) ; my_decimal_cmp(cvalue, mvalue) > 0) ;
else return (maxmin->null_value && !cache->null_value) ||
return (maxmin->null_value && !cache->null_value) || (!cache->null_value && !maxmin->null_value &&
(!cache->null_value && !maxmin->null_value && my_decimal_cmp(cvalue,mvalue) < 0);
my_decimal_cmp(cvalue,mvalue) < 0);
} }
bool select_max_min_finder_subselect::cmp_str() 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) || return (cache->null_value && !maxmin->null_value) ||
(!cache->null_value && !maxmin->null_value && (!cache->null_value && !maxmin->null_value &&
sortcmp(val1, val2, cache->collation.collation) > 0) ; sortcmp(val1, val2, cache->collation.collation) > 0) ;
else return (maxmin->null_value && !cache->null_value) ||
return (maxmin->null_value && !cache->null_value) || (!cache->null_value && !maxmin->null_value &&
(!cache->null_value && !maxmin->null_value && sortcmp(val1, val2, cache->collation.collation) < 0);
sortcmp(val1, val2, cache->collation.collation) < 0);
} }
bool select_exists_subselect::send_data(List<Item> &items) bool select_exists_subselect::send_data(List<Item> &items)

View File

@ -7217,8 +7217,9 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
if (conds) if (conds)
{ {
conds= and_conds(conds, table->on_expr); conds= and_conds(conds, table->on_expr);
if (!conds->fixed) /* conds is always a new item as both cond and on_expr existed */
conds->fix_fields(join->thd, 0, &conds); DBUG_ASSERT(!conds->fixed);
conds->fix_fields(join->thd, 0, &conds);
} }
else else
conds= table->on_expr; conds= table->on_expr;

View File

@ -743,12 +743,12 @@ int decimal_shift(decimal *dec, int shift)
Convert string to decimal Convert string to decimal
SYNOPSIS SYNOPSIS
str2decl() internal_str2decl()
from - value to convert from - value to convert. Doesn't have to be \0 terminated!
to - decimal where where the result will be stored to - decimal where where the result will be stored
to->buf and to->len must be set. to->buf and to->len must be set.
end - if not NULL, *end will be set to the char where end - Pointer to pointer to end of string. Will on return be
conversion ended set to the char after the last used character
fixed - use to->intg, to->frac as limits for input number fixed - use to->intg, to->frac as limits for input number
NOTE NOTE
@ -757,31 +757,36 @@ int decimal_shift(decimal *dec, int shift)
RETURN VALUE RETURN VALUE
E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW/E_DEC_BAD_NUM/E_DEC_OOM 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; int i, intg, frac, error, intg1, frac1;
dec1 x,*buf; dec1 x,*buf;
LINT_INIT(error);
sanity(to); 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++; s++;
if (s == end_of_string)
goto fatal_error;
if ((to->sign= (*s == '-'))) if ((to->sign= (*s == '-')))
s++; s++;
else if (*s == '+') else if (*s == '+')
s++; s++;
s1=s; s1=s;
while (my_isdigit(&my_charset_latin1, *s)) while (s < end_of_string && my_isdigit(&my_charset_latin1, *s))
s++; s++;
intg=s-s1; intg=s-s1;
if (*s=='.') if (s < end_of_string && *s=='.')
{ {
endp= s+1; endp= s+1;
while (my_isdigit(&my_charset_latin1, *endp)) while (s < end_of_string && my_isdigit(&my_charset_latin1, *endp))
endp++; endp++;
frac= endp - s - 1; frac= endp - s - 1;
} }
@ -791,12 +796,12 @@ static int str2dec(char *from, decimal *to, char **end, my_bool fixed)
endp= s; endp= s;
} }
if (end) *end= (char*) endp;
*end= endp;
if (frac+intg == 0) if (frac+intg == 0)
return E_DEC_BAD_NUM; goto fatal_error;
error= 0;
if (fixed) if (fixed)
{ {
if (frac > to->frac) if (frac > to->frac)
@ -812,7 +817,10 @@ static int str2dec(char *from, decimal *to, char **end, my_bool fixed)
intg1=ROUND_UP(intg); intg1=ROUND_UP(intg);
frac1=ROUND_UP(frac); frac1=ROUND_UP(frac);
if (intg1+frac1 > to->len) if (intg1+frac1 > to->len)
return E_DEC_OOM; {
error= E_DEC_OOM;
goto fatal_error;
}
} }
else else
{ {
@ -861,36 +869,43 @@ static int str2dec(char *from, decimal *to, char **end, my_bool fixed)
} }
if (i) if (i)
*buf=x*powers10[DIG_PER_DEC1-i]; *buf=x*powers10[DIG_PER_DEC1-i];
if (*endp == 'e' || *endp == 'E')
/* Handle exponent */
if (endp+1 < end_of_string && (*endp == 'e' || *endp == 'E'))
{ {
long exp= strtol(endp + 1, &endp, 10); int str_error;
longlong exp= my_strtoll10(endp+1, (char**) &end_of_string, &str_error);
if (end) if (end_of_string != endp +1) /* If at least one digit */
*end= endp; {
*end= (char*) end_of_string;
if (exp > INT_MAX/2) if (str_error > 0)
return E_DEC_OVERFLOW; {
if (exp < INT_MIN/2 && error != E_DEC_OVERFLOW) error= E_DEC_BAD_NUM;
return E_DEC_TRUNCATED; goto fatal_error;
}
if(error != E_DEC_OVERFLOW) if (exp > INT_MAX/2 || (str_error == 0 && exp < 0))
error= decimal_shift(to, exp); {
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; 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 Convert decimal to double
@ -932,9 +947,10 @@ int decimal2double(decimal *from, double *to)
int double2decimal(double from, decimal *to) int double2decimal(double from, decimal *to)
{ {
/* TODO: fix it, when we'll have dtoa */ /* TODO: fix it, when we'll have dtoa */
char s[400]; char s[400], *end;
sprintf(s, "%f", from); sprintf(s, "%f", from);
return string2decimal(s, to, 0); end= strend(s);
return string2decimal(s, to, &end);
} }
static int ull2dec(ulonglong from, decimal *to) static int ull2dec(ulonglong from, decimal *to)
@ -2160,13 +2176,13 @@ void check_result_code(int actual, int want)
{ {
if (actual != want) if (actual != want)
{ {
printf("\n^^^^^^^^^^^^^ mast return %d\n", want); printf("\n^^^^^^^^^^^^^ must return %d\n", want);
exit(1); 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]; char s[100];
int slen=sizeof(s); 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); 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; int res;
sprintf(s1, "'%s'", s); sprintf(s1, "'%s'", s);
end= strend(s);
printf("len=%2d %-30s => res=%d ", a.len, s1, 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); print_decimal(&a, orig, res, ex);
printf("\n"); 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; double x;
int res; int res;
sprintf(s1, "'%s'", s); sprintf(s1, "'%s'", s);
string2decimal(s, &a, 0); end= strend(s);
string2decimal(s, &a, &end);
res=decimal2double(&a, &x); res=decimal2double(&a, &x);
if (full) dump_decimal(&a); if (full) dump_decimal(&a);
printf("%-40s => res=%d %.*g\n", s1, res, a.intg+a.frac, x); printf("%-40s => res=%d %.*g\n", s1, res, a.intg+a.frac, x);
check_result_code(res, ex); 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); int res, i, size=decimal_bin_size(p, s);
sprintf(s1, "'%s'", str); sprintf(s1, "'%s'", str);
string2decimal(str, &a, 0); end= strend(str);
string2decimal(str, &a, &end);
res=decimal2bin(&a, buf, p, s); res=decimal2bin(&a, buf, p, s);
printf("%-31s {%2d, %2d} => res=%d size=%-2d ", s1, p, s, res, size); printf("%-31s {%2d, %2d} => res=%d size=%-2d ", s1, p, s, res, size);
if (full) 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); print_decimal(&a, orig, res, ex);
printf("\n"); printf("\n");
} }
void test_f2d(double from, int ex) void test_f2d(double from, int ex)
{ {
int res; int res;
@ -2273,7 +2293,7 @@ void test_f2d(double from, int ex)
printf("\n"); printf("\n");
} }
void test_ull2d(ulonglong from, char *orig, int ex) void test_ull2d(ulonglong from, const char *orig, int ex)
{ {
char s[100]; char s[100];
int res; int res;
@ -2285,7 +2305,7 @@ void test_ull2d(ulonglong from, char *orig, int ex)
printf("\n"); printf("\n");
} }
void test_ll2d(longlong from, char *orig, int ex) void test_ll2d(longlong from, const char *orig, int ex)
{ {
char s[100]; char s[100];
int res; int res;
@ -2297,13 +2317,14 @@ void test_ll2d(longlong from, char *orig, int ex)
printf("\n"); 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; ulonglong x;
int res; int res;
string2decimal(s, &a, 0); end= strend(s);
string2decimal(s, &a, &end);
res=decimal2ulonglong(&a, &x); res=decimal2ulonglong(&a, &x);
if (full) dump_decimal(&a); if (full) dump_decimal(&a);
longlong10_to_str(x,s1,10); 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; longlong x;
int res; int res;
string2decimal(s, &a, 0); end= strend(s);
string2decimal(s, &a, &end);
res=decimal2longlong(&a, &x); res=decimal2longlong(&a, &x);
if (full) dump_decimal(&a); if (full) dump_decimal(&a);
longlong10_to_str(x,s1,-10); 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; int res;
sprintf(s, "'%s' + '%s'", s1, s2); sprintf(s, "'%s' + '%s'", s1, s2);
string2decimal(s1, &a, 0); end= strend(s1);
string2decimal(s2, &b, 0); string2decimal(s1, &a, &end);
end= strend(s2);
string2decimal(s2, &b, &end);
res=decimal_add(&a, &b, &c); res=decimal_add(&a, &b, &c);
printf("%-40s => res=%d ", s, res); printf("%-40s => res=%d ", s, res);
print_decimal(&c, orig, res, ex); print_decimal(&c, orig, res, ex);
printf("\n"); 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; int res;
sprintf(s, "'%s' - '%s'", s1, s2); sprintf(s, "'%s' - '%s'", s1, s2);
string2decimal(s1, &a, 0); end= strend(s1);
string2decimal(s2, &b, 0); string2decimal(s1, &a, &end);
end= strend(s2);
string2decimal(s2, &b, &end);
res=decimal_sub(&a, &b, &c); res=decimal_sub(&a, &b, &c);
printf("%-40s => res=%d ", s, res); printf("%-40s => res=%d ", s, res);
print_decimal(&c, orig, res, ex); print_decimal(&c, orig, res, ex);
printf("\n"); 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; int res;
sprintf(s, "'%s' <=> '%s'", s1, s2); sprintf(s, "'%s' <=> '%s'", s1, s2);
string2decimal(s1, &a, 0); end= strend(s1);
string2decimal(s2, &b, 0); string2decimal(s1, &a, &end);
end= strend(s2);
string2decimal(s2, &b, &end);
res=decimal_cmp(&a, &b); res=decimal_cmp(&a, &b);
printf("%-40s => res=%d\n", s, res); printf("%-40s => res=%d\n", s, res);
if (orig != 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; int res;
sprintf(s, "'%s' * '%s'", s1, s2); sprintf(s, "'%s' * '%s'", s1, s2);
string2decimal(s1, &a, 0); end= strend(s1);
string2decimal(s2, &b, 0); string2decimal(s1, &a, &end);
end= strend(s2);
string2decimal(s2, &b, &end);
res=decimal_mul(&a, &b, &c); res=decimal_mul(&a, &b, &c);
printf("%-40s => res=%d ", s, res); printf("%-40s => res=%d ", s, res);
print_decimal(&c, orig, res, ex); print_decimal(&c, orig, res, ex);
printf("\n"); 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; int res;
sprintf(s, "'%s' / '%s'", s1, s2); sprintf(s, "'%s' / '%s'", s1, s2);
string2decimal(s1, &a, 0); end= strend(s1);
string2decimal(s2, &b, 0); string2decimal(s1, &a, &end);
end= strend(s2);
string2decimal(s2, &b, &end);
res=decimal_div(&a, &b, &c, 5); res=decimal_div(&a, &b, &c, 5);
printf("%-40s => res=%d ", s, res); printf("%-40s => res=%d ", s, res);
check_result_code(res, ex); check_result_code(res, ex);
@ -2407,13 +2439,15 @@ void test_dv(char *s1, char *s2, char *orig, int ex)
printf("\n"); 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; int res;
sprintf(s, "'%s' %% '%s'", s1, s2); sprintf(s, "'%s' %% '%s'", s1, s2);
string2decimal(s1, &a, 0); end= strend(s1);
string2decimal(s2, &b, 0); string2decimal(s1, &a, &end);
end= strend(s2);
string2decimal(s2, &b, &end);
res=decimal_mod(&a, &b, &c); res=decimal_mod(&a, &b, &c);
printf("%-40s => res=%d ", s, res); printf("%-40s => res=%d ", s, res);
check_result_code(res, ex); check_result_code(res, ex);
@ -2424,14 +2458,17 @@ void test_md(char *s1, char *s2, char *orig, int ex)
printf("\n"); 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; int res;
sprintf(s, "'%s', %d, %s", s1, n, round_mode[mode]); 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); res=decimal_round(&a, &b, n, mode);
printf("%-40s => res=%d ", s, res); printf("%-40s => res=%d ", s, res);
print_decimal(&b, orig, res, ex); 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]; char s[100];
sprintf(s, "%d, %d", precision, frac); 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]; char s2[100];
int slen= sizeof(s2); int slen= sizeof(s2);
int res; int res;
sprintf(s, "'%s', %d, %d, '%c'", s1, prec, dec, filler); 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); res= decimal2string(&a, s2, &slen, prec, dec, filler);
printf("%-40s => res=%d '%s'", s, res, s2); printf("%-40s => res=%d '%s'", s, res, s2);
check_result_code(res, ex); 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; int res;
sprintf(s, "'%s' %s %d", s1, ((shift < 0) ? ">>" : "<<"), abs(shift)); 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); res= decimal_shift(&a, shift);
printf("%-40s => res=%d ", s, res); printf("%-40s => res=%d ", s, res);
print_decimal(&a, orig, res, ex); 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); sprintf(s, "'%s'", s1);
printf("%-40s => ", s); printf("%-40s => ", s);
string2decimal(s1, &a, 0); end= strend(s1);
string2decimal(s1, &a, &end);
decimal_optimize_fraction(&a); decimal_optimize_fraction(&a);
print_decimal(&a, orig, 0, 0); print_decimal(&a, orig, 0, 0);
printf("\n"); printf("\n");