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