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