Merge bk-internal.mysql.com:/home/bk/mysql-5.0

into mysql.com:/home/my/mysql-5.0
This commit is contained in:
monty@mysql.com 2005-02-19 19:00:41 +02:00
commit 88d2e2973d
28 changed files with 855 additions and 686 deletions

View file

@ -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 { \

View file

@ -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');

View file

@ -30,6 +30,12 @@ Y-N-N-Y-N Y,N,N,Y,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,
select elt(2,1),field(NULL,"a","b","c");
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

View file

@ -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);

View file

@ -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:

View file

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

View file

@ -18,6 +18,8 @@ select export_set(9,"Y","N","-",5),export_set(9,"Y","N"),export_set(9,"Y","N",""
# Wrong usage of functions
#
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);

View file

@ -165,6 +165,8 @@ insert into t1 values ("00000000000001"),("+0000000000001"),("-0000000000001");
insert into t1 values ("+111111111.11"),("111111111.11"),("-11111111.11");
insert into t1 values ("-111111111.11"),("+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;

View file

@ -73,6 +73,99 @@ bool Item::val_bool()
}
String *Item::val_string_from_real(String *str)
{
double nr= val_real();
if (null_value)
return 0; /* purecov: inspected */
str->set(nr,decimals, &my_charset_bin);
return str;
}
String *Item::val_string_from_int(String *str)
{
longlong nr= val_int();
if (null_value)
return 0;
if (unsigned_flag)
str->set((ulonglong) nr, &my_charset_bin);
else
str->set(nr, &my_charset_bin);
return str;
}
String *Item::val_string_from_decimal(String *str)
{
my_decimal dec_buf, *dec= val_decimal(&dec_buf);
if (null_value)
return 0;
my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf);
my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, 0, str);
return str;
}
my_decimal *Item::val_decimal_from_real(my_decimal *decimal_value)
{
double nr= val_real();
if (null_value)
return 0;
double2my_decimal(E_DEC_FATAL_ERROR, nr, decimal_value);
return (decimal_value);
}
my_decimal *Item::val_decimal_from_int(my_decimal *decimal_value)
{
longlong nr= val_int();
if (null_value)
return 0;
int2my_decimal(E_DEC_FATAL_ERROR, nr, unsigned_flag, decimal_value);
return decimal_value;
}
my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value)
{
String *res;
char *end_ptr;
int error;
if (!(res= val_str(&str_value)))
return 0; // NULL or EOM
end_ptr= (char*) res->ptr()+ res->length();
str2my_decimal(E_DEC_FATAL_ERROR, res->ptr(), res->length(), res->charset(),
decimal_value);
return decimal_value;
}
double Item::val_real_from_decimal()
{
/* Note that fix_fields may not be called for Item_avg_field items */
double result;
my_decimal value_buff, *dec_val= val_decimal(&value_buff);
if (null_value)
return 0.0;
my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &result);
return result;
}
longlong Item::val_int_from_decimal()
{
/* Note that fix_fields may not be called for Item_avg_field items */
longlong result;
my_decimal value, *dec_val= val_decimal(&value);
if (null_value)
return 0;
my_decimal2int(E_DEC_FATAL_ERROR, dec_val, unsigned_flag, &result);
return result;
}
Item::Item():
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;
}

View file

@ -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 : "???"; }

View file

@ -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;
}

View file

@ -357,18 +357,15 @@ public:
};
class Item_func_int_div :public Item_func
class Item_func_int_div :public Item_int_func
{
public:
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();
};

View file

@ -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()
{

View file

@ -125,15 +125,6 @@ Item *Item_sum::get_tmp_table_item(THD *thd)
}
my_decimal *Item_sum::val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed);
DBUG_ASSERT(decimal_value);
int2my_decimal(E_DEC_FATAL_ERROR, val_int(), unsigned_flag, decimal_value);
return decimal_value;
}
bool Item_sum::walk (Item_processor processor, byte *argument)
{
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);

View file

@ -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() {}

View file

@ -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:

View file

@ -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

View file

@ -68,10 +68,13 @@ inline uint my_decimal_size(uint precision, uint scale)
}
/* my_decimal class limits 'decimal' type to what we need in MySQL */
/* It internally all necessary space iside the instance so no extra */
/* 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*/

View file

@ -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)
{

View file

@ -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());
}

View file

@ -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;

View file

@ -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);

View file

@ -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())

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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)

View file

@ -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;

View file

@ -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");