diff options
author | unknown <hf@deer.(none)> | 2005-02-09 02:50:45 +0400 |
---|---|---|
committer | unknown <hf@deer.(none)> | 2005-02-09 02:50:45 +0400 |
commit | 91db48e35a57421c00f65d5ce82e84b843ceec22 (patch) | |
tree | 9631c72d46b0fd08479ad02de00e5846cd339cda | |
parent | 63bcbfc4339ae843dc367d08fff0760da4d484c3 (diff) | |
download | mariadb-git-91db48e35a57421c00f65d5ce82e84b843ceec22.tar.gz |
Precision Math implementation
BitKeeper/etc/ignore:
Added client/decimal.c client/my_decimal.cc client/my_decimal.h to the ignore list
104 files changed, 9107 insertions, 1706 deletions
diff --git a/.bzrignore b/.bzrignore index 74e098e888f..0d352209a08 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1056,3 +1056,6 @@ include/mysqld_ername.h include/mysqld_error.h include/sql_state.h support-files/ndb-config-2-node.ini +client/decimal.c +client/my_decimal.cc +client/my_decimal.h diff --git a/client/Makefile.am b/client/Makefile.am index 2721953629e..d3307f9da42 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -34,7 +34,8 @@ mysqltest_SOURCES= mysqltest.c $(top_srcdir)/mysys/my_getsystime.c mysqltest_LDADD = $(top_builddir)/regex/libregex.a $(LDADD) mysqlbinlog_SOURCES = mysqlbinlog.cc $(top_srcdir)/mysys/mf_tempdir.c mysqlmanagerc_SOURCES = mysqlmanagerc.c -sql_src=log_event.h mysql_priv.h log_event.cc +sql_src=log_event.h mysql_priv.h log_event.cc my_decimal.h my_decimal.cc +strings_src=decimal.c # Fix for mit-threads DEFS = -DUNDEF_THREADS_HACK @@ -43,7 +44,11 @@ link_sources: for f in $(sql_src) ; do \ rm -f $(srcdir)/$$f; \ @LN_CP_F@ $(top_srcdir)/sql/$$f $(srcdir)/$$f; \ - done; + done; \ + for f in $(strings_src) ; do \ + rm -f $(srcdir)/$$f; \ + @LN_CP_F@ $(top_srcdir)/strings/$$f $(srcdir)/$$f; \ + done; # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 0afd4074284..dc1c1e6fc02 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -1280,8 +1280,14 @@ int main(int argc, char** argv) */ #ifdef __WIN__ +#include "my_decimal.h" +#include "decimal.c" +#include "my_decimal.cpp" #include "log_event.cpp" #else +#include "my_decimal.h" +#include "decimal.c" +#include "my_decimal.cc" #include "log_event.cc" #endif diff --git a/include/decimal.h b/include/decimal.h index 4d1fbfddc01..1e0ee97c267 100644 --- a/include/decimal.h +++ b/include/decimal.h @@ -26,7 +26,9 @@ typedef struct st_decimal { decimal_digit *buf; } decimal; -int decimal2string(decimal *from, char *to, int *to_len); +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); @@ -35,6 +37,7 @@ int decimal2longlong(decimal *from, longlong *to); int longlong2decimal(longlong from, decimal *to); int decimal2double(decimal *from, double *to); int double2decimal(double from, decimal *to); +void decimal_optimize_fraction(decimal *from); int decimal2bin(decimal *from, char *to, int precision, int scale); int bin2decimal(char *from, decimal *to, int precision, int scale); @@ -50,6 +53,7 @@ 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_is_zero(decimal *from); +void max_decimal(int precision, int frac, decimal *to); /* set a decimal to zero */ @@ -65,7 +69,8 @@ int decimal_is_zero(decimal *from); of the decimal (including decimal dot, possible sign and \0) */ -#define decimal_string_size(dec) ((dec)->intg + (dec)->frac + ((dec)->frac > 0) + 2) +#define decimal_string_size(dec) (((dec)->intg ? (dec)->intg : 1) + \ + (dec)->frac + ((dec)->frac > 0) + 2) /* negate a decimal */ #define decimal_neg(dec) do { (dec)->sign^=1; } while(0) diff --git a/include/mysql_com.h b/include/mysql_com.h index 59b2ee743ec..66860389c4a 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -211,6 +211,7 @@ enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, MYSQL_TYPE_DATETIME, MYSQL_TYPE_YEAR, MYSQL_TYPE_NEWDATE, MYSQL_TYPE_VARCHAR, MYSQL_TYPE_BIT, + MYSQL_TYPE_NEWDECIMAL=246, MYSQL_TYPE_ENUM=247, MYSQL_TYPE_SET=248, MYSQL_TYPE_TINY_BLOB=249, @@ -226,6 +227,7 @@ enum enum_field_types { MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY, /* For backward compatibility */ #define CLIENT_MULTI_QUERIES CLIENT_MULTI_STATEMENTS #define FIELD_TYPE_DECIMAL MYSQL_TYPE_DECIMAL +#define FIELD_TYPE_NEWDECIMAL MYSQL_TYPE_NEWDECIMAL #define FIELD_TYPE_TINY MYSQL_TYPE_TINY #define FIELD_TYPE_SHORT MYSQL_TYPE_SHORT #define FIELD_TYPE_LONG MYSQL_TYPE_LONG @@ -341,7 +343,8 @@ struct rand_struct { /* The following is for user defined functions */ -enum Item_result {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT}; +enum Item_result {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT, + DECIMAL_RESULT}; typedef struct st_udf_args { diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 258391ac899..a1e13be8e25 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -3186,6 +3186,8 @@ my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind) case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: param->store_param_func= store_param_str; /* For variable length types user must set either length or @@ -3512,6 +3514,8 @@ static void fetch_string_with_conversion(MYSQL_BIND *param, char *value, case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: default: { /* @@ -4249,6 +4253,8 @@ static my_bool setup_one_fetch_function(MYSQL_BIND *param, MYSQL_FIELD *field) break; case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: DBUG_ASSERT(param->buffer_length != 0); param->fetch_result= fetch_result_str; break; @@ -4308,6 +4314,7 @@ static my_bool setup_one_fetch_function(MYSQL_BIND *param, MYSQL_FIELD *field) field->max_length= MAX_DATE_STRING_REP_LENGTH; break; case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: case MYSQL_TYPE_ENUM: case MYSQL_TYPE_SET: case MYSQL_TYPE_GEOMETRY: diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index 2f90d22f990..3c33b56ba1c 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -62,7 +62,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \ unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc \ spatial.cc gstream.cc sql_help.cc tztime.cc protocol_cursor.cc \ sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \ - parse_file.cc sql_view.cc sql_trigger.cc + parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources) $(sqlexamplessources) libmysqld_a_SOURCES= diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result index 4c70e72bdfb..4268b121b1d 100644 --- a/mysql-test/r/bigint.result +++ b/mysql-test/r/bigint.result @@ -7,7 +7,7 @@ select 9223372036854775807,-009223372036854775808; 9223372036854775807 -9223372036854775808 select +9999999999999999999,-9999999999999999999; 9999999999999999999 -9999999999999999999 -9999999999999999999 -10000000000000000000 +9999999999999999999 -9999999999999999999 select cast(9223372036854775808 as unsigned)+1; cast(9223372036854775808 as unsigned)+1 9223372036854775809 @@ -16,7 +16,7 @@ select 9223372036854775808+1; 9223372036854775809 select -(0-3),round(-(0-3)), round(9999999999999999999); -(0-3) round(-(0-3)) round(9999999999999999999) -3 3 10000000000000000000 +3 3 9999999999999999999 create table t1 (a bigint unsigned not null, primary key(a)); insert into t1 values (18446744073709551615), (0xFFFFFFFFFFFFFFFE), (18446744073709551613), (18446744073709551612); select * from t1; diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index 1f2d60fb79a..1ca913e1259 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -91,7 +91,10 @@ CASE WHEN 1 THEN 'a' ELSE 1.0 END AS c5, CASE WHEN 1 THEN 1.0 ELSE 'a' END AS c6, CASE WHEN 1 THEN 1 ELSE 1.0 END AS c7, CASE WHEN 1 THEN 1.0 ELSE 1 END AS c8, -CASE WHEN 1 THEN 1.0 END AS c9 +CASE WHEN 1 THEN 1.0 END AS c9, +CASE WHEN 1 THEN 0.1e1 else 0.1 END AS c10, +CASE WHEN 1 THEN 0.1e1 else 1 END AS c11, +CASE WHEN 1 THEN 0.1e1 else '1' END AS c12 ; SHOW CREATE TABLE t1; Table Create Table @@ -100,11 +103,14 @@ t1 CREATE TABLE `t1` ( `c2` varchar(1) character set latin1 collate latin1_danish_ci NOT NULL default '', `c3` varbinary(1) NOT NULL default '', `c4` varbinary(1) NOT NULL default '', - `c5` varbinary(3) NOT NULL default '', - `c6` varbinary(3) NOT NULL default '', - `c7` double(3,1) NOT NULL default '0.0', - `c8` double(3,1) NOT NULL default '0.0', - `c9` double(3,1) default NULL + `c5` varbinary(4) NOT NULL default '', + `c6` varbinary(4) NOT NULL default '', + `c7` decimal(5,1) NOT NULL default '0.0', + `c8` decimal(5,1) NOT NULL default '0.0', + `c9` decimal(5,1) default NULL, + `c10` double NOT NULL default '0', + `c11` double NOT NULL default '0', + `c12` varbinary(5) NOT NULL default '' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; SELECT CASE @@ -146,11 +152,11 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `COALESCE(1)` int(1) NOT NULL default '0', - `COALESCE(1.0)` double(3,1) NOT NULL default '0.0', + `COALESCE(1.0)` decimal(5,1) NOT NULL default '0.0', `COALESCE('a')` varchar(1) NOT NULL default '', - `COALESCE(1,1.0)` double(3,1) NOT NULL default '0.0', + `COALESCE(1,1.0)` decimal(5,1) NOT NULL default '0.0', `COALESCE(1,'1')` varbinary(1) NOT NULL default '', - `COALESCE(1.1,'1')` varbinary(3) NOT NULL default '', + `COALESCE(1.1,'1')` varbinary(4) NOT NULL default '', `COALESCE('a' COLLATE latin1_bin,'b')` varchar(1) character set latin1 collate latin1_bin NOT NULL default '' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 05d1ba026ba..1c378f88e5c 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -103,9 +103,9 @@ Field Type Null Key Default Extra a datetime NO 0000-00-00 00:00:00 b time NO 00:00:00 c date NO 0000-00-00 -d bigint(17) NO 0 -e double(18,1) NO 0.0 -f bigint(17) NO 0 +d int(2) NO 0 +e decimal(6,1) NO 0.0 +f bigint(18) NO 0 drop table t2; create table t2 select CAST("2001-12-29" AS DATE) as d, CAST("20:45:11" AS TIME) as t, CAST("2001-12-29 20:45:11" AS DATETIME) as dt; describe t2; @@ -418,7 +418,7 @@ d date YES NULL e varchar(1) NO f datetime YES NULL g time YES NULL -h longblob NO +h varbinary(23) NO dd time YES NULL select * from t2; a b c d e f g h dd @@ -437,7 +437,7 @@ t2 CREATE TABLE `t2` ( `ifnull(e,e)` bigint(20) default NULL, `ifnull(f,f)` float(3,2) default NULL, `ifnull(g,g)` double(4,3) default NULL, - `ifnull(h,h)` decimal(5,4) default NULL, + `ifnull(h,h)` decimal(6,4) default NULL, `ifnull(i,i)` year(4) default NULL, `ifnull(j,j)` date default NULL, `ifnull(k,k)` datetime NOT NULL default '0000-00-00 00:00:00', diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index 1e1d6f96eb7..177994b488d 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -462,5 +462,5 @@ rout int(11) default '0' INSERT INTO t1 VALUES ('1',1,0); SELECT DISTINCT html,SUM(rout)/(SUM(rin)+1) as 'prod' FROM t1 GROUP BY rin; html prod -1 0.00 +1 0.00000 drop table t1; diff --git a/mysql-test/r/func_equal.result b/mysql-test/r/func_equal.result index 352b76f2744..fe5e5b1b371 100644 --- a/mysql-test/r/func_equal.result +++ b/mysql-test/r/func_equal.result @@ -1,7 +1,7 @@ drop table if exists t1,t2; -select 0<=>0,0.0<=>0.0,"A"<=>"A",NULL<=>NULL; -0<=>0 0.0<=>0.0 "A"<=>"A" NULL<=>NULL -1 1 1 1 +select 0<=>0,0.0<=>0.0,0E0=0E0,"A"<=>"A",NULL<=>NULL; +0<=>0 0.0<=>0.0 0E0=0E0 "A"<=>"A" NULL<=>NULL +1 1 1 1 1 select 1<=>0,0<=>NULL,NULL<=>0; 1<=>0 0<=>NULL NULL<=>0 0 0 0 @@ -11,6 +11,12 @@ select 1.0<=>0.0,0.0<=>NULL,NULL<=>0.0; select "A"<=>"B","A"<=>NULL,NULL<=>"A"; "A"<=>"B" "A"<=>NULL NULL<=>"A" 0 0 0 +select 0<=>0.0, 0.0<=>0E0, 0E0<=>"0", 10.0<=>1E1, 10<=>10.0, 10<=>1E1; +0<=>0.0 0.0<=>0E0 0E0<=>"0" 10.0<=>1E1 10<=>10.0 10<=>1E1 +1 1 1 1 1 1 +select 1.0<=>0E1,10<=>NULL,NULL<=>0.0, NULL<=>0E0; +1.0<=>0E1 10<=>NULL NULL<=>0.0 NULL<=>0E0 +0 0 0 0 create table t1 (id int, value int); create table t2 (id int, value int); insert into t1 values (1,null); diff --git a/mysql-test/r/func_op.result b/mysql-test/r/func_op.result index 6cd975b0911..5f89fe7b727 100644 --- a/mysql-test/r/func_op.result +++ b/mysql-test/r/func_op.result @@ -1,6 +1,6 @@ select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2; 1+1 1-1 1+1*2 8/5 8%5 mod(8,5) mod(8,5)|0 -(1+1)*-2 -2 0 3 1.60 3 3 3 4 +2 0 3 1.60000 3 3 3 4 explain extended select 1+1,1-1,1+1*2,8/5,8%5,mod(8,5),mod(8,5)|0,-(1+1)*-2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index f7b4d302a52..24740442821 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -440,12 +440,12 @@ create table t2 (user_id integer not null, date date); insert into t2 values (1, '2002-06-09'),(2, '2002-06-09'),(1, '2002-06-09'),(3, '2002-06-09'),(4, '2002-06-09'),(4, '2002-06-09'); select u.gender as gender, count(distinct u.id) as dist_count, (count(distinct u.id)/5*100) as percentage from t1 u, t2 l where l.user_id = u.id group by u.gender; gender dist_count percentage -F 3 60.00 -M 1 20.00 +F 3 60.00000 +M 1 20.00000 select u.gender as gender, count(distinct u.id) as dist_count, (count(distinct u.id)/5*100) as percentage from t1 u, t2 l where l.user_id = u.id group by u.gender order by percentage; gender dist_count percentage -M 1 20.00 -F 3 60.00 +M 1 20.00000 +F 3 60.00000 drop table t1,t2; CREATE TABLE t1 (ID1 int, ID2 int, ID int NOT NULL AUTO_INCREMENT,PRIMARY KEY(ID )); diff --git a/mysql-test/r/index_merge_innodb.result b/mysql-test/r/index_merge_innodb.result index 4c6be698749..52e2a4046cf 100644 --- a/mysql-test/r/index_merge_innodb.result +++ b/mysql-test/r/index_merge_innodb.result @@ -69,9 +69,11 @@ id select_type table type possible_keys key key_len ref rows Extra select pk from t1 where key2 = 1 and key1 = 1; pk 26 +27 select pk from t1 ignore index(key1,key2) where key2 = 1 and key1 = 1; pk 26 +27 drop table t1; create table t1 ( pk int primary key auto_increment, diff --git a/mysql-test/r/index_merge_ror_cpk.result b/mysql-test/r/index_merge_ror_cpk.result index c344cef5db9..6cfeb20b2de 100644 --- a/mysql-test/r/index_merge_ror_cpk.result +++ b/mysql-test/r/index_merge_ror_cpk.result @@ -56,7 +56,7 @@ pk1 pk2 95 59 explain select * from t1 where badkey=1 and key1=10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref key1 key1 4 const 101 Using where +1 SIMPLE t1 ref key1 key1 4 const 100 Using where explain select * from t1 where pk1 < 7500 and key1 = 10; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index_merge PRIMARY,key1 key1,PRIMARY 4,4 NULL 38 Using intersect(key1,PRIMARY); Using where @@ -74,13 +74,13 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index_merge PRIMARY,key1,pktail2ok pktail2ok,key1 8,4 NULL 199 Using sort_union(pktail2ok,key1); Using where explain select * from t1 where pktail3bad=1 and key1=10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref key1,pktail3bad pktail3bad 4 const ROWS Using where +1 SIMPLE t1 ref key1,pktail3bad key1 4 const 100 Using where explain select * from t1 where pktail4bad=1 and key1=10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref key1,pktail4bad pktail4bad 4 const 99 Using where +1 SIMPLE t1 ref key1,pktail4bad key1 4 const 100 Using where explain select * from t1 where pktail5bad=1 and key1=10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref key1,pktail5bad pktail5bad 4 const 99 Using where +1 SIMPLE t1 ref key1,pktail5bad key1 4 const 100 Using where explain select pk1,pk2,key1,key2 from t1 where key1 = 10 and key2=10 limit 10; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index_merge key1,key2 key1,key2 4,4 NULL 1 Using intersect(key1,key2); Using where; Using index diff --git a/mysql-test/r/metadata.result b/mysql-test/r/metadata.result index 48c09f369b3..6a2cf466cfa 100644 --- a/mysql-test/r/metadata.result +++ b/mysql-test/r/metadata.result @@ -2,7 +2,7 @@ drop table if exists t1,t2; select 1, 1.0, -1, "hello", NULL; Catalog Database Table Table_alias Column Column_alias Name Type Length Max length Is_null Flags Decimals Charsetnr def 1 8 1 1 N 32897 0 63 -def 1.0 5 3 3 N 32897 1 63 +def 1.0 246 4 3 N 161 1 63 def -1 8 2 2 N 32897 0 63 def hello 253 5 5 N 1 31 8 def NULL 6 0 0 Y 32896 0 63 @@ -18,7 +18,7 @@ def test t1 t1 d d 3 11 0 Y 32768 0 63 def test t1 t1 e e 8 20 0 Y 32768 0 63 def test t1 t1 f f 4 3 0 Y 32768 2 63 def test t1 t1 g g 5 4 0 Y 32768 3 63 -def test t1 t1 h h 0 7 0 Y 32768 4 63 +def test t1 t1 h h 246 5 0 Y 0 4 63 def test t1 t1 i i 13 4 0 Y 32864 0 63 def test t1 t1 j j 10 10 0 Y 128 0 63 def test t1 t1 k k 7 19 0 N 1249 0 63 diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index b06909fb1c8..9f08fae4964 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -19,13 +19,13 @@ INSERT INTO t1 VALUES (1), (2); </database> </mysqldump> DROP TABLE t1; -CREATE TABLE t1 (a decimal(240, 20)); +CREATE TABLE t1 (a decimal(64, 20)); INSERT INTO t1 VALUES ("1234567890123456789012345678901234567890"), ("0987654321098765432109876543210987654321"); CREATE TABLE `t1` ( - `a` decimal(240,20) default NULL + `a` decimal(64,20) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1; -INSERT INTO `t1` VALUES ('1234567890123456789012345678901234567890.00000000000000000000'),('0987654321098765432109876543210987654321.00000000000000000000'); +INSERT INTO `t1` VALUES ('1234567890123456789012345678901234567890.00000000000000000000'),('987654321098765432109876543210987654321.00000000000000000000'); DROP TABLE t1; CREATE TABLE t1 (a double); INSERT INTO t1 VALUES ('-9e999999'); diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index f398c69a424..a04fa75082f 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -164,48 +164,48 @@ product country_id year sum(profit) NULL NULL NULL 7785 select concat(product,':',country_id) as 'prod', concat(":",year,":") as 'year',1+1, sum(profit)/count(*) from t1 group by 1,2 with rollup; prod year 1+1 sum(profit)/count(*) -Calculator:1 :1999: 2 50.00 -Calculator:1 :2000: 2 75.00 -Calculator:1 NULL 2 62.50 -Calculator:2 :2000: 2 75.00 -Calculator:2 NULL 2 75.00 -Computer:1 :1999: 2 1350.00 -Computer:1 :2000: 2 1500.00 -Computer:1 NULL 2 1400.00 -Computer:2 :2000: 2 1350.00 -Computer:2 NULL 2 1350.00 -Phone:3 :2003: 2 10.00 -Phone:3 NULL 2 10.00 -TV:1 :1999: 2 125.00 -TV:1 :2000: 2 150.00 -TV:1 NULL 2 133.33 -TV:2 :2000: 2 100.00 -TV:2 NULL 2 100.00 -NULL NULL 2 519.00 +Calculator:1 :1999: 2 50.00000 +Calculator:1 :2000: 2 75.00000 +Calculator:1 NULL 2 62.50000 +Calculator:2 :2000: 2 75.00000 +Calculator:2 NULL 2 75.00000 +Computer:1 :1999: 2 1350.00000 +Computer:1 :2000: 2 1500.00000 +Computer:1 NULL 2 1400.00000 +Computer:2 :2000: 2 1350.00000 +Computer:2 NULL 2 1350.00000 +Phone:3 :2003: 2 10.00000 +Phone:3 NULL 2 10.00000 +TV:1 :1999: 2 125.00000 +TV:1 :2000: 2 150.00000 +TV:1 NULL 2 133.33333 +TV:2 :2000: 2 100.00000 +TV:2 NULL 2 100.00000 +NULL NULL 2 519.00000 select product, sum(profit)/count(*) from t1 group by product with rollup; product sum(profit)/count(*) -Calculator 68.75 -Computer 1380.00 -Phone 10.00 -TV 120.00 -NULL 519.00 +Calculator 68.75000 +Computer 1380.00000 +Phone 10.00000 +TV 120.00000 +NULL 519.00000 select left(product,4) as prod, sum(profit)/count(*) from t1 group by prod with rollup; prod sum(profit)/count(*) -Calc 68.75 -Comp 1380.00 -Phon 10.00 -TV 120.00 -NULL 519.00 +Calc 68.75000 +Comp 1380.00000 +Phon 10.00000 +TV 120.00000 +NULL 519.00000 select concat(product,':',country_id), 1+1, sum(profit)/count(*) from t1 group by concat(product,':',country_id) with rollup; concat(product,':',country_id) 1+1 sum(profit)/count(*) -Calculator:1 2 62.50 -Calculator:2 2 75.00 -Computer:1 2 1400.00 -Computer:2 2 1350.00 -Phone:3 2 10.00 -TV:1 2 133.33 -TV:2 2 100.00 -NULL 2 519.00 +Calculator:1 2 62.50000 +Calculator:2 2 75.00000 +Computer:1 2 1400.00000 +Computer:2 2 1350.00000 +Phone:3 2 10.00000 +TV:1 2 133.33333 +TV:2 2 100.00000 +NULL 2 519.00000 select product, country , year, sum(profit) from t1,t2 where t1.country_id=t2.country_id group by product, country, year with rollup; product country year sum(profit) Calculator India 2000 150 diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result index f5c71d3ed23..153121f0662 100644 --- a/mysql-test/r/ps_1general.result +++ b/mysql-test/r/ps_1general.result @@ -293,7 +293,7 @@ t2 MyISAM 9 Fixed 0 0 0 64424509439 1024 0 NULL # # # latin1_swedish_ci NULL prepare stmt4 from ' show table status from test like ''t9%'' '; execute stmt4; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t9 MyISAM 10 Dynamic 2 220 440 4294967295 2048 0 NULL # # # latin1_swedish_ci NULL +t9 MyISAM 10 Dynamic 2 216 432 4294967295 2048 0 NULL # # # latin1_swedish_ci NULL prepare stmt4 from ' show status like ''Threads_running'' '; execute stmt4; Variable_name Value diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index 50a74dfad63..78436b69ec7 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -59,8 +59,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 0 9 6 Y 32768 4 63 -def test t9 t9 c12 c12 0 10 6 Y 32768 4 63 +def test t9 t9 c11 c11 246 7 6 Y 0 4 63 +def test t9 t9 c12 c12 246 8 6 Y 0 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 1249 0 63 @@ -1772,8 +1772,8 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` double(3,1) NOT NULL default '0.0', - `param02` double default NULL, + `const02` decimal(3,1) NOT NULL default '0.0', + `param02` decimal(64,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, `const04` varchar(3) NOT NULL default '', @@ -1794,7 +1794,7 @@ t5 CREATE TABLE `t5` ( `param11` bigint(20) default NULL, `const12` binary(0) default NULL, `param12` bigint(20) default NULL, - `param13` double default NULL, + `param13` decimal(64,30) default NULL, `param14` longtext, `param15` longblob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -1802,9 +1802,9 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Name Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 5 3 3 N 32769 1 63 -def test t5 t5 param02 param02 5 20 1 Y 32768 31 63 -def test t5 t5 const03 const03 5 23 1 N 32769 31 63 +def test t5 t5 const02 const02 246 3 3 N 1 1 63 +def test t5 t5 param02 param02 246 64 32 Y 0 30 63 +def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 20 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 @@ -1824,13 +1824,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 5 20 0 Y 32768 31 63 +def test t5 t5 param13 param13 246 64 0 Y 0 30 63 def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 const01 8 param01 8 const02 8.0 -param02 8 +param02 8.000000000000000000000000000000 const03 8 param03 8 const04 abc @@ -1922,8 +1922,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -1945,7 +1945,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4, @arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8, @arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12, @@ -1969,8 +1969,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2019,8 +2019,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2042,7 +2042,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; @arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32 @@ -2059,8 +2059,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2107,8 +2107,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2130,7 +2130,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32 @@ -2151,8 +2151,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2197,8 +2197,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2220,7 +2220,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; execute full_info ; @@ -2235,8 +2235,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2584,7 +2584,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '9223372036854775807' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2607,7 +2607,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -9223372036854775808 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2666,6 +2666,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 127 @@ -2678,7 +2679,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '1.11111111111111111111e+50' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2703,7 +2704,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -1.11111111111111111111e+50 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2716,6 +2717,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 -128 @@ -2813,10 +2815,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 41 4 41 41 41 41 41 41 41 41 41 41 42 4 42 42 42 42 42 42 42 42 42 42 43 4 43 43 43 43 43 43 43 43 43 43 -50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00 -51 5 51 51 51 51 51 51 51 51 51 51 -52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00 -53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00 +50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 +51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 +52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 +53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00 55 5 55 55 55 55 55 55 55 55 55 55 56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00 diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index 209a22e4a9e..e5db53e1c18 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -59,8 +59,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 0 9 6 Y 32768 4 63 -def test t9 t9 c12 c12 0 10 6 Y 32768 4 63 +def test t9 t9 c11 c11 246 7 6 Y 0 4 63 +def test t9 t9 c12 c12 246 8 6 Y 0 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 1249 0 63 @@ -1755,8 +1755,8 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` double(3,1) NOT NULL default '0.0', - `param02` double default NULL, + `const02` decimal(3,1) NOT NULL default '0.0', + `param02` decimal(64,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, `const04` varchar(3) NOT NULL default '', @@ -1777,7 +1777,7 @@ t5 CREATE TABLE `t5` ( `param11` bigint(20) default NULL, `const12` binary(0) default NULL, `param12` bigint(20) default NULL, - `param13` double default NULL, + `param13` decimal(64,30) default NULL, `param14` longtext, `param15` longblob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -1785,9 +1785,9 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Name Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 5 3 3 N 32769 1 63 -def test t5 t5 param02 param02 5 20 1 Y 32768 31 63 -def test t5 t5 const03 const03 5 23 1 N 32769 31 63 +def test t5 t5 const02 const02 246 3 3 N 1 1 63 +def test t5 t5 param02 param02 246 64 32 Y 0 30 63 +def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 20 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 @@ -1807,13 +1807,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 5 20 0 Y 32768 31 63 +def test t5 t5 param13 param13 246 64 0 Y 0 30 63 def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 const01 8 param01 8 const02 8.0 -param02 8 +param02 8.000000000000000000000000000000 const03 8 param03 8 const04 abc @@ -1905,8 +1905,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -1928,7 +1928,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4, @arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8, @arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12, @@ -1952,8 +1952,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2002,8 +2002,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2025,7 +2025,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; @arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32 @@ -2042,8 +2042,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2090,8 +2090,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2113,7 +2113,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32 @@ -2134,8 +2134,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2180,8 +2180,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2203,7 +2203,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; execute full_info ; @@ -2218,8 +2218,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2567,7 +2567,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '9223372036854775807' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2590,7 +2590,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -9223372036854775808 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2649,6 +2649,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 127 @@ -2661,7 +2662,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '1.11111111111111111111e+50' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2686,7 +2687,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -1.11111111111111111111e+50 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2699,6 +2700,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 -128 @@ -2796,10 +2798,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 41 4 41 41 41 41 41 41 41 41 41 41 42 4 42 42 42 42 42 42 42 42 42 42 43 4 43 43 43 43 43 43 43 43 43 43 -50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00 -51 5 51 51 51 51 51 51 51 51 51 51 -52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00 -53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00 +50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 +51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 +52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 +53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00 55 5 55 55 55 55 55 55 55 55 55 55 56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00 diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index f0be4d119bc..ad02de1110c 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -60,8 +60,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 0 9 6 Y 32768 4 63 -def test t9 t9 c12 c12 0 10 6 Y 32768 4 63 +def test t9 t9 c11 c11 246 7 6 Y 0 4 63 +def test t9 t9 c12 c12 246 8 6 Y 0 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 1249 0 63 @@ -1756,8 +1756,8 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` double(3,1) NOT NULL default '0.0', - `param02` double default NULL, + `const02` decimal(3,1) NOT NULL default '0.0', + `param02` decimal(64,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, `const04` varchar(3) NOT NULL default '', @@ -1778,7 +1778,7 @@ t5 CREATE TABLE `t5` ( `param11` bigint(20) default NULL, `const12` binary(0) default NULL, `param12` bigint(20) default NULL, - `param13` double default NULL, + `param13` decimal(64,30) default NULL, `param14` longtext, `param15` longblob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -1786,9 +1786,9 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Name Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 5 3 3 N 32769 1 63 -def test t5 t5 param02 param02 5 20 1 Y 32768 31 63 -def test t5 t5 const03 const03 5 23 1 N 32769 31 63 +def test t5 t5 const02 const02 246 3 3 N 1 1 63 +def test t5 t5 param02 param02 246 64 32 Y 0 30 63 +def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 20 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 @@ -1808,13 +1808,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 5 20 0 Y 32768 31 63 +def test t5 t5 param13 param13 246 64 0 Y 0 30 63 def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 const01 8 param01 8 const02 8.0 -param02 8 +param02 8.000000000000000000000000000000 const03 8 param03 8 const04 abc @@ -1906,8 +1906,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -1929,7 +1929,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4, @arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8, @arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12, @@ -1953,8 +1953,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2003,8 +2003,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2026,7 +2026,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; @arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32 @@ -2043,8 +2043,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2091,8 +2091,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2114,7 +2114,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32 @@ -2135,8 +2135,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2181,8 +2181,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2204,7 +2204,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; execute full_info ; @@ -2219,8 +2219,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2568,7 +2568,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '9223372036854775807' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2591,7 +2591,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -9223372036854775808 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2650,6 +2650,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 127 @@ -2662,7 +2663,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '1.11111111111111111111e+50' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2687,7 +2688,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -1.11111111111111111111e+50 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2700,6 +2701,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 -128 @@ -2797,10 +2799,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 41 4 41 41 41 41 41 41 41 41 41 41 42 4 42 42 42 42 42 42 42 42 42 42 43 4 43 43 43 43 43 43 43 43 43 43 -50 5 50 50 50 50 50 50 50 50 50 50 -51 5 51 51 51 51 51 51 51 51 51 51 -52 5 52 52 52 52 52 52 52 52 52 52 -53 5 53 53 53 53 53 53 53 53 53 53 +50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 +51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 +52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 +53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 54 5 54 54 54 54 54 54 54 54 54 54 55 5 55 55 55 55 55 55 55 55 55 55 56 6 56 56 56 56 56 56 56 56 56 56 diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index a62d00c71c0..374f6142c44 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -102,8 +102,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 0 9 6 Y 32768 4 63 -def test t9 t9 c12 c12 0 10 6 Y 32768 4 63 +def test t9 t9 c11 c11 246 7 6 Y 0 4 63 +def test t9 t9 c12 c12 246 8 6 Y 0 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 1249 0 63 @@ -1692,8 +1692,8 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` double(3,1) NOT NULL default '0.0', - `param02` double default NULL, + `const02` decimal(3,1) NOT NULL default '0.0', + `param02` decimal(64,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, `const04` varchar(3) NOT NULL default '', @@ -1714,7 +1714,7 @@ t5 CREATE TABLE `t5` ( `param11` bigint(20) default NULL, `const12` binary(0) default NULL, `param12` bigint(20) default NULL, - `param13` double default NULL, + `param13` decimal(64,30) default NULL, `param14` longtext, `param15` longblob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -1722,9 +1722,9 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Name Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 5 3 3 N 32769 1 63 -def test t5 t5 param02 param02 5 20 1 Y 32768 31 63 -def test t5 t5 const03 const03 5 23 1 N 32769 31 63 +def test t5 t5 const02 const02 246 3 3 N 1 1 63 +def test t5 t5 param02 param02 246 64 32 Y 0 30 63 +def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 20 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 @@ -1744,13 +1744,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 5 20 0 Y 32768 31 63 +def test t5 t5 param13 param13 246 64 0 Y 0 30 63 def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 const01 8 param01 8 const02 8.0 -param02 8 +param02 8.000000000000000000000000000000 const03 8 param03 8 const04 abc @@ -1842,8 +1842,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -1865,7 +1865,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4, @arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8, @arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12, @@ -1889,8 +1889,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -1939,8 +1939,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -1962,7 +1962,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; @arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32 @@ -1979,8 +1979,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2027,8 +2027,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2050,7 +2050,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32 @@ -2071,8 +2071,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2117,8 +2117,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2140,7 +2140,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; execute full_info ; @@ -2155,8 +2155,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2504,7 +2504,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '9223372036854775807' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2527,7 +2527,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -9223372036854775808 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2586,6 +2586,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 127 @@ -2598,7 +2599,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '1.11111111111111111111e+50' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2623,7 +2624,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -1.11111111111111111111e+50 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2636,6 +2637,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 -128 @@ -2733,10 +2735,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 41 4 41 41 41 41 41 41 41 41 41 41 42 4 42 42 42 42 42 42 42 42 42 42 43 4 43 43 43 43 43 43 43 43 43 43 -50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00 -51 5 51 51 51 51 51 51 51 51 51 51 -52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00 -53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00 +50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 +51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 +52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 +53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00 55 5 55 55 55 55 55 55 55 55 55 55 56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00 @@ -3111,8 +3113,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 0 9 6 Y 32768 4 63 -def test t9 t9 c12 c12 0 10 6 Y 32768 4 63 +def test t9 t9 c11 c11 246 7 6 Y 0 4 63 +def test t9 t9 c12 c12 246 8 6 Y 0 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 1249 0 63 @@ -4701,8 +4703,8 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` double(3,1) NOT NULL default '0.0', - `param02` double default NULL, + `const02` decimal(3,1) NOT NULL default '0.0', + `param02` decimal(64,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, `const04` varchar(3) NOT NULL default '', @@ -4723,7 +4725,7 @@ t5 CREATE TABLE `t5` ( `param11` bigint(20) default NULL, `const12` binary(0) default NULL, `param12` bigint(20) default NULL, - `param13` double default NULL, + `param13` decimal(64,30) default NULL, `param14` longtext, `param15` longblob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -4731,9 +4733,9 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Name Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 5 3 3 N 32769 1 63 -def test t5 t5 param02 param02 5 20 1 Y 32768 31 63 -def test t5 t5 const03 const03 5 23 1 N 32769 31 63 +def test t5 t5 const02 const02 246 3 3 N 1 1 63 +def test t5 t5 param02 param02 246 64 32 Y 0 30 63 +def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 20 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 @@ -4753,13 +4755,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 5 20 0 Y 32768 31 63 +def test t5 t5 param13 param13 246 64 0 Y 0 30 63 def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 const01 8 param01 8 const02 8.0 -param02 8 +param02 8.000000000000000000000000000000 const03 8 param03 8 const04 abc @@ -4851,8 +4853,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -4874,7 +4876,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4, @arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8, @arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12, @@ -4898,8 +4900,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -4948,8 +4950,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -4971,7 +4973,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; @arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32 @@ -4988,8 +4990,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -5036,8 +5038,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -5059,7 +5061,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32 @@ -5080,8 +5082,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -5126,8 +5128,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -5149,7 +5151,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; execute full_info ; @@ -5164,8 +5166,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -5513,7 +5515,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '9223372036854775807' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -5536,7 +5538,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -9223372036854775808 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -5595,6 +5597,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 127 @@ -5607,7 +5610,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '1.11111111111111111111e+50' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -5632,7 +5635,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -1.11111111111111111111e+50 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -5645,6 +5648,7 @@ Warning 1264 Out of range value adjusted for column 'c4' at row 1 Warning 1264 Out of range value adjusted for column 'c5' at row 1 Warning 1264 Out of range value adjusted for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 -128 @@ -5742,10 +5746,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 41 4 41 41 41 41 41 41 41 41 41 41 42 4 42 42 42 42 42 42 42 42 42 42 43 4 43 43 43 43 43 43 43 43 43 43 -50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00 -51 5 51 51 51 51 51 51 51 51 51 51 -52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00 -53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00 +50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 +51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 +52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 +53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00 55 5 55 55 55 55 55 55 55 55 55 55 56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00 diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index 9a922d75cdc..bf7ef64d052 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -59,8 +59,8 @@ def test t9 t9 c7 c7 4 12 1 Y 32768 31 63 def test t9 t9 c8 c8 5 22 1 Y 32768 31 63 def test t9 t9 c9 c9 5 22 1 Y 32768 31 63 def test t9 t9 c10 c10 5 22 1 Y 32768 31 63 -def test t9 t9 c11 c11 0 9 6 Y 32768 4 63 -def test t9 t9 c12 c12 0 10 6 Y 32768 4 63 +def test t9 t9 c11 c11 246 7 6 Y 0 4 63 +def test t9 t9 c12 c12 246 8 6 Y 0 4 63 def test t9 t9 c13 c13 10 10 10 Y 128 0 63 def test t9 t9 c14 c14 12 19 19 Y 128 0 63 def test t9 t9 c15 c15 7 19 19 N 1249 0 63 @@ -1755,8 +1755,8 @@ Table Create Table t5 CREATE TABLE `t5` ( `const01` bigint(1) NOT NULL default '0', `param01` bigint(20) default NULL, - `const02` double(3,1) NOT NULL default '0.0', - `param02` double default NULL, + `const02` decimal(3,1) NOT NULL default '0.0', + `param02` decimal(64,30) default NULL, `const03` double NOT NULL default '0', `param03` double default NULL, `const04` varchar(3) NOT NULL default '', @@ -1777,7 +1777,7 @@ t5 CREATE TABLE `t5` ( `param11` bigint(20) default NULL, `const12` binary(0) default NULL, `param12` bigint(20) default NULL, - `param13` double default NULL, + `param13` decimal(64,30) default NULL, `param14` longtext, `param15` longblob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 @@ -1785,9 +1785,9 @@ select * from t5 ; Catalog Database Table Table_alias Column Column_alias Name Type Length Max length Is_null Flags Decimals Charsetnr def test t5 t5 const01 const01 8 1 1 N 32769 0 63 def test t5 t5 param01 param01 8 20 1 Y 32768 0 63 -def test t5 t5 const02 const02 5 3 3 N 32769 1 63 -def test t5 t5 param02 param02 5 20 1 Y 32768 31 63 -def test t5 t5 const03 const03 5 23 1 N 32769 31 63 +def test t5 t5 const02 const02 246 3 3 N 1 1 63 +def test t5 t5 param02 param02 246 64 32 Y 0 30 63 +def test t5 t5 const03 const03 5 17 1 N 32769 31 63 def test t5 t5 param03 param03 5 20 1 Y 32768 31 63 def test t5 t5 const04 const04 253 3 3 N 1 0 8 def test t5 t5 param04 param04 252 16777215 3 Y 16 0 8 @@ -1807,13 +1807,13 @@ def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 -def test t5 t5 param13 param13 5 20 0 Y 32768 31 63 +def test t5 t5 param13 param13 246 64 0 Y 0 30 63 def test t5 t5 param14 param14 252 16777215 0 Y 16 0 8 def test t5 t5 param15 param15 252 16777215 0 Y 144 0 63 const01 8 param01 8 const02 8.0 -param02 8 +param02 8.000000000000000000000000000000 const03 8 param03 8 const04 abc @@ -1905,8 +1905,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -1928,7 +1928,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select @arg01:= c1, @arg02:= c2, @arg03:= c3, @arg04:= c4, @arg05:= c5, @arg06:= c6, @arg07:= c7, @arg08:= c8, @arg09:= c9, @arg10:= c10, @arg11:= c11, @arg12:= c12, @@ -1952,8 +1952,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2002,8 +2002,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2025,7 +2025,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; @arg01:= c1 @arg02:= c2 @arg03:= c3 @arg04:= c4 @arg05:= c5 @arg06:= c6 @arg07:= c7 @arg08:= c8 @arg09:= c9 @arg10:= c10 @arg11:= c11 @arg12:= c12 @arg13:= c13 @arg14:= c14 @arg15:= c15 @arg16:= c16 @arg17:= c17 @arg18:= c18 @arg19:= c19 @arg20:= c20 @arg21:= c21 @arg22:= c22 @arg23:= c23 @arg24:= c24 @arg25:= c25 @arg26:= c26 @arg27:= c27 @arg28:= c28 @arg29:= c29 @arg30:= c30 @arg31:= c31 @arg32:= c32 @@ -2042,8 +2042,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2090,8 +2090,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2113,7 +2113,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday select c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32 @@ -2134,8 +2134,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2180,8 +2180,8 @@ def @arg07 253 20 1 Y 128 31 63 def @arg08 253 20 1 Y 128 31 63 def @arg09 253 20 1 Y 128 31 63 def @arg10 253 20 1 Y 128 31 63 -def @arg11 253 20 1 Y 128 31 63 -def @arg12 253 20 1 Y 128 31 63 +def @arg11 253 64 6 Y 128 30 63 +def @arg12 253 64 6 Y 128 30 63 def @arg13 253 8192 10 Y 128 31 63 def @arg14 253 8192 19 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2203,7 +2203,7 @@ def @arg30 253 8192 8 Y 0 31 8 def @arg31 253 8192 3 Y 0 31 8 def @arg32 253 8192 6 Y 0 31 8 @arg01 @arg02 @arg03 @arg04 @arg05 @arg06 @arg07 @arg08 @arg09 @arg10 @arg11 @arg12 @arg13 @arg14 @arg15 @arg16 @arg17 @arg18 @arg19 @arg20 @arg21 @arg22 @arg23 @arg24 @arg25 @arg26 @arg27 @arg28 @arg29 @arg30 @arg31 @arg32 -1 1 1 1 1 1 1 1 1 1 1 1 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday +1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday set @my_key= 0 ; execute stmt1 using @my_key ; execute full_info ; @@ -2218,8 +2218,8 @@ def @arg07 253 20 0 Y 128 31 63 def @arg08 253 20 0 Y 128 31 63 def @arg09 253 20 0 Y 128 31 63 def @arg10 253 20 0 Y 128 31 63 -def @arg11 253 20 0 Y 128 31 63 -def @arg12 253 20 0 Y 128 31 63 +def @arg11 253 64 0 Y 128 30 63 +def @arg12 253 64 0 Y 128 30 63 def @arg13 253 8192 0 Y 128 31 63 def @arg14 253 8192 0 Y 128 31 63 def @arg15 253 8192 19 Y 128 31 63 @@ -2567,7 +2567,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '9223372036854775807' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2590,7 +2590,7 @@ c7 9.22337e+18 c8 9.22337203685478e+18 c9 9.22337203685478e+18 c10 9.22337203685478e+18 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -9223372036854775808 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2661,7 +2661,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= '1.11111111111111111111e+50' ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2674,6 +2674,7 @@ Warning 1265 Data truncated for column 'c4' at row 1 Warning 1265 Data truncated for column 'c5' at row 1 Warning 1265 Data truncated for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 1 @@ -2686,7 +2687,7 @@ c7 3.40282e+38 c8 1.11111111111111e+50 c9 1.11111111111111e+50 c10 1.11111111111111e+50 -c12 99999.9999 +c12 9999.9999 execute my_delete ; set @arg00= -1.11111111111111111111e+50 ; execute my_insert using @arg00, @arg00, @arg00, @arg00, @arg00, @arg00, @@ -2724,6 +2725,7 @@ Warning 1265 Data truncated for column 'c4' at row 1 Warning 1265 Data truncated for column 'c5' at row 1 Warning 1265 Data truncated for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 -1 @@ -2796,10 +2798,10 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 41 4 41 41 41 41 41 41 41 41 41 41 42 4 42 42 42 42 42 42 42 42 42 42 43 4 43 43 43 43 43 43 43 43 43 43 -50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00 -51 5 51 51 51 51 51 51 51 51 51 51 -52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00 -53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00 +50 5 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 50.0 +51 5 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 51.0 +52 5 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 52.0 +53 5 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 53.0 54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00 55 5 55 55 55 55 55 55 55 55 55 55 56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00 diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index 5047160bf75..4f6a62004d2 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -2674,6 +2674,7 @@ Warning 1265 Data truncated for column 'c4' at row 1 Warning 1265 Data truncated for column 'c5' at row 1 Warning 1265 Data truncated for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 1 @@ -2724,6 +2725,7 @@ Warning 1265 Data truncated for column 'c4' at row 1 Warning 1265 Data truncated for column 'c5' at row 1 Warning 1265 Data truncated for column 'c6' at row 1 Warning 1264 Out of range value adjusted for column 'c7' at row 1 +Note 1265 Data truncated for column 'c12' at row 1 Warning 1264 Out of range value adjusted for column 'c12' at row 1 execute my_select ; c1 -1 diff --git a/mysql-test/r/row.result b/mysql-test/r/row.result index 76d6fa13766..40a31563604 100644 --- a/mysql-test/r/row.result +++ b/mysql-test/r/row.result @@ -14,6 +14,8 @@ row(10,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)) select row('a',1.5,3) IN (row(1,2,3), row('a',1.5,3), row('a','a','a')); row('a',1.5,3) IN (row(1,2,3), row('a',1.5,3), row('a','a','a')) 1 +Warnings: +Error 1366 Incorrect decimal value: '' for column '' at row -1 select row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3)); row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3)) 1 diff --git a/mysql-test/r/rpl_user_variables.result b/mysql-test/r/rpl_user_variables.result index 2c2a17c953a..2e39f1f6422 100644 --- a/mysql-test/r/rpl_user_variables.result +++ b/mysql-test/r/rpl_user_variables.result @@ -84,27 +84,27 @@ slave-bin.000001 229 User var 2 272 @`i2`=-12345678901234 slave-bin.000001 272 User var 2 315 @`i3`=0 slave-bin.000001 315 User var 2 358 @`i4`=-1 slave-bin.000001 358 Query 1 470 use `test`; insert into t1 values (@i1), (@i2), (@i3), (@i4) -slave-bin.000001 470 User var 2 513 @`r1`=12.5 -slave-bin.000001 513 User var 2 556 @`r2`=-12.5 -slave-bin.000001 556 Query 1 654 use `test`; insert into t1 values (@r1), (@r2) -slave-bin.000001 654 User var 2 703 @`s1`=_latin1 0x5468697320697320612074657374 COLLATE latin1_swedish_ci -slave-bin.000001 703 User var 2 738 @`s2`=_latin1 "" COLLATE latin1_swedish_ci -slave-bin.000001 738 User var 2 780 @`s3`=_latin1 0x61626327646566 COLLATE latin1_swedish_ci -slave-bin.000001 780 User var 2 822 @`s4`=_latin1 0x6162635C646566 COLLATE latin1_swedish_ci -slave-bin.000001 822 User var 2 864 @`s5`=_latin1 0x61626327646566 COLLATE latin1_swedish_ci -slave-bin.000001 864 Query 1 983 use `test`; insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5) -slave-bin.000001 983 User var 2 1009 @`n1`=NULL -slave-bin.000001 1009 Query 1 1100 use `test`; insert into t1 values (@n1) -slave-bin.000001 1100 User var 2 1126 @`n2`=NULL -slave-bin.000001 1126 Query 1 1217 use `test`; insert into t1 values (@n2) -slave-bin.000001 1217 Query 1 1334 use `test`; insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1) -slave-bin.000001 1334 User var 2 1376 @`a`=2 -slave-bin.000001 1376 Query 1 1477 use `test`; insert into t1 values (@a+(@b:=@a+1)) -slave-bin.000001 1477 User var 2 1514 @`q`=_latin1 0x616263 COLLATE latin1_swedish_ci -slave-bin.000001 1514 Query 1 1647 use `test`; insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2')) -slave-bin.000001 1647 User var 2 1689 @`a`=5 -slave-bin.000001 1689 Query 1 1784 use `test`; insert into t1 values (@a),(@a) -slave-bin.000001 1784 User var 2 1809 @`a`=NULL -slave-bin.000001 1809 Query 1 1911 use `test`; insert into t1 values (@a),(@a),(@a*5) +slave-bin.000001 470 User var 2 509 @`r1`=12.5 +slave-bin.000001 509 User var 2 548 @`r2`=-12.5 +slave-bin.000001 548 Query 1 646 use `test`; insert into t1 values (@r1), (@r2) +slave-bin.000001 646 User var 2 695 @`s1`=_latin1 0x5468697320697320612074657374 COLLATE latin1_swedish_ci +slave-bin.000001 695 User var 2 730 @`s2`=_latin1 "" COLLATE latin1_swedish_ci +slave-bin.000001 730 User var 2 772 @`s3`=_latin1 0x61626327646566 COLLATE latin1_swedish_ci +slave-bin.000001 772 User var 2 814 @`s4`=_latin1 0x6162635C646566 COLLATE latin1_swedish_ci +slave-bin.000001 814 User var 2 856 @`s5`=_latin1 0x61626327646566 COLLATE latin1_swedish_ci +slave-bin.000001 856 Query 1 975 use `test`; insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5) +slave-bin.000001 975 User var 2 1001 @`n1`=NULL +slave-bin.000001 1001 Query 1 1092 use `test`; insert into t1 values (@n1) +slave-bin.000001 1092 User var 2 1118 @`n2`=NULL +slave-bin.000001 1118 Query 1 1209 use `test`; insert into t1 values (@n2) +slave-bin.000001 1209 Query 1 1326 use `test`; insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1) +slave-bin.000001 1326 User var 2 1368 @`a`=2 +slave-bin.000001 1368 Query 1 1469 use `test`; insert into t1 values (@a+(@b:=@a+1)) +slave-bin.000001 1469 User var 2 1506 @`q`=_latin1 0x616263 COLLATE latin1_swedish_ci +slave-bin.000001 1506 Query 1 1639 use `test`; insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2')) +slave-bin.000001 1639 User var 2 1681 @`a`=5 +slave-bin.000001 1681 Query 1 1776 use `test`; insert into t1 values (@a),(@a) +slave-bin.000001 1776 User var 2 1801 @`a`=NULL +slave-bin.000001 1801 Query 1 1903 use `test`; insert into t1 values (@a),(@a),(@a*5) drop table t1; stop slave; diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 7d5b2ed18cb..b72754d3374 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -1672,7 +1672,7 @@ fld1 count(*) 158402 4181 select sum(Period)/count(*) from t1; sum(Period)/count(*) -9410.00 +9410.00000 select companynr,count(price) as "count",sum(price) as "sum" ,abs(sum(price)/count(price)-avg(price)) as "diff",(0+count(price))*companynr as func from t3 group by companynr; companynr count sum diff func 37 12543 309394878010 0.0000 464091 @@ -2109,7 +2109,7 @@ select @b; aaaa select @c; @c -6.26 +6.260 create table t1 (a int not null auto_increment primary key); insert into t1 values (); insert into t1 values (); diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result index 72a763db1b1..2e48ddf6d53 100644 --- a/mysql-test/r/strict.result +++ b/mysql-test/r/strict.result @@ -531,7 +531,6 @@ Warning 1264 Out of range value adjusted for column 'col1' at row 1 Warning 1264 Out of range value adjusted for column 'col2' at row 1 Warning 1264 Out of range value adjusted for column 'col1' at row 2 Warning 1264 Out of range value adjusted for column 'col2' at row 2 -Warning 1264 Out of range value adjusted for column 'col2' at row 2 UPDATE IGNORE t1 SET col2=1/NULL where col1=0; SELECT * FROM t1; col1 col2 @@ -556,6 +555,7 @@ INSERT INTO t1 VALUES(-9223372036854775808,0),(0,0),(9223372036854775807,1844674 INSERT INTO t1 VALUES('-9223372036854775808','0'),('9223372036854775807','18446744073709551615'); INSERT INTO t1 VALUES(-9223372036854774000.0,0.0),(9223372036854775700.0,1844674407370954000.0); INSERT INTO t1 (col1) VALUES(-9223372036854775809); +ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 (col1) VALUES(9223372036854775808); INSERT INTO t1 (col2) VALUES(-1); INSERT INTO t1 (col2) VALUES(18446744073709551616); @@ -595,6 +595,7 @@ Error 1365 Division by 0 Error 1365 Division by 0 INSERT IGNORE INTO t1 VALUES(-9223372036854775809,-1),(9223372036854775808,18446744073709551616); Warnings: +Warning 1264 Out of range value adjusted for column 'col1' at row 1 Warning 1264 Out of range value adjusted for column 'col2' at row 2 INSERT IGNORE INTO t1 VALUES('-9223372036854775809','-1'),('9223372036854775808','18446744073709551616'); Warnings: @@ -616,9 +617,8 @@ col1 col2 9223372036854775807 18446744073709551615 -9223372036854775808 0 9223372036854775807 18446744073709551615 --9223372036854773760 0 -9223372036854775807 1844674407370953984 --9223372036854775808 NULL +-9223372036854774000 0 +9223372036854775700 1844674407370954000 -9223372036854775808 NULL NULL 18446744073709551615 2 NULL @@ -632,12 +632,17 @@ NULL NULL DROP TABLE t1; CREATE TABLE t1 (col1 NUMERIC(4,2)); INSERT INTO t1 VALUES (10.55),(10.5555),(0),(-10.55),(-10.5555),(11),(1e+01); +Warnings: +Note 1265 Data truncated for column 'col1' at row 2 +Note 1265 Data truncated for column 'col1' at row 5 INSERT INTO t1 VALUES ('10.55'),('10.5555'),('-10.55'),('-10.5555'),('11'),('1e+01'); Warnings: Note 1265 Data truncated for column 'col1' at row 2 Note 1265 Data truncated for column 'col1' at row 4 INSERT INTO t1 VALUES (101.55); +ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 VALUES (101); +ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 VALUES (-101.55); ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 VALUES (1010.55); @@ -645,7 +650,9 @@ ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 VALUES (1010); ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 VALUES ('101.55'); +ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 VALUES ('101'); +ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 VALUES ('-101.55'); ERROR 22003: Out of range value adjusted for column 'col1' at row 1 INSERT INTO t1 VALUES ('-1010.55'); @@ -661,14 +668,15 @@ ERROR 22012: Division by 0 UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0; ERROR 22012: Division by 0 INSERT INTO t1 (col1) VALUES (''); -ERROR 01000: Data truncated for column 'col1' at row 1 +ERROR HY000: Incorrect decimal value: '' for column 'col1' at row 1 INSERT INTO t1 (col1) VALUES ('a59b'); -ERROR 01000: Data truncated for column 'col1' at row 1 +ERROR HY000: Incorrect decimal value: 'a59b' for column 'col1' at row 1 INSERT INTO t1 (col1) VALUES ('1a'); -ERROR 01000: Data truncated for column 'col1' at row 1 +Warnings: +Note 1265 Data truncated for column 'col1' at row 1 INSERT IGNORE INTO t1 (col1) VALUES ('2a'); Warnings: -Warning 1265 Data truncated for column 'col1' at row 1 +Note 1265 Data truncated for column 'col1' at row 1 INSERT IGNORE INTO t1 values (1/0); Warnings: Error 1365 Division by 0 @@ -695,22 +703,19 @@ NULL 11.00 10.00 10.55 -10.55 --10.55 +10.56 -10.55 +-10.56 11.00 10.00 -101.55 -101.00 -101.55 -101.00 +1.00 2.00 NULL -999.99 +99.99 -99.99 -999.99 +99.99 -99.99 -999.99 +99.99 -99.99 DROP TABLE t1; CREATE TABLE t1 (col1 FLOAT, col2 FLOAT UNSIGNED); diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 5ca0c9356e6..2e9f199e8bb 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -890,7 +890,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 Using index 2 DEPENDENT SUBQUERY t2 index_subquery a a 5 func 2 Using index Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`a`) in t2 on a chicking NULL))) AS `t1.a in (select t2.a from t2)` from `test`.`t1` +Note 1003 select `test`.`t1`.`a` AS `a`,<in_optimizer>(`test`.`t1`.`a`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`a`) in t2 on a checking NULL))) AS `t1.a in (select t2.a from t2)` from `test`.`t1` CREATE TABLE t3 (a int(11) default '0'); INSERT INTO t3 VALUES (1),(2),(3); SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1; @@ -1462,25 +1462,25 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL s1 5 NULL 3 Using index 2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 Using index Warnings: -Note 1003 select `test`.`t1`.`s1` AS `s1`,not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 chicking NULL)))) AS `s1 NOT IN (SELECT s1 FROM t2)` from `test`.`t1` +Note 1003 select `test`.`t1`.`s1` AS `s1`,not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL)))) AS `s1 NOT IN (SELECT s1 FROM t2)` from `test`.`t1` explain extended select s1, s1 = ANY (SELECT s1 FROM t2) from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL s1 5 NULL 3 Using index 2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 Using index Warnings: -Note 1003 select `test`.`t1`.`s1` AS `s1`,<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 chicking NULL))) AS `s1 = ANY (SELECT s1 FROM t2)` from `test`.`t1` +Note 1003 select `test`.`t1`.`s1` AS `s1`,<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL))) AS `s1 = ANY (SELECT s1 FROM t2)` from `test`.`t1` explain extended select s1, s1 <> ALL (SELECT s1 FROM t2) from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL s1 5 NULL 3 Using index 2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 Using index Warnings: -Note 1003 select `test`.`t1`.`s1` AS `s1`,not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 chicking NULL)))) AS `s1 <> ALL (SELECT s1 FROM t2)` from `test`.`t1` +Note 1003 select `test`.`t1`.`s1` AS `s1`,not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL)))) AS `s1 <> ALL (SELECT s1 FROM t2)` from `test`.`t1` explain extended select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL s1 5 NULL 3 Using index 2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 1 Using index; Using where Warnings: -Note 1003 select `test`.`t1`.`s1` AS `s1`,not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 chicking NULL where (`test`.`t2`.`s1` < _latin1'a2'))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from `test`.`t1` +Note 1003 select `test`.`t1`.`s1` AS `s1`,not(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`test`.`t1`.`s1`) in t2 on s1 checking NULL where (`test`.`t2`.`s1` < _latin1'a2'))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from `test`.`t1` drop table t1,t2; create table t2 (a int, b int); create table t3 (a int); diff --git a/mysql-test/r/sum_distinct.result b/mysql-test/r/sum_distinct.result index c7f1a660267..34242817a54 100644 --- a/mysql-test/r/sum_distinct.result +++ b/mysql-test/r/sum_distinct.result @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1, t2; CREATE TABLE t1 ( id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, gender CHAR(1), diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index c9a272df1ba..2045b7e65dd 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -156,6 +156,9 @@ insert into t1 values ("0.0"),("-0.0"),("+0.0"),("01.0"),("+01.0"),("-01.0"); insert into t1 values ("-.1"),("+.1"),(".1"); insert into t1 values ("00000000000001"),("+0000000000001"),("-0000000000001"); insert into t1 values ("+111111111.11"),("111111111.11"),("-11111111.11"); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 2 insert into t1 values ("-111111111.11"),("+1111111111.11"),("1111111111.11"); Warnings: Warning 1264 Out of range value adjusted for column 'a' at row 1 @@ -164,7 +167,7 @@ Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000"); Warnings: Warning 1264 Out of range value adjusted for column 'a' at row 1 -Warning 1265 Data truncated for column 'a' at row 2 +Note 1265 Data truncated for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); Warnings: @@ -172,24 +175,24 @@ Note 1265 Data truncated for column 'a' at row 3 select * from t1; a 0.00 --0.00 -+0.00 -01.00 -+01.00 --01.00 +0.00 +0.00 +1.00 +1.00 +-1.00 -0.10 -+0.10 0.10 -000000001.00 -+00000001.00 --00000001.00 -111111111.11 -111111111.11 +0.10 +1.00 +1.00 +-1.00 +99999999.99 +99999999.99 -11111111.11 -99999999.99 -999999999.99 -999999999.99 -999999999.99 +99999999.99 +99999999.99 +99999999.99 0.00 -99999999.99 123.40 @@ -222,7 +225,7 @@ Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000"); Warnings: Warning 1264 Out of range value adjusted for column 'a' at row 1 -Warning 1265 Data truncated for column 'a' at row 2 +Note 1265 Data truncated for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); Warnings: @@ -231,15 +234,15 @@ select * from t1; a 0.00 0.00 -+0.00 -01.00 -+01.00 +0.00 +1.00 +1.00 0.00 0.00 -+0.10 0.10 -00000001.00 -+0000001.00 +0.10 +1.00 +1.00 0.00 99999999.99 99999999.99 @@ -280,7 +283,7 @@ Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values ("1e+1000"),("1e-1000"),("-1e+1000"); Warnings: Warning 1264 Out of range value adjusted for column 'a' at row 1 -Warning 1265 Data truncated for column 'a' at row 2 +Note 1265 Data truncated for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values ("123.4e"),("123.4e+2"),("123.4e-2"),("123e1"),("123e+0"); Warnings: @@ -319,6 +322,9 @@ insert into t1 values (0.0),("-0.0"),(+0.0),(01.0),(+01.0),(-01.0); insert into t1 values (-.1),(+.1),(.1); insert into t1 values (00000000000001),(+0000000000001),(-0000000000001); insert into t1 values (+111111111.11),(111111111.11),(-11111111.11); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 2 insert into t1 values (-111111111.11),(+1111111111.11),(1111111111.11); Warnings: Warning 1264 Out of range value adjusted for column 'a' at row 1 @@ -327,12 +333,15 @@ Warning 1264 Out of range value adjusted for column 'a' at row 3 insert into t1 values (1e+100),(1e-100),(-1e+100); 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 (123.4e0),(123.4e+2),(123.4e-2),(123e1),(123e+0); +Warnings: +Note 1265 Data truncated for column 'a' at row 3 select * from t1; a 0.00 --0.00 +0.00 0.00 1.00 1.00 @@ -343,13 +352,13 @@ a 1.00 1.00 -1.00 -111111111.11 -111111111.11 +99999999.99 +99999999.99 -11111111.11 -99999999.99 -999999999.99 -999999999.99 -999999999.99 +99999999.99 +99999999.99 +99999999.99 0.00 -99999999.99 123.40 @@ -362,16 +371,17 @@ create table t1 (a decimal); insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+12345678901'),(99999999999999); Warnings: Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 6 Warning 1264 Out of range value adjusted for column 'a' at row 7 select * from t1; a -9999999999 -1 -+1 -01 -+0000000001 -12345678901 -99999999999 +1 +1 +1 +9999999999 +9999999999 drop table t1; create table t1 (a decimal unsigned); insert into t1 values (-99999999999999),(-1),('+1'),('01'),('+00000000000001'),('+1234567890'),(99999999999999); @@ -381,11 +391,11 @@ Warning 1264 Out of range value adjusted for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 7 select * from t1; a -0 -0 -+1 -01 -+000000001 +9999999999 +9999999999 +1 +1 +1 1234567890 9999999999 drop table t1; @@ -397,8 +407,8 @@ Warning 1264 Out of range value adjusted for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 7 select * from t1; a -0000000000 -0000000000 +9999999999 +9999999999 0000000001 0000000001 0000000001 @@ -413,8 +423,8 @@ Warning 1264 Out of range value adjusted for column 'a' at row 2 Warning 1264 Out of range value adjusted for column 'a' at row 7 select * from t1; a -0000000000 -0000000000 +9999999999 +9999999999 0000000001 0000000001 0000000001 @@ -424,19 +434,17 @@ drop table t1; create table t1(a decimal(10,0)); insert into t1 values ("1e4294967295"); Warnings: -Warning 1265 Data truncated for column 'a' at row 1 Warning 1264 Out of range value adjusted for column 'a' at row 1 select * from t1; a -99999999999 +9999999999 delete from t1; insert into t1 values("1e4294967297"); Warnings: -Warning 1265 Data truncated for column 'a' at row 1 Warning 1264 Out of range value adjusted for column 'a' at row 1 select * from t1; a -99999999999 +9999999999 drop table t1; CREATE TABLE t1 (a_dec DECIMAL(-1,0)); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-1,0))' at line 1 @@ -448,7 +456,7 @@ CREATE TABLE t1 (a_dec DECIMAL(0,11)); SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a_dec` decimal(12,11) default NULL + `a_dec` decimal(11,11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; create table t1(a decimal(7,3)); @@ -456,64 +464,64 @@ insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000 select * from t1; a 1.000 -+1.000 +1.000 -1.000 -00001.000 -+0001.000 --0001.000 +1.000 +1.000 +-1.000 +10.000 +10.000 +-10.000 +10.000 10.000 -+10.000 -10.000 -00010.000 -+0010.000 --0010.000 100.000 -+100.000 +100.000 +-100.000 +100.000 +100.000 -100.000 -00100.000 -+0100.000 --0100.000 1000.000 -+1000.000 +1000.000 -1000.000 -01000.000 -+1000.000 +1000.000 +1000.000 -1000.000 -10000.000 -10000.000 +9999.999 +9999.999 -9999.999 -10000.000 -10000.000 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 -99999.999 -99999.999 +9999.999 +9999.999 -9999.999 drop table t1; create table t1(a decimal(7,3) unsigned); @@ -521,22 +529,22 @@ insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000 select * from t1; a 1.000 -+1.000 +1.000 0.000 -0001.000 -+001.000 +1.000 +1.000 0.000 10.000 -+10.000 +10.000 0.000 -0010.000 -+010.000 +10.000 +10.000 0.000 100.000 -+100.000 +100.000 0.000 -0100.000 -+100.000 +100.000 +100.000 0.000 1000.000 1000.000 diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index c77b3ad7578..8140167870e 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -66,7 +66,7 @@ select a from t1 order by a; a -0.010 -0.002 --0.000 +0.000 0.000 1.000 select min(a) from t1; @@ -119,7 +119,7 @@ select a from t1 order by a; a -0.010 -0.002 --0.000 +0.000 0.000 1.000 select min(a) from t1; @@ -142,6 +142,9 @@ create table t1 (c20 char); insert into t1 values (5000.0); Warnings: Warning 1265 Data truncated for column 'c20' at row 1 +insert into t1 values (0.5e4); +Warnings: +Warning 1265 Data truncated for column 'c20' at row 1 drop table t1; create table t1 (f float(54)); ERROR 42000: Incorrect column specifier for column 'f' diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result new file mode 100644 index 00000000000..cf23d4162ae --- /dev/null +++ b/mysql-test/r/type_newdecimal.result @@ -0,0 +1,843 @@ +drop table if exists t1; +select 1.1 IN (1.0, 1.2); +1.1 IN (1.0, 1.2) +0 +select 1.1 IN (1.0, 1.2, 1.1, 1.4, 0.5); +1.1 IN (1.0, 1.2, 1.1, 1.4, 0.5) +1 +select 1.1 IN (1.0, 1.2, NULL, 1.4, 0.5); +1.1 IN (1.0, 1.2, NULL, 1.4, 0.5) +NULL +select 0.5 IN (1.0, 1.2, NULL, 1.4, 0.5); +0.5 IN (1.0, 1.2, NULL, 1.4, 0.5) +1 +select 1 IN (1.11, 1.2, 1.1, 1.4, 1, 0.5); +1 IN (1.11, 1.2, 1.1, 1.4, 1, 0.5) +1 +select 1 IN (1.11, 1.2, 1.1, 1.4, NULL, 0.5); +1 IN (1.11, 1.2, 1.1, 1.4, NULL, 0.5) +NULL +select case 1.0 when 0.1 then "a" when 1.0 then "b" else "c" END; +case 1.0 when 0.1 then "a" when 1.0 then "b" else "c" END +b +select case 0.1 when 0.1 then "a" when 1.0 then "b" else "c" END; +case 0.1 when 0.1 then "a" when 1.0 then "b" else "c" END +a +select case 1 when 0.1 then "a" when 1.0 then "b" else "c" END; +case 1 when 0.1 then "a" when 1.0 then "b" else "c" END +b +select case 1.0 when 0.1 then "a" when 1 then "b" else "c" END; +case 1.0 when 0.1 then "a" when 1 then "b" else "c" END +b +select case 1.001 when 0.1 then "a" when 1 then "b" else "c" END; +case 1.001 when 0.1 then "a" when 1 then "b" else "c" END +c +create table t1 (a decimal(6,3)); +insert into t1 values (1.0), (NULL), (0.1); +select * from t1; +a +1.000 +NULL +0.100 +select 0.1 in (1.0, 1.2, 1.1, a, 1.4, 0.5) from t1; +0.1 in (1.0, 1.2, 1.1, a, 1.4, 0.5) +0 +NULL +1 +drop table t1; +create table t1 select if(1, 1.1, 1.2), if(0, 1.1, 1.2), if(0.1, 1.1, 1.2), if(0, 1, 1.1), if(0, NULL, 1.2), if(1, 0.22e1, 1.1), if(1E0, 1.1, 1.2); +select * from t1; +if(1, 1.1, 1.2) if(0, 1.1, 1.2) if(0.1, 1.1, 1.2) if(0, 1, 1.1) if(0, NULL, 1.2) if(1, 0.22e1, 1.1) if(1E0, 1.1, 1.2) +1.1 1.2 1.1 1.1 1.2 2.2 1.1 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `if(1, 1.1, 1.2)` decimal(5,1) NOT NULL default '0.0', + `if(0, 1.1, 1.2)` decimal(5,1) NOT NULL default '0.0', + `if(0.1, 1.1, 1.2)` decimal(5,1) NOT NULL default '0.0', + `if(0, 1, 1.1)` decimal(5,1) NOT NULL default '0.0', + `if(0, NULL, 1.2)` decimal(5,1) default NULL, + `if(1, 0.22e1, 1.1)` double NOT NULL default '0', + `if(1E0, 1.1, 1.2)` decimal(5,1) NOT NULL default '0.0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 select nullif(1.1, 1.1), nullif(1.1, 1.2), nullif(1.1, 0.11e1), nullif(1.0, 1), nullif(1, 1.0), nullif(1, 1.1); +select * from t1; +nullif(1.1, 1.1) nullif(1.1, 1.2) nullif(1.1, 0.11e1) nullif(1.0, 1) nullif(1, 1.0) nullif(1, 1.1) +NULL 1.1 NULL NULL NULL 1 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `nullif(1.1, 1.1)` decimal(5,1) default NULL, + `nullif(1.1, 1.2)` decimal(5,1) default NULL, + `nullif(1.1, 0.11e1)` double(4,1) default NULL, + `nullif(1.0, 1)` decimal(5,1) default NULL, + `nullif(1, 1.0)` decimal(1,0) default NULL, + `nullif(1, 1.1)` decimal(1,0) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (a decimal(4,2)); +insert into t1 value (10000), (1.1e10), ("11111"), (100000.1); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 2 +Warning 1264 Out of range value adjusted for column 'a' at row 3 +Warning 1264 Out of range value adjusted for column 'a' at row 4 +insert into t1 value (-10000), (-1.1e10), ("-11111"), (-100000.1); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 2 +Warning 1264 Out of range value adjusted for column 'a' at row 3 +Warning 1264 Out of range value adjusted for column 'a' at row 4 +select a from t1; +a +99.99 +99.99 +99.99 +99.99 +-99.99 +-99.99 +-99.99 +-99.99 +drop table t1; +create table t1 (a decimal(4,2) unsigned); +insert into t1 value (10000), (1.1e10), ("11111"), (100000.1); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 2 +Warning 1264 Out of range value adjusted for column 'a' at row 3 +Warning 1264 Out of range value adjusted for column 'a' at row 4 +insert into t1 value (-10000), (-1.1e10), ("-11111"), (-100000.1); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 2 +Warning 1264 Out of range value adjusted for column 'a' at row 3 +Warning 1264 Out of range value adjusted for column 'a' at row 4 +select a from t1; +a +99.99 +99.99 +99.99 +99.99 +99.99 +0.00 +0.00 +0.00 +drop table t1; +create table t1 (a bigint); +insert into t1 values (18446744073709551615.0); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +insert into t1 values (9223372036854775808.0); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +insert into t1 values (-18446744073709551615.0); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +select * from t1; +a +9223372036854775807 +9223372036854775807 +-9223372036854775808 +drop table t1; +create table t1 (a bigint unsigned); +insert into t1 values (18446744073709551615.0); +insert into t1 values (9223372036854775808.0); +insert into t1 values (9999999999999999999999999.000); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +insert into t1 values (-1.0); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +select * from t1; +a +18446744073709551615 +9223372036854775808 +18446744073709551615 +0 +drop table t1; +create table t1 (a tinyint); +insert into t1 values (18446744073709551615.0); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 1 +insert into t1 values (9223372036854775808.0); +Warnings: +Warning 1264 Out of range value adjusted for column 'a' at row 1 +Warning 1264 Out of range value adjusted for column 'a' at row 1 +select * from t1; +a +127 +127 +drop table t1; +create table t1 select round(15.4,-1), truncate(-5678.123451,-3), abs(-1.1), -(-1.1); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `round(15.4,-1)` decimal(5,0) NOT NULL default '0', + `truncate(-5678.123451,-3)` decimal(13,0) NOT NULL default '0', + `abs(-1.1)` decimal(6,1) NOT NULL default '0.0', + `-(-1.1)` decimal(7,1) NOT NULL default '0.0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +CREATE TABLE t1 (a varchar(64) character set ucs2, b decimal(10,3)); +INSERT INTO t1 VALUES ("1.1", 0), ("2.1", 0); +update t1 set b=a; +SELECT * FROM t1; +a b +1.1 1.100 +2.1 2.100 +DROP TABLE t1; +set session sql_mode='traditional'; +select 1e10/0e0; +1e10/0e0 +NULL +Warnings: +Error 1365 Division by 0 +create table wl1612 (col1 int, col2 decimal(38,10), col3 numeric(38,10)); +insert into wl1612 values(1,12345678901234567890.1234567890,12345678901234567890.1234567890); +select * from wl1612; +col1 col2 col3 +1 12345678901234567890.1234567890 12345678901234567890.1234567890 +insert into wl1612 values(2,01234567890123456789.0123456789,01234567890123456789.0123456789); +select * from wl1612 where col1=2; +col1 col2 col3 +2 1234567890123456789.0123456789 1234567890123456789.0123456789 +insert into wl1612 values(3,1234567890123456789012345678.0123456789,1234567890123456789012345678.0123456789); +select * from wl1612 where col1=3; +col1 col2 col3 +3 1234567890123456789012345678.0123456789 1234567890123456789012345678.0123456789 +select col1/0 from wl1612; +col1/0 +NULL +NULL +NULL +Warnings: +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +select col2/0 from wl1612; +col2/0 +NULL +NULL +NULL +Warnings: +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +select col3/0 from wl1612; +col3/0 +NULL +NULL +NULL +Warnings: +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +insert into wl1612 values(5,5000.0005,5000.0005); +insert into wl1612 values(6,5000.0005,5000.0005); +select sum(col2),sum(col3) from wl1612; +sum(col2) sum(col3) +1234567903703703580370380357.1491481468 1234567903703703580370380357.1491481468 +insert into wl1612 values(7,500000.000005,500000.000005); +insert into wl1612 values(8,500000.000005,500000.000005); +select sum(col2),sum(col3) from wl1612 where col1>4; +sum(col2) sum(col3) +1010000.0010100000 1010000.0010100000 +insert into wl1612 (col1, col2) values(9,1.01234567891); +Warnings: +Note 1265 Data truncated for column 'col2' at row 1 +insert into wl1612 (col1, col2) values(10,1.01234567894); +Warnings: +Note 1265 Data truncated for column 'col2' at row 1 +insert into wl1612 (col1, col2) values(11,1.01234567895); +Warnings: +Note 1265 Data truncated for column 'col2' at row 1 +insert into wl1612 (col1, col2) values(12,1.01234567896); +Warnings: +Note 1265 Data truncated for column 'col2' at row 1 +select col1,col2 from wl1612 where col1>8; +col1 col2 +9 1.0123456789 +10 1.0123456789 +11 1.0123456790 +12 1.0123456790 +insert into wl1612 (col1, col3) values(13,1.01234567891); +Warnings: +Note 1265 Data truncated for column 'col3' at row 1 +insert into wl1612 (col1, col3) values(14,1.01234567894); +Warnings: +Note 1265 Data truncated for column 'col3' at row 1 +insert into wl1612 (col1, col3) values(15,1.01234567895); +Warnings: +Note 1265 Data truncated for column 'col3' at row 1 +insert into wl1612 (col1, col3) values(16,1.01234567896); +Warnings: +Note 1265 Data truncated for column 'col3' at row 1 +select col1,col3 from wl1612 where col1>12; +col1 col3 +13 1.0123456789 +14 1.0123456789 +15 1.0123456790 +16 1.0123456790 +select col1 from wl1612 where col1>4 and col2=1.01234567891; +col1 +select col1 from wl1612 where col1>4 and col2=1.0123456789; +col1 +9 +10 +select col1 from wl1612 where col1>4 and col2<>1.0123456789; +col1 +5 +6 +7 +8 +11 +12 +select col1 from wl1612 where col1>4 and col2<1.0123456789; +col1 +select col1 from wl1612 where col1>4 and col2<=1.0123456789; +col1 +9 +10 +select col1 from wl1612 where col1>4 and col2>1.0123456789; +col1 +5 +6 +7 +8 +11 +12 +select col1 from wl1612 where col1>4 and col2>=1.0123456789; +col1 +5 +6 +7 +8 +9 +10 +11 +12 +select col1 from wl1612 where col1>4 and col2=1.012345679; +col1 +11 +12 +select col1 from wl1612 where col1>4 and col2<>1.012345679; +col1 +5 +6 +7 +8 +9 +10 +select col1 from wl1612 where col1>4 and col3=1.01234567891; +col1 +select col1 from wl1612 where col1>4 and col3=1.0123456789; +col1 +13 +14 +select col1 from wl1612 where col1>4 and col3<>1.0123456789; +col1 +5 +6 +7 +8 +15 +16 +select col1 from wl1612 where col1>4 and col3<1.0123456789; +col1 +select col1 from wl1612 where col1>4 and col3<=1.0123456789; +col1 +13 +14 +select col1 from wl1612 where col1>4 and col3>1.0123456789; +col1 +5 +6 +7 +8 +15 +16 +select col1 from wl1612 where col1>4 and col3>=1.0123456789; +col1 +5 +6 +7 +8 +13 +14 +15 +16 +select col1 from wl1612 where col1>4 and col3=1.012345679; +col1 +15 +16 +select col1 from wl1612 where col1>4 and col3<>1.012345679; +col1 +5 +6 +7 +8 +13 +14 +drop table wl1612; +select 1/3; +1/3 +0.33333 +select 0.8=0.7+0.1; +0.8=0.7+0.1 +1 +select 0.7+0.1; +0.7+0.1 +0.8 +create table wl1612_1 (col1 int); +insert into wl1612_1 values(10); +select * from wl1612_1 where 0.8=0.7+0.1; +col1 +10 +select 0.07+0.07 from wl1612_1; +0.07+0.07 +0.14 +select 0.07-0.07 from wl1612_1; +0.07-0.07 +0.00 +select 0.07*0.07 from wl1612_1; +0.07*0.07 +0.0049 +select 0.07/0.07 from wl1612_1; +0.07/0.07 +1.000000000 +drop table wl1612_1; +create table wl1612_2 (col1 decimal(10,2), col2 numeric(10,2)); +insert into wl1612_2 values(1,1); +insert into wl1612_2 values(+1,+1); +insert into wl1612_2 values(+01,+01); +insert into wl1612_2 values(+001,+001); +select col1,count(*) from wl1612_2 group by col1; +col1 count(*) +1.00 4 +select col2,count(*) from wl1612_2 group by col2; +col2 count(*) +1.00 4 +drop table wl1612_2; +create table wl1612_3 (col1 decimal(10,2), col2 numeric(10,2)); +insert into wl1612_3 values('1','1'); +insert into wl1612_3 values('+1','+1'); +insert into wl1612_3 values('+01','+01'); +insert into wl1612_3 values('+001','+001'); +select col1,count(*) from wl1612_3 group by col1; +col1 count(*) +1.00 4 +select col2,count(*) from wl1612_3 group by col2; +col2 count(*) +1.00 4 +drop table wl1612_3; +select mod(234,10) ; +mod(234,10) +4 +select mod(234.567,10.555); +mod(234.567,10.555) +2.357 +select mod(-234.567,10.555); +mod(-234.567,10.555) +-2.357 +select mod(234.567,-10.555); +mod(234.567,-10.555) +2.357 +select round(15.1); +round(15.1) +15 +select round(15.4); +round(15.4) +15 +select round(15.5); +round(15.5) +16 +select round(15.6); +round(15.6) +16 +select round(15.9); +round(15.9) +16 +select round(-15.1); +round(-15.1) +-15 +select round(-15.4); +round(-15.4) +-15 +select round(-15.5); +round(-15.5) +-16 +select round(-15.6); +round(-15.6) +-16 +select round(-15.9); +round(-15.9) +-16 +select round(15.1,1); +round(15.1,1) +15.1 +select round(15.4,1); +round(15.4,1) +15.4 +select round(15.5,1); +round(15.5,1) +15.5 +select round(15.6,1); +round(15.6,1) +15.6 +select round(15.9,1); +round(15.9,1) +15.9 +select round(-15.1,1); +round(-15.1,1) +-15.1 +select round(-15.4,1); +round(-15.4,1) +-15.4 +select round(-15.5,1); +round(-15.5,1) +-15.5 +select round(-15.6,1); +round(-15.6,1) +-15.6 +select round(-15.9,1); +round(-15.9,1) +-15.9 +select round(15.1,0); +round(15.1,0) +15 +select round(15.4,0); +round(15.4,0) +15 +select round(15.5,0); +round(15.5,0) +16 +select round(15.6,0); +round(15.6,0) +16 +select round(15.9,0); +round(15.9,0) +16 +select round(-15.1,0); +round(-15.1,0) +-15 +select round(-15.4,0); +round(-15.4,0) +-15 +select round(-15.5,0); +round(-15.5,0) +-16 +select round(-15.6,0); +round(-15.6,0) +-16 +select round(-15.9,0); +round(-15.9,0) +-16 +select round(15.1,-1); +round(15.1,-1) +20 +select round(15.4,-1); +round(15.4,-1) +20 +select round(15.5,-1); +round(15.5,-1) +20 +select round(15.6,-1); +round(15.6,-1) +20 +select round(15.9,-1); +round(15.9,-1) +20 +select round(-15.1,-1); +round(-15.1,-1) +-20 +select round(-15.4,-1); +round(-15.4,-1) +-20 +select round(-15.5,-1); +round(-15.5,-1) +-20 +select round(-15.6,-1); +round(-15.6,-1) +-20 +select round(-15.91,-1); +round(-15.91,-1) +-20 +select truncate(5678.123451,0); +truncate(5678.123451,0) +5678 +select truncate(5678.123451,1); +truncate(5678.123451,1) +5678.1 +select truncate(5678.123451,2); +truncate(5678.123451,2) +5678.12 +select truncate(5678.123451,3); +truncate(5678.123451,3) +5678.123 +select truncate(5678.123451,4); +truncate(5678.123451,4) +5678.1234 +select truncate(5678.123451,5); +truncate(5678.123451,5) +5678.12345 +select truncate(5678.123451,6); +truncate(5678.123451,6) +5678.123451 +select truncate(5678.123451,-1); +truncate(5678.123451,-1) +5670 +select truncate(5678.123451,-2); +truncate(5678.123451,-2) +5600 +select truncate(5678.123451,-3); +truncate(5678.123451,-3) +5000 +select truncate(5678.123451,-4); +truncate(5678.123451,-4) +0 +select truncate(-5678.123451,0); +truncate(-5678.123451,0) +-5678 +select truncate(-5678.123451,1); +truncate(-5678.123451,1) +-5678.1 +select truncate(-5678.123451,2); +truncate(-5678.123451,2) +-5678.12 +select truncate(-5678.123451,3); +truncate(-5678.123451,3) +-5678.123 +select truncate(-5678.123451,4); +truncate(-5678.123451,4) +-5678.1234 +select truncate(-5678.123451,5); +truncate(-5678.123451,5) +-5678.12345 +select truncate(-5678.123451,6); +truncate(-5678.123451,6) +-5678.123451 +select truncate(-5678.123451,-1); +truncate(-5678.123451,-1) +-5670 +select truncate(-5678.123451,-2); +truncate(-5678.123451,-2) +-5600 +select truncate(-5678.123451,-3); +truncate(-5678.123451,-3) +-5000 +select truncate(-5678.123451,-4); +truncate(-5678.123451,-4) +0 +create table wl1612_4 (col1 int, col2 decimal(30,25), col3 numeric(30,25)); +insert into wl1612_4 values(1,0.0123456789012345678912345,0.0123456789012345678912345); +select col2/9999999999 from wl1612_4 where col1=1; +col2/9999999999 +0.0000000000012345678902469135781481410000000000000000000 +select col3/9999999999 from wl1612_4 where col1=1; +col3/9999999999 +0.0000000000012345678902469135781481410000000000000000000 +select 9999999999/col2 from wl1612_4 where col1=1; +9999999999/col2 +810000007209.00007 +select 9999999999/col3 from wl1612_4 where col1=1; +9999999999/col3 +810000007209.00007 +select col2*9999999999 from wl1612_4 where col1=1; +col2*9999999999 +123456789.0000000000111104321087655 +select col3*9999999999 from wl1612_4 where col1=1; +col3*9999999999 +123456789.0000000000111104321087655 +insert into wl1612_4 values(2,55555.0123456789012345678912345,55555.0123456789012345678912345); +select col2/9999999999 from wl1612_4 where col1=2; +col2/9999999999 +0.0000055555012351234402469691331481460000000000000000000 +select col3/9999999999 from wl1612_4 where col1=2; +col3/9999999999 +0.0000055555012351234402469691331481460000000000000000000 +select 9999999999/col2 from wl1612_4 where col1=2; +9999999999/col2 +180001.76000 +select 9999999999/col3 from wl1612_4 where col1=2; +9999999999/col3 +180001.76000 +select col2*9999999999 from wl1612_4 where col1=2; +col2*9999999999 +555550123401234.0000000000111104321087655 +select col3*9999999999 from wl1612_4 where col1=2; +col3*9999999999 +555550123401234.0000000000111104321087655 +drop table wl1612_4; +set sql_mode=''; +select 23.4 + (-41.7), 23.4 - (41.7) = -18.3; +23.4 + (-41.7) 23.4 - (41.7) = -18.3 +-18.3 1 +select -18.3=-18.3; +-18.3=-18.3 +1 +select 18.3=18.3; +18.3=18.3 +1 +select -18.3=18.3; +-18.3=18.3 +0 +select 0.8 = 0.7 + 0.1; +0.8 = 0.7 + 0.1 +1 +create procedure p1 () begin +declare v1, v2, v3, v4 decimal(16,12); declare v5 int; +set v1 = 1; set v2 = 2; set v3 = 1000000000000; set v4 = 2000000000000; set v5 = 0; +while v5 < 100000 do +set v1 = v1 + 0.000000000001; set v2 = v2 - 0.000000000001; set v3 = v3 + 1; set v4 = v4 - 1; set v5 = v5 + 1; +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 +drop procedure p1; +drop table if exists t1; +Warnings: +Note 1051 Unknown table 't1' +create table t1 (col1 decimal(38)); +insert into t1 values (12345678901234567890123456789012345678); +select * from t1; +col1 +12345678901234567890123456789012345678 +drop table t1; +create table t1 (col1 decimal(31,30)); +insert into t1 values (0.00000000001); +select * from t1; +col1 +0.000000000010000000000000000000 +drop table t1; +select 7777777777777777777777777777777777777 * 10; +7777777777777777777777777777777777777 * 10 +77777777777777777777777777777777777770 +select .7777777777777777777777777777777777777 * +1000000000000000000; +.7777777777777777777777777777777777777 * +1000000000000000000 +777777777777777777.7777777777777777777000000000000000000 +select .7777777777777777777777777777777777777 - 0.1; +.7777777777777777777777777777777777777 - 0.1 +0.6777777777777777777777777777777777777 +select .343434343434343434 + .343434343434343434; +.343434343434343434 + .343434343434343434 +0.686868686868686868 +select abs(9999999999999999999999); +abs(9999999999999999999999) +9999999999999999999999 +select abs(-9999999999999999999999); +abs(-9999999999999999999999) +9999999999999999999999 +select ceiling(99999999999999999999); +ceiling(99999999999999999999) +99999999999999999999 +select ceiling(9.9999999999999999999); +ceiling(9.9999999999999999999) +10 +select ceiling(-9.9999999999999999999); +ceiling(-9.9999999999999999999) +-10 +select floor(9999999999999999999999); +floor(9999999999999999999999) +9999999999999999999999 +select floor(9.999999999999999999999); +floor(9.999999999999999999999) +10 +select floor(-9.999999999999999999999); +floor(-9.999999999999999999999) +-10 +select floor(-999999999999999999999.999); +floor(-999999999999999999999.999) +-1000000000000000000000 +select ceiling(999999999999999999999.999); +ceiling(999999999999999999999.999) +1000000000000000000000 +select 99999999999999999999999999999999999999 mod 3; +99999999999999999999999999999999999999 mod 3 +0 +select round(99999999999999999.999); +round(99999999999999999.999) +100000000000000000 +select round(-99999999999999999.999); +round(-99999999999999999.999) +-100000000000000000 +select round(99999999999999999.999,3); +round(99999999999999999.999,3) +99999999999999999.999 +select round(-99999999999999999.999,3); +round(-99999999999999999.999,3) +-99999999999999999.999 +select truncate(99999999999999999999999999999999999999,31); +truncate(99999999999999999999999999999999999999,31) +99999999999999999999999999999999999999.000000000000000000000000000 +select truncate(99.999999999999999999999999999999999999,31); +truncate(99.999999999999999999999999999999999999,31) +99.9999999999999999999999999999999 +select truncate(99999999999999999999999999999999999999,-31); +truncate(99999999999999999999999999999999999999,-31) +99999990000000000000000000000000000000 +create table t1 as select 0.5; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `0.5` decimal(3,1) NOT NULL default '0.0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +select round(1.5),round(2.5); +round(1.5) round(2.5) +2 3 +select 0.07 * 0.07; +0.07 * 0.07 +0.0049 +set sql_mode='traditional'; +select 1E-500 = 0; +1E-500 = 0 +1 +select 1 / 1E-500; +1 / 1E-500 +NULL +Warnings: +Error 1365 Division by 0 +select 1 / 0; +1 / 0 +NULL +Warnings: +Error 1365 Division by 0 +set sql_mode='ansi,traditional'; +CREATE TABLE Sow6_2f (col1 NUMERIC(4,2)); +INSERT INTO Sow6_2f VALUES (10.55); +INSERT INTO Sow6_2f VALUES (10.5555); +Warnings: +Note 1265 Data truncated for column 'col1' at row 1 +INSERT INTO Sow6_2f VALUES (-10.55); +INSERT INTO Sow6_2f VALUES (-10.5555); +Warnings: +Note 1265 Data truncated for column 'col1' at row 1 +INSERT INTO Sow6_2f VALUES (11); +INSERT INTO Sow6_2f VALUES (101.55); +ERROR 22003: Out of range value adjusted for column 'col1' at row 1 +UPDATE Sow6_2f SET col1 = col1 * 50 WHERE col1 = 11; +ERROR 22003: Out of range value adjusted for column 'col1' at row 5 +UPDATE Sow6_2f SET col1 = col1 / 0 WHERE col1 > 0; +ERROR 22012: Division by 0 +SELECT MOD(col1,0) FROM Sow6_2f; +MOD(col1,0) +NULL +NULL +NULL +NULL +NULL +Warnings: +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +Error 1365 Division by 0 +INSERT INTO Sow6_2f VALUES ('a59b'); +ERROR HY000: Incorrect decimal value: 'a59b' for column 'col1' at row 1 +drop table Sow6_2f; diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result index 1a66f0d91d2..e553d9d86f2 100644 --- a/mysql-test/r/type_ranges.result +++ b/mysql-test/r/type_ranges.result @@ -87,6 +87,8 @@ DROP INDEX test ON t1; insert into t1 values (10, 1,1,1,1,1,1,1,1,1,1,1,1,1,NULL,0,0,0,1,1,1,1,'one','one'); insert into t1 values (NULL,2,2,2,2,2,2,2,2,2,2,2,2,2,NULL,NULL,NULL,NULL,NULL,NULL,2,2,'two','two,one'); insert into t1 values (0,1/3,3,3,3,3,3,3,3,3,3,3,3,3,NULL,'19970303','10:10:10','19970303101010','','','','3',3,3); +Warnings: +Warning 1265 Data truncated for column 'string' at row 1 insert into t1 values (0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,NULL,19970807,080706,19970403090807,-1,-1,-1,'-1',-1,-1); Warnings: Warning 1264 Out of range value adjusted for column 'utiny' at row 1 @@ -122,7 +124,7 @@ select auto,string,tiny,short,medium,long_int,longlong,real_float,real_double,ut auto string tiny short medium long_int longlong real_float real_double utiny ushort umedium ulong ulonglong mod(floor(time_stamp/1000000),1000000)-mod(curdate(),1000000) date_field time_field date_time blob_col tinyblob_col mediumblob_col longblob_col 10 1 1 1 1 1 1 1.0 1.0000 1 00001 1 1 1 0 0000-00-00 00:00:00 0000-00-00 00:00:00 1 1 1 1 11 2 2 2 2 2 2 2.0 2.0000 2 00002 2 2 2 0 NULL NULL NULL NULL NULL 2 2 -12 0.33 3 3 3 3 3 3.0 3.0000 3 00003 3 3 3 0 1997-03-03 10:10:10 1997-03-03 10:10:10 3 +12 0.33333333 3 3 3 3 3 3.0 3.0000 3 00003 3 3 3 0 1997-03-03 10:10:10 1997-03-03 10:10:10 3 13 -1 -1 -1 -1 -1 -1 -1.0 -1.0000 0 00000 0 0 18446744073709551615 0 1997-08-07 08:07:06 1997-04-03 09:08:07 -1 -1 -1 -1 14 -429496729 -128 -32768 -8388608 -2147483648 -4294967295 -4294967296.0 -4294967295.0000 0 00000 0 0 18446744069414584321 0 0000-00-00 00:00:00 0000-00-00 00:00:00 -4294967295 -4294967295 -4294967295 -4294967295 15 4294967295 127 32767 8388607 2147483647 4294967295 4294967296.0 4294967295.0000 255 65535 16777215 4294967295 4294967295 0 0000-00-00 00:00:00 0000-00-00 00:00:00 4294967295 4294967295 4294967295 4294967295 @@ -174,7 +176,7 @@ Warning 1265 Data truncated for column 'new_field' at row 7 select * from t2; auto string mediumblob_col new_field 1 2 2 ne -2 0.33 ne +2 0.33333333 ne 3 -1 -1 ne 4 -429496729 -4294967295 ne 5 4294967295 4294967295 ne @@ -268,7 +270,7 @@ drop table t2; create table t2 (primary key (auto)) select auto+1 as auto,1 as t1, 'a' as t2, repeat('a',256) as t3, binary repeat('b',256) as t4, repeat('a',4096) as t5, binary repeat('b',4096) as t6, '' as t7, binary '' as t8 from t1; show full columns from t2; Field Type Collation Null Key Default Extra Privileges Comment -auto bigint(17) unsigned NULL NO PRI 0 select,insert,update,references +auto int(6) unsigned NULL NO PRI 0 select,insert,update,references t1 bigint(1) NULL NO 0 select,insert,update,references t2 varchar(1) latin1_swedish_ci NO select,insert,update,references t3 varchar(256) latin1_swedish_ci NO select,insert,update,references diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index cdae2cd1bcf..5a60ef8abfb 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -565,7 +565,7 @@ a show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` double(53,1) NOT NULL default '0.0' + `a` decimal(20,1) NOT NULL default '0.0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; create table t2 (it1 tinyint, it2 tinyint not null, i int not null, ib bigint, f float, d double, y year, da date, dt datetime, sc char(10), sv varchar(10), b blob, tx text); @@ -788,11 +788,11 @@ create table t3 select * from t2 union select * from t1; select * from t3; d 1.234567800 -100000000.0 +100000000.000000000 show create table t3; Table Create Table t3 CREATE TABLE `t3` ( - `d` decimal(10,9) default NULL + `d` decimal(19,9) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1,t2,t3; create table t1 select 1 union select -1; diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 1659a9dddb5..57b73a0515e 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -500,14 +500,15 @@ t1 CREATE TABLE `t1` ( `c5` bigint(20) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; -set @arg00= 8, @arg01= 8.8, @arg02= 'a string'; -create table t1 as select @arg00 as c1, @arg01 as c2, @arg02 as c3; +set @arg00= 8, @arg01= 8.8, @arg02= 'a string', @arg03= 0.2e0; +create table t1 as select @arg00 as c1, @arg01 as c2, @arg02 as c3, @arg03 as c4; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `c1` bigint(20) default NULL, - `c2` double default NULL, - `c3` longtext + `c2` decimal(64,30) default NULL, + `c3` longtext, + `c4` double default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; SET GLOBAL MYISAM_DATA_POINTER_SIZE= 8; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 239849ed8d1..1bdf81a5ee4 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -448,7 +448,7 @@ create view v1 as select a+1 from t1; create table t2 select * from v1; show columns from t2; Field Type Null Key Default Extra -a+1 bigint(17) YES NULL +a+1 bigint(12) YES NULL select * from t2; a+1 2 diff --git a/mysql-test/t/case.test b/mysql-test/t/case.test index 87e456baba7..fed3ff07a13 100644 --- a/mysql-test/t/case.test +++ b/mysql-test/t/case.test @@ -58,7 +58,10 @@ CREATE TABLE t1 SELECT CASE WHEN 1 THEN 1.0 ELSE 'a' END AS c6, CASE WHEN 1 THEN 1 ELSE 1.0 END AS c7, CASE WHEN 1 THEN 1.0 ELSE 1 END AS c8, - CASE WHEN 1 THEN 1.0 END AS c9 + CASE WHEN 1 THEN 1.0 END AS c9, + CASE WHEN 1 THEN 0.1e1 else 0.1 END AS c10, + CASE WHEN 1 THEN 0.1e1 else 1 END AS c11, + CASE WHEN 1 THEN 0.1e1 else '1' END AS c12 ; SHOW CREATE TABLE t1; DROP TABLE t1; diff --git a/mysql-test/t/func_equal.test b/mysql-test/t/func_equal.test index cbf589ffcc2..f446e277c92 100644 --- a/mysql-test/t/func_equal.test +++ b/mysql-test/t/func_equal.test @@ -11,10 +11,12 @@ drop table if exists t1,t2; # First some simple tests # -select 0<=>0,0.0<=>0.0,"A"<=>"A",NULL<=>NULL; +select 0<=>0,0.0<=>0.0,0E0=0E0,"A"<=>"A",NULL<=>NULL; select 1<=>0,0<=>NULL,NULL<=>0; select 1.0<=>0.0,0.0<=>NULL,NULL<=>0.0; select "A"<=>"B","A"<=>NULL,NULL<=>"A"; +select 0<=>0.0, 0.0<=>0E0, 0E0<=>"0", 10.0<=>1E1, 10<=>10.0, 10<=>1E1; +select 1.0<=>0E1,10<=>NULL,NULL<=>0.0, NULL<=>0E0; # # Test with tables diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 4b74dcbe1fb..3f19c7f0c52 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -14,7 +14,7 @@ DROP TABLE t1; # Bug #2005 # -CREATE TABLE t1 (a decimal(240, 20)); +CREATE TABLE t1 (a decimal(64, 20)); INSERT INTO t1 VALUES ("1234567890123456789012345678901234567890"), ("0987654321098765432109876543210987654321"); --exec $MYSQL_DUMP --compact test t1 diff --git a/mysql-test/t/strict.test b/mysql-test/t/strict.test index df3f6b49f84..2c15edb5fc3 100644 --- a/mysql-test/t/strict.test +++ b/mysql-test/t/strict.test @@ -388,9 +388,7 @@ INSERT INTO t1 VALUES(-9223372036854775808,0),(0,0),(9223372036854775807,1844674 INSERT INTO t1 VALUES('-9223372036854775808','0'),('9223372036854775807','18446744073709551615'); INSERT INTO t1 VALUES(-9223372036854774000.0,0.0),(9223372036854775700.0,1844674407370954000.0); -# The following should give an error, but doesn't until we fix the interface -# for Field_longlong::store() - +-- error 1264 INSERT INTO t1 (col1) VALUES(-9223372036854775809); INSERT INTO t1 (col1) VALUES(9223372036854775808); INSERT INTO t1 (col2) VALUES(-1); @@ -449,7 +447,9 @@ INSERT INTO t1 VALUES ('10.55'),('10.5555'),('-10.55'),('-10.5555'),('11'),('1e+ -- The 2 following inserts should generate a warning, but doesn't yet -- because NUMERIC works like DECIMAL +--error 1264 INSERT INTO t1 VALUES (101.55); +--error 1264 INSERT INTO t1 VALUES (101); --error 1264 INSERT INTO t1 VALUES (-101.55); @@ -459,7 +459,9 @@ INSERT INTO t1 VALUES (1010.55); INSERT INTO t1 VALUES (1010); -- The 2 following inserts should generate a warning, but doesn't yet -- because NUMERIC works like DECIMAL +--error 1264 INSERT INTO t1 VALUES ('101.55'); +--error 1264 INSERT INTO t1 VALUES ('101'); --error 1264 INSERT INTO t1 VALUES ('-101.55'); @@ -475,11 +477,13 @@ UPDATE t1 SET col1 =col1 * 50000 WHERE col1 =11; UPDATE t1 SET col1 =col1 / 0 WHERE col1 > 0; --error 1365 UPDATE t1 SET col1= MOD(col1,0) WHERE col1 > 0; ---error 1265 +#--error 1265 +--error 1366 INSERT INTO t1 (col1) VALUES (''); ---error 1265 +#--error 1265 +--error 1366 INSERT INTO t1 (col1) VALUES ('a59b'); ---error 1265 +#--error 1265 INSERT INTO t1 (col1) VALUES ('1a'); INSERT IGNORE INTO t1 (col1) VALUES ('2a'); INSERT IGNORE INTO t1 values (1/0); diff --git a/mysql-test/t/sum_distinct.test b/mysql-test/t/sum_distinct.test index efbb21a7b85..964da9defa6 100644 --- a/mysql-test/t/sum_distinct.test +++ b/mysql-test/t/sum_distinct.test @@ -2,7 +2,7 @@ # Various tests for SUM(DISTINCT ...) # --disable_warnings -DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1, t2; --enable_warnings CREATE TABLE t1 ( diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test index 80eff1f2859..4f40d97743a 100644 --- a/mysql-test/t/type_float.test +++ b/mysql-test/t/type_float.test @@ -84,6 +84,7 @@ drop table t1; # create table t1 (c20 char); insert into t1 values (5000.0); +insert into t1 values (0.5e4); drop table t1; # Errors diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test new file mode 100644 index 00000000000..3922a0448e9 --- /dev/null +++ b/mysql-test/t/type_newdecimal.test @@ -0,0 +1,873 @@ +--disable_warnings +drop table if exists t1; +--enable_warnings +# +# constant IN function test +# +select 1.1 IN (1.0, 1.2); +select 1.1 IN (1.0, 1.2, 1.1, 1.4, 0.5); +select 1.1 IN (1.0, 1.2, NULL, 1.4, 0.5); +select 0.5 IN (1.0, 1.2, NULL, 1.4, 0.5); +select 1 IN (1.11, 1.2, 1.1, 1.4, 1, 0.5); +select 1 IN (1.11, 1.2, 1.1, 1.4, NULL, 0.5); + +# +# case function test +# +select case 1.0 when 0.1 then "a" when 1.0 then "b" else "c" END; +select case 0.1 when 0.1 then "a" when 1.0 then "b" else "c" END; +select case 1 when 0.1 then "a" when 1.0 then "b" else "c" END; +select case 1.0 when 0.1 then "a" when 1 then "b" else "c" END; +select case 1.001 when 0.1 then "a" when 1 then "b" else "c" END; + +# +# non constant IN test +# +create table t1 (a decimal(6,3)); +insert into t1 values (1.0), (NULL), (0.1); +select * from t1; +select 0.1 in (1.0, 1.2, 1.1, a, 1.4, 0.5) from t1; +drop table t1; + +# +# if function test +# +create table t1 select if(1, 1.1, 1.2), if(0, 1.1, 1.2), if(0.1, 1.1, 1.2), if(0, 1, 1.1), if(0, NULL, 1.2), if(1, 0.22e1, 1.1), if(1E0, 1.1, 1.2); +select * from t1; +show create table t1; +drop table t1; + +# +# NULLIF +# +create table t1 select nullif(1.1, 1.1), nullif(1.1, 1.2), nullif(1.1, 0.11e1), nullif(1.0, 1), nullif(1, 1.0), nullif(1, 1.1); +select * from t1; +show create table t1; +drop table t1; + +# +# saving in decimal field with overflow +# + +create table t1 (a decimal(4,2)); +insert into t1 value (10000), (1.1e10), ("11111"), (100000.1); +insert into t1 value (-10000), (-1.1e10), ("-11111"), (-100000.1); +select a from t1; +drop table t1; +create table t1 (a decimal(4,2) unsigned); +insert into t1 value (10000), (1.1e10), ("11111"), (100000.1); +insert into t1 value (-10000), (-1.1e10), ("-11111"), (-100000.1); +select a from t1; +drop table t1; + + +# +# saving in field with overflow from decimal +# +create table t1 (a bigint); +insert into t1 values (18446744073709551615.0); +insert into t1 values (9223372036854775808.0); +insert into t1 values (-18446744073709551615.0); +select * from t1; +drop table t1; +create table t1 (a bigint unsigned); +insert into t1 values (18446744073709551615.0); +insert into t1 values (9223372036854775808.0); +insert into t1 values (9999999999999999999999999.000); +insert into t1 values (-1.0); +select * from t1; +drop table t1; +create table t1 (a tinyint); +insert into t1 values (18446744073709551615.0); +insert into t1 values (9223372036854775808.0); +select * from t1; +drop table t1; + +# +# test that functions create decimal fields +# +create table t1 select round(15.4,-1), truncate(-5678.123451,-3), abs(-1.1), -(-1.1); +show create table t1; +drop table t1; + +# +# conversion from ucs2 +# +CREATE TABLE t1 (a varchar(64) character set ucs2, b decimal(10,3)); +INSERT INTO t1 VALUES ("1.1", 0), ("2.1", 0); +update t1 set b=a; +SELECT * FROM t1; +DROP TABLE t1; + +# +# Trydy's tests +# +set session sql_mode='traditional'; +select 1e10/0e0; +create table wl1612 (col1 int, col2 decimal(38,10), col3 numeric(38,10)); +insert into wl1612 values(1,12345678901234567890.1234567890,12345678901234567890.1234567890); +select * from wl1612; +insert into wl1612 values(2,01234567890123456789.0123456789,01234567890123456789.0123456789); +select * from wl1612 where col1=2; +insert into wl1612 values(3,1234567890123456789012345678.0123456789,1234567890123456789012345678.0123456789); +select * from wl1612 where col1=3; + +select col1/0 from wl1612; +select col2/0 from wl1612; +select col3/0 from wl1612; + +insert into wl1612 values(5,5000.0005,5000.0005); +insert into wl1612 values(6,5000.0005,5000.0005); +select sum(col2),sum(col3) from wl1612; +#select avg(col2),avg(col3) from wl1612; + +insert into wl1612 values(7,500000.000005,500000.000005); +insert into wl1612 values(8,500000.000005,500000.000005); +select sum(col2),sum(col3) from wl1612 where col1>4; +#select avg(col2),avg(col3) from wl1612 where col1>4; + +#insert into wl1612 (col1,col2) values(9,123456789012345678901234567890); +#insert into wl1612 (col1,col3) values(9,123456789012345678901234567890); + +insert into wl1612 (col1, col2) values(9,1.01234567891); +insert into wl1612 (col1, col2) values(10,1.01234567894); +insert into wl1612 (col1, col2) values(11,1.01234567895); +insert into wl1612 (col1, col2) values(12,1.01234567896); +select col1,col2 from wl1612 where col1>8; + +insert into wl1612 (col1, col3) values(13,1.01234567891); +insert into wl1612 (col1, col3) values(14,1.01234567894); +insert into wl1612 (col1, col3) values(15,1.01234567895); +insert into wl1612 (col1, col3) values(16,1.01234567896); +select col1,col3 from wl1612 where col1>12; + +select col1 from wl1612 where col1>4 and col2=1.01234567891; +#-- should return 0 rows +# +select col1 from wl1612 where col1>4 and col2=1.0123456789; +#-- should return col1 values 9 & 10 +# +select col1 from wl1612 where col1>4 and col2<>1.0123456789; +#-- should return col1 values 5,6,7,8,11,12 +# +select col1 from wl1612 where col1>4 and col2<1.0123456789; +#-- should return 0 rows +# +select col1 from wl1612 where col1>4 and col2<=1.0123456789; +#-- should return col1 values 9 & 10 +# +select col1 from wl1612 where col1>4 and col2>1.0123456789; +#-- should return col1 values 5,6,7,8,11,12 +# +select col1 from wl1612 where col1>4 and col2>=1.0123456789; +#-- should return col1 values 5,6,7,8,910,11,12 +# +#select col1, col2 from wl1612 where col1=11 or col1=12; +select col1 from wl1612 where col1>4 and col2=1.012345679; +#-- should return col1 values 11,12 +# +select col1 from wl1612 where col1>4 and col2<>1.012345679; +#-- should return col1 values 5,6,7,8,9,10 +# +select col1 from wl1612 where col1>4 and col3=1.01234567891; +#-- should return 0 rows +# +select col1 from wl1612 where col1>4 and col3=1.0123456789; +#-- should return col1 values 13,14 +# +select col1 from wl1612 where col1>4 and col3<>1.0123456789; +#-- should return col1 values 5,6,7,8,15,16 +# +select col1 from wl1612 where col1>4 and col3<1.0123456789; +#-- should return 0 rows +# +select col1 from wl1612 where col1>4 and col3<=1.0123456789; +#-- should return col1 values 13,14 +# +select col1 from wl1612 where col1>4 and col3>1.0123456789; +#-- should return col1 values 5,6,7,8,15,16 +# +select col1 from wl1612 where col1>4 and col3>=1.0123456789; +#-- should return col1 values 5,6,7,8,13,14,15,16 +# +select col1 from wl1612 where col1>4 and col3=1.012345679; +#-- should return col1 values 15,16 +# +select col1 from wl1612 where col1>4 and col3<>1.012345679; +#-- should return col1 values 5,6,7,8,13,14 +# +drop table wl1612; +# +select 1/3; +# +select 0.8=0.7+0.1; +#-- should return 1 (true) +# +select 0.7+0.1; +# +create table wl1612_1 (col1 int); +insert into wl1612_1 values(10); +# +select * from wl1612_1 where 0.8=0.7+0.1; +#--should return 1 row (col1=10) +# +select 0.07+0.07 from wl1612_1; +# +select 0.07-0.07 from wl1612_1; +# +select 0.07*0.07 from wl1612_1; +# +select 0.07/0.07 from wl1612_1; +# +drop table wl1612_1; +# +create table wl1612_2 (col1 decimal(10,2), col2 numeric(10,2)); +insert into wl1612_2 values(1,1); +insert into wl1612_2 values(+1,+1); +insert into wl1612_2 values(+01,+01); +insert into wl1612_2 values(+001,+001); +# +select col1,count(*) from wl1612_2 group by col1; +# +select col2,count(*) from wl1612_2 group by col2; +# +drop table wl1612_2; +# +create table wl1612_3 (col1 decimal(10,2), col2 numeric(10,2)); +insert into wl1612_3 values('1','1'); +insert into wl1612_3 values('+1','+1'); +# +insert into wl1612_3 values('+01','+01'); +insert into wl1612_3 values('+001','+001'); +# +select col1,count(*) from wl1612_3 group by col1; +# +select col2,count(*) from wl1612_3 group by col2; +# +drop table wl1612_3; +# +select mod(234,10) ; +#-- should return 4 +# +select mod(234.567,10.555); +#-- should return 2.357 +# +select mod(-234.567,10.555); +#-- should return -2.357 +# +select mod(234.567,-10.555); +#-- should return 2.357 +# +select round(15.1); +#-- should return 15 +# +select round(15.4); +#-- should return 15 +# +select round(15.5); +#-- should return 16 +# +select round(15.6); +#-- should return 16 +# +select round(15.9); +#-- should return 16 +# +select round(-15.1); +#-- should return -15 +# +select round(-15.4); +#-- should return -15 +# +select round(-15.5); +#-- should return -16 +# +select round(-15.6); +#-- should return -16 +# +select round(-15.9); +#-- should return -16 +# +select round(15.1,1); +#-- should return 15.1 +# +select round(15.4,1); +#-- should return 15.4 +# +select round(15.5,1); +#-- should return 15.5 +# +select round(15.6,1); +#-- should return 15.6 +# +select round(15.9,1); +#-- should return 15.9 +# +select round(-15.1,1); +#-- should return -15.1 +# +select round(-15.4,1); +#-- should return -15.4 +# +select round(-15.5,1); +#-- should return -15.5 +# +select round(-15.6,1); +#-- should return -15.6 +# +select round(-15.9,1); +#-- should return -15.9 +# +select round(15.1,0); +#-- should return 15 +# +select round(15.4,0); +#-- should return 15 +# +select round(15.5,0); +#-- should return 16 +# +select round(15.6,0); +#-- should return 16 +# +select round(15.9,0); +#-- should return 16 +# +select round(-15.1,0); +#-- should return -15 +# +select round(-15.4,0); +#-- should return -15 +# +select round(-15.5,0); +#-- should return -16 +# +select round(-15.6,0); +#-- should return -16 +# +select round(-15.9,0); +#-- should return -16 +# +select round(15.1,-1); +#-- should return 20 +# +select round(15.4,-1); +#-- should return 20 +# +select round(15.5,-1); +#-- should return 20 +# +select round(15.6,-1); +#-- should return 20 +# +select round(15.9,-1); +#-- should return 20 +# +select round(-15.1,-1); +#-- should return -20 +# +select round(-15.4,-1); +#-- should return -20 +# +select round(-15.5,-1); +#-- should return -20 +# +select round(-15.6,-1); +#-- should return -20 +# +select round(-15.91,-1); +#-- should return -20 +# +select truncate(5678.123451,0); +#-- should return 5678 +# +select truncate(5678.123451,1); +#-- should return 5678.1 +# +select truncate(5678.123451,2); +#-- should return 5678.12 +# +select truncate(5678.123451,3); +#-- should return 5678.123 +# +select truncate(5678.123451,4); +#-- should return 5678.1234 +# +select truncate(5678.123451,5); +#-- should return 5678.12345 +# +select truncate(5678.123451,6); +#-- should return 5678.123451 +# +select truncate(5678.123451,-1); +#-- should return 5670 +# +select truncate(5678.123451,-2); +#-- should return 5600 +# +select truncate(5678.123451,-3); +#-- should return 5000 +# +select truncate(5678.123451,-4); +#-- should return 0 +# +select truncate(-5678.123451,0); +#-- should return -5678 +# +select truncate(-5678.123451,1); +#-- should return -5678.1 +# +select truncate(-5678.123451,2); +#-- should return -5678.12 +# +select truncate(-5678.123451,3); +#-- should return -5678.123 +# +select truncate(-5678.123451,4); +#-- should return -5678.1234 +# +select truncate(-5678.123451,5); +#-- should return -5678.12345 +# +select truncate(-5678.123451,6); +#-- should return -5678.123451 +# +select truncate(-5678.123451,-1); +#-- should return -5670 +# +select truncate(-5678.123451,-2); +#-- should return -5600 +# +select truncate(-5678.123451,-3); +#-- should return -5000 +# +select truncate(-5678.123451,-4); +#-- should return 0 +# +#drop table if exists wl1612_4; +create table wl1612_4 (col1 int, col2 decimal(30,25), col3 numeric(30,25)); +# +insert into wl1612_4 values(1,0.0123456789012345678912345,0.0123456789012345678912345); +# +select col2/9999999999 from wl1612_4 where col1=1; +# +select col3/9999999999 from wl1612_4 where col1=1; +# +select 9999999999/col2 from wl1612_4 where col1=1; +# +select 9999999999/col3 from wl1612_4 where col1=1; +# +select col2*9999999999 from wl1612_4 where col1=1; +# +select col3*9999999999 from wl1612_4 where col1=1; +# +insert into wl1612_4 values(2,55555.0123456789012345678912345,55555.0123456789012345678912345); +# +select col2/9999999999 from wl1612_4 where col1=2; +# +select col3/9999999999 from wl1612_4 where col1=2; +# +select 9999999999/col2 from wl1612_4 where col1=2; +# +select 9999999999/col3 from wl1612_4 where col1=2; +# +select col2*9999999999 from wl1612_4 where col1=2; +# +select col3*9999999999 from wl1612_4 where col1=2; +# +drop table wl1612_4; +# +# +# +# +#-- Additional tests for WL#1612 Precision math +# +#-- 1. Comparisons should show that a number is +#-- exactly equal to its value as displayed. +# +set sql_mode=''; +# +select 23.4 + (-41.7), 23.4 - (41.7) = -18.3; +# +select -18.3=-18.3; +# +select 18.3=18.3; +# +select -18.3=18.3; +# +select 0.8 = 0.7 + 0.1; +# +#-- 2. Adding (one millionth) one million times should be the same as +#-- adding 1. So a stored procedure with many iterations will show if +#-- small errors accumulate. +# +#drop procedure p1; +# +delimiter // +# +create procedure p1 () begin + declare v1, v2, v3, v4 decimal(16,12); declare v5 int; + set v1 = 1; set v2 = 2; set v3 = 1000000000000; set v4 = 2000000000000; set v5 = 0; + while v5 < 100000 do + set v1 = v1 + 0.000000000001; set v2 = v2 - 0.000000000001; set v3 = v3 + 1; set v4 = v4 - 1; set v5 = v5 + 1; + end while; select v1, v2, v3 * 0.000000000001, v4 * 0.000000000001; end;// +# +call p1()// +#-- should return +# -- v1=1.0000001 +# -- v2=1.999999900000 +# -- v3=1.0000001 +# -- v4=1.999999900000 +# +delimiter ;// +# +drop procedure p1; +# +#-- 3. It should be possible to define a column +#-- with up to 38 digits precision either before +#-- or after the decimal point. Any number which +#-- is inserted, if it's within the range, should +#-- be exactly the same as the number that gets +#-- selected. +# +drop table if exists t1; +# +create table t1 (col1 decimal(38)); +# +insert into t1 values (12345678901234567890123456789012345678); +# +select * from t1; +#-- should return: +#+----------------------------------------+ +#| col1 | +#+----------------------------------------+ +#| 12345678901234567890123456789012345678 | +#+----------------------------------------+ +# +#drop table t1; +# +#create table t1 (col1 decimal(38,38)); +# +#insert into t1 values (.12345678901234567890123456789012345678); +# +#select * from t1; +#-- should return: +#+------------------------------------------+ +#| col1 | +#+------------------------------------------+ +#| 0.12345678901234567890123456789012345678 | +#+------------------------------------------+ +# +drop table t1; +# +create table t1 (col1 decimal(31,30)); +# +insert into t1 values (0.00000000001); +# +select * from t1; +#-- should return: +#+---------------+ +#|col1 | +#+---------------+ +#| 0.00000000001 | +#+---------------+ +# +drop table t1; +# +#-- 4. The usual arithmetic operators / * + - should work. +# +#select 77777777777777777777777777777777777777 / 7777777777777777777777777777777777777 = 10; +#-- should return 0 (false). +# +select 7777777777777777777777777777777777777 * 10; +#-- should return 77777777777777777777777777777777777770 +# +select .7777777777777777777777777777777777777 * + 1000000000000000000; +#-- should return 777777777777777777.7777777777777777777 +# +select .7777777777777777777777777777777777777 - 0.1; +#-- should return .6777777777777777777777777777777777777 +# +select .343434343434343434 + .343434343434343434; +#-- should return .686868686868686868 +# +#-- 5. All arithmetic functions mentioned in the +#MySQL Reference Manual should work. +# +select abs(9999999999999999999999); +#-- should return 9999999999999999999999 +# +select abs(-9999999999999999999999); +#-- should return 9999999999999999999999 +# +select ceiling(99999999999999999999); +#-- should return 99999999999999999999 +# +select ceiling(9.9999999999999999999); +#-- should return 10 +# +select ceiling(-9.9999999999999999999); +#-- should return 9 +# +select floor(9999999999999999999999); +#-- should return 9999999999999999999999 +# +select floor(9.999999999999999999999); +#-- should return 9 +# +select floor(-9.999999999999999999999); +#-- should return -10 +# +select floor(-999999999999999999999.999); +select ceiling(999999999999999999999.999); +# +# +select 99999999999999999999999999999999999999 mod 3; +#-- should return 0 +# +select round(99999999999999999.999); +#-- should return 100000000000000000 +# +select round(-99999999999999999.999); +#-- should return -100000000000000000 +# +select round(99999999999999999.999,3); +#-- should return 100000000000000000.000 +# +select round(-99999999999999999.999,3); +#-- should return -100000000000000000.000 +# +select truncate(99999999999999999999999999999999999999,31); +#-- should return 99999999999999999999999999999999999999.000 +# +select truncate(99.999999999999999999999999999999999999,31); +#-- should return 99.9999999999999999999999999999999 +# +select truncate(99999999999999999999999999999999999999,-31); +-- should return 90000000000000000000000000000000 +# +#-- 6. Set functions (AVG, SUM, COUNT) should work. +# +#drop table if exists t1; +# +#delimiter // +# +#create procedure p1 () begin +# declare v1 int default 1; declare v2 decimal(0,38) default 0; +# create table t1 (col1 decimal(0,38)); +# while v1 <= 10000 do +# insert into t1 values (-v2); +# set v2 = v2 + 0.00000000000000000000000000000000000001; +# set v1 = v1 + 1; +# end while; +# select avg(col1),sum(col1),count(col1) from t1; end;// +# +#call p1()// +#-- should return +# -- avg(col1)=0.00000000000000000000000000000000000001 added 10,000 times, then divided by 10,000 +# -- sum(col1)=0.00000000000000000000000000000000000001 added 10,000 times +# +# -- count(col1)=10000 +# +#delimiter ;// +# +#drop procedure p1; +#drop table t1; +# +#-- 7. When I say DECIMAL(x) I should be able to store x digits. +#-- If I can't, there should be an error at CREATE time. +# +#drop table if exists t1; +# +#create table t1 (col1 decimal(254)); +#-- should return SQLSTATE 22003 numeric value out of range +# +#-- 8. When I say DECIMAL(x,y) there should be no silent change of precision or scale. +# +#drop table if exists t1; +# +#create table t1 (col1 decimal(0,38)); +# +#show create table t1; +#-- should return: +#+-------+--------------------------------+ +#| Table | Create Table | +#+-------+--------------------------------+ +#| t9 | CREATE TABLE `t1` ( | +#|`s1` decimal(0,38) default NULL | +#| ) ENGINE=MyISAM DEFAULT CHARSET=latin1 | +#+-------+--------------------------------+ +# +#drop table t1; +# +#-- 9. From WL#1612 "The future" point 2.: +#-- The standard requires that we treat numbers like "0.5" as +#-- DECIMAL or NUMERIC, not as floating-point. +# +#drop table if exists t1; +# +# +create table t1 as select 0.5; +# +show create table t1; +#-- should return: +#+-------+-----------------------------------+ +#| Table | Create Table | +#+-------+-----------------------------------+ +#| t7 | CREATE TABLE `t1` ( | +#| `0.5` decimal(3,1) NOT NULL default '0.0' | +#| ) ENGINE=MyISAM DEFAULT CHARSET=latin1 | +#+-------+-----------------------------------+ +# +drop table t1; +# +#-- 10. From WL#1612, "The future", point 3.: We have to start rounding correctly. +# +select round(1.5),round(2.5); +#-- should return: +#+------------+------------+ +#| round(1.5) | round(2.5) | +#+------------+------------+ +#| 2 | 3 | +#+------------+------------+ +# +#-- 11. From WL#1612, "The future", point 4.: "select 0.07 * 0.07;" should return 0.0049, not 0.00. +#-- If operand#1 has scale X and operand#2 has scale Y, then result should have scale (X+Y). +# +select 0.07 * 0.07; +#-- should return 0.0049 +# +#-- 12. From WL#1612, "The future", point 5.: Division by zero is an error. +# +set sql_mode='traditional'; +# +select 1E-500 = 0; +#-- should return 1 (true). +# +select 1 / 1E-500; +# +#-- should return SQLSTATE 22012 division by zero. +# +select 1 / 0; +#-- should return SQLSTATE 22012 division by zero. +# +#+-------+ +#| 1 / 0 | +#+-------+ +#| NULL | +#+-------+ +#1 row in set, 1 warning (0.00 sec) +# +#-- 13. From WL#1612 "The future" point 6.: Overflow is an error. +# +#set sql_mode=''; +# +#select 1E300 * 1E300; +#-- should return SQLSTATE 22003 numeric value out of range +# +#select 18446744073709551615 + 1; +#-- should return SQLSTATE 22003 numeric value out of range +# +#-- 14. From WL#1612 "The future" point 7.: +#-- If s1 is INTEGER and s2 is DECIMAL, then +#-- "create table tk7 as select avg(s1),avg(s2) from tk;" +#-- should not create a table with "double(17,4)" data types. +#-- The result of AVG must still be exact numeric, with a +#-- scale the same or greater than the operand's scale. +#-- The result of SUM must still be exact numeric, with +#-- a scale the same as the operand's scale. +# +#drop table if exists t1; +#drop table if exists t2; +# +#create table t1 (col1 int, col2 decimal(5)); +# +#create table t2 as select avg(col1),avg(col2) from t1; +# +# +#show create table t2; +#-- should return: +#+-------+---------------------------------+ +#| Table | Create Table | +#+-------+---------------------------------+ +#| t2 | CREATE TABLE `t2` ( | +#| `avg(col1)` decimal(17,4) default NULL, | +#| `avg(col2)` decimal(17,5) default NULL | +#| ) ENGINE=MyISAM DEFAULT CHARSET=latin1 | +#+-------+---------------------------------+ +# +#drop table t2; +#drop table t1; +# +#-- 15. From WL#1612 "The future" point 8.: Stop storing leading "+" signs and leading "0"s. +# +#drop table if exists t1; +# +#create table t1 (col1 decimal(5,2),col2 decimal(5) zerofill, col3 decimal(3,1)); +# +#insert into t1 values (1,1,1); +# +#select col1 from t1 union select col2 from t1 union select col3 from t1; +# +#drop table t1; +# +#-- 16. From WL#1612, The future" point 9.: +#-- Accept the data type and precision and scale as the user +#-- asks, or return an error, but don't change to something else. +# +#drop table if exists t1; +# +#create table t1 (col1 numeric(4,2)); +# +#show create table t1; +# +#drop table t1; +# +#-- 17. The scripts in the following bugs should work: +# + +#BUG#559 Maximum precision for DECIMAL column ... +#BUG#1499 INSERT/UPDATE into decimal field rounding problem +#BUG#1845 Not correctly recognising value for decimal field +#BUG#2493 Round function doesn't work correctly +#BUG#2649 round(0.5) gives 0 (should be 1) +#BUG#3612 impicite rounding of VARCHARS during aritchmetic operations... +#BUG#3722 SELECT fails for certain values in Double(255,10) column. +#BUG#4485 Floating point conversions are inconsistent +#BUG#4891 MATH +#BUG#5931 Out-of-range values are accepted +#BUG#6048 Stored procedure causes operating system reboot +#BUG#6053 DOUBLE PRECISION literal + +-- 18. Tests from 'traditional' mode tests +# +set sql_mode='ansi,traditional'; +# +CREATE TABLE Sow6_2f (col1 NUMERIC(4,2)); +#-- should return OK +INSERT INTO Sow6_2f VALUES (10.55); +#-- should return OK +INSERT INTO Sow6_2f VALUES (10.5555); +#-- should return OK +INSERT INTO Sow6_2f VALUES (-10.55); +#-- should return OK +INSERT INTO Sow6_2f VALUES (-10.5555); +#-- should return OK +INSERT INTO Sow6_2f VALUES (11); +#-- should return OK +-- error 1264 +INSERT INTO Sow6_2f VALUES (101.55); +#-- should return SQLSTATE 22003 numeric value out of range +-- error 1264 +UPDATE Sow6_2f SET col1 = col1 * 50 WHERE col1 = 11; +#-- should return SQLSTATE 22003 numeric value out of range +-- error 1365 +UPDATE Sow6_2f SET col1 = col1 / 0 WHERE col1 > 0; +#-- should return SQLSTATE 22012 division by zero +SELECT MOD(col1,0) FROM Sow6_2f; +#-- should return SQLSTATE 22012 division by zero +-- error 1366 +INSERT INTO Sow6_2f VALUES ('a59b'); +#-- should return SQLSTATE 22018 invalid character value for cast +drop table Sow6_2f; diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 6c1ae733647..44a324de867 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -368,8 +368,8 @@ show create table t1; drop table t1; # # What types and widths have variables? -set @arg00= 8, @arg01= 8.8, @arg02= 'a string'; -create table t1 as select @arg00 as c1, @arg01 as c2, @arg02 as c3; +set @arg00= 8, @arg01= 8.8, @arg02= 'a string', @arg03= 0.2e0; +create table t1 as select @arg00 as c1, @arg01 as c2, @arg02 as c3, @arg03 as c4; show create table t1; drop table t1; diff --git a/sql/Makefile.am b/sql/Makefile.am index 3c520ac971c..498fb93abf3 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -58,7 +58,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ log_event.h sql_repl.h slave.h \ stacktrace.h sql_sort.h sql_cache.h set_var.h \ spatial.h gstream.h client_settings.h tzfile.h \ - tztime.h \ + tztime.h my_decimal.h\ sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \ parse_file.h sql_view.h sql_trigger.h \ examples/ha_example.h examples/ha_archive.h \ @@ -95,7 +95,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \ stacktrace.c repl_failsafe.h repl_failsafe.cc \ sql_olap.cc sql_view.cc \ gstream.cc spatial.cc sql_help.cc protocol_cursor.cc \ - tztime.cc my_time.c \ + tztime.cc my_time.c my_decimal.cc\ sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \ sp_cache.cc parse_file.cc sql_trigger.cc \ examples/ha_example.cc examples/ha_archive.cc \ diff --git a/sql/field.cc b/sql/field.cc index f95eaaba5df..ad66fec2fc2 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -52,6 +52,25 @@ const char field_separator=','; Static help functions *****************************************************************************/ +/* + Numeric fields base class constructor +*/ +Field_num::Field_num(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, + struct st_table *table_arg, + uint8 dec_arg, bool zero_arg, bool unsigned_arg) + :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, table_arg), + dec(dec_arg),zerofill(zero_arg),unsigned_flag(unsigned_arg) +{ + if (zerofill) + flags|=ZEROFILL_FLAG; + if (unsigned_flag) + flags|=UNSIGNED_FLAG; +} + + void Field_num::prepend_zeros(String *value) { int diff; @@ -82,7 +101,7 @@ void Field_num::prepend_zeros(String *value) Make this multi-byte-character safe RETURN - 0 ok + 0 OK 1 error. A warning is pushed if field_name != 0 */ @@ -104,7 +123,7 @@ bool Field::check_int(const char *str, int length, const char *int_end, } end= str+length; if ((str= int_end) == end) - return 0; // ok; All digits was used + return 0; // OK; All digits was used /* Allow end .0000 */ if (*str == '.') @@ -125,6 +144,32 @@ bool Field::check_int(const char *str, int length, const char *int_end, } +/* + Process decimal library return codes and issue warnings for overflow and + truncation. + + SYNOPSIS + Field::check_overflow() + op_result decimal library return code (E_DEC_* see include/decimal.h) + + RETURN + 1 there was overflow + 0 no error or some other errors except overflow +*/ + +int Field::check_overflow(int op_result) +{ + if (op_result == E_DEC_OVERFLOW) + { + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + return 1; + } + else if (op_result == E_DEC_TRUNCATED) + set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1); + /* we return 1 only in case of EFL */ + return 0; +} + #ifdef NOT_USED static bool test_if_real(const char *str,int length, CHARSET_INFO *cs) { @@ -191,6 +236,10 @@ static Field::field_cast_enum field_cast_decimal[]= {Field::FIELD_CAST_DECIMAL, Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; +static Field::field_cast_enum field_cast_new_decimal[]= +{Field::FIELD_CAST_NEWDECIMAL, + Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, + Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_tiny[]= {Field::FIELD_CAST_TINY, Field::FIELD_CAST_SHORT, Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG, @@ -283,6 +332,9 @@ static Field::field_cast_enum field_cast_varstring[]= static Field::field_cast_enum field_cast_blob[]= {Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; +static Field::field_cast_enum field_cast_bit[]= +{Field::FIELD_CAST_BIT, + Field::FIELD_CAST_STOP}; /* Geometrical, enum and set fields can be casted only to expressions */ @@ -302,7 +354,8 @@ static Field::field_cast_enum *field_cast_array[]= field_cast_timestamp, field_cast_year, field_cast_date, field_cast_newdate, field_cast_time, field_cast_datetime, field_cast_string, field_cast_varstring, field_cast_blob, - field_cast_geom, field_cast_enum, field_cast_set + field_cast_geom, field_cast_enum, field_cast_set, field_cast_bit, + field_cast_new_decimal }; @@ -398,6 +451,14 @@ bool Field::send_binary(Protocol *protocol) } +my_decimal *Field::val_decimal(my_decimal *decimal) +{ + /* This never have to be called */ + DBUG_ASSERT(0); + return 0; +} + + void Field_num::add_zerofill_and_unsigned(String &res) const { if (unsigned_flag) @@ -406,6 +467,7 @@ void Field_num::add_zerofill_and_unsigned(String &res) const res.append(" zerofill"); } + void Field::make_field(Send_field *field) { field->db_name= orig_table->s->table_cache_key; @@ -420,12 +482,155 @@ void Field::make_field(Send_field *field) } +/* + Conversion from decimal to longlong with checking overflow and + setting correct value (min/max) in case of overflow + + SYNOPSIS + Field::convert_decimal2longlong() + val value which have to be converted + unsigned_flag type of integer in which we convert val + err variable to pass error code + + RETURN + value converted from val +*/ +longlong Field::convert_decimal2longlong(const my_decimal *val, + bool unsigned_flag, int *err) +{ + longlong i; + if (unsigned_flag) + { + if (val->sign()) + { + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + i= 0; + *err= 1; + } + else if (check_overflow(my_decimal2int(E_DEC_ERROR & + ~E_DEC_OVERFLOW & ~E_DEC_TRUNCATED, + val, TRUE, &i))) + { + i= ~(longlong) 0; + *err= 1; + } + } + else if (check_overflow(my_decimal2int(E_DEC_ERROR & + ~E_DEC_OVERFLOW & ~E_DEC_TRUNCATED, + val, FALSE, &i))) + { + i= (val->sign() ? LONGLONG_MIN : LONGLONG_MAX); + *err= 1; + } + return i; +} + + +/* + Storing decimal in integer fields. + + SYNOPSIS + Field_num::store_decimal() + val value for storing + + NOTE + This method is used by all integer fields, real/decimal redefine it + + RETURN + 0 OK + != 0 error +*/ + +int Field_num::store_decimal(const my_decimal *val) +{ + int err= 0; + longlong i= convert_decimal2longlong(val, unsigned_flag, &err); + return test(err | store(i)); +} + + +/* + Return decimal value of integer field + + SYNOPSIS + Field_num::val_decimal() + decimal_value buffer for storing decimal value + + NOTE + This method is used by all integer fields, real/decimal redefine it + All longlong values fit in our decimal buffer which cal store 8*9=72 + digits of integer number + + RETURN + pointer to decimal buffer with value of field +*/ + +my_decimal* Field_num::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(result_type() == INT_RESULT); + longlong nr= val_int(); + if (!is_null()) + int2my_decimal(E_DEC_FATAL_ERROR, nr, unsigned_flag, decimal_value); + return decimal_value; +} + + +Field_str::Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, + struct st_table *table_arg,CHARSET_INFO *charset) + :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, table_arg) +{ + field_charset=charset; + if (charset->state & MY_CS_BINSORT) + flags|=BINARY_FLAG; +} + + void Field_num::make_field(Send_field *field) { Field::make_field(field); field->decimals= dec; } +/* + Decimal representation of Field_str + + SYNOPSIS + Field_str::store_decimal() + d value for storing + + NOTE + Field_str is the base class for fields like Field_date, and some + similar. Some dates use fraction and also string value should be + converted to floating point value according our rules, so we use double + to store value of decimal in string + + RETURN + 0 OK + != 0 error +*/ + +int Field_str::store_decimal(const my_decimal *d) +{ + double val; + /* TODO: use decimal2string? */ + int err= check_overflow(my_decimal2double(E_DEC_FATAL_ERROR & + ~E_DEC_OVERFLOW, d, &val)); + return err | store(val); +} + + +my_decimal *Field_str::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(result_type() == INT_RESULT); + longlong nr= val_int(); + if (is_null()) + int2my_decimal(E_DEC_FATAL_ERROR, nr, 0, decimal_value); + return decimal_value; +} + uint Field::fill_cache_field(CACHE_FIELD *copy) { @@ -697,7 +902,7 @@ void Field_decimal::overflow(bool negative) int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String tmp(buff,sizeof(buff), &my_charset_bin); /* Convert character set if the old one is multi byte */ @@ -838,7 +1043,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) /* We only have to generate warnings if count_cuted_fields is set. This is to avoid extra checks of the number when they are not needed. - Even if this flag is not set, it's ok to increment warnings, if + Even if this flag is not set, it's OK to increment warnings, if it makes the code easer to read. */ @@ -1255,6 +1460,275 @@ void Field_decimal::sql_type(String &res) const /**************************************************************************** +** Field_new_decimal +****************************************************************************/ + +/* + Constructors of new decimal field. In case of using NOT_FIXED_DEC it try + to use maximally allowed length (DECIMAL_MAX_LENGTH) and number of digits + after decimal point maximally close to half of this range + (min(DECIMAL_MAX_LENGTH/2, NOT_FIXED_DEC-1)) +*/ +Field_new_decimal::Field_new_decimal(char *ptr_arg, + uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, + const char *field_name_arg, + struct st_table *table_arg, + uint8 dec_arg,bool zero_arg, + bool unsigned_arg) + :Field_num(ptr_arg, + (dec_arg == NOT_FIXED_DEC || len_arg > DECIMAL_MAX_LENGTH ? + DECIMAL_MAX_LENGTH : len_arg), + null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, table_arg, + (dec_arg == NOT_FIXED_DEC ? + min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1) : + dec_arg), + zero_arg, unsigned_arg) +{ + bin_size= my_decimal_get_binary_size(field_length, dec); +} + + +Field_new_decimal::Field_new_decimal(uint32 len_arg, + bool maybe_null, + const char *name, + struct st_table *t_arg, + uint8 dec_arg) + :Field_num((char*) 0, + (dec_arg == NOT_FIXED_DEC|| len_arg > DECIMAL_MAX_LENGTH ? + DECIMAL_MAX_LENGTH : len_arg), + maybe_null ? (uchar*) "": 0, 0, + NONE, name, t_arg, + (dec_arg == NOT_FIXED_DEC ? + min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1) : + dec_arg), + 0, 0) +{ + bin_size= my_decimal_get_binary_size(field_length, dec); +} + + +void Field_new_decimal::reset(void) +{ + store_value(&decimal_zero); +} + + +/* + Generate max/min decimal value in case of overflow. + + SYNOPSIS + Field_new_decimal::set_value_on_overflow(); + decimal_value buffer for value + sign sign of value which caused overflow +*/ + +void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value, + bool sign) +{ + DBUG_ENTER("Field_new_decimal::set_value_on_overflow"); + max_my_decimal(decimal_value, field_length, decimals()); + if (sign) + { + if (unsigned_flag) + my_decimal_set_zero(decimal_value); + else + decimal_value->sign(TRUE); + } + DBUG_VOID_RETURN; +} + + +/* + Store decimal value in the binary buffer + + SYNOPSIS + store_value(const my_decimal *decimal_value) + decimal_value my_decimal + + DESCRIPTION + checks if decimal_value fits into field size. + if it does, stores the decimal in the buffer using binary format. + Otherwise sets maximal number that can be stored in the field. +*/ + +bool Field_new_decimal::store_value(const my_decimal *decimal_value) +{ + DBUG_ENTER("Field_new_decimal::store_value"); + my_decimal *dec= (my_decimal*)decimal_value; + DBUG_EXECUTE("enter", print_decimal(dec);); + + /* check that we do not try to write negative value in unsigned field */ + if (unsigned_flag && decimal_value->sign()) + { + DBUG_PRINT("info", ("unsigned overflow")); + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + dec= &decimal_zero; + } + DBUG_PRINT("info", ("saving with precision %d, scale: %d", + (int)field_length, (int)decimals())); + DBUG_EXECUTE("info", print_decimal(dec);); + + if (check_overflow(my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, + dec, ptr, + field_length, + decimals()))) + { + my_decimal buff; + DBUG_PRINT("info", ("overflow")); + set_value_on_overflow(&buff, dec->sign()); + my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, field_length, decimals()); + DBUG_EXECUTE("info", print_decimal_buff(&buff, ptr, bin_size);); + DBUG_RETURN(1); + } + DBUG_EXECUTE("info", print_decimal_buff(dec, ptr, bin_size);); + DBUG_RETURN(0); +} + + +int Field_new_decimal::store(const char *from, uint length, + CHARSET_INFO *charset) +{ + DBUG_ENTER("Field_new_decimal::store(char*)"); + int err; + my_decimal decimal_value; + switch ((err= str2my_decimal(E_DEC_FATAL_ERROR & + ~(E_DEC_OVERFLOW | E_DEC_BAD_NUM), + from, length, charset, &decimal_value))) + { + case E_DEC_TRUNCATED: + set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1); + break; + case E_DEC_OVERFLOW: + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); + set_value_on_overflow(&decimal_value, decimal_value.sign()); + break; + case E_DEC_BAD_NUM: + push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, + ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), + "decimal", from, field_name, + (ulong) table->in_use->row_count); + my_decimal_set_zero(&decimal_value); + break; + } + + DBUG_EXECUTE("info", print_decimal(&decimal_value);); + store_value(&decimal_value); + DBUG_RETURN(err); +} + + +int Field_new_decimal::store(double nr) +{ + my_decimal decimal_value; + int err= double2my_decimal(E_DEC_FATAL_ERROR & + ~E_DEC_OVERFLOW, nr, + &decimal_value); + /* + TODO: fix following when double2my_decimal when double2decimal + will return E_DEC_TRUNCATED always correctly + */ + if (!err) + { + double nr2; + my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &nr2); + if (nr2 != nr) + err= E_DEC_TRUNCATED; + } + if (check_overflow(err)) + set_value_on_overflow(&decimal_value, decimal_value.sign()); + store_value(&decimal_value); + return err; +} + + +int Field_new_decimal::store(longlong nr) +{ + my_decimal decimal_value; + int err; + if ((err= check_overflow(int2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, + nr, unsigned_flag, &decimal_value)))) + set_value_on_overflow(&decimal_value, decimal_value.sign()); + store_value(&decimal_value); + return err; +} + + +int Field_new_decimal::store_decimal(const my_decimal *decimal_value) +{ + return store_value(decimal_value); +} + + +double Field_new_decimal::val_real(void) +{ + double dbl; + my_decimal decimal_value; + my_decimal2double(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), &dbl); + return dbl; +} + + +longlong Field_new_decimal::val_int(void) +{ + longlong i; + my_decimal decimal_value; + my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), + unsigned_flag, &i); + return i; +} + + +my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value) +{ + DBUG_ENTER("Field_new_decimal::val_decimal"); + binary2my_decimal(E_DEC_FATAL_ERROR, ptr, decimal_value, + field_length, + decimals()); + DBUG_EXECUTE("info", print_decimal_buff(decimal_value, ptr, bin_size);); + DBUG_RETURN(decimal_value); +} + + +String *Field_new_decimal::val_str(String *val_buffer, + String *val_ptr __attribute__((unused))) +{ + my_decimal decimal_value; + int fixed_precision= (zerofill ? + (field_length + (decimals() ? 1 : 0)) : + 0); + my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), + fixed_precision, decimals(), '0', + val_buffer); + return val_buffer; +} + + +int Field_new_decimal::cmp(const char *a,const char*b) +{ + return memcmp(a, b, bin_size); +} + + +void Field_new_decimal::sort_string(char *buff, + uint length __attribute__((unused))) +{ + memcpy(buff, ptr, bin_size); +} + + +void Field_new_decimal::sql_type(String &str) const +{ + CHARSET_INFO *cs= str.charset(); + str.length(cs->cset->snprintf(cs, (char*) str.ptr(), str.alloced_length(), + "decimal(%d,%d)", field_length, (int)dec)); + add_zerofill_and_unsigned(str); +} + +/**************************************************************************** ** tiny int ****************************************************************************/ @@ -2554,7 +3028,6 @@ int Field_float::store(longlong nr) return store((double)nr); } - double Field_float::val_real(void) { float j; @@ -2835,6 +3308,12 @@ int Field_double::store(longlong nr) return store((double)nr); } +int Field_real::store_decimal(const my_decimal *dm) +{ + double dbl; + my_decimal2double(E_DEC_FATAL_ERROR, dm, &dbl); + return store(dbl); +} double Field_double::val_real(void) { @@ -2865,6 +3344,13 @@ longlong Field_double::val_int(void) } +my_decimal *Field_real::val_decimal(my_decimal *decimal_value) +{ + double2my_decimal(E_DEC_FATAL_ERROR, val_real(), decimal_value); + return decimal_value; +} + + String *Field_double::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { @@ -3032,7 +3518,7 @@ void Field_double::sql_type(String &res) const TIMESTAMP_OLD_FIELD - old timestamp, if there was not any fields with auto-set-on-update (or now() as default) in this table before, then this field has NOW() as default and is updated when row changes, else it is - field which has 0 as default value and is not automaitcally updated. + field which has 0 as default value and is not automatically updated. TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update automatically (TIMESTAMP DEFAULT NOW()) TIMESTAMP_UN_FIELD - field which is set on update automatically but has not @@ -3094,7 +3580,7 @@ timestamp_auto_set_type Field_timestamp::get_auto_set_type() const return TIMESTAMP_AUTO_SET_ON_UPDATE; case TIMESTAMP_OLD_FIELD: /* - Altough we can have several such columns in legacy tables this + Although we can have several such columns in legacy tables this function should be called only for first of them (i.e. the one having auto-set property). */ @@ -3598,7 +4084,7 @@ String *Field_time::val_str(String *val_buffer, /* - Normally we would not consider 'time' as a vaild date, but we allow + Normally we would not consider 'time' as a valid date, but we allow get_date() here to be able to do things like DATE_FORMAT(time, "%l.%i %p") */ @@ -4319,7 +4805,7 @@ String *Field_datetime::val_str(String *val_buffer, longlongget(tmp,ptr); /* - Avoid problem with slow longlong aritmetic and sprintf + Avoid problem with slow longlong arithmetic and sprintf */ part1=(long) (tmp/LL(1000000)); @@ -4437,14 +4923,14 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) { int error= 0; uint32 not_used; - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String tmpstr(buff,sizeof(buff), &my_charset_bin); uint copy_length; /* See the comment for Field_long::store(long long) */ DBUG_ASSERT(table->in_use == current_thd); - /* Convert character set if nesessary */ + /* Convert character set if necessary */ if (String::needs_conversion(length, cs, field_charset, ¬_used)) { uint conv_errors; @@ -4542,6 +5028,16 @@ int Field_string::store(longlong nr) return Field_string::store(buff,(uint)l,cs); } +int Field_longstr::store_decimal(const my_decimal *d) +{ + uint buf_size= my_decimal_string_length(d); + char *buff= (char *)my_alloca(buf_size); + String str(buff, buf_size, &my_charset_bin); + my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str); + int result= store(str.ptr(), str.length(), str.charset()); + my_afree(buff); + return result; +} double Field_string::val_real(void) { @@ -4561,6 +5057,14 @@ longlong Field_string::val_int(void) } +my_decimal *Field_longstr::val_decimal(my_decimal *decimal_value) +{ + str2my_decimal(E_DEC_FATAL_ERROR, ptr, field_length, charset(), + decimal_value); + return decimal_value; +} + + String *Field_string::val_str(String *val_buffer __attribute__((unused)), String *val_ptr) { @@ -4792,11 +5296,11 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) { int error= 0; uint32 not_used, copy_length; - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String tmpstr(buff,sizeof(buff), &my_charset_bin); enum MYSQL_ERROR::enum_warning_level level= MYSQL_ERROR::WARN_LEVEL_WARN; - /* Convert character set if nesessary */ + /* Convert character set if necessary */ if (String::needs_conversion(length, cs, field_charset, ¬_used)) { uint conv_errors; @@ -4872,7 +5376,6 @@ longlong Field_varstring::val_int(void) &end_not_used, ¬_used); } - String *Field_varstring::val_str(String *val_buffer __attribute__((unused)), String *val_ptr) { @@ -5273,7 +5776,7 @@ Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg,uint blob_pack_length, CHARSET_INFO *cs) - :Field_str(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L, + :Field_longstr(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, table_arg, cs), packlength(blob_pack_length) @@ -5396,12 +5899,12 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) else { bool was_conversion; - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String tmpstr(buff,sizeof(buff), &my_charset_bin); uint copy_length; uint32 not_used; - /* Convert character set if nesessary */ + /* Convert character set if necessary */ if ((was_conversion= String::needs_conversion(length, cs, field_charset, ¬_used))) { @@ -5415,7 +5918,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) copy_length= max_data_length(); /* - copy_length is ok as last argument to well_formed_len as this is never + copy_length is OK as last argument to well_formed_len as this is never used to limit the length of the data. The cut of long data is done with the 'min()' call below. */ @@ -5457,7 +5960,6 @@ int Field_blob::store(longlong nr) return Field_blob::store(value.ptr(), (uint) value.length(), cs); } - double Field_blob::val_real(void) { int not_used; @@ -5485,7 +5987,6 @@ longlong Field_blob::val_int(void) return my_strntoll(charset(),blob,length,10,NULL,¬_used); } - String *Field_blob::val_str(String *val_buffer __attribute__((unused)), String *val_ptr) { @@ -5998,10 +6499,10 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) { int err= 0; uint32 not_used; - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String tmpstr(buff,sizeof(buff), &my_charset_bin); - /* Convert character set if nesessary */ + /* Convert character set if necessary */ if (String::needs_conversion(length, cs, field_charset, ¬_used)) { uint dummy_errors; @@ -6182,10 +6683,10 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) char *not_used; uint not_used2; uint32 not_used_offset; - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String tmpstr(buff,sizeof(buff), &my_charset_bin); - /* Convert character set if nesessary */ + /* Convert character set if necessary */ if (String::needs_conversion(length, cs, field_charset, ¬_used_offset)) { uint dummy_errors; @@ -6444,6 +6945,14 @@ int Field_bit::store(longlong nr) } +int Field_bit::store_decimal(const my_decimal *val) +{ + int err= 0; + longlong i= convert_decimal2longlong(val, 1, &err); + return test(err | store(i)); +} + + double Field_bit::val_real(void) { return (double) Field_bit::val_int(); @@ -6487,6 +6996,13 @@ String *Field_bit::val_str(String *val_buffer, } +my_decimal *Field_bit::val_decimal(my_decimal *deciaml_value) +{ + int2my_decimal(E_DEC_FATAL_ERROR, val_int(), 1, deciaml_value); + return deciaml_value; +} + + int Field_bit::key_cmp(const byte *str, uint length) { if (bit_len) @@ -6593,6 +7109,9 @@ void create_field::create_length_to_internal_length(void) /* We need one extra byte to store the bits we save among the null bits */ key_length= pack_length+ test(length & 7); break; + case MYSQL_TYPE_NEWDECIMAL: + key_length= pack_length= my_decimal_get_binary_size(length, decimals); + break; default: key_length= pack_length= calc_pack_length(sql_type, length); break; @@ -6646,7 +7165,8 @@ uint32 calc_pack_length(enum_field_types type,uint32 length) case FIELD_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr; case FIELD_TYPE_GEOMETRY: return 4+portable_sizeof_char_ptr; case FIELD_TYPE_SET: - case FIELD_TYPE_ENUM: abort(); return 0; // This shouldn't happen + case FIELD_TYPE_ENUM: + case FIELD_TYPE_NEWDECIMAL: abort(); return 0; // This shouldn't happen case FIELD_TYPE_BIT: return length / 8; default: return 0; } @@ -6767,6 +7287,12 @@ Field *make_field(char *ptr, uint32 field_length, f_decimals(pack_flag), f_is_zerofill(pack_flag) != 0, f_is_dec(pack_flag) == 0); + case FIELD_TYPE_NEWDECIMAL: + return new Field_new_decimal(ptr,field_length,null_pos,null_bit, + unireg_check, field_name, table, + f_decimals(pack_flag), + f_is_zerofill(pack_flag) != 0, + f_is_dec(pack_flag) == 0); case FIELD_TYPE_FLOAT: return new Field_float(ptr,field_length,null_pos,null_bit, unireg_check, field_name, table, @@ -6959,7 +7485,7 @@ create_field::create_field(Field *old_field,Field *orig_field) /* Produce warning or note about data saved into field - SYNOPSYS + SYNOPSIS set_warning() level - level of message (Note/Warning/Error) code - error code of message to be produced @@ -6991,7 +7517,7 @@ Field::set_warning(const uint level, const uint code, int cuted_increment) /* Produce warning or note about datetime string data saved into field - SYNOPSYS + SYNOPSIS set_datime_warning() level - level of message (Note/Warning/Error) code - error code of message to be produced @@ -7020,7 +7546,7 @@ Field::set_datetime_warning(const uint level, const uint code, /* Produce warning or note about integer datetime value saved into field - SYNOPSYS + SYNOPSIS set_warning() level - level of message (Note/Warning/Error) code - error code of message to be produced @@ -7052,7 +7578,7 @@ Field::set_datetime_warning(const uint level, const uint code, /* Produce warning or note about double datetime data saved into field - SYNOPSYS + SYNOPSIS set_warning() level - level of message (Note/Warning/Error) code - error code of message to be produced diff --git a/sql/field.h b/sql/field.h index 756fa713707..d0b43e77e5a 100644 --- a/sql/field.h +++ b/sql/field.h @@ -80,7 +80,8 @@ public: FIELD_CAST_TIMESTAMP, FIELD_CAST_YEAR, FIELD_CAST_DATE, FIELD_CAST_NEWDATE, FIELD_CAST_TIME, FIELD_CAST_DATETIME, FIELD_CAST_STRING, FIELD_CAST_VARSTRING, FIELD_CAST_BLOB, - FIELD_CAST_GEOM, FIELD_CAST_ENUM, FIELD_CAST_SET, FIELD_CAST_BIT + FIELD_CAST_GEOM, FIELD_CAST_ENUM, FIELD_CAST_SET, FIELD_CAST_BIT, + FIELD_CAST_NEWDECIMAL }; utype unireg_check; @@ -96,9 +97,11 @@ public: virtual int store(const char *to,uint length,CHARSET_INFO *cs)=0; virtual int store(double nr)=0; virtual int store(longlong nr)=0; + virtual int store_decimal(const my_decimal *d)=0; virtual int store_time(TIME *ltime, timestamp_type t_type); virtual double val_real(void)=0; virtual longlong val_int(void)=0; + virtual my_decimal *val_decimal(my_decimal *); inline String *val_str(String *str) { return val_str(str, str); } /* val_str(buf1, buf2) gets two buffers and should use them as follows: @@ -287,10 +290,16 @@ public: int cuted_increment); void set_datetime_warning(const uint level, const uint code, double nr, timestamp_type ts_type); + int check_overflow(int op_result); virtual field_cast_enum field_cast_type()= 0; bool field_cast_compatible(field_cast_enum type); /* maximum possible display length */ virtual uint32 max_length()= 0; + /* length of field value symbolic representation (in bytes) */ + virtual uint32 representation_length() { return field_length; } + /* convert decimal to longlong with overflow check */ + longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag, + int *err); friend bool reopen_table(THD *,struct st_table *,bool); friend int cre_myisam(my_string name, register TABLE *form, uint options, ulonglong auto_increment_value); @@ -317,16 +326,7 @@ public: uchar null_bit_arg, utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg, - uint8 dec_arg,bool zero_arg,bool unsigned_arg) - :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg), - dec(dec_arg),zerofill(zero_arg),unsigned_flag(unsigned_arg) - { - if (zerofill) - flags|=ZEROFILL_FLAG; - if (unsigned_flag) - flags|=UNSIGNED_FLAG; - } + uint8 dec_arg, bool zero_arg, bool unsigned_arg); Item_result result_type () const { return REAL_RESULT; } void prepend_zeros(String *value); void add_zerofill_and_unsigned(String &res) const; @@ -335,6 +335,8 @@ public: uint decimals() const { return (uint) dec; } uint size_of() const { return sizeof(*this); } bool eq_def(Field *field); + int store_decimal(const my_decimal *); + my_decimal *val_decimal(my_decimal *); }; @@ -345,18 +347,12 @@ public: Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, const char *field_name_arg, - struct st_table *table_arg,CHARSET_INFO *charset) - :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg) - { - field_charset=charset; - if (charset->state & MY_CS_BINSORT) - flags|=BINARY_FLAG; - } + struct st_table *table_arg, CHARSET_INFO *charset); Item_result result_type () const { return STRING_RESULT; } uint decimals() const { return NOT_FIXED_DEC; } int store(double nr); int store(longlong nr)=0; + int store_decimal(const my_decimal *); int store(const char *to,uint length,CHARSET_INFO *cs)=0; uint size_of() const { return sizeof(*this); } CHARSET_INFO *charset(void) const { return field_charset; } @@ -364,19 +360,54 @@ public: bool binary() const { return field_charset == &my_charset_bin; } uint32 max_length() { return field_length; } friend class create_field; + my_decimal *val_decimal(my_decimal *); +}; + +/* base class for Item_string, Item_valstring, Item_blob */ +class Field_longstr :public Field_str +{ +public: + Field_longstr(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, + struct st_table *table_arg,CHARSET_INFO *charset) + :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg, table_arg, charset) + {} + + my_decimal *val_decimal(my_decimal *); + int store_decimal(const my_decimal *d); +}; + +/* base class for float and double and decimal (old one) */ +class Field_real :public Field_num { +public: + + Field_real(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, + struct st_table *table_arg, + uint8 dec_arg, bool zero_arg, bool unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg, table_arg, dec_arg, zero_arg, unsigned_arg) + {} + + + int store_decimal(const my_decimal *); + my_decimal *val_decimal(my_decimal *); }; -class Field_decimal :public Field_num { +class Field_decimal :public Field_real { public: Field_decimal(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg, uint8 dec_arg,bool zero_arg,bool unsigned_arg) - :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg, - dec_arg, zero_arg,unsigned_arg) + :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, table_arg, + dec_arg, zero_arg, unsigned_arg) {} enum_field_types type() const { return FIELD_TYPE_DECIMAL;} enum ha_base_keytype key_type() const @@ -398,6 +429,46 @@ public: }; +/* New decimal/numeric field which use fixed point arithmetic */ +class Field_new_decimal :public Field_num { +public: + uint bin_size; + Field_new_decimal(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + struct st_table *table_arg, + uint8 dec_arg, bool zero_arg, bool unsigned_arg); + Field_new_decimal(uint32 len_arg, bool maybe_null_arg, + const char *field_name_arg, + struct st_table *table_arg, uint8 dec_arg); + enum_field_types type() const { return FIELD_TYPE_NEWDECIMAL;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + Item_result result_type () const { return DECIMAL_RESULT; } + void reset(void); + bool store_value(const my_decimal *decimal_value); + void set_value_on_overflow(my_decimal *decimal_value, bool sign); + int store(const char *to, uint length, CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); + int store_decimal(const my_decimal *); + double val_real(void); + longlong val_int(void); + my_decimal *val_decimal(my_decimal *); + String *val_str(String*, String *); + int cmp(const char *, const char*); + void sort_string(char *buff, uint length); + bool zero_pack() const { return 0; } + void sql_type(String &str) const; + uint32 max_length() + { return field_length + 1 + (dec ? 1 : 0) + (field_length == dec ? 1 : 0); } + uint32 representation_length() + { return field_length + 1 + (dec ? 1 : 0) + (field_length == dec ? 1 : 0); }; + field_cast_enum field_cast_type() { return FIELD_CAST_NEWDECIMAL; } + uint size_of() const { return sizeof(*this); } + uint32 pack_length() const { return (uint32) bin_size; } +}; + + class Field_tiny :public Field_num { public: Field_tiny(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, @@ -576,21 +647,22 @@ public: }; #endif -class Field_float :public Field_num { + +class Field_float :public Field_real { public: Field_float(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg, - uint8 dec_arg,bool zero_arg,bool unsigned_arg) - :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg, - dec_arg, zero_arg,unsigned_arg) + uint8 dec_arg,bool zero_arg,bool unsigned_arg) + :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, table_arg, + dec_arg, zero_arg, unsigned_arg) {} Field_float(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, struct st_table *table_arg, uint8 dec_arg) - :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, - NONE, field_name_arg, table_arg,dec_arg,0,0) + :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, + NONE, field_name_arg, table_arg, dec_arg, 0, 0) {} enum_field_types type() const { return FIELD_TYPE_FLOAT;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; } @@ -611,21 +683,21 @@ public: }; -class Field_double :public Field_num { +class Field_double :public Field_real { public: Field_double(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg, uint8 dec_arg,bool zero_arg,bool unsigned_arg) - :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg, - dec_arg, zero_arg,unsigned_arg) + :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, table_arg, + dec_arg, zero_arg, unsigned_arg) {} Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, struct st_table *table_arg, uint8 dec_arg) - :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, - NONE, field_name_arg, table_arg,dec_arg,0,0) + :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, + NONE, field_name_arg, table_arg, dec_arg, 0, 0) {} enum_field_types type() const { return FIELD_TYPE_DOUBLE;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; } @@ -646,7 +718,7 @@ public: }; -/* Everything saved in this will disapper. It will always return NULL */ +/* Everything saved in this will disappear. It will always return NULL */ class Field_null :public Field_str { static uchar null[1]; @@ -662,9 +734,11 @@ public: { null[0]=1; return 0; } int store(double nr) { null[0]=1; return 0; } int store(longlong nr) { null[0]=1; return 0; } + int store_decimal(const my_decimal *d) { null[0]=1; return 0; } void reset(void) {} double val_real(void) { return 0.0;} longlong val_int(void) { return 0;} + my_decimal *val_decimal(my_decimal *) { return 0; } String *val_str(String *value,String *value2) { value2->length(0); return value2;} int cmp(const char *a, const char *b) { return 0;} @@ -892,18 +966,18 @@ public: }; -class Field_string :public Field_str { +class Field_string :public Field_longstr { public: Field_string(char *ptr_arg, uint32 len_arg,uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg, CHARSET_INFO *cs) - :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg,cs) {}; + :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, table_arg, cs) {}; Field_string(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, - struct st_table *table_arg, CHARSET_INFO *cs) - :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0, - NONE, field_name_arg, table_arg, cs) {}; + struct st_table *table_arg, CHARSET_INFO *cs) + :Field_longstr((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, table_arg, cs) {}; enum_field_types type() const { @@ -942,7 +1016,7 @@ public: }; -class Field_varstring :public Field_str { +class Field_varstring :public Field_longstr { public: /* Store number of bytes used to store length (1 or 2) */ uint32 length_bytes; @@ -952,19 +1026,19 @@ public: uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg, CHARSET_INFO *cs) - :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg, cs), - length_bytes(length_bytes_arg) + :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, table_arg, cs), + length_bytes(length_bytes_arg) { if (table) table->s->varchar_fields++; } Field_varstring(uint32 len_arg,bool maybe_null_arg, - const char *field_name_arg, - struct st_table *table_arg, CHARSET_INFO *cs) - :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0, - NONE, field_name_arg, table_arg, cs), - length_bytes(len_arg < 256 ? 1 :2) + const char *field_name_arg, + struct st_table *table_arg, CHARSET_INFO *cs) + :Field_longstr((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, table_arg, cs), + length_bytes(len_arg < 256 ? 1 :2) { if (table) table->s->varchar_fields++; @@ -1012,7 +1086,7 @@ public: }; -class Field_blob :public Field_str { +class Field_blob :public Field_longstr { protected: uint packlength; String value; // For temporaries @@ -1023,8 +1097,8 @@ public: CHARSET_INFO *cs); Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, struct st_table *table_arg, CHARSET_INFO *cs) - :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0, - NONE, field_name_arg, table_arg, cs), + :Field_longstr((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, table_arg, cs), packlength(4) { flags|= BLOB_FLAG; @@ -1103,9 +1177,7 @@ public: bool has_charset(void) const { return charset() == &my_charset_bin ? FALSE : TRUE; } field_cast_enum field_cast_type() { return FIELD_CAST_BLOB; } - uint32 max_length(); -}; - + uint32 max_length();}; #ifdef HAVE_SPATIAL class Field_geom :public Field_blob { @@ -1130,7 +1202,7 @@ public: int store(const char *to, uint length, CHARSET_INFO *charset); int store(double nr) { return 1; } int store(longlong nr) { return 1; } - + int store_decimal(const my_decimal *) { return 1; } void get_key_image(char *buff,uint length,imagetype type); field_cast_enum field_cast_type() { return FIELD_CAST_GEOM; } }; @@ -1224,9 +1296,11 @@ public: int store(const char *to, uint length, CHARSET_INFO *charset); int store(double nr); int store(longlong nr); + int store_decimal(const my_decimal *); double val_real(void); longlong val_int(void); String *val_str(String*, String *); + my_decimal *val_decimal(my_decimal *); int cmp(const char *a, const char *b) { return cmp_binary(a, b); } int key_cmp(const byte *a, const byte *b) diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 002f059f70b..57161a7063e 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -586,6 +586,9 @@ void field_conv(Field *to,Field *from) !(to->flags & UNSIGNED_FLAG && !(from->flags & UNSIGNED_FLAG)) && to->real_type() != FIELD_TYPE_ENUM && to->real_type() != FIELD_TYPE_SET && + (to->real_type() != FIELD_TYPE_NEWDECIMAL || + (to->field_length == from->field_length && + (((Field_num*)to)->dec == ((Field_num*)from)->dec))) && from->charset() == to->charset() && to->table->s->db_low_byte_first == from->table->s->db_low_byte_first) { // Identical fields @@ -623,6 +626,11 @@ void field_conv(Field *to,Field *from) } else if (from->result_type() == REAL_RESULT) to->store(from->val_real()); + else if (from->result_type() == DECIMAL_RESULT) + { + my_decimal buff; + to->store_decimal(from->val_decimal(&buff)); + } else to->store(from->val_int()); } diff --git a/sql/filesort.cc b/sql/filesort.cc index 1665358dbf0..956ac2ef61b 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -703,6 +703,22 @@ static void make_sortkey(register SORTPARAM *param, #endif break; } + case DECIMAL_RESULT: + { + my_decimal dec_buf, *dec_val= item->val_decimal(&dec_buf); + if ((maybe_null=item->null_value)) + { + bzero((char*)to, sort_field->length+1); + to++; + break; + } + if ((maybe_null=item->maybe_null)) + *to++=1; + my_decimal2binary(E_DEC_FATAL_ERROR, dec_val, (byte*)to, + item->max_length - (item->decimals ? 1:0), + item->decimals); + break; + } case REAL_RESULT: { double value= item->val_real(); @@ -1212,6 +1228,12 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset) sortorder->length=4; #endif break; + case DECIMAL_RESULT: + sortorder->length= + my_decimal_get_binary_size(sortorder->item->max_length - + (sortorder->item->decimals ? 1 : 0), + sortorder->item->decimals); + break; case REAL_RESULT: sortorder->length=sizeof(double); break; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index be493138fd0..052ee0643ee 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -2159,6 +2159,8 @@ get_innobase_type_from_mysql_type( } else { return(DATA_MYSQL); } + case FIELD_TYPE_NEWDECIMAL: + return(DATA_BINARY); case FIELD_TYPE_LONG: case FIELD_TYPE_LONGLONG: case FIELD_TYPE_TINY: diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 9631b78bca3..ad7e775aacf 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -727,7 +727,7 @@ int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt) if ((error= mi_assign_to_key_cache(file, map, new_key_cache))) { - char buf[80]; + char buf[STRING_BUFFER_USUAL_SIZE]; my_snprintf(buf, sizeof(buf), "Failed to flush to index file (errno: %d)", error); errmsg= buf; diff --git a/sql/item.cc b/sql/item.cc index 30e03916a74..17ded05766f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -44,6 +44,34 @@ void item_init(void) item_user_lock_init(); } + +/* +TODO: make this functions class dependent +*/ +bool Item::val_bool() +{ + switch(result_type()) + { + case INT_RESULT: + return val_int(); + case DECIMAL_RESULT: + { + my_decimal decimal_value; + my_decimal *val= val_decimal(&decimal_value); + if (val) + return !my_decimal_is_zero(val); + return 0; + } + case REAL_RESULT: + case STRING_RESULT: + return val_real() != 0.0; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } +} + + Item::Item(): name(0), orig_name(0), name_length(0), fixed(0), collation(&my_charset_bin, DERIVATION_COERCIBLE) @@ -72,7 +100,7 @@ Item::Item(): } /* - Constructor used by Item_field, Item_*_ref & agregate (sum) functions. + Constructor used by Item_field, Item_*_ref & aggregate (sum) functions. Used for duplicating lists in processing queries with temporary tables */ @@ -148,7 +176,7 @@ bool Item::cleanup_processor(byte *arg) void Item::rename(char *new_name) { /* - we can compare pointers to names here, bacause if name was not changed, + we can compare pointers to names here, because if name was not changed, pointer will be same */ if (!orig_name && new_name != name) @@ -411,6 +439,55 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions) } +double Item_splocal::val_real() +{ + DBUG_ASSERT(fixed); + Item *it= this_item(); + double ret= it->val_real(); + Item::null_value= it->null_value; + return ret; +} + + +longlong Item_splocal::val_int() +{ + DBUG_ASSERT(fixed); + Item *it= this_item(); + longlong ret= it->val_int(); + Item::null_value= it->null_value; + return ret; +} + + +String *Item_splocal::val_str(String *sp) +{ + DBUG_ASSERT(fixed); + Item *it= this_item(); + String *ret= it->val_str(sp); + Item::null_value= it->null_value; + return ret; +} + + +my_decimal *Item_splocal::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed); + Item *it= this_item(); + my_decimal value, *val= it->val_decimal(&value); + Item::null_value= it->null_value; + return val; +} + + +bool Item_splocal::is_null() +{ + Item *it= this_item(); + bool ret= it->is_null(); + Item::null_value= it->null_value; + return ret; +} + + Item * Item_splocal::this_item() { @@ -438,12 +515,38 @@ Item_splocal::type() const } +bool Item_splocal::fix_fields(THD *, struct st_table_list *, Item **) +{ + Item *it= this_item(); + DBUG_ASSERT(it->fixed); + max_length= it->max_length; + decimals= it->decimals; + fixed= 1; + return FALSE; +} + + +void Item_splocal::cleanup() +{ + fixed= 0; +} + + +void Item_splocal::print(String *str) +{ + str->reserve(m_name.length+8); + str->append(m_name.str, m_name.length); + str->append('@'); + str->qs_append(m_offset); +} + + /* Aggregate two collations together taking into account their coercibility (aka derivation): - 0 == DERIVATION_EXPLICIT - an explicitely written COLLATE clause + 0 == DERIVATION_EXPLICIT - an explicitly written COLLATE clause 1 == DERIVATION_NONE - a mix of two different collations 2 == DERIVATION_IMPLICIT - a column 3 == DERIVATION_COERCIBLE - a string constant @@ -482,7 +585,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags) /* We do allow to use binary strings (like BLOBS) together with character strings. - Binaries have more precedance than a character + Binaries have more precedence than a character string of the same derivation. */ if (collation == &my_charset_bin) @@ -634,8 +737,8 @@ void Item_field::set_field(Field *field_par) { field=result_field=field_par; // for easy coding with fields maybe_null=field->maybe_null(); - max_length=field_par->field_length; decimals= field->decimals(); + max_length= field_par->representation_length(); table_name= *field_par->table_name; field_name= field_par->field_name; db_name= field_par->table->s->db; @@ -743,6 +846,7 @@ String *Item_field::val_str(String *str) return field->val_str(str,&str_value); } + double Item_field::val_real() { DBUG_ASSERT(fixed == 1); @@ -751,6 +855,7 @@ double Item_field::val_real() return field->val_real(); } + longlong Item_field::val_int() { DBUG_ASSERT(fixed == 1); @@ -760,6 +865,14 @@ longlong Item_field::val_int() } +my_decimal *Item_field::val_decimal(my_decimal *decimal_value) +{ + if ((null_value= field->is_null())) + return 0; + return field->val_decimal(decimal_value); +} + + String *Item_field::str_result(String *str) { if ((null_value=result_field->is_null())) @@ -814,6 +927,40 @@ longlong Item_field::val_int_result() } +my_decimal *Item_field::val_decimal_result(my_decimal *decimal_value) +{ + if ((null_value= result_field->is_null())) + return 0; + return result_field->val_decimal(decimal_value); +} + + +bool Item_field::val_bool_result() +{ + if ((null_value= result_field->is_null())) + return FALSE; + switch (result_field->result_type()) + { + case INT_RESULT: + return result_field->val_int(); + case DECIMAL_RESULT: + { + my_decimal decimal_value; + my_decimal *val= result_field->val_decimal(&decimal_value); + if (val) + return !my_decimal_is_zero(val); + return 0; + } + case REAL_RESULT: + case STRING_RESULT: + return result_field->val_real() != 0.0; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } +} + + bool Item_field::eq(const Item *item, bool binary_cmp) const { if (item->type() != FIELD_ITEM) @@ -872,10 +1019,17 @@ Item_int::Item_int(const char *str_arg, uint length) value= my_strtoll10(str_arg, &end_ptr, &error); max_length= (uint) (end_ptr - str_arg); name= (char*) str_arg; + unsigned_flag= value > 0; fixed= 1; } +my_decimal *Item_int::val_decimal(my_decimal *decimal_value) +{ + int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_value); + return decimal_value; +} + String *Item_int::val_str(String *str) { // following assert is redundant, because fixed=1 assigned in constructor @@ -916,7 +1070,98 @@ void Item_uint::print(String *str) } -String *Item_real::val_str(String *str) +Item_decimal::Item_decimal(const char *str_arg, uint length, + CHARSET_INFO *charset) +{ + str2my_decimal(E_DEC_FATAL_ERROR, str_arg, length, charset, &decimal_value); + name= (char*) str_arg; + decimals= (uint8) decimal_value.frac; + max_length= my_decimal_max_length(&decimal_value); + fixed= 1; + unsigned_flag= !decimal_value.sign(); +} + +Item_decimal::Item_decimal(longlong val, bool unsig) +{ + int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value); + decimals= (uint8) decimal_value.frac; + max_length= my_decimal_max_length(&decimal_value); + fixed= 1; + unsigned_flag= !decimal_value.sign(); +} + + +Item_decimal::Item_decimal(double val, int precision, int scale) +{ + double2my_decimal(E_DEC_FATAL_ERROR, val, &decimal_value); + decimals= (uint8) decimal_value.frac; + max_length= my_decimal_max_length(&decimal_value); + fixed= 1; + unsigned_flag= !decimal_value.sign(); +} + + +Item_decimal::Item_decimal(const char *str, const my_decimal *val_arg, + uint decimal_par, uint length) +{ + my_decimal2decimal(val_arg, &decimal_value); + name= (char*) str; + decimals= (uint8) decimal_par; + max_length= length; + fixed= 1; + unsigned_flag= !decimal_value.sign(); +} + + +Item_decimal::Item_decimal(my_decimal *value_par) +{ + my_decimal2decimal(value_par, &decimal_value); + decimals= (uint8) decimal_value.frac; + max_length= my_decimal_max_length(value_par); + fixed= 1; + unsigned_flag= !decimal_value.sign(); +} + + +Item_decimal::Item_decimal(const char *bin, int precision, int scale) +{ + binary2my_decimal(E_DEC_FATAL_ERROR, bin, &decimal_value, precision, scale); + decimals= (uint8) decimal_value.frac; + max_length= my_decimal_max_length(&decimal_value); + fixed= 1; + unsigned_flag= !decimal_value.sign(); +} + + +longlong Item_decimal::val_int() +{ + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &result); + return result; +} + +double Item_decimal::val_real() +{ + double result; + my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &result); + return result; +} + +String *Item_decimal::val_str(String *result) +{ + result->set_charset(&my_charset_bin); + my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, result); + return result; +} + +void Item_decimal::print(String *str) +{ + my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, &str_value); + str->append(str_value); +} + + +String *Item_float::val_str(String *str) { // following assert is redundant, because fixed=1 assigned in constructor DBUG_ASSERT(fixed == 1); @@ -925,6 +1170,15 @@ String *Item_real::val_str(String *str) } +my_decimal *Item_float::val_decimal(my_decimal *decimal_value) +{ + // following assert is redundant, because fixed=1 assigned in constructor + DBUG_ASSERT(fixed == 1); + double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_value); + return (decimal_value); +} + + void Item_string::print(String *str) { str->append('_'); @@ -934,8 +1188,20 @@ void Item_string::print(String *str) str->append('\''); } + +my_decimal *Item_string::val_decimal(my_decimal *decimal_value) +{ + /* following assert is redundant, because fixed=1 assigned in constructor */ + DBUG_ASSERT(fixed == 1); + string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value); + return (decimal_value); +} + + bool Item_null::eq(const Item *item, bool binary_cmp) const { return item->type() == type(); } + + double Item_null::val_real() { // following assert is redundant, because fixed=1 assigned in constructor @@ -959,6 +1225,11 @@ String *Item_null::val_str(String *str) return 0; } +my_decimal *Item_null::val_decimal(my_decimal *decimal_value) +{ + return 0; +} + Item *Item_null::safe_charset_converter(CHARSET_INFO *tocs) { @@ -1005,7 +1276,6 @@ void Item_param::set_null() { DBUG_ENTER("Item_param::set_null"); /* These are cleared after each execution by reset() method */ - max_length= 0; null_value= 1; /* Because of NULL and string values we need to set max_length for each new @@ -1042,6 +1312,32 @@ void Item_param::set_double(double d) /* + Set decimal parameter value from string. + + SYNOPSIS + set_decimal() + str - character string + length - string length + + NOTE + as we use character strings to send decimal values in + binary protocol, we use str2my_decimal to convert it to + internal decimal value. +*/ +void Item_param::set_decimal(const char *str, ulong length) +{ + DBUG_ENTER("Item_param::set_decimal"); + + str2my_decimal(E_DEC_FATAL_ERROR, str, &decimal_value); + state= DECIMAL_VALUE; + decimals= decimal_value.frac; + max_length= decimal_value.intg + decimals + 2; + maybe_null= 0; + DBUG_VOID_RETURN; +} + + +/* Set parameter value from TIME value. SYNOPSIS @@ -1094,6 +1390,7 @@ bool Item_param::set_str(const char *str, ulong length) &dummy_errors)) DBUG_RETURN(TRUE); state= STRING_VALUE; + max_length= length; maybe_null= 0; /* max_length and decimals are set after charset conversion */ /* sic: str may be not null-terminated, don't add DBUG_PRINT here */ @@ -1133,7 +1430,7 @@ bool Item_param::set_longdata(const char *str, ulong length) RETURN 0 OK - 1 Out of memort + 1 Out of memory */ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) @@ -1179,6 +1476,15 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) DBUG_RETURN(1); break; } + case DECIMAL_RESULT: + { + const my_decimal *ent_value= (const my_decimal *)entry->value; + my_decimal2decimal(ent_value, &decimal_value); + state= DECIMAL_VALUE; + decimals= ent_value->frac; + max_length= ent_value->intg + decimals + 2; + break; + } default: DBUG_ASSERT(0); set_null(); @@ -1210,7 +1516,7 @@ void Item_param::reset() str_value.length(0); str_value_ptr.length(0); /* - We must prevent all charset conversions untill data has been written + We must prevent all charset conversions until data has been written to the binary log. */ str_value.set_charset(&my_charset_bin); @@ -1238,6 +1544,8 @@ int Item_param::save_in_field(Field *field, bool no_conversions) return field->store(value.integer); case REAL_VALUE: return field->store(value.real); + case DECIMAL_VALUE: + return field->store_decimal(&decimal_value); case TIME_VALUE: field->store_time(&value.time, value.time.time_type); return 0; @@ -1288,6 +1596,12 @@ double Item_param::val_real() return value.real; case INT_VALUE: return (double) value.integer; + case DECIMAL_VALUE: + { + double result; + my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &result); + return result; + } case STRING_VALUE: case LONG_DATA_VALUE: { @@ -1318,6 +1632,12 @@ longlong Item_param::val_int() return (longlong) (value.real + (value.real > 0 ? 0.5 : -0.5)); case INT_VALUE: return value.integer; + case DECIMAL_VALUE: + { + longlong i; + my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &i); + return i; + } case STRING_VALUE: case LONG_DATA_VALUE: { @@ -1336,6 +1656,36 @@ longlong Item_param::val_int() } +my_decimal *Item_param::val_decimal(my_decimal *dec) +{ + switch (state) { + case DECIMAL_VALUE: + return &decimal_value; + case REAL_VALUE: + double2my_decimal(E_DEC_FATAL_ERROR, value.real, dec); + return dec; + case INT_VALUE: + int2my_decimal(E_DEC_FATAL_ERROR, value.integer, unsigned_flag, dec); + return dec; + case STRING_VALUE: + case LONG_DATA_VALUE: + string2my_decimal(E_DEC_FATAL_ERROR, &str_value, dec); + return dec; + case TIME_VALUE: + { + longlong i= (longlong) TIME_to_ulonglong(&value.time); + int2my_decimal(E_DEC_FATAL_ERROR, i, 0, dec); + return dec; + } + case NULL_VALUE: + return 0; + default: + DBUG_ASSERT(0); + } + return 0; +} + + String *Item_param::val_str(String* str) { switch (state) { @@ -1348,6 +1698,11 @@ String *Item_param::val_str(String* str) case INT_VALUE: str->set(value.integer, &my_charset_bin); return str; + case DECIMAL_VALUE: + if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, + 0, 0, 0, str) <= 1) + return str; + return NULL; case TIME_VALUE: { if (str->reserve(MAX_DATE_STRING_REP_LENGTH)) @@ -1380,6 +1735,11 @@ const String *Item_param::query_val_str(String* str) const case REAL_VALUE: str->set(value.real, NOT_FIXED_DEC, &my_charset_bin); break; + case DECIMAL_VALUE: + if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, + 0, 0, 0, str) > 1) + return &my_null_string; + break; case TIME_VALUE: { char *buf, *ptr; @@ -1474,7 +1834,7 @@ void Item_param::print(String *str) } else { - char buffer[80]; + char buffer[STRING_BUFFER_USUAL_SIZE]; String tmp(buffer, sizeof(buffer), &my_charset_bin); const String *res; res= query_val_str(&tmp); @@ -1505,6 +1865,17 @@ String *Item_copy_string::val_str(String *str) } +my_decimal *Item_copy_string::val_decimal(my_decimal *decimal_value) +{ + // Item_copy_string is used without fix_fields call + if (null_value) + return 0; + string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value); + return (decimal_value); +} + + + int Item_copy_string::save_in_field(Field *field, bool no_conversions) { if (null_value) @@ -1548,6 +1919,24 @@ longlong Item_ref_null_helper::val_int() } +my_decimal *Item_ref_null_helper::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed == 1); + my_decimal *val= (*ref)->val_decimal_result(decimal_value); + owner->was_null|= null_value= (*ref)->null_value; + return val; +} + + +bool Item_ref_null_helper::val_bool() +{ + DBUG_ASSERT(fixed == 1); + bool val= (*ref)->val_bool_result(); + owner->was_null|= null_value= (*ref)->null_value; + return val; +} + + String* Item_ref_null_helper::val_str(String* s) { DBUG_ASSERT(fixed == 1); @@ -1931,7 +2320,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE) { if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel))) - return TRUE; /* Some error occured (e.g. ambigous names). */ + return TRUE; /* Some error occurred (e.g. ambiguous names). */ if (ref != not_found_item) { DBUG_ASSERT(*ref && (*ref)->fixed); @@ -1995,7 +2384,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) rf is Item_ref => never substitute other items (in this case) during fix_fields() => we can use rf after fix_fields() */ - if (rf->fix_fields(thd, tables, reference) || rf->check_cols(1)) + if (!rf->fixed && + rf->fix_fields(thd, tables, reference) || rf->check_cols(1)) return TRUE; mark_as_dependent(thd, last, current_sel, rf); @@ -2016,7 +2406,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) rf is Item_ref => never substitute other items (in this case) during fix_fields() => we can use rf after fix_fields() */ - return rf->fix_fields(thd, tables, reference) || rf->check_cols(1); + return (!rf->fixed && + rf->fix_fields(thd, tables, reference) || rf->check_cols(1)); } } } @@ -2089,7 +2480,7 @@ void Item_field::cleanup() Item_ident::cleanup(); /* Even if this object was created by direct link to field in setup_wild() - it will be linked correctly next tyme by name of field and table alias. + it will be linked correctly next time by name of field and table alias. I.e. we can drop 'field'. */ field= result_field= 0; @@ -2263,9 +2654,17 @@ void Item_empty_string::make_field(Send_field *tmp_field) enum_field_types Item::field_type() const { - return ((result_type() == STRING_RESULT) ? MYSQL_TYPE_VARCHAR : - (result_type() == INT_RESULT) ? FIELD_TYPE_LONGLONG : - FIELD_TYPE_DOUBLE); + switch (result_type()) + { + case STRING_RESULT: return MYSQL_TYPE_VARCHAR; + case INT_RESULT: return FIELD_TYPE_LONGLONG; + case DECIMAL_RESULT: return FIELD_TYPE_NEWDECIMAL; + case REAL_RESULT: return FIELD_TYPE_DOUBLE; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + return FIELD_TYPE_VAR_STRING; + }; } @@ -2318,6 +2717,11 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) case MYSQL_TYPE_DECIMAL: return new Field_decimal((char*) 0, max_length, null_ptr, 0, Field::NONE, name, table, decimals, 0, unsigned_flag); + case MYSQL_TYPE_NEWDECIMAL: + return new Field_new_decimal((char*) 0, max_length - (decimals?1:0), + null_ptr, 0, + Field::NONE, name, table, decimals, 0, + unsigned_flag); case MYSQL_TYPE_TINY: return new Field_tiny((char*) 0, max_length, null_ptr, 0, Field::NONE, name, table, 0, unsigned_flag); @@ -2453,7 +2857,7 @@ int Item_null::save_in_field(Field *field, bool no_conversions) field Field where we want to store NULL RETURN VALUES - 0 ok + 0 OK 1 Field doesn't support NULL values */ @@ -2492,6 +2896,15 @@ int Item::save_in_field(Field *field, bool no_conversions) field->set_notnull(); error=field->store(nr); } + else if (result_type() == DECIMAL_RESULT) + { + my_decimal decimal_value; + my_decimal *value= val_decimal(&decimal_value); + if (null_value) + return set_field_to_null(field); + field->set_notnull(); + error=field->store_decimal(value); + } else { longlong nr=val_int(); @@ -2533,9 +2946,18 @@ int Item_int::save_in_field(Field *field, bool no_conversions) return field->store(nr); } + +int Item_decimal::save_in_field(Field *field, bool no_conversions) +{ + field->set_notnull(); + return field->store_decimal(&decimal_value); +} + + Item_num *Item_uint::neg() { - return new Item_real(name, - ((double) value), 0, max_length); + Item_decimal *item= new Item_decimal(value, 0); + return item->neg(); } @@ -2544,7 +2966,7 @@ Item_num *Item_uint::neg() value is not a true double value (overflow) */ -Item_real::Item_real(const char *str_arg, uint length) +Item_float::Item_float(const char *str_arg, uint length) { int error; char *end_not_used; @@ -2566,7 +2988,7 @@ Item_real::Item_real(const char *str_arg, uint length) } -int Item_real::save_in_field(Field *field, bool no_conversions) +int Item_float::save_in_field(Field *field, bool no_conversions) { double nr= val_real(); if (null_value) @@ -2576,7 +2998,7 @@ int Item_real::save_in_field(Field *field, bool no_conversions) } -void Item_real::print(String *str) +void Item_float::print(String *str) { if (presentation) { @@ -2639,6 +3061,16 @@ longlong Item_hex_string::val_int() } +my_decimal *Item_hex_string::val_decimal(my_decimal *decimal_value) +{ + // following assert is redundant, because fixed=1 assigned in constructor + DBUG_ASSERT(fixed == 1); + ulonglong value= (ulonglong)val_int(); + int2my_decimal(E_DEC_FATAL_ERROR, value, TRUE, decimal_value); + return (decimal_value); +} + + int Item_hex_string::save_in_field(Field *field, bool no_conversions) { int error; @@ -2728,6 +3160,7 @@ bool Item::send(Protocol *protocol, String *buffer) case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_BIT: + case MYSQL_TYPE_NEWDECIMAL: { String *res; if ((res=val_str(buffer))) @@ -2818,6 +3251,20 @@ bool Item_field::send(Protocol *protocol, String *buffer) } +Item_ref::Item_ref(Item **item, const char *table_name_par, + const char *field_name_par) + :Item_ident(NullS, table_name_par, field_name_par), result_field(0), + ref(item) +{ + /* + This constructor used to create some internals references over fixed items + */ + DBUG_ASSERT(ref); + if (*ref) + set_properties(); +} + + /* Resolve the name of a reference to a column reference. @@ -2888,7 +3335,7 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) Item **group_by_ref= NULL; if (!(ref= resolve_ref_in_select_and_group(thd, this, current_sel))) - return TRUE; /* Some error occured (e.g. ambigous names). */ + return TRUE; /* Some error occurred (e.g. ambiguous names). */ if (ref == not_found_item) /* This reference was not resolved. */ { @@ -2918,7 +3365,7 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE) { if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel))) - return TRUE; /* Some error occured (e.g. ambigous names). */ + return TRUE; /* Some error occurred (e.g. ambiguous names). */ if (ref != not_found_item) { DBUG_ASSERT(*ref && (*ref)->fixed); @@ -3145,6 +3592,106 @@ String *Item_ref::str_result(String* str) } +my_decimal *Item_ref::val_decimal_result(my_decimal *decimal_value) +{ + if (result_field) + { + if ((null_value= result_field->is_null())) + return 0; + return result_field->val_decimal(decimal_value); + } + return val_decimal(decimal_value); +} + + +bool Item_ref::val_bool_result() +{ + if (result_field) + { + if ((null_value= result_field->is_null())) + return 0; + switch (result_field->result_type()) + { + case INT_RESULT: + return result_field->val_int(); + case DECIMAL_RESULT: + { + my_decimal decimal_value; + my_decimal *val= result_field->val_decimal(&decimal_value); + if (val) + return !my_decimal_is_zero(val); + return 0; + } + case REAL_RESULT: + case STRING_RESULT: + return result_field->val_real() != 0.0; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } + } + return val_bool(); +} + + +double Item_ref::val_real() +{ + DBUG_ASSERT(fixed); + double tmp=(*ref)->val_result(); + null_value=(*ref)->null_value; + return tmp; +} + + +longlong Item_ref::val_int() +{ + DBUG_ASSERT(fixed); + longlong tmp=(*ref)->val_int_result(); + null_value=(*ref)->null_value; + return tmp; +} + + +bool Item_ref::val_bool() +{ + DBUG_ASSERT(fixed); + bool tmp= (*ref)->val_bool_result(); + null_value= (*ref)->null_value; + return tmp; +} + + +String *Item_ref::val_str(String* tmp) +{ + DBUG_ASSERT(fixed); + tmp=(*ref)->str_result(tmp); + null_value=(*ref)->null_value; + return tmp; +} + + +bool Item_ref::is_null() +{ + DBUG_ASSERT(fixed); + (void) (*ref)->val_int_result(); + return (*ref)->null_value; +} + + +bool Item_ref::get_date(TIME *ltime,uint fuzzydate) +{ + return (null_value=(*ref)->get_date_result(ltime,fuzzydate)); +} + + +my_decimal *Item_ref::val_decimal(my_decimal *decimal_value) +{ + my_decimal *val= (*ref)->val_decimal(decimal_value); + null_value= (*ref)->null_value; + return val; +} + + void Item_ref_null_helper::print(String *str) { str->append("<ref_null_helper>(", 18); @@ -3156,6 +3703,59 @@ void Item_ref_null_helper::print(String *str) } +double Item_direct_ref::val_real() +{ + double tmp=(*ref)->val_real(); + null_value=(*ref)->null_value; + return tmp; +} + + +longlong Item_direct_ref::val_int() +{ + longlong tmp=(*ref)->val_int(); + null_value=(*ref)->null_value; + return tmp; +} + + +String *Item_direct_ref::val_str(String* tmp) +{ + tmp=(*ref)->val_str(tmp); + null_value=(*ref)->null_value; + return tmp; +} + + +my_decimal *Item_direct_ref::val_decimal(my_decimal *decimal_value) +{ + my_decimal *tmp= (*ref)->val_decimal(decimal_value); + null_value=(*ref)->null_value; + return tmp; +} + + +bool Item_direct_ref::val_bool() +{ + bool tmp= (*ref)->val_bool(); + null_value=(*ref)->null_value; + return tmp; +} + + +bool Item_direct_ref::is_null() +{ + (void) (*ref)->val_int(); + return (*ref)->null_value; +} + + +bool Item_direct_ref::get_date(TIME *ltime,uint fuzzydate) +{ + return (null_value=(*ref)->get_date(ltime,fuzzydate)); +} + + void Item_null_helper::print(String *str) { str->append("<null_helper>(", 14); @@ -3380,6 +3980,9 @@ Item_result item_cmp_type(Item_result a,Item_result b) return INT_RESULT; else if (a == ROW_RESULT || b == ROW_RESULT) return ROW_RESULT; + if ((a == INT_RESULT || a == DECIMAL_RESULT) && + (b == INT_RESULT || b == DECIMAL_RESULT)) + return DECIMAL_RESULT; return REAL_RESULT; } @@ -3394,7 +3997,9 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) item->result_type()); char *name=item->name; // Alloced by sql_alloc - if (res_type == STRING_RESULT) + switch (res_type) + { + case STRING_RESULT: { char buff[MAX_FIELD_WIDTH]; String tmp(buff,sizeof(buff),&my_charset_bin),*result; @@ -3407,22 +4012,40 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) char *tmp_str= sql_strmake(result->ptr(), length); new_item= new Item_string(name, tmp_str, length, result->charset()); } + break; } - else if (res_type == INT_RESULT) + case INT_RESULT: { longlong result=item->val_int(); uint length=item->max_length; bool null_value=item->null_value; new_item= (null_value ? (Item*) new Item_null(name) : (Item*) new Item_int(name, result, length)); + break; } - else + case REAL_RESULT: { // It must REAL_RESULT double result= item->val_real(); uint length=item->max_length,decimals=item->decimals; bool null_value=item->null_value; new_item= (null_value ? (Item*) new Item_null(name) : (Item*) - new Item_real(name, result, decimals, length)); + new Item_float(name, result, decimals, length)); + break; + } + case DECIMAL_RESULT: + { + my_decimal decimal_value; + my_decimal *result= item->val_decimal(&decimal_value); + uint length= item->max_length, decimals= item->decimals; + bool null_value= item->null_value; + new_item= (null_value ? + (Item*) new Item_null(name) : + (Item*) new Item_decimal(name, result, length, decimals)); + break; + } + case ROW_RESULT: + default: + DBUG_ASSERT(0); } if (new_item) thd->change_item_tree(ref, new_item); @@ -3453,6 +4076,16 @@ bool field_is_equal_to_item(Field *field,Item *item) } if (res_type == INT_RESULT) return 1; // Both where of type int + if (res_type == DECIMAL_RESULT) + { + my_decimal item_buf, *item_val, + field_buf, *field_val; + item_val= item->val_decimal(&item_buf); + if (item->null_value) + return 1; // This must be true + field_val= field->val_decimal(&field_buf); + return !my_decimal_cmp(item_val, field_val); + } double result= item->val_real(); if (item->null_value) return 1; @@ -3467,6 +4100,8 @@ Item_cache* Item_cache::get_cache(Item_result type) return new Item_cache_int(); case REAL_RESULT: return new Item_cache_real(); + case DECIMAL_RESULT: + return new Item_cache_decimal(); case STRING_RESULT: return new Item_cache_str(); case ROW_RESULT: @@ -3494,6 +4129,23 @@ void Item_cache_int::store(Item *item) { value= item->val_int_result(); null_value= item->null_value; + unsigned_flag= item->unsigned_flag; +} + + +String *Item_cache_int::val_str(String *str) +{ + DBUG_ASSERT(fixed == 1); + str->set(value, default_charset()); + return str; +} + + +my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val) +{ + DBUG_ASSERT(fixed == 1); + int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val); + return decimal_val; } @@ -3504,6 +4156,69 @@ void Item_cache_real::store(Item *item) } +longlong Item_cache_real::val_int() +{ + DBUG_ASSERT(fixed == 1); + return (longlong) (value+(value > 0 ? 0.5 : -0.5)); +} + + +String* Item_cache_real::val_str(String *str) +{ + DBUG_ASSERT(fixed == 1); + str->set(value, decimals, default_charset()); + return str; +} + + +my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val) +{ + DBUG_ASSERT(fixed == 1); + double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); + return decimal_val; +} + + +void Item_cache_decimal::store(Item *item) +{ + my_decimal *val= item->val_decimal_result(&decimal_value); + if (val != &decimal_value) + my_decimal2decimal(val, &decimal_value); + null_value= item->null_value; +} + +double Item_cache_decimal::val_real() +{ + DBUG_ASSERT(fixed); + double res; + my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res); + return res; +} + +longlong Item_cache_decimal::val_int() +{ + DBUG_ASSERT(fixed); + longlong res; + my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res); + return res; +} + +String* Item_cache_decimal::val_str(String *str) +{ + DBUG_ASSERT(fixed); + my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE, + &decimal_value); + my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, str); + return str; +} + +my_decimal *Item_cache_decimal::val_decimal(my_decimal *val) +{ + DBUG_ASSERT(fixed); + return &decimal_value; +} + + void Item_cache_str::store(Item *item) { value_buff.set(buffer, sizeof(buffer), item->collation.collation); @@ -3525,7 +4240,6 @@ void Item_cache_str::store(Item *item) } } - double Item_cache_str::val_real() { DBUG_ASSERT(fixed == 1); @@ -3549,6 +4263,16 @@ longlong Item_cache_str::val_int() return (longlong)0; } +my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val) +{ + DBUG_ASSERT(fixed == 1); + if (value) + string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); + else + decimal_val= 0; + return decimal_val; +} + bool Item_cache_row::allocate(uint num) { @@ -3701,18 +4425,18 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item, TABLE *table) /* - STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT + STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT DECIMAL_RESULT ROW_RESULT should never appear in Item_type_holder::join_types, but it is included in following table just to make table full (there DBUG_ASSERT in function to catch ROW_RESULT) */ -static Item_result type_convertor[4][4]= -{{STRING_RESULT, STRING_RESULT, STRING_RESULT, ROW_RESULT}, - {STRING_RESULT, REAL_RESULT, REAL_RESULT, ROW_RESULT}, - {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT}, - {ROW_RESULT, ROW_RESULT, ROW_RESULT, ROW_RESULT}}; - +static Item_result type_convertor[5][5]= +{{STRING_RESULT, STRING_RESULT, STRING_RESULT, ROW_RESULT, STRING_RESULT}, + {STRING_RESULT, REAL_RESULT, REAL_RESULT, ROW_RESULT, REAL_RESULT}, + {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT, DECIMAL_RESULT}, + {ROW_RESULT, ROW_RESULT, ROW_RESULT, ROW_RESULT, ROW_RESULT}, + {STRING_RESULT, REAL_RESULT, DECIMAL_RESULT, ROW_RESULT, DECIMAL_RESULT}}; /* Values of 'from' field can be stored in 'to' field. @@ -3730,6 +4454,12 @@ static Item_result type_convertor[4][4]= inline bool is_attr_compatible(Item *from, Item *to) { return ((to->max_length >= from->max_length) && + ((to->result_type() != DECIMAL_RESULT && + to->result_type() != REAL_RESULT && + to->result_type() != INT_RESULT) || + (to->decimals >= from->decimals) && + ((to->max_length - to->decimals) >= + (from->max_length - from->decimals))) && (to->maybe_null || !from->maybe_null) && (to->result_type() != STRING_RESULT || from->result_type() != STRING_RESULT || @@ -3778,6 +4508,9 @@ bool Item_type_holder::join_types(THD *thd, Item *item, TABLE *table) if (use_new_field || (new_result_type != item_type) || (new_length > max_length) || (!maybe_null && item->maybe_null) || + ((new_result_type == REAL_RESULT || new_result_type == DECIMAL_RESULT) && + (decimals < item->decimals || + (max_length - decimals) < (new_length - item->decimals))) || (item_type == STRING_RESULT && collation.collation != item->collation.collation)) { @@ -3805,8 +4538,20 @@ bool Item_type_holder::join_types(THD *thd, Item *item, TABLE *table) return 1; } - max_length= max(max_length, new_length); - decimals= max(decimals, item->decimals); + if (new_result_type == DECIMAL_RESULT) + { + int intp1= new_length - item->decimals; + int intp2= max_length - decimals; + max_length= max(intp1, intp2); + decimals= max(decimals, item->decimals); + /* can't be overflow because it work only for decimals (no strings) */ + max_length+= decimals; + } + else + { + max_length= max(max_length, new_length); + decimals= max(decimals, item->decimals); + } maybe_null|= item->maybe_null; item_type= new_result_type; } @@ -3823,6 +4568,7 @@ uint32 Item_type_holder::real_length(Item *item) switch (item->result_type()) { case STRING_RESULT: + case DECIMAL_RESULT: return item->max_length; case REAL_RESULT: return 53; @@ -3848,6 +4594,11 @@ longlong Item_type_holder::val_int() return 0; } +my_decimal *Item_type_holder::val_decimal(my_decimal *) +{ + DBUG_ASSERT(0); // should never be called + return 0; +} String *Item_type_holder::val_str(String*) { diff --git a/sql/item.h b/sql/item.h index 8209c566025..ccbc00470e5 100644 --- a/sql/item.h +++ b/sql/item.h @@ -27,7 +27,7 @@ class Item_field; /* "Declared Type Collation" - A combination of collation and its deriviation. + A combination of collation and its derivation. */ enum Derivation @@ -45,7 +45,7 @@ enum Derivation MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value (i.e. constant). MY_COLL_ALLOW_CONV - allow any kind of conversion - (combintion of the above two) + (combination of the above two) MY_COLL_DISALLOW_NONE - don't allow return DERIVATION_NONE (e.g. when aggregating for comparison) MY_COLL_CMP_CONV - combination of MY_COLL_ALLOW_CONV @@ -130,7 +130,7 @@ public: PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM, SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER, - PARAM_ITEM, TRIGGER_FIELD_ITEM}; + PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; @@ -156,11 +156,11 @@ public: // alloc & destruct is done as start of select using sql_alloc Item(); /* - Constructor used by Item_field, Item_ref & agregate (sum) functions. + Constructor used by Item_field, Item_ref & aggregate (sum) functions. Used for duplicating lists in processing queries with temporary tables Also it used for Item_cond_and/Item_cond_or for creating - top AND/OR ctructure of WHERE clause to protect it of + top AND/OR structure of WHERE clause to protect it of optimisation changes in prepared statements */ Item(THD *thd, Item *item); @@ -193,40 +193,107 @@ public: virtual enum_field_types field_type() const; virtual enum Type type() const =0; /* valXXX methods must return NULL or 0 or 0.0 if null_value is set. */ + /* + Return double precision floating point representation of item. + + SYNOPSIS + val_real() + + RETURN + In case of NULL value return 0.0 and set null_value flag to TRUE. + If value is not null null_value flag will be reset to FALSE. + */ virtual double val_real()=0; + /* + Return integer representation of item. + + SYNOPSIS + val_int() + + RETURN + In case of NULL value return 0 and set null_value flag to TRUE. + If value is not null null_value flag will be reset to FALSE. + */ virtual longlong val_int()=0; /* Return string representation of this item object. - The argument to val_str() is an allocated buffer this or any - nested Item object can use to store return value of this method. - This buffer should only be used if the item itself doesn't have an - own String buffer. In case when the item maintains it's own string - buffer, it's preferrable to return it instead to minimize number of - mallocs/memcpys. - The caller of this method can modify returned string, but only in - case when it was allocated on heap, (is_alloced() is true). This - allows the caller to efficiently use a buffer allocated by a child - without having to allocate a buffer of it's own. The buffer, given - to val_str() as agrument, belongs to the caller and is later used - by the caller at it's own choosing. - A few implications from the above: - - unless you return a string object which only points to your buffer - but doesn't manages it you should be ready that it will be - modified. - - even for not allocated strings (is_alloced() == false) the caller - can change charset (see Item_func_{typecast/binary}. XXX: is this - a bug? - - still you should try to minimize data copying and return internal - object whenever possible. + SYNOPSIS + val_str() + str an allocated buffer this or any nested Item object can use to + store return value of this method. + + NOTE + Buffer passed via argument should only be used if the item itself + doesn't have an own String buffer. In case when the item maintains + it's own string buffer, it's preferable to return it instead to + minimize number of mallocs/memcpys. + The caller of this method can modify returned string, but only in case + when it was allocated on heap, (is_alloced() is true). This allows + the caller to efficiently use a buffer allocated by a child without + having to allocate a buffer of it's own. The buffer, given to + val_str() as argument, belongs to the caller and is later used by the + caller at it's own choosing. + A few implications from the above: + - unless you return a string object which only points to your buffer + but doesn't manages it you should be ready that it will be + modified. + - even for not allocated strings (is_alloced() == false) the caller + can change charset (see Item_func_{typecast/binary}. XXX: is this + a bug? + - still you should try to minimize data copying and return internal + object whenever possible. + + RETURN + In case of NULL value return 0 (NULL pointer) and set null_value flag + to TRUE. + If value is not null null_value flag will be reset to FALSE. + */ + virtual String *val_str(String *str)=0; + /* + Return decimal representation of item with fixed point. + + SYNOPSIS + val_decimal() + decimal_buffer buffer which can be used by Item for returning value + (but can be not) + + NOTE + Returned value should not be changed if it is not the same which was + passed via argument. + + RETURN + Return pointer on my_decimal (it can be other then passed via argument) + if value is not NULL (null_value flag will be reset to FALSE). + In case of NULL value it return 0 pointer and set null_value flag + to TRUE. + */ + virtual my_decimal *val_decimal(my_decimal *decimal_buffer)= 0; + /* + Return boolean value of item. + + RETURN + FALSE value is false or NULL + TRUE value is true (not equal to 0) */ - virtual String *val_str(String*)=0; + bool val_bool(); 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 : "???"; } + + /* + *result* family of methods is analog of *val* family (see above) but + return value of result_field of item if it is present. If Item have not + result field, it return val(). This methods set null_value flag in same + way as *val* methods do it. + */ virtual double val_result() { return val_real(); } virtual longlong val_int_result() { return val_int(); } virtual String *str_result(String* tmp) { return val_str(tmp); } + virtual my_decimal *val_decimal_result(my_decimal *val) + { return val_decimal(val); } + virtual bool val_bool_result() { return val_bool(); } + /* bit map of tables used by item */ virtual table_map used_tables() const { return (table_map) 0L; } /* @@ -287,14 +354,14 @@ public: virtual void top_level_item() {} /* set field of temporary table for Item which can be switched on temporary - table during query processing (groupping and so on) + table during query processing (grouping and so on) */ virtual void set_result_field(Field *field) {} virtual bool is_result_field() { return 0; } virtual bool is_bool_func() { return 0; } virtual void save_in_result_field(bool no_conversions) {} /* - set value of aggegate function in case of no rows for groupping were found + set value of aggregate function in case of no rows for grouping were found */ virtual void no_rows_in_result() {} virtual Item *copy_or_same(THD *thd) { return this; } @@ -368,6 +435,9 @@ public: Item *this_item(); Item *this_const_item() const; + bool fix_fields(THD *, struct st_table_list *, Item **); + void cleanup(); + inline uint get_offset() { return m_offset; @@ -377,37 +447,12 @@ public: // the item in the frame enum Type type() const; - inline double val_real() - { - Item *it= this_item(); - double ret= it->val_real(); - Item::null_value= it->null_value; - return ret; - } - - inline longlong val_int() - { - Item *it= this_item(); - longlong ret= it->val_int(); - Item::null_value= it->null_value; - return ret; - } - - inline String *val_str(String *sp) - { - Item *it= this_item(); - String *ret= it->val_str(sp); - Item::null_value= it->null_value; - return ret; - } - - inline bool is_null() - { - Item *it= this_item(); - bool ret= it->is_null(); - Item::null_value= it->null_value; - return ret; - } + double val_real(); + longlong val_int(); + String *val_str(String *sp); + my_decimal *val_decimal(my_decimal *); + inline bool is_null(); + void print(String *str); inline void make_field(Send_field *field) { @@ -432,14 +477,6 @@ public: return this_item()->save_in_field(field, no_conversions); } - void print(String *str) - { - str->reserve(m_name.length+8); - str->append(m_name.str, m_name.length); - str->append('@'); - str->qs_append(m_offset); - } - inline bool send(Protocol *protocol, String *str) { return this_item()->send(protocol, str); @@ -544,10 +581,13 @@ public: bool eq(const Item *item, bool binary_cmp) const; double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal *); String *val_str(String*); double val_result(); longlong val_int_result(); String *str_result(String* tmp); + my_decimal *val_decimal_result(my_decimal *); + bool val_bool_result(); bool send(Protocol *protocol, String *str_arg); void reset_field(Field *f); bool fix_fields(THD *, struct st_table_list *, Item **); @@ -600,12 +640,13 @@ public: double val_real(); longlong val_int(); String *val_str(String *str); + my_decimal *val_decimal(my_decimal *); int save_in_field(Field *field, bool no_conversions); int save_safe_in_field(Field *field); bool send(Protocol *protocol, String *str); enum Item_result result_type () const { return STRING_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_NULL; } - // to prevent drop fixed flag (no need parent cleanup call) + /* to prevent drop fixed flag (no need parent cleanup call) */ void cleanup() {} bool basic_const_item() const { return 1; } Item *new_item() { return new Item_null(name); } @@ -623,7 +664,8 @@ public: enum enum_item_param_state { NO_VALUE, NULL_VALUE, INT_VALUE, REAL_VALUE, - STRING_VALUE, TIME_VALUE, LONG_DATA_VALUE + STRING_VALUE, TIME_VALUE, LONG_DATA_VALUE, + DECIMAL_VALUE } state; /* @@ -637,6 +679,7 @@ public: Can not be declared inside the union as it's not a POD type. */ String str_value_ptr; + my_decimal decimal_value; union { longlong integer; @@ -688,6 +731,7 @@ public: double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal*); String *val_str(String*); bool get_time(TIME *tm); bool get_date(TIME *tm, uint fuzzydate); @@ -696,6 +740,7 @@ public: void set_null(); void set_int(longlong i, uint32 max_length_arg); void set_double(double i); + void set_decimal(const char *str, ulong length); bool set_str(const char *str, ulong length); bool set_longdata(const char *str, ulong length); void set_time(TIME *tm, timestamp_type type, uint32 max_length_arg); @@ -746,6 +791,7 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } longlong val_int() { DBUG_ASSERT(fixed == 1); return value; } double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; } + my_decimal *val_decimal(my_decimal *); String *val_str(String*); int save_in_field(Field *field, bool no_conversions); bool basic_const_item() const { return 1; } @@ -784,14 +830,52 @@ public: }; -class Item_real :public Item_num +/* decimal (fixed point) constant */ +class Item_decimal :public Item_num +{ +protected: + my_decimal decimal_value; +public: + Item_decimal(const char *str_arg, uint length, CHARSET_INFO *charset); + Item_decimal(const char *str, const my_decimal *val_arg, + uint decimal_par, uint length); + Item_decimal(my_decimal *value_par); + Item_decimal(longlong val, bool unsig); + Item_decimal(double val, int precision, int scale); + Item_decimal(const char *bin, int precision, int scale); + + enum Type type() const { return DECIMAL_ITEM; } + enum Item_result result_type () const { return DECIMAL_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; } + longlong val_int(); + double val_real(); + String *val_str(String*); + my_decimal *val_decimal(my_decimal *val) { return &decimal_value; } + int save_in_field(Field *field, bool no_conversions); + bool basic_const_item() const { return 1; } + Item *new_item() + { + return new Item_decimal(name, &decimal_value, decimals, max_length); + } + // to prevent drop fixed flag (no need parent cleanup call) + void cleanup() {} + void print(String *str); + Item_num *neg() + { + my_decimal_neg(&decimal_value); + unsigned_flag= !decimal_value.sign(); + return this; + } +}; + +class Item_float :public Item_num { char *presentation; public: double value; // Item_real() :value(0) {} - Item_real(const char *str_arg, uint length); - Item_real(const char *str,double val_arg,uint decimal_par,uint length) + Item_float(const char *str_arg, uint length); + Item_float(const char *str,double val_arg,uint decimal_par,uint length) :value(val_arg) { presentation= name=(char*) str; @@ -799,7 +883,8 @@ public: max_length=length; fixed= 1; } - Item_real(double value_par) :presentation(0), value(value_par) { fixed= 1; } + Item_float(double value_par) :presentation(0), value(value_par) { fixed= 1; } + int save_in_field(Field *field, bool no_conversions); enum Type type() const { return REAL_ITEM; } enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } @@ -810,37 +895,29 @@ public: return (longlong) (value+(value > 0 ? 0.5 : -0.5)); } String *val_str(String*); + my_decimal *val_decimal(my_decimal *); bool basic_const_item() const { return 1; } // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} - Item *new_item() { return new Item_real(name,value,decimals,max_length); } + Item *new_item() + { return new Item_float(name, value, decimals, max_length); } Item_num *neg() { value= -value; return this; } void print(String *str); }; -class Item_static_real_func :public Item_real +class Item_static_float_func :public Item_float { const char *func_name; public: - Item_static_real_func(const char *str, double val_arg, uint decimal_par, + Item_static_float_func(const char *str, double val_arg, uint decimal_par, uint length) - :Item_real(NullS, val_arg, decimal_par, length), func_name(str) + :Item_float(NullS, val_arg, decimal_par, length), func_name(str) {} void print(String *str) { str->append(func_name); } }; -class Item_float :public Item_real -{ -public: - Item_float(const char *str,uint length) :Item_real(str,length) - { - decimals=NOT_FIXED_DEC; - max_length=DBL_DIG+8; - } -}; - class Item_string :public Item { public: @@ -894,6 +971,7 @@ public: DBUG_ASSERT(fixed == 1); return (String*) &str_value; } + my_decimal *val_decimal(my_decimal *); int save_in_field(Field *field, bool no_conversions); enum Item_result result_type () const { return STRING_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } @@ -932,7 +1010,7 @@ class Item_datetime :public Item_string { public: Item_datetime(const char *item_name): Item_string(item_name,"",0, - &my_charset_bin) + &my_charset_bin) { max_length=19;} enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } }; @@ -971,6 +1049,7 @@ public: longlong val_int(); bool basic_const_item() const { return 1; } String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; } + my_decimal *val_decimal(my_decimal *); int save_in_field(Field *field, bool no_conversions); enum Item_result result_type () const { return STRING_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } @@ -1033,54 +1112,25 @@ public: TODO we probably fix a superset of problems like in BUG#6658. Check this with Bar, and if we have a more broader set of problems like this. */ - Item_ref(Item **item, const char *table_name_par, const char *field_name_par) - :Item_ident(NullS, table_name_par, field_name_par), result_field(0), ref(item) - { - DBUG_ASSERT(item); - if (*item) - set_properties(); - } + Item_ref(Item **item, const char *table_name_par, const char *field_name_par); /* Constructor need to process subselect with temporary tables (see Item) */ Item_ref(THD *thd, Item_ref *item) :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {} enum Type type() const { return REF_ITEM; } bool eq(const Item *item, bool binary_cmp) const { return ref && (*ref)->eq(item, binary_cmp); } - double val_real() - { - DBUG_ASSERT(fixed); - double tmp=(*ref)->val_result(); - null_value=(*ref)->null_value; - return tmp; - } - longlong val_int() - { - DBUG_ASSERT(fixed); - longlong tmp=(*ref)->val_int_result(); - null_value=(*ref)->null_value; - return tmp; - } - String *val_str(String* tmp) - { - DBUG_ASSERT(fixed); - tmp=(*ref)->str_result(tmp); - null_value=(*ref)->null_value; - return tmp; - } - bool is_null() - { - DBUG_ASSERT(fixed); - (void) (*ref)->val_int_result(); - return (*ref)->null_value; - } - bool get_date(TIME *ltime,uint fuzzydate) - { - DBUG_ASSERT(fixed); - return (null_value=(*ref)->get_date_result(ltime,fuzzydate)); - } + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal *); + bool val_bool(); + String *val_str(String* tmp); + bool is_null(); + bool get_date(TIME *ltime,uint fuzzydate); double val_result(); longlong val_int_result(); String *str_result(String* tmp); + my_decimal *val_decimal_result(my_decimal *); + bool val_bool_result(); bool send(Protocol *prot, String *tmp); void make_field(Send_field *field) { (*ref)->make_field(field); } bool fix_fields(THD *, struct st_table_list *, Item **); @@ -1121,33 +1171,13 @@ public: /* Constructor need to process subselect with temporary tables (see Item) */ Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {} - double val_real() - { - double tmp=(*ref)->val_real(); - null_value=(*ref)->null_value; - return tmp; - } - longlong val_int() - { - longlong tmp=(*ref)->val_int(); - null_value=(*ref)->null_value; - return tmp; - } - String *val_str(String* tmp) - { - tmp=(*ref)->val_str(tmp); - null_value=(*ref)->null_value; - return tmp; - } - bool is_null() - { - (void) (*ref)->val_int(); - return (*ref)->null_value; - } - bool get_date(TIME *ltime,uint fuzzydate) - { - return (null_value=(*ref)->get_date(ltime,fuzzydate)); - } + double val_real(); + longlong val_int(); + String *val_str(String* tmp); + my_decimal *val_decimal(my_decimal *); + bool val_bool(); + bool is_null(); + bool get_date(TIME *ltime,uint fuzzydate); }; @@ -1164,6 +1194,8 @@ public: double val_real(); longlong val_int(); String* val_str(String* s); + my_decimal *val_decimal(my_decimal *); + bool val_bool(); bool get_date(TIME *ltime, uint fuzzydate); void print(String *str); }; @@ -1174,7 +1206,8 @@ class Item_null_helper :public Item_ref_null_helper public: Item_null_helper(Item_in_subselect* master, Item *item, const char *table_name_par, const char *field_name_par) - :Item_ref_null_helper(master, &item, table_name_par, field_name_par), + :Item_ref_null_helper(master, (store= 0, &store), table_name_par, + field_name_par), store(item) { ref= &store; } void print(String *str); @@ -1243,6 +1276,7 @@ public: return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),10, (char**) 0,&err); } String *val_str(String*); + my_decimal *val_decimal(my_decimal *); void make_field(Send_field *field) { item->make_field(field); } void copy(); int save_in_field(Field *field, bool no_conversions); @@ -1291,6 +1325,15 @@ public: }; +class Item_decimal_buff :public Item_buff +{ + Item *item; + my_decimal value; +public: + Item_decimal_buff(Item *item_par); + bool cmp(void); +}; + class Item_field_buff :public Item_buff { char *buff; @@ -1453,24 +1496,23 @@ public: void print(String *str); }; + class Item_cache_int: public Item_cache { +protected: longlong value; public: Item_cache_int(): Item_cache(), value(0) {} - + void store(Item *item); double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; } longlong val_int() { DBUG_ASSERT(fixed == 1); return value; } - String* val_str(String *str) - { - DBUG_ASSERT(fixed == 1); - str->set(value, default_charset()); - return str; - } + String* val_str(String *str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return INT_RESULT; } }; + class Item_cache_real: public Item_cache { double value; @@ -1479,30 +1521,41 @@ public: void store(Item *item); double val_real() { DBUG_ASSERT(fixed == 1); return value; } - longlong val_int() - { - DBUG_ASSERT(fixed == 1); - return (longlong) (value+(value > 0 ? 0.5 : -0.5)); - } - String* val_str(String *str) - { - str->set(value, decimals, default_charset()); - return str; - } + longlong val_int(); + String* val_str(String *str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return REAL_RESULT; } }; + +class Item_cache_decimal: public Item_cache +{ +protected: + my_decimal decimal_value; +public: + Item_cache_decimal(): Item_cache() {} + + void store(Item *item); + double val_real(); + longlong val_int(); + String* val_str(String *str); + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type() const { return DECIMAL_RESULT; } +}; + + class Item_cache_str: public Item_cache { - char buffer[80]; + char buffer[STRING_BUFFER_USUAL_SIZE]; String *value, value_buff; public: Item_cache_str(): Item_cache(), value(0) { } - + void store(Item *item); double val_real(); longlong val_int(); String* val_str(String *) { DBUG_ASSERT(fixed == 1); return value; } + my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return STRING_RESULT; } CHARSET_INFO *charset() const { return value->charset(); }; }; @@ -1547,6 +1600,12 @@ public: illegal_method_call((const char*)"val_str"); return 0; }; + my_decimal *val_decimal(my_decimal *val) + { + illegal_method_call((const char*)"val_decimal"); + return 0; + }; + enum Item_result result_type() const { return ROW_RESULT; } uint cols() { return item_count; } @@ -1585,6 +1644,7 @@ public: enum Type type() const { return TYPE_HOLDER; } double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal *); String *val_str(String*); bool join_types(THD *thd, Item *, TABLE *); Field *example() { return field_example; } diff --git a/sql/item_buff.cc b/sql/item_buff.cc index 66de26dba9a..7c77f7fa3bc 100644 --- a/sql/item_buff.cc +++ b/sql/item_buff.cc @@ -28,11 +28,21 @@ Item_buff *new_Item_buff(Item *item) if (item->type() == Item::FIELD_ITEM && !(((Item_field *) item)->field->flags & BLOB_FLAG)) return new Item_field_buff((Item_field *) item); - if (item->result_type() == STRING_RESULT) + switch (item->result_type()) + { + case STRING_RESULT: return new Item_str_buff((Item_field *) item); - if (item->result_type() == INT_RESULT) + case INT_RESULT: return new Item_int_buff((Item_field *) item); - return new Item_real_buff(item); + case REAL_RESULT: + return new Item_real_buff(item); + case DECIMAL_RESULT: + return new Item_decimal_buff(item); + case ROW_RESULT: + default: + DBUG_ASSERT(0); + return 0; + } } Item_buff::~Item_buff() {} @@ -107,6 +117,27 @@ bool Item_field_buff::cmp(void) } +Item_decimal_buff::Item_decimal_buff(Item *it) + :item(it) +{ + my_decimal_set_zero(&value); +} + + +bool Item_decimal_buff::cmp() +{ + my_decimal tmp; + my_decimal *ptmp= item->val_decimal(&tmp); + if (null_value != item->null_value || my_decimal_cmp(&value, ptmp) == 0) + { + null_value= item->null_value; + my_decimal2decimal(ptmp, &value); + return TRUE; + } + return FALSE; +} + + /***************************************************************************** ** Instansiate templates *****************************************************************************/ diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 1079e31e23a..71a4e4dda53 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -31,6 +31,8 @@ static Item_result item_store_type(Item_result a,Item_result b) return STRING_RESULT; else if (a == REAL_RESULT || b == REAL_RESULT) return REAL_RESULT; + else if (a == DECIMAL_RESULT || b == DECIMAL_RESULT) + return DECIMAL_RESULT; else return INT_RESULT; } @@ -51,7 +53,8 @@ static void agg_cmp_type(Item_result *type, Item **items, uint nitems) type[0]= item_cmp_type(type[0], items[i]->result_type()); } -static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname) +static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, + const char *fname) { my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0), c1.collation->name,c1.derivation_name(), @@ -104,7 +107,7 @@ Item_bool_func2* Le_creator::create(Item *a, Item *b) const longlong Item_func_not::val_int() { DBUG_ASSERT(fixed == 1); - double value= args[0]->val_real(); + bool value= args[0]->val_bool(); null_value=args[0]->null_value; return ((!null_value && value == 0) ? 1 : 0); } @@ -116,11 +119,11 @@ longlong Item_func_not::val_int() longlong Item_func_not_all::val_int() { DBUG_ASSERT(fixed == 1); - double value= args[0]->val_real(); + bool value= args[0]->val_bool(); /* - return TRUE if there was records in underlaying select in max/min - optimisation (ALL subquery) + return TRUE if there was records in underlying select in max/min + optimization (ALL subquery) */ if (empty_underlying_subquery()) return 1; @@ -147,7 +150,7 @@ void Item_func_not_all::print(String *str) /* Special NOP (No OPeration) for ALL subquery it is like Item_func_not_all - (return TRUE if underlaying sudquery do not return rows) but if subquery + (return TRUE if underlying subquery do not return rows) but if subquery returns some rows it return same value as argument (TRUE/FALSE). */ @@ -157,8 +160,8 @@ longlong Item_func_nop_all::val_int() longlong value= args[0]->val_int(); /* - return FALSE if there was records in underlaying select in max/min - optimisation (SAME/ANY subquery) + return FALSE if there was records in underlying select in max/min + optimization (SAME/ANY subquery) */ if (empty_underlying_subquery()) return 0; @@ -270,7 +273,9 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) owner= item; func= comparator_matrix[type] [test(owner->functype() == Item_func::EQUAL_FUNC)]; - if (type == ROW_RESULT) + switch(type) + { + case ROW_RESULT: { uint n= (*a)->cols(); if (n != (*b)->cols()) @@ -290,8 +295,9 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) } comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)); } + break; } - else if (type == STRING_RESULT) + case STRING_RESULT: { /* We must set cmp_charset here as we may be called from for an automatic @@ -315,7 +321,7 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) func= &Arg_comparator::compare_e_binary_string; /* - As this is binary comparsion, mark all fields that they can't be + As this is binary compassion, mark all fields that they can't be transformed. Otherwise we would get into trouble with comparisons like: WHERE col= 'j' AND col LIKE BINARY 'j' @@ -325,14 +331,16 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) (*a)->transform(&Item::set_no_const_sub, (byte*) 0); (*b)->transform(&Item::set_no_const_sub, (byte*) 0); } + break; } - else if (type == INT_RESULT) + case INT_RESULT: { if (func == &Arg_comparator::compare_int_signed) { if ((*a)->unsigned_flag) - func= ((*b)->unsigned_flag)? &Arg_comparator::compare_int_unsigned : - &Arg_comparator::compare_int_unsigned_signed; + func= (((*b)->unsigned_flag)? + &Arg_comparator::compare_int_unsigned : + &Arg_comparator::compare_int_unsigned_signed); else if ((*b)->unsigned_flag) func= &Arg_comparator::compare_int_signed_unsigned; } @@ -341,6 +349,13 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) if ((*a)->unsigned_flag ^ (*b)->unsigned_flag) func= &Arg_comparator::compare_e_int_diff_signedness; } + break; + } + case DECIMAL_RESULT: + case REAL_RESULT: + break; + default: + DBUG_ASSERT(0); } return 0; } @@ -434,6 +449,24 @@ int Arg_comparator::compare_real() return -1; } +int Arg_comparator::compare_decimal() +{ + my_decimal value1; + my_decimal *val1= (*a)->val_decimal(&value1); + if (!(*a)->null_value) + { + my_decimal value2; + my_decimal *val2= (*b)->val_decimal(&value2); + if (!(*b)->null_value) + { + owner->null_value= 0; + return my_decimal_cmp(val1, val2); + } + } + owner->null_value= 1; + return -1; +} + int Arg_comparator::compare_e_real() { double val1= (*a)->val_real(); @@ -443,6 +476,16 @@ int Arg_comparator::compare_e_real() return test(val1 == val2); } +int Arg_comparator::compare_e_decimal() +{ + my_decimal value1, value2; + my_decimal *val1= (*a)->val_decimal(&value1); + my_decimal *val2= (*b)->val_decimal(&value2); + if ((*a)->null_value || (*b)->null_value) + return test((*a)->null_value && (*b)->null_value); + return test(my_decimal_cmp(val1, val2) == 0); +} + int Arg_comparator::compare_int_signed() { longlong val1= (*a)->val_int(); @@ -776,6 +819,8 @@ longlong Item_func_strcmp::val_int() void Item_func_interval::fix_length_and_dec() { + use_decimal_comparison= (row->el(0)->result_type() == DECIMAL_RESULT) || + (row->el(0)->result_type() == INT_RESULT); if (row->cols() > 8) { bool consts=1; @@ -786,10 +831,41 @@ void Item_func_interval::fix_length_and_dec() } if (consts && - (intervals=(double*) sql_alloc(sizeof(double)*(row->cols()-1)))) + (intervals= + (interval_range*) sql_alloc(sizeof(interval_range)*(row->cols()-1)))) { - for (uint i=1 ; i < row->cols(); i++) - intervals[i-1]= row->el(i)->val_real(); + if (use_decimal_comparison) + { + for (uint i=1 ; i < row->cols(); i++) + { + Item *el= row->el(i); + interval_range *range= intervals + (i-1); + if ((el->result_type() == DECIMAL_RESULT) || + (el->result_type() == INT_RESULT)) + { + range->type= DECIMAL_RESULT; + range->dec.init(); + my_decimal *dec= el->val_decimal(&range->dec); + if (dec != &range->dec) + { + range->dec= *dec; + range->dec.fix_buffer_pointer(); + } + } + else + { + range->type= REAL_RESULT; + range->dbl= el->val_real(); + } + } + } + else + { + for (uint i=1 ; i < row->cols(); i++) + { + intervals[i-1].dbl= row->el(i)->val_real(); + } + } } } maybe_null= 0; @@ -812,6 +888,11 @@ longlong Item_func_interval::val_int() { DBUG_ASSERT(fixed == 1); double value= row->el(0)->val_real(); + my_decimal dec_buf, *dec= NULL; + if (use_decimal_comparison) + { + dec= row->el(0)->val_decimal(&dec_buf); + } uint i; if (row->el(0)->null_value) @@ -824,18 +905,37 @@ longlong Item_func_interval::val_int() while (start != end) { uint mid= (start + end + 1) / 2; - if (intervals[mid] <= value) + interval_range *range= intervals + mid; + my_bool cmp_result; + if (dec && range->type == DECIMAL_RESULT) + cmp_result= my_decimal_cmp(&range->dec, dec) <= 0; + else + cmp_result= (range->dbl <= value); + if (cmp_result) start= mid; else end= mid - 1; } - return (value < intervals[start]) ? 0 : start + 1; + interval_range *range= intervals+start; + return ((dec && range->type == DECIMAL_RESULT) ? + my_decimal_cmp(dec, &range->dec) < 0 : + value < range->dbl) ? 0 : start + 1; } for (i=1 ; i < row->cols() ; i++) { - if (row->el(i)->val_real() > value) - return i-1; + Item *el= row->el(i); + if (use_decimal_comparison && + ((el->result_type() == DECIMAL_RESULT) || + (el->result_type() == INT_RESULT))) + { + my_decimal e_dec_buf, *e_dec= row->el(i)->val_decimal(&e_dec_buf); + if (my_decimal_cmp(e_dec, dec) > 0) + return i-1; + } + else + if (row->el(i)->val_real() > value) + return i-1; } return i-1; } @@ -847,7 +947,7 @@ void Item_func_between::fix_length_and_dec() /* As some compare functions are generated after sql_yacc, - we have to check for out of memory conditons here + we have to check for out of memory conditions here */ if (!args[0] || !args[1] || !args[2]) return; @@ -857,7 +957,7 @@ void Item_func_between::fix_length_and_dec() return; /* - Make a special case of compare with date/time and longlong fields. + Make a special ease of compare with date/time and longlong fields. They are compared as integers, so for const item this time-consuming conversion can be done only once, not for every single comparison */ @@ -926,6 +1026,24 @@ longlong Item_func_between::val_int() null_value= value >= a; } } + else if (cmp_type == DECIMAL_RESULT) + { + my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf), + a_buf, *a_dec, b_buf, *b_dec; + if ((null_value=args[0]->null_value)) + return 0; /* purecov: inspected */ + a_dec= args[1]->val_decimal(&a_buf); + b_dec= args[2]->val_decimal(&b_buf); + if (!args[1]->null_value && !args[2]->null_value) + return (my_decimal_cmp(dec, a_dec)>=0) && (my_decimal_cmp(dec, b_dec)<=0); + + if (args[1]->null_value && args[2]->null_value) + null_value=1; + else if (args[1]->null_value) + null_value= (my_decimal_cmp(dec, b_dec) <= 0); + else + null_value= (my_decimal_cmp(dec, a_dec) >= 0); + } else { double value= args[0]->val_real(),a,b; @@ -965,14 +1083,26 @@ void Item_func_ifnull::fix_length_and_dec() { maybe_null=args[1]->maybe_null; - max_length=max(args[0]->max_length,args[1]->max_length); - decimals=max(args[0]->decimals,args[1]->decimals); + decimals= max(args[0]->decimals, args[1]->decimals); + max_length= (max(args[0]->max_length - args[0]->decimals, + args[1]->max_length - args[1]->decimals) + + decimals); agg_result_type(&cached_result_type, args, 2); - if (cached_result_type == STRING_RESULT) + switch (cached_result_type) + { + case STRING_RESULT: agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV); - else if (cached_result_type != REAL_RESULT) + break; + case DECIMAL_RESULT: + case REAL_RESULT: + break; + case INT_RESULT: decimals= 0; - + break; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } cached_field_type= args[0]->field_type(); if (cached_field_type != args[1]->field_type()) cached_field_type= Item_func::field_type(); @@ -1020,6 +1150,24 @@ Item_func_ifnull::val_int() return value; } + +my_decimal *Item_func_ifnull::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed == 1); + my_decimal *value= args[0]->val_decimal(decimal_value); + if (!args[0]->null_value) + { + null_value= 0; + return value; + } + value= args[1]->val_decimal(decimal_value); + if ((null_value= args[1]->null_value)) + return 0; + return value; +} + + + String * Item_func_ifnull::val_str(String *str) { @@ -1043,8 +1191,10 @@ void Item_func_if::fix_length_and_dec() { maybe_null=args[1]->maybe_null || args[2]->maybe_null; - max_length=max(args[1]->max_length,args[2]->max_length); - decimals=max(args[1]->decimals,args[2]->decimals); + decimals= max(args[1]->decimals, args[2]->decimals); + max_length= (max(args[1]->max_length - args[1]->decimals, + args[2]->max_length - args[2]->decimals) + + decimals); enum Item_result arg1_type=args[1]->result_type(); enum Item_result arg2_type=args[2]->result_type(); bool null1=args[1]->const_item() && args[1]->null_value; @@ -1080,7 +1230,7 @@ double Item_func_if::val_real() { DBUG_ASSERT(fixed == 1); - Item *arg= args[0]->val_int() ? args[1] : args[2]; + Item *arg= args[0]->val_bool() ? args[1] : args[2]; double value= arg->val_real(); null_value=arg->null_value; return value; @@ -1090,7 +1240,7 @@ longlong Item_func_if::val_int() { DBUG_ASSERT(fixed == 1); - Item *arg= args[0]->val_int() ? args[1] : args[2]; + Item *arg= args[0]->val_bool() ? args[1] : args[2]; longlong value=arg->val_int(); null_value=arg->null_value; return value; @@ -1100,7 +1250,7 @@ String * Item_func_if::val_str(String *str) { DBUG_ASSERT(fixed == 1); - Item *arg= args[0]->val_int() ? args[1] : args[2]; + Item *arg= args[0]->val_bool() ? args[1] : args[2]; String *res=arg->val_str(str); if (res) res->set_charset(collation.collation); @@ -1109,6 +1259,17 @@ Item_func_if::val_str(String *str) } +my_decimal * +Item_func_if::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed == 1); + Item *arg= args[0]->val_bool() ? args[1] : args[2]; + my_decimal *value= arg->val_decimal(decimal_value); + null_value= arg->null_value; + return value; +} + + void Item_func_nullif::fix_length_and_dec() { @@ -1125,6 +1286,7 @@ Item_func_nullif::fix_length_and_dec() } } + /* nullif () returns NULL if arguments are equal, else it returns the first argument. @@ -1178,6 +1340,22 @@ Item_func_nullif::val_str(String *str) } +my_decimal * +Item_func_nullif::val_decimal(my_decimal * decimal_value) +{ + DBUG_ASSERT(fixed == 1); + my_decimal *res; + if (!cmp.compare()) + { + null_value=1; + return 0; + } + res= args[0]->val_decimal(decimal_value); + null_value= args[0]->null_value; + return res; +} + + bool Item_func_nullif::is_null() { @@ -1193,14 +1371,16 @@ Item_func_nullif::is_null() Item *Item_func_case::find_item(String *str) { - String *first_expr_str,*tmp; + String *first_expr_str, *tmp; + my_decimal *first_expr_dec, first_expr_dec_val; longlong first_expr_int; double first_expr_real; - + /* These will be initialized later */ LINT_INIT(first_expr_str); LINT_INIT(first_expr_int); LINT_INIT(first_expr_real); + LINT_INIT(first_expr_dec); if (first_expr_num != -1) { @@ -1221,9 +1401,14 @@ Item *Item_func_case::find_item(String *str) if (args[first_expr_num]->null_value) return else_expr_num != -1 ? args[else_expr_num] : 0; break; + case DECIMAL_RESULT: + first_expr_dec= args[first_expr_num]->val_decimal(&first_expr_dec_val); + if (args[first_expr_num]->null_value) + return else_expr_num != -1 ? args[else_expr_num] : 0; + break; case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } @@ -1235,7 +1420,7 @@ Item *Item_func_case::find_item(String *str) if (first_expr_num == -1) { // No expression between CASE and the first WHEN - if (args[i]->val_int()) + if (args[i]->val_bool()) return args[i+1]; continue; } @@ -1253,9 +1438,16 @@ Item *Item_func_case::find_item(String *str) if (args[i]->val_real() == first_expr_real && !args[i]->null_value) return args[i+1]; break; + case DECIMAL_RESULT: + { + my_decimal value; + if (my_decimal_cmp(args[i]->val_decimal(&value), first_expr_dec) == 0) + return args[i+1]; + break; + } case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } @@ -1320,6 +1512,27 @@ double Item_func_case::val_real() return res; } + +my_decimal *Item_func_case::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed == 1); + char buff[MAX_FIELD_WIDTH]; + String dummy_str(buff, sizeof(buff), default_charset()); + Item *item= find_item(&dummy_str); + my_decimal *res; + + if (!item) + { + null_value=1; + return 0; + } + + res= item->val_decimal(decimal_value); + null_value= item->null_value; + return res; +} + + void Item_func_case::fix_length_and_dec() { Item **agg; @@ -1358,7 +1571,7 @@ void Item_func_case::fix_length_and_dec() agg_cmp_type(&cmp_type, agg, nagg); if ((cmp_type == STRING_RESULT) && agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV)) - return; + return; } if (else_expr_num == -1 || args[else_expr_num]->maybe_null) @@ -1453,20 +1666,45 @@ double Item_func_coalesce::val_real() } +my_decimal *Item_func_coalesce::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed == 1); + null_value= 0; + for (uint i= 0; i < arg_count; i++) + { + my_decimal *res= args[i]->val_decimal(decimal_value); + if (!args[i]->null_value) + return res; + } + null_value=1; + return 0; +} + + void Item_func_coalesce::fix_length_and_dec() { - max_length= 0; - decimals= 0; agg_result_type(&cached_result_type, args, arg_count); - for (uint i=0 ; i < arg_count ; i++) + switch (cached_result_type) { - set_if_bigger(max_length,args[i]->max_length); - set_if_bigger(decimals,args[i]->decimals); - } - if (cached_result_type == STRING_RESULT) + case STRING_RESULT: + count_only_length(); + decimals= NOT_FIXED_DEC; agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV); - else if (cached_result_type != REAL_RESULT) + break; + case DECIMAL_RESULT: + count_decimal_length(); + break; + case REAL_RESULT: + count_real_length(); + break; + case INT_RESULT: + count_only_length(); decimals= 0; + break; + case ROW_RESULT: + defaullt: + DBUG_ASSERT(0); + } } /**************************************************************************** @@ -1483,11 +1721,24 @@ static int cmp_double(void *cmp_arg, double *a,double *b) return *a < *b ? -1 : *a == *b ? 0 : 1; } -static int cmp_row(void *cmp_arg, cmp_item_row* a, cmp_item_row* b) +static int cmp_row(void *cmp_arg, cmp_item_row *a, cmp_item_row *b) { return a->compare(b); } + +static int cmp_decimal(void *cmp_arg, my_decimal *a, my_decimal *b) +{ + /* + We need call of fixing buffer pointer, because fast sort just copy + decimal buffers in memory and pointers left pointing on old buffer place + */ + a->fix_buffer_pointer(); + b->fix_buffer_pointer(); + return my_decimal_cmp(a, b); +} + + int in_vector::find(Item *item) { byte *result=get_value(item); @@ -1612,17 +1863,47 @@ byte *in_double::get_value(Item *item) return (byte*) &tmp; } -cmp_item* cmp_item::get_comparator(Item *item) + +in_decimal::in_decimal(uint elements) + :in_vector(elements, sizeof(my_decimal),(qsort2_cmp) cmp_decimal, 0) +{} + + +void in_decimal::set(uint pos, Item *item) +{ + /* as far as 'item' is constant, we can store reference on my_decimal */ + my_decimal *dec= ((my_decimal *)base) + pos; + dec->len= DECIMAL_BUFF_LENGTH; + dec->fix_buffer_pointer(); + my_decimal *res= item->val_decimal(dec); + if (res != dec) + my_decimal2decimal(res, dec); +} + + +byte *in_decimal::get_value(Item *item) +{ + my_decimal *result= item->val_decimal(&val); + if (item->null_value) + return 0; + return (byte *)result; +} + + +cmp_item* cmp_item::get_comparator(Item_result type, + CHARSET_INFO *cs) { - switch (item->result_type()) { + switch (type) { case STRING_RESULT: - return new cmp_item_sort_string(item->collation.collation); + return new cmp_item_sort_string(cs); case INT_RESULT: return new cmp_item_int; case REAL_RESULT: return new cmp_item_real; case ROW_RESULT: return new cmp_item_row; + case DECIMAL_RESULT: + return new cmp_item_decimal; default: DBUG_ASSERT(0); break; @@ -1681,7 +1962,9 @@ void cmp_item_row::store_value(Item *item) for (uint i=0; i < n; i++) { if (!comparators[i]) - if (!(comparators[i]= cmp_item::get_comparator(item->el(i)))) + if (!(comparators[i]= + cmp_item::get_comparator(item->el(i)->result_type(), + item->el(i)->collation.collation))) break; // new failed comparators[i]->store_value(item->el(i)); item->null_value|= item->el(i)->null_value; @@ -1752,6 +2035,36 @@ int cmp_item_row::compare(cmp_item *c) } +void cmp_item_decimal::store_value(Item *item) +{ + my_decimal *val= item->val_decimal(&value); + if (val != &value) + my_decimal2decimal(val, &value); +} + + +int cmp_item_decimal::cmp(Item *arg) +{ + my_decimal tmp_buf, *tmp= arg->val_decimal(&tmp_buf); + if (arg->null_value) + return 1; + return my_decimal_cmp(&value, tmp); +} + + +int cmp_item_decimal::compare(cmp_item *c) +{ + cmp_item_decimal *cmp= (cmp_item_decimal *)c; + return my_decimal_cmp(&value, &cmp->value); +} + + +cmp_item* cmp_item_decimal::make_same() +{ + return new cmp_item_decimal(); +} + + bool Item_func_in::nulls_in_row() { Item **arg,**arg_end; @@ -1807,6 +2120,9 @@ void Item_func_in::fix_length_and_dec() case ROW_RESULT: array= new in_row(arg_count-1, args[0]); break; + case DECIMAL_RESULT: + array= new in_decimal(arg_count - 1); + break; default: DBUG_ASSERT(0); return; @@ -1828,7 +2144,7 @@ void Item_func_in::fix_length_and_dec() } else { - in_item= cmp_item::get_comparator(args[0]); + in_item= cmp_item::get_comparator(cmp_type, cmp_collation.collation); if (cmp_type == STRING_RESULT) in_item->cmp_charset= cmp_collation.collation; } @@ -2003,7 +2319,7 @@ bool Item_cond::walk(Item_processor processor, byte *arg) DESCRIPTION The function recursively applies the transform method with the - same transformer to each member item of the codition list. + same transformer to each member item of the condition list. If the call of the method for a member item returns a new item the old item is substituted for a new one. After this the transform method is applied to the root node @@ -2088,7 +2404,6 @@ void Item_cond::split_sum_func(THD *thd, Item **ref_pointer_array, ref_pointer_array[el]= item; Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name); fields.push_front(item); - ref_pointer_array[el]= item; thd->change_item_tree(ref, new_item); } item->update_used_tables(); @@ -2157,7 +2472,7 @@ void Item_cond::neg_arguments(THD *thd) /* - Evalution of AND(expr, expr, expr ...) + Evaluation of AND(expr, expr, expr ...) NOTES: abort_if_null is set for AND expressions for which we don't care if the @@ -2182,7 +2497,7 @@ longlong Item_cond_and::val_int() null_value= 0; while ((item=li++)) { - if (item->val_int() == 0) + if (!item->val_bool()) { if (abort_on_null || !(null_value= item->null_value)) return 0; // return FALSE @@ -2200,7 +2515,7 @@ longlong Item_cond_or::val_int() null_value=0; while ((item=li++)) { - if (item->val_int() != 0) + if (item->val_bool()) { null_value=0; return 1; @@ -2439,7 +2754,7 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) DBUG_ASSERT(fixed == 0); if ((!args[0]->fixed && args[0]->fix_fields(thd, tables, args)) || args[0]->check_cols(1) || - (!args[1]->fixed && + (!args[1]->fixed && args[1]->fix_fields(thd,tables, args + 1)) || args[1]->check_cols(1)) return TRUE; /* purecov: inspected */ with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func; @@ -2813,7 +3128,7 @@ longlong Item_cond_xor::val_int() /* Apply NOT transformation to the item and return a new one. - SYNPOSIS + SYNOPSIS neg_transformer() thd thread handler @@ -2991,10 +3306,10 @@ uint Item_equal::members() SYNOPSIS contains() - field field whose occurence is to be checked + field field whose occurrence is to be checked DESCRIPTION - The function checks whether field is occured in the Item_equal object + The function checks whether field is occurred in the Item_equal object RETURN VALUES 1 if nultiple equality contains a reference to field @@ -3022,7 +3337,7 @@ bool Item_equal::contains(Field *field) item multiple equality whose members are to be joined DESCRIPTION - The function actually merges two multiple equalitis. + The function actually merges two multiple equalities. After this operation the Item_equal object additionally contains the field items of another item of the type Item_equal. If the optional constant items are not equal the cond_false flag is @@ -3159,7 +3474,8 @@ longlong Item_equal::val_int() void Item_equal::fix_length_and_dec() { Item *item= const_item ? const_item : get_first(); - eval_item= cmp_item::get_comparator(item); + eval_item= cmp_item::get_comparator(item->result_type(), + item->collation.collation); if (item->result_type() == STRING_RESULT) eval_item->cmp_charset= cmp_collation.collation; } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 181f1312d46..717bcbca7d5 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -67,6 +67,7 @@ public: int compare_string(); // compare args[0] & args[1] int compare_binary_string(); // compare args[0] & args[1] int compare_real(); // compare args[0] & args[1] + int compare_decimal(); // compare args[0] & args[1] int compare_int_signed(); // compare args[0] & args[1] int compare_int_signed_unsigned(); int compare_int_unsigned_signed(); @@ -75,11 +76,12 @@ public: int compare_e_string(); // compare args[0] & args[1] int compare_e_binary_string(); // compare args[0] & args[1] int compare_e_real(); // compare args[0] & args[1] + int compare_e_decimal(); // compare args[0] & args[1] int compare_e_int(); // compare args[0] & args[1] int compare_e_int_diff_signedness(); int compare_e_row(); // compare args[0] & args[1] - static arg_cmp_func comparator_matrix [4][2]; + static arg_cmp_func comparator_matrix [5][2]; friend class Item_func; }; @@ -269,7 +271,7 @@ public: class Item_func_not_all :public Item_func_not { - /* allow to check presence od values in max/min optimisation */ + /* allow to check presence of values in max/min optimization */ Item_sum_hybrid *test_sum_item; Item_maxmin_subselect *test_sub_item; @@ -421,10 +423,18 @@ public: }; +struct interval_range +{ + Item_result type; + double dbl; + my_decimal dec; +}; + class Item_func_interval :public Item_int_func { Item_row *row; - double *intervals; + my_bool use_decimal_comparison; + interval_range *intervals; public: Item_func_interval(Item_row *a) :Item_int_func(a),row(a),intervals(0) @@ -437,24 +447,43 @@ public: }; -class Item_func_ifnull :public Item_func +class Item_func_coalesce :public Item_func { +protected: enum Item_result cached_result_type; + Item_func_coalesce(Item *a, Item *b) + :Item_func(a, b), cached_result_type(INT_RESULT) + {} +public: + Item_func_coalesce(List<Item> &list) + :Item_func(list),cached_result_type(INT_RESULT) + {} + double val_real(); + longlong val_int(); + String *val_str(String *); + my_decimal *val_decimal(my_decimal *); + void fix_length_and_dec(); + enum Item_result result_type () const { return cached_result_type; } + const char *func_name() const { return "coalesce"; } + table_map not_null_tables() const { return 0; } +}; + + +class Item_func_ifnull :public Item_func_coalesce +{ +protected: enum_field_types cached_field_type; bool field_type_defined; public: - Item_func_ifnull(Item *a,Item *b) - :Item_func(a,b), cached_result_type(INT_RESULT) - {} + Item_func_ifnull(Item *a, Item *b) :Item_func_coalesce(a,b) {} double val_real(); longlong val_int(); String *val_str(String *str); - enum Item_result result_type () const { return cached_result_type; } + my_decimal *val_decimal(my_decimal *); enum_field_types field_type() const; void fix_length_and_dec(); const char *func_name() const { return "ifnull"; } Field *tmp_table_field(TABLE *table); - table_map not_null_tables() const { return 0; } }; @@ -468,6 +497,7 @@ public: double val_real(); longlong val_int(); String *val_str(String *str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return cached_result_type; } bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref) { @@ -491,6 +521,7 @@ public: double val_real(); longlong val_int(); String *val_str(String *str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return cached_result_type; } void fix_length_and_dec(); const char *func_name() const { return "nullif"; } @@ -500,23 +531,6 @@ public: }; -class Item_func_coalesce :public Item_func -{ - enum Item_result cached_result_type; -public: - Item_func_coalesce(List<Item> &list) - :Item_func(list),cached_result_type(INT_RESULT) - {} - double val_real(); - longlong val_int(); - String *val_str(String *); - void fix_length_and_dec(); - enum Item_result result_type () const { return cached_result_type; } - const char *func_name() const { return "coalesce"; } - table_map not_null_tables() const { return 0; } -}; - - class Item_func_case :public Item_func { int first_expr_num, else_expr_num; @@ -529,7 +543,7 @@ public: Item_func_case(List<Item> &list, Item *first_expr_arg, Item *else_expr_arg) :Item_func(), first_expr_num(-1), else_expr_num(-1), cached_result_type(INT_RESULT) - { + { ncases= list.elements; if (first_expr_arg) { @@ -546,6 +560,7 @@ public: double val_real(); longlong val_int(); String *val_str(String *); + my_decimal *val_decimal(my_decimal *); void fix_length_and_dec(); table_map not_null_tables() const { return 0; } enum Item_result result_type () const { return cached_result_type; } @@ -586,7 +601,7 @@ public: class in_string :public in_vector { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String tmp; public: in_string(uint elements,qsort2_cmp cmp_func, CHARSET_INFO *cs); @@ -613,6 +628,16 @@ public: byte *get_value(Item *item); }; +class in_decimal :public in_vector +{ + my_decimal val; +public: + in_decimal(uint elements); + void set(uint pos, Item *item); + byte *get_value(Item *item); +}; + + /* ** Classes for easy comparing of non const items */ @@ -627,7 +652,7 @@ public: virtual int cmp(Item *item)= 0; // for optimized IN with row virtual int compare(cmp_item *item)= 0; - static cmp_item* get_comparator(Item *); + static cmp_item* get_comparator(Item_result type, CHARSET_INFO *cs); virtual cmp_item *make_same()= 0; virtual void store_value_by_template(cmp_item *tmpl, Item *item) { @@ -648,7 +673,7 @@ public: class cmp_item_sort_string :public cmp_item_string { protected: - char value_buff[80]; + char value_buff[STRING_BUFFER_USUAL_SIZE]; String value; public: cmp_item_sort_string(CHARSET_INFO *cs): @@ -660,7 +685,7 @@ public: } int cmp(Item *arg) { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String tmp(buff, sizeof(buff), cmp_charset), *res; if (!(res= arg->val_str(&tmp))) return 1; /* Can't be right */ @@ -714,6 +739,18 @@ public: cmp_item *make_same(); }; + +class cmp_item_decimal :public cmp_item +{ + my_decimal value; +public: + void store_value(Item *item); + int cmp(Item *arg); + int compare(cmp_item *c); + cmp_item *make_same(); +}; + + class cmp_item_row :public cmp_item { cmp_item **comparators; @@ -996,26 +1033,26 @@ public: /* - The class Item_equal is used to represent conjuctions of equality + The class Item_equal is used to represent conjunctions of equality predicates of the form field1 = field2, and field=const in where conditions and on expressions. All equality predicates of the form field1=field2 contained in a - conjuction are substituted for a sequence of items of this class. - An item of this class Item_equal(f1,f2,...fk) respresents a + conjunction are substituted for a sequence of items of this class. + An item of this class Item_equal(f1,f2,...fk) represents a multiple equality f1=f2=...=fk. - If a conjuction contains predicates f1=f2 and f2=f3, a new item of + If a conjunction contains predicates f1=f2 and f2=f3, a new item of this class is created Item_equal(f1,f2,f3) representing the multiple equality f1=f2=f3 that substitutes the above equality predicates in - the conjuction. - A conjuction of the predicates f2=f1 and f3=f1 and f3=f2 will be + the conjunction. + A conjunction of the predicates f2=f1 and f3=f1 and f3=f2 will be substituted for the item representing the same multiple equality f1=f2=f3. - An item Item_equal(f1,f2) can appear instead of a conjuction of + An item Item_equal(f1,f2) can appear instead of a conjunction of f2=f1 and f1=f2, or instead of just the predicate f1=f2. - An item of the class Item_equal inherites equalities from outer + An item of the class Item_equal inherits equalities from outer conjunctive levels. Suppose we have a where condition of the following form: @@ -1026,7 +1063,7 @@ public: f1=f3 will be substituted for Item_equal(f1,f2,f3,f4,f5); An object of the class Item_equal can contain an optional constant - item c. Thenit represents a multiple equality of the form + item c. Then it represents a multiple equality of the form c=f1=...=fk. Objects of the class Item_equal are used for the following: @@ -1044,7 +1081,7 @@ public: 3. An object Item_equal(t1.f1,...,tk.fk) is used to optimize the selected execution plan for the query: if table ti is accessed before the table tj then in any predicate P in the where condition - the occurence of tj.fj is substituted for ti.fi. This can allow + the occurrence of tj.fj is substituted for ti.fi. This can allow an evaluation of the predicate at an earlier step. When feature 1 is supported they say that join transitive closure @@ -1175,7 +1212,7 @@ public: /* - XOR is Item_cond, not an Item_int_func bevause we could like to + XOR is Item_cond, not an Item_int_func because we could like to optimize (a XOR b) later on. It's low prio, though */ @@ -1192,7 +1229,7 @@ public: }; -/* Some usefull inline functions */ +/* Some useful inline functions */ inline Item *and_conds(Item *a, Item *b) { diff --git a/sql/item_create.cc b/sql/item_create.cc index 9fb44658dd5..6bd5c0c9a52 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -289,7 +289,7 @@ Item *create_func_period_diff(Item* a, Item *b) Item *create_func_pi(void) { - return new Item_static_real_func("pi()", M_PI, 6, 8); + return new Item_static_float_func("pi()", M_PI, 6, 8); } Item *create_func_pow(Item* a, Item *b) @@ -454,7 +454,7 @@ Item *create_load_file(Item* a) } -Item *create_func_cast(Item *a, Cast_target cast_type, int len, +Item *create_func_cast(Item *a, Cast_target cast_type, int len, int dec, CHARSET_INFO *cs) { Item *res; @@ -467,6 +467,9 @@ Item *create_func_cast(Item *a, Cast_target cast_type, int len, case ITEM_CAST_DATE: res= new Item_date_typecast(a); break; case ITEM_CAST_TIME: res= new Item_time_typecast(a); break; case ITEM_CAST_DATETIME: res= new Item_datetime_typecast(a); break; + case ITEM_CAST_DECIMAL: + res= new Item_decimal_typecast(a, (len>0) ? len : 10, dec ? dec : 2); + break; case ITEM_CAST_CHAR: res= new Item_char_typecast(a, len, cs ? cs : current_thd->variables.collation_connection); diff --git a/sql/item_create.h b/sql/item_create.h index 1be33fef257..0a9af144ec0 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -28,7 +28,8 @@ Item *create_func_bit_length(Item* a); Item *create_func_coercibility(Item* a); Item *create_func_ceiling(Item* a); Item *create_func_char_length(Item* a); -Item *create_func_cast(Item *a, Cast_target cast_type, int len, CHARSET_INFO *cs); +Item *create_func_cast(Item *a, Cast_target cast_type, int len, int dec, + CHARSET_INFO *cs); Item *create_func_connection_id(void); Item *create_func_conv(Item* a, Item *b, Item *c); Item *create_func_cos(Item* a); diff --git a/sql/item_func.cc b/sql/item_func.cc index e1d81b2a37d..68654338cf6 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -194,6 +194,11 @@ bool Item_func::agg_arg_charsets(DTCollation &coll, } if ((*arg)->type() == FIELD_ITEM) ((Item_field *)(*arg))->no_const_subst= 1; + /* + We do not check conv->fixed, because Item_func_conv_charset which can + be return by safe_charset_converter can't be fixed at creation, also + it do not need tables (second argument) for name resolving + */ *arg= conv; conv->fix_fields(thd, 0, arg); } @@ -414,7 +419,6 @@ void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array, ref_pointer_array[el]= item; Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name); fields.push_front(item); - ref_pointer_array[el]= item; thd->change_item_tree(arg, new_item); } } @@ -519,15 +523,26 @@ Field *Item_func::tmp_table_field(TABLE *t_arg) case STRING_RESULT: res= make_string_field(t_arg); break; + case DECIMAL_RESULT: + res= new Field_new_decimal(max_length + (decimals?1:0), maybe_null, + name, t_arg, decimals); + break; case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } return res; } +my_decimal *Item_func::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed); + int2my_decimal(E_DEC_FATAL_ERROR, val_int(), unsigned_flag, decimal_value); + return decimal_value; +} + String *Item_real_func::val_str(String *str) { @@ -540,38 +555,97 @@ String *Item_real_func::val_str(String *str) } -String *Item_num_func::val_str(String *str) +void Item_func::fix_num_length_and_dec() { - DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) + decimals= 0; + for (uint i=0 ; i < arg_count ; i++) { - 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); + set_if_bigger(decimals, args[i]->decimals); } - else + max_length= float_length(decimals); +} + + +void Item_func_numhybrid::fix_num_length_and_dec() +{} + + +/* + Set max_length/decimals of function if function is fixed point and + result length/precision depends on argument ones + + SYNOPSIS + Item_func::count_decimal_length() +*/ + +void Item_func::count_decimal_length() +{ + uint32 length= 0; + decimals= 0; + for (uint i=0 ; i < arg_count ; i++) { - double nr= val_real(); - if (null_value) - return 0; /* purecov: inspected */ - str->set(nr,decimals,&my_charset_bin); + set_if_bigger(decimals, args[i]->decimals); + set_if_bigger(length, (args[i]->max_length - args[i]->decimals)); } - return str; + max_length= length; + length+= decimals; + if (length < max_length) // If previous operation gave overflow + max_length= UINT_MAX32; + else + max_length= length; } -void Item_func::fix_num_length_and_dec() +/* + Set max_length of if it is maximum length of its arguments + + SYNOPSIS + Item_func::count_only_length() +*/ + +void Item_func::count_only_length() { - decimals=0; + max_length= 0; + for (uint i=0 ; i < arg_count ; i++) + set_if_bigger(max_length, args[i]->max_length); +} + + +/* + Set max_length/decimals of function if function is floating point and + result length/precision depends on argument ones + + SYNOPSIS + Item_func::count_real_length() +*/ + +void Item_func::count_real_length() +{ + uint32 length= 0; + decimals= 0; + max_length= 0; for (uint i=0 ; i < arg_count ; i++) - set_if_bigger(decimals,args[i]->decimals); - max_length=float_length(decimals); + { + if (decimals != NOT_FIXED_DEC) + { + set_if_bigger(decimals, args[i]->decimals); + set_if_bigger(length, (args[i]->max_length - args[i]->decimals)); + } + set_if_bigger(max_length, args[i]->max_length); + } + if (decimals != NOT_FIXED_DEC) + { + max_length= length; + length+= decimals; + if (length < max_length) // If previous operation gave overflow + max_length= UINT_MAX32; + else + max_length= length; + } } + + void Item_func::signal_divide_by_null() { THD *thd= current_thd; @@ -602,45 +676,221 @@ String *Item_int_func::val_str(String *str) return str; } + /* - Change from REAL_RESULT (default) to INT_RESULT if both arguments are - integers + Check arguments here to determine result's type for function with two + arguments. + + SYNOPSIS + Item_num_op::find_num_type() */ void Item_num_op::find_num_type(void) { - if (args[0]->result_type() == INT_RESULT && - args[1]->result_type() == INT_RESULT) + DBUG_ENTER("Item_num_op::find_num_type"); + DBUG_PRINT("info", ("name %s", func_name())); + DBUG_ASSERT(arg_count == 2); + Item_result r0= args[0]->result_type(); + Item_result r1= args[1]->result_type(); + + if (r0 == REAL_RESULT || r1 == REAL_RESULT || + r0 == STRING_RESULT || r1 ==STRING_RESULT) + { + count_real_length(); + max_length= float_length(decimals); + hybrid_type= REAL_RESULT; + } + else if (r0 == DECIMAL_RESULT || r1 == DECIMAL_RESULT) { + hybrid_type= DECIMAL_RESULT; + result_precision(); + } + else if (r0 == INT_RESULT && r1 == INT_RESULT) + { + decimals= 0; hybrid_type=INT_RESULT; unsigned_flag=args[0]->unsigned_flag | args[1]->unsigned_flag; + result_precision(); } + DBUG_PRINT("info", ("Type: %s", + (hybrid_type == REAL_RESULT ? "REAL_RESULT" : + hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : + hybrid_type == INT_RESULT ? "INT_RESULT" : + "--ILLEGAL!!!--"))); + DBUG_VOID_RETURN; } -String *Item_num_op::val_str(String *str) + +/* + Set result type of function if it (type) is depends only on first argument + + 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()) + { + case INT_RESULT: + unsigned_flag=args[0]->unsigned_flag; + hybrid_type= INT_RESULT; + break; + case STRING_RESULT: + case REAL_RESULT: + hybrid_type= REAL_RESULT; + max_length= float_length(decimals); + break; + case DECIMAL_RESULT: + hybrid_type= DECIMAL_RESULT; + break; + default: + DBUG_ASSERT(0); + } + DBUG_PRINT("info", ("Type: %s", + (hybrid_type == REAL_RESULT ? "REAL_RESULT" : + hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : + hybrid_type == INT_RESULT ? "INT_RESULT" : + "--ILLEGAL!!!--"))); + DBUG_VOID_RETURN; +} + + +void Item_func_num1::fix_num_length_and_dec() +{ + decimals= args[0]->decimals; + max_length= args[0]->max_length; +} + + +void Item_func_numhybrid::fix_length_and_dec() +{ + fix_num_length_and_dec(); + find_num_type(); +} + + +String *Item_func_numhybrid::val_str(String *str) { DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) + switch (hybrid_type) { - longlong nr=val_int(); + case DECIMAL_RESULT: + { + my_decimal decimal_value, *val; + if (!(val= decimal_op(&decimal_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); + break; + } + case INT_RESULT: + { + longlong nr= int_op(); if (null_value) return 0; /* purecov: inspected */ if (!unsigned_flag) str->set(nr,&my_charset_bin); else str->set((ulonglong) nr,&my_charset_bin); + break; } - else + case REAL_RESULT: { - double nr= val_real(); + double nr=real_op(); if (null_value) return 0; /* purecov: inspected */ str->set(nr,decimals,&my_charset_bin); + break; + } + default: + DBUG_ASSERT(0); } return str; } +double Item_func_numhybrid::val_real() +{ + DBUG_ASSERT(fixed == 1); + switch (hybrid_type) + { + case DECIMAL_RESULT: + { + my_decimal decimal_value, *val; + if (!(val= decimal_op(&decimal_value))) + return 0.0; + double result; + my_decimal2double(E_DEC_FATAL_ERROR, val, &result); + return result; + } + case INT_RESULT: + return (double)int_op(); + case REAL_RESULT: + return real_op(); + default: + DBUG_ASSERT(0); + } + return 0.0; +} + + +longlong Item_func_numhybrid::val_int() +{ + DBUG_ASSERT(fixed == 1); + switch (hybrid_type) + { + case DECIMAL_RESULT: + { + my_decimal decimal_value, *val; + if (!(val= decimal_op(&decimal_value))) + return 0; + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result); + return result; + } + case INT_RESULT: + return int_op(); + case REAL_RESULT: + return (longlong)real_op(); + default: + DBUG_ASSERT(0); + } + return 0; +} + + +my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value) +{ + my_decimal *val= decimal_value; + DBUG_ASSERT(fixed == 1); + switch (hybrid_type) + { + case DECIMAL_RESULT: + val= decimal_op(decimal_value); + break; + case INT_RESULT: + { + longlong result= int_op(); + int2my_decimal(E_DEC_FATAL_ERROR, result, unsigned_flag, decimal_value); + break; + } + case REAL_RESULT: + { + double result= int_op(); + double2my_decimal(E_DEC_FATAL_ERROR, result, decimal_value); + break; + } + case STRING_RESULT: + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } + return val; +} + + void Item_func_signed::print(String *str) { str->append("cast(", 5); @@ -659,26 +909,83 @@ void Item_func_unsigned::print(String *str) } -double Item_func_plus::val_real() +String *Item_decimal_typecast::val_str(String *str) +{ + my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); + my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, &tmp_buf); + my_decimal2string(E_DEC_FATAL_ERROR, &tmp_buf, 0, 0, 0, str); + return str; +} + + +double Item_decimal_typecast::val_real() +{ + my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); + double res; + my_decimal2double(E_DEC_FATAL_ERROR, tmp, &res); + return res; +} + + +longlong Item_decimal_typecast::val_int() +{ + my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf); + longlong res; + my_decimal2int(E_DEC_FATAL_ERROR, tmp, unsigned_flag, &res); + return res; +} + + +my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec) +{ + my_decimal tmp_buf, *tmp= args[0]->val_decimal(&tmp_buf); + my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, dec); + return dec; +} + + +double Item_func_plus::real_op() { - DBUG_ASSERT(fixed == 1); double value= args[0]->val_real() + args[1]->val_real(); if ((null_value=args[0]->null_value || args[1]->null_value)) return 0.0; return value; } -longlong Item_func_plus::val_int() + +longlong Item_func_plus::int_op() { - DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) - { - longlong value=args[0]->val_int()+args[1]->val_int(); - if ((null_value=args[0]->null_value || args[1]->null_value)) - return 0; - return value; - } - return (longlong) Item_func_plus::val_real(); + longlong value=args[0]->val_int()+args[1]->val_int(); + if ((null_value=args[0]->null_value || args[1]->null_value)) + return 0; + return value; +} + + +my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value) +{ + my_decimal value1, *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) + return 0; + return decimal_value; +} + +/* + Set precision of results for additive operations (+ and -) + + SYNOPSIS + Item_func_additive_op::result_precision() +*/ +void Item_func_additive_op::result_precision() +{ + decimals= max(args[0]->decimals, args[1]->decimals); + max_length= (max(args[0]->max_length - args[0]->decimals, + args[1]->max_length - args[1]->decimals) + + decimals + 1); } @@ -696,53 +1003,80 @@ void Item_func_minus::fix_length_and_dec() } -double Item_func_minus::val_real() +double Item_func_minus::real_op() { - DBUG_ASSERT(fixed == 1); double value= args[0]->val_real() - args[1]->val_real(); if ((null_value=args[0]->null_value || args[1]->null_value)) return 0.0; return value; } -longlong Item_func_minus::val_int() + +longlong Item_func_minus::int_op() { - DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) - { - longlong value=args[0]->val_int() - args[1]->val_int(); - if ((null_value=args[0]->null_value || args[1]->null_value)) - return 0; - return value; - } - return (longlong) Item_func_minus::val_real(); + longlong value=args[0]->val_int() - args[1]->val_int(); + if ((null_value=args[0]->null_value || args[1]->null_value)) + return 0; + return value; } -double Item_func_mul::val_real() +my_decimal *Item_func_minus::decimal_op(my_decimal *decimal_value) +{ + my_decimal value1, *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) + return 0; + return decimal_value; +} + + +double Item_func_mul::real_op() { DBUG_ASSERT(fixed == 1); double value= args[0]->val_real() * args[1]->val_real(); if ((null_value=args[0]->null_value || args[1]->null_value)) - return 0.0; /* purecov: inspected */ + return 0.0; return value; } -longlong Item_func_mul::val_int() + +longlong Item_func_mul::int_op() { DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) - { - longlong value=args[0]->val_int()*args[1]->val_int(); - if ((null_value=args[0]->null_value || args[1]->null_value)) - return 0; /* purecov: inspected */ - return value; - } - return (longlong) Item_func_mul::val_real(); + longlong value=args[0]->val_int()*args[1]->val_int(); + if ((null_value=args[0]->null_value || args[1]->null_value)) + return 0; + return value; +} + + +my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value) +{ + my_decimal value1, *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) + return 0; + return decimal_value; +} + + +void Item_func_mul::result_precision() +{ + decimals= args[0]->decimals + args[1]->decimals; + max_length= ((args[0]->max_length - args[0]->decimals) + + (args[1]->max_length - args[1]->decimals) + + decimals); } -double Item_func_div::val_real() +double Item_func_div::real_op() { DBUG_ASSERT(fixed == 1); double value= args[0]->val_real(); @@ -758,34 +1092,66 @@ double Item_func_div::val_real() } -longlong Item_func_div::val_int() +my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value) { - DBUG_ASSERT(fixed == 1); - if (hybrid_type == INT_RESULT) + my_decimal value1, *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)) + return 0; + switch (my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value, + val1, val2, DECIMAL_DIV_SCALE_INCREASE)) { - longlong value=args[0]->val_int(); - longlong val2=args[1]->val_int(); - if ((null_value= args[0]->null_value || args[1]->null_value)) - return 0; - if (val2 == 0) - { - signal_divide_by_null(); - return 0; - } - return value/val2; + case E_DEC_TRUNCATED: + case E_DEC_OK: + return decimal_value; + case E_DEC_DIV_ZERO: + signal_divide_by_null(); + default: + return 0; } - return (longlong) Item_func_div::val_real(); +} + + +void Item_func_div::result_precision() +{ + decimals= (args[0]->decimals + args[0]->decimals + + DECIMAL_DIV_SCALE_INCREASE); + max_length= ((args[0]->max_length - args[0]->decimals) + + (args[1]->max_length - args[1]->decimals) + + decimals); } void Item_func_div::fix_length_and_dec() { - decimals=max(args[0]->decimals,args[1]->decimals)+2; - set_if_smaller(decimals, NOT_FIXED_DEC); - max_length=args[0]->max_length - args[0]->decimals + decimals; - uint tmp=float_length(decimals); - set_if_smaller(max_length,tmp); - maybe_null=1; + DBUG_ENTER("Item_func_div::fix_length_and_dec"); + Item_num_op::fix_length_and_dec(); + switch(hybrid_type) + { + case REAL_RESULT: + { + decimals=max(args[0]->decimals,args[1]->decimals)+2; + set_if_smaller(decimals, NOT_FIXED_DEC); + max_length=args[0]->max_length - args[0]->decimals + decimals; + uint tmp=float_length(decimals); + set_if_smaller(max_length,tmp); + break; + } + case INT_RESULT: + hybrid_type= DECIMAL_RESULT; + DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT")); + result_precision(); + break; + case DECIMAL_RESULT: + result_precision(); + break; + default: + DBUG_ASSERT(0); + } + maybe_null= 1; // devision by zero + DBUG_VOID_RETURN; } @@ -808,15 +1174,43 @@ 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() { - find_num_type(); max_length=args[0]->max_length - args[0]->decimals; maybe_null=1; + unsigned_flag=args[0]->unsigned_flag | args[1]->unsigned_flag; } -double Item_func_mod::val_real() +longlong Item_func_mod::int_op() +{ + DBUG_ASSERT(fixed == 1); + longlong value= args[0]->val_int(); + longlong val2= args[1]->val_int(); + if ((null_value= args[0]->null_value || args[1]->null_value)) + return 0; /* purecov: inspected */ + if (val2 == 0) + { + signal_divide_by_null(); + return 0; + } + return value % val2; +} + +double Item_func_mod::real_op() { DBUG_ASSERT(fixed == 1); double value= args[0]->val_real(); @@ -831,67 +1225,81 @@ double Item_func_mod::val_real() return fmod(value,val2); } -longlong Item_func_mod::val_int() + +my_decimal *Item_func_mod::decimal_op(my_decimal *decimal_value) { - DBUG_ASSERT(fixed == 1); - longlong value= args[0]->val_int(); - longlong val2= args[1]->val_int(); - if ((null_value= args[0]->null_value || args[1]->null_value)) - return 0; /* purecov: inspected */ - if (val2 == 0) + my_decimal value1, *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)) + return 0; + switch (my_decimal_mod(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value, + val1, val2)) { + case E_DEC_TRUNCATED: + case E_DEC_OK: + return decimal_value; + case E_DEC_DIV_ZERO: signal_divide_by_null(); + default: return 0; } - return value % val2; } -void Item_func_mod::fix_length_and_dec() + +void Item_func_mod::result_precision() { - Item_num_op::fix_length_and_dec(); + decimals= max(args[0]->decimals, args[1]->decimals); + max_length= max(args[0]->max_length, args[1]->max_length); } -double Item_func_neg::val_real() +double Item_func_neg::real_op() { - DBUG_ASSERT(fixed == 1); double value= args[0]->val_real(); - null_value=args[0]->null_value; + null_value= args[0]->null_value; return -value; } -longlong Item_func_neg::val_int() +longlong Item_func_neg::int_op() { - DBUG_ASSERT(fixed == 1); - longlong value=args[0]->val_int(); - null_value=args[0]->null_value; + longlong value= args[0]->val_int(); + null_value= args[0]->null_value; return -value; } -void Item_func_neg::fix_length_and_dec() +my_decimal *Item_func_neg::decimal_op(my_decimal *decimal_value) { - enum Item_result arg_result= args[0]->result_type(); - enum Item::Type arg_type= args[0]->type(); - decimals=args[0]->decimals; - max_length=args[0]->max_length; - hybrid_type= REAL_RESULT; - - /* - We need to account for added '-' in the following cases: - A) argument is a real or integer positive constant - in this case - argument's max_length is set to actual number of bytes occupied, and not - maximum number of bytes real or integer may require. Note that all - constants are non negative so we don't need to account for removed '-'. - B) argument returns a string. - */ - if (arg_result == STRING_RESULT || - (arg_type == REAL_ITEM && ((Item_real*)args[0])->value >= 0) || - (arg_type == INT_ITEM && ((Item_int*)args[0])->value > 0)) - max_length++; + my_decimal val, *value= args[0]->val_decimal(&val); + if (!(null_value= args[0]->null_value)) + { + my_decimal2decimal(value, decimal_value); + my_decimal_neg(decimal_value); + } + return decimal_value; +} + + +void Item_func_neg::fix_num_length_and_dec() +{ + decimals= args[0]->decimals; + /* 1 add because sign can appear */ + max_length= args[0]->max_length + 1; + unsigned_flag= 0; +} - if (args[0]->result_type() == INT_RESULT) + +void Item_func_signproc::fix_length_and_dec() +{ + DBUG_ENTER("Item_func_signproc::fix_length_and_dec"); + Item_func_num1::fix_length_and_dec(); + 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 @@ -903,42 +1311,47 @@ void Item_func_neg::fix_length_and_dec() (This is needed because the lex parser doesn't anymore handle signed integers) */ - if (args[0]->type() != INT_ITEM || - ((ulonglong) ((Item_uint*) args[0])->value <= - (ulonglong) LONGLONG_MIN)) - hybrid_type= INT_RESULT; + hybrid_type= DECIMAL_RESULT; + DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT")); } + DBUG_VOID_RETURN; } -double Item_func_abs::val_real() +double Item_func_abs::real_op() { - DBUG_ASSERT(fixed == 1); double value= args[0]->val_real(); - null_value=args[0]->null_value; + null_value= args[0]->null_value; return fabs(value); } -longlong Item_func_abs::val_int() +longlong Item_func_abs::int_op() { - DBUG_ASSERT(fixed == 1); - longlong value=args[0]->val_int(); - null_value=args[0]->null_value; + longlong value= args[0]->val_int(); + null_value= args[0]->null_value; return value >= 0 ? value : -value; } -void Item_func_abs::fix_length_and_dec() +my_decimal *Item_func_abs::decimal_op(my_decimal *decimal_value) { - decimals=args[0]->decimals; - max_length=args[0]->max_length; - hybrid_type= REAL_RESULT; - if (args[0]->result_type() == INT_RESULT) + my_decimal val, *value= args[0]->val_decimal(&val); + if (!(null_value= args[0]->null_value)) { - hybrid_type= INT_RESULT; - unsigned_flag= 1; + my_decimal2decimal(value, decimal_value); + if (decimal_value->sign()) + my_decimal_neg(decimal_value); } + return decimal_value; +} + + +void Item_func_abs::fix_length_and_dec() +{ + Item_func_num1::fix_length_and_dec(); + if (hybrid_type == INT_RESULT) + unsigned_flag= 1; } @@ -1139,42 +1552,148 @@ void Item_func_integer::fix_length_and_dec() decimals=0; } -longlong Item_func_ceiling::val_int() +void Item_func_int_val::fix_num_length_and_dec() { - DBUG_ASSERT(fixed == 1); - double value= args[0]->val_real(); - null_value=args[0]->null_value; + max_length= args[0]->max_length - (args[0]->decimals ? + args[0]->decimals + 1 : + 0) + 2; + uint tmp= float_length(decimals); + set_if_smaller(max_length,tmp); + decimals= 0; +} + + +void Item_func_int_val::find_num_type() +{ + DBUG_ENTER("Item_func_int_val::find_num_type"); + DBUG_PRINT("info", ("name %s", func_name())); + switch(hybrid_type= args[0]->result_type()) + { + case STRING_RESULT: + case REAL_RESULT: + hybrid_type= REAL_RESULT; + max_length= float_length(decimals); + break; + case INT_RESULT: + case DECIMAL_RESULT: + /* + -2 because in most high position can't be used any digit for longlong + and one position for increasing value during operation + */ + if ((args[0]->max_length - args[0]->decimals) >= + (DECIMAL_LONGLONG_DIGITS - 2)) + { + hybrid_type= DECIMAL_RESULT; + } + else + { + unsigned_flag= args[0]->unsigned_flag; + hybrid_type= INT_RESULT; + } + break; + default: + DBUG_ASSERT(0); + } + DBUG_PRINT("info", ("Type: %s", + (hybrid_type == REAL_RESULT ? "REAL_RESULT" : + hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : + hybrid_type == INT_RESULT ? "INT_RESULT" : + "--ILLEGAL!!!--"))); + + DBUG_VOID_RETURN; +} + + +longlong Item_func_ceiling::int_op() +{ + /* + the volatile's for BUG #3051 to calm optimizer down (because of gcc's + bug) + */ + volatile double value= args[0]->val_real(); + null_value= args[0]->null_value; return (longlong) ceil(value); } -longlong Item_func_floor::val_int() + +double Item_func_ceiling::real_op() { - DBUG_ASSERT(fixed == 1); - // the volatile's for BUG #3051 to calm optimizer down (because of gcc's bug) + /* + the volatile's for BUG #3051 to calm optimizer down (because of gcc's + bug) + */ volatile double value= args[0]->val_real(); - null_value=args[0]->null_value; + null_value= args[0]->null_value; + return ceil(value); +} + + +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) + return 0; + return decimal_value; +} + + +longlong Item_func_floor::int_op() +{ + /* + the volatile's for BUG #3051 to calm optimizer down (because of gcc's + bug) + */ + volatile double value= args[0]->val_real(); + null_value= args[0]->null_value; return (longlong) floor(value); } -void Item_func_round::fix_length_and_dec() + +double Item_func_floor::real_op() { - max_length=args[0]->max_length; - decimals=args[0]->decimals; + /* + the volatile's for BUG #3051 to calm optimizer down (because of gcc's + bug) + */ + volatile double value= args[0]->val_real(); + null_value= args[0]->null_value; + return floor(value); +} + + +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) + return 0; + return decimal_value; +} + + +void Item_func_round::fix_num_length_and_dec() +{ + max_length= args[0]->max_length; + decimals= NOT_FIXED_DEC; if (args[1]->const_item()) { int tmp=(int) args[1]->val_int(); if (tmp < 0) decimals=0; else - decimals=min(tmp,NOT_FIXED_DEC); + decimals=min(tmp, NOT_FIXED_DEC); } } -double Item_func_round::val_real() +double Item_func_round::real_op() { - DBUG_ASSERT(fixed == 1); double value= args[0]->val_real(); int dec=(int) args[1]->val_int(); + if (dec > 0) + decimals= dec; // to get correct output uint abs_dec=abs(dec); double tmp; /* @@ -1201,6 +1720,58 @@ double Item_func_round::val_real() } +longlong Item_func_round::int_op() +{ + longlong value= args[0]->val_int(); + int dec=(int) args[1]->val_int(); + decimals= 0; + uint abs_dec; + if ((null_value= args[0]->null_value || args[1]->null_value)) + return 0; + if (dec >= 0) + return value; // integer have not digits after point + + abs_dec= -dec; + double tmp; + /* + tmp2 is here to avoid return the value with 80 bit precision + This will fix that the test round(0.1,1) = round(0.1,1) is true + */ + volatile double tmp2; + + tmp= (abs_dec < array_elements(log_10) ? + log_10[abs_dec] : pow(10.0, (double) abs_dec)); + + if (truncate) + { + if (unsigned_flag) + tmp2= floor(((double)((ulonglong)value))/tmp)*tmp; + else if (value >= 0) + tmp2= floor(((double)value)/tmp)*tmp; + else + tmp2= ceil(((double)value)/tmp)*tmp; + } + else + tmp2= rint(((double)value)/tmp)*tmp; + return (longlong)tmp2; +} + + +my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value) +{ + my_decimal val, *value= args[0]->val_decimal(&val); + 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) + return 0; + return decimal_value; +} + + bool Item_func_rand::fix_fields(THD *thd, struct st_table_list *tables, Item **ref) { @@ -1291,10 +1862,8 @@ void Item_func_min_max::fix_length_and_dec() for (uint i=0 ; i < arg_count ; i++) { - if (max_length < args[i]->max_length) - max_length=args[i]->max_length; - if (decimals < args[i]->decimals) - decimals=args[i]->decimals; + set_if_bigger(max_length, args[i]->max_length); + set_if_bigger(decimals, args[i]->decimals); if (!args[i]->maybe_null) maybe_null=0; cmp_type=item_cmp_type(cmp_type,args[i]->result_type()); @@ -1319,6 +1888,14 @@ String *Item_func_min_max::val_str(String *str) str->set((ulonglong) nr,&my_charset_bin); return str; } + case DECIMAL_RESULT: + { + my_decimal dec_buf, *dec_val= val_decimal(&dec_buf); + if (null_value) + return 0; + my_decimal2string(E_DEC_FATAL_ERROR, dec_val, 0, 0, 0, str); + return str; + } case REAL_RESULT: { double nr= val_real(); @@ -1357,7 +1934,7 @@ String *Item_func_min_max::val_str(String *str) } case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); return 0; } @@ -1410,6 +1987,40 @@ longlong Item_func_min_max::val_int() return value; } + +my_decimal *Item_func_min_max::val_decimal(my_decimal *dec) +{ + DBUG_ASSERT(fixed == 1); + my_decimal tmp_buf, *tmp, *res= NULL; + null_value=1; + for (uint i=0; i < arg_count ; i++) + { + if (null_value) + { + res= args[i]->val_decimal(dec); + null_value= args[i]->null_value; + } + else + { + tmp= args[i]->val_decimal(&tmp_buf); + if (args[i]->null_value) + continue; + if ((my_decimal_cmp(tmp, res) * cmp_sign) < 0) + { + if (tmp == &tmp_buf) + { + my_decimal2decimal(tmp, dec); + res= dec; + } + else + res= tmp; + } + } + } + return res; +} + + longlong Item_func_length::val_int() { DBUG_ASSERT(fixed == 1); @@ -1533,6 +2144,21 @@ longlong Item_func_field::val_int() return (longlong) (i); } } + else if (cmp_type == DECIMAL_RESULT) + { + my_decimal dec_arg_buf, *dec_arg, + dec_buf, *dec= args[0]->val_decimal(&dec_buf); + if (args[0]->is_null()) + return 0; + 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)) + return (longlong) (i); + } + } else { double val= args[0]->val_real(); @@ -1776,7 +2402,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, arg != arg_end ; arg++,i++) { - if (!(*arg)->fixed && + if (!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg)) DBUG_RETURN(1); // we can't assign 'item' before, because fix_fields() can change arg @@ -1792,7 +2418,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, Moreover, some arguments can represent a numeric input which doesn't effect the result character set and collation. There is no a general rule for UDF. Everything depends on - the particular user definted function. + the particular user defined function. */ if (item->collation.collation->state & MY_CS_BINSORT) func->collation.set(&my_charset_bin); @@ -1803,7 +2429,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, const_item_cache&=item->const_item(); f_args.arg_type[i]=item->result_type(); } - //TODO: why all folowing memory is not allocated with 1 call of sql_alloc? + //TODO: why all following memory is not allocated with 1 call of sql_alloc? if (!(buffers=new String[arg_count]) || !(f_args.args= (char**) sql_alloc(arg_count * sizeof(char *))) || !(f_args.lengths= (ulong*) sql_alloc(arg_count * sizeof(long))) || @@ -1903,6 +2529,7 @@ bool udf_handler::get_arguments() f_args.args[i]=0; switch (f_args.arg_type[i]) { case STRING_RESULT: + case DECIMAL_RESULT: { String *res=args[i]->val_str(&buffers[str_count++]); if (!(args[i]->null_value)) @@ -1930,7 +2557,7 @@ bool udf_handler::get_arguments() break; case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } @@ -1975,6 +2602,31 @@ String *udf_handler::val_str(String *str,String *save_str) } +my_decimal *udf_handler::val_decimal(my_bool *null_value, my_decimal *dec_buf) +{ + char buf[DECIMAL_MAX_STR_LENGTH+1], *end; + ulong res_length= DECIMAL_MAX_STR_LENGTH; + + if (get_arguments()) + { + *null_value=1; + return 0; + } + char *(*func)(UDF_INIT *, UDF_ARGS *, char *, ulong *, uchar *, uchar *)= + (char* (*)(UDF_INIT *, UDF_ARGS *, char *, ulong *, uchar *, uchar *)) + u_d->func; + + char *res= func(&initid, &f_args, buf, &res_length, &is_null, &error); + if (is_null || error) + { + *null_value= 1; + return 0; + } + buf[res_length]= 0; + str2my_decimal(E_DEC_FATAL_ERROR, buf, dec_buf, &end); + return dec_buf; +} + double Item_func_udf_float::val_real() { @@ -2021,6 +2673,59 @@ String *Item_func_udf_int::val_str(String *str) return str; } + +longlong Item_func_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; +} + + +double Item_func_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; +} + + +my_decimal *Item_func_udf_decimal::val_decimal(my_decimal *dec_buf) +{ + DBUG_ASSERT(fixed == 1); + DBUG_ENTER("Item_func_udf_decimal::val_decimal"); + DBUG_PRINT("info",("result_type: %d arg_count: %d", + args[0]->result_type(), arg_count)); + + DBUG_RETURN(udf.val_decimal(&null_value, dec_buf)); +} + + +String *Item_func_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; +} + + +void Item_func_udf_decimal::fix_length_and_dec() +{ + fix_num_length_and_dec(); +} + + /* Default max_length is max argument length */ void Item_func_udf_str::fix_length_and_dec() @@ -2417,7 +3122,7 @@ longlong Item_func_benchmark::val_int() break; case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); return 0; } @@ -2583,6 +3288,8 @@ bool Item_func_set_user_var::update_hash(void *ptr, uint length, entry->value[length]= 0; // Store end \0 } memcpy(entry->value,ptr,length); + if (type == DECIMAL_RESULT) + ((my_decimal*)entry->value)->fix_buffer_pointer(); entry->length= length; entry->type=type; entry->collation.set(cs, dv); @@ -2598,7 +3305,7 @@ bool Item_func_set_user_var::update_hash(void *ptr, uint length, /* Get the value of a variable as a double */ -double user_var_entry::val(my_bool *null_value) +double user_var_entry::val_real(my_bool *null_value) { if ((*null_value= (value == 0))) return 0.0; @@ -2608,6 +3315,12 @@ double user_var_entry::val(my_bool *null_value) return *(double*) value; case INT_RESULT: return (double) *(longlong*) value; + case DECIMAL_RESULT: + { + double result; + my_decimal2double(E_DEC_FATAL_ERROR, (my_decimal *)value, &result); + return result; + } case STRING_RESULT: return my_atof(value); // This is null terminated case ROW_RESULT: @@ -2630,6 +3343,12 @@ longlong user_var_entry::val_int(my_bool *null_value) return (longlong) *(double*) value; case INT_RESULT: return *(longlong*) value; + case DECIMAL_RESULT: + { + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, (my_decimal *)value, 1, &result); + return result; + } case STRING_RESULT: { int error; @@ -2658,6 +3377,9 @@ String *user_var_entry::val_str(my_bool *null_value, String *str, case INT_RESULT: str->set(*(longlong*) value, &my_charset_bin); break; + case DECIMAL_RESULT: + my_decimal2string(E_DEC_FATAL_ERROR, (my_decimal *)value, 0, 0, 0, str); + break; case STRING_RESULT: if (str->copy(value, length, collation.collation)) str= 0; // EOM error @@ -2668,16 +3390,43 @@ String *user_var_entry::val_str(my_bool *null_value, String *str, return(str); } +/* Get the value of a variable as a decimal */ + +my_decimal *user_var_entry::val_decimal(my_bool *null_value, my_decimal *val) +{ + if ((*null_value= (value == 0))) + return 0; + + switch (type) { + case REAL_RESULT: + double2my_decimal(E_DEC_FATAL_ERROR, *(double*) value, val); + break; + case INT_RESULT: + int2my_decimal(E_DEC_FATAL_ERROR, *(longlong*) value, 0, val); + break; + case DECIMAL_RESULT: + val= (my_decimal *)value; + break; + case STRING_RESULT: + str2my_decimal(E_DEC_FATAL_ERROR, value, length, collation.collation, val); + break; + case ROW_RESULT: + DBUG_ASSERT(1); // Impossible + break; + } + return(val); +} + /* This functions is invoked on SET @variable or @variable:= expression. - Evaluete (and check expression), store results. + Evaluate (and check expression), store results. SYNOPSYS Item_func_set_user_var::check() NOTES - For now it always return OK. All problem with value evalueting - will be catched by thd->net.report_error check in sql_set_variables(). + For now it always return OK. All problem with value evaluating + will be caught by thd->net.report_error check in sql_set_variables(). RETURN FALSE OK. @@ -2704,9 +3453,14 @@ Item_func_set_user_var::check() save_result.vstr= args[0]->val_str(&value); break; } + case DECIMAL_RESULT: + { + save_result.vdec= args[0]->val_decimal(&decimal_buff); + break; + } case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } @@ -2725,7 +3479,7 @@ Item_func_set_user_var::check() the value method used by the user RETURN - 0 Ok + 0 OK 1 EOM Error */ @@ -2762,9 +3516,20 @@ Item_func_set_user_var::update() args[0]->collation.derivation); break; } + case DECIMAL_RESULT: + { + if (!save_result.vdec) // Null value + res= update_hash((void*) 0, 0, DECIMAL_RESULT, &my_charset_bin, + DERIVATION_NONE); + else + res= update_hash((void*) save_result.vdec, + sizeof(my_decimal), DECIMAL_RESULT, + &my_charset_bin, DERIVATION_NONE); + break; + } case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } @@ -2777,7 +3542,7 @@ double Item_func_set_user_var::val_real() DBUG_ASSERT(fixed == 1); check(); update(); // Store expression - return entry->val(&null_value); + return entry->val_real(&null_value); } longlong Item_func_set_user_var::val_int() @@ -2797,6 +3562,15 @@ String *Item_func_set_user_var::val_str(String *str) } +my_decimal *Item_func_set_user_var::val_decimal(my_decimal *val) +{ + DBUG_ASSERT(fixed == 1); + check(); + update(); // Store expression + return entry->val_decimal(&null_value, val); +} + + void Item_func_set_user_var::print(String *str) { str->append("(@", 2); @@ -2833,7 +3607,16 @@ double Item_func_get_user_var::val_real() DBUG_ASSERT(fixed == 1); if (!var_entry) return 0.0; // No such variable - return (var_entry->val(&null_value)); + return (var_entry->val_real(&null_value)); +} + + +my_decimal *Item_func_get_user_var::val_decimal(my_decimal *dec) +{ + DBUG_ASSERT(fixed == 1); + if (!var_entry) + return 0; + return var_entry->val_decimal(&null_value, dec); } @@ -2864,7 +3647,7 @@ longlong Item_func_get_user_var::val_int() RETURN 0 OK - 1 Failed to put appropiate record into binary log + 1 Failed to put appropriate record into binary log */ @@ -2888,8 +3671,8 @@ int get_var_with_binlog(THD *thd, LEX_STRING &name, that it gets into the binlog (if it didn't, the slave could be influenced by a variable of the same name previously set by another thread). - We create it like if it had been explicitely set with SET before. - The 'new' mimicks what sql_yacc.yy does when 'SET @a=10;'. + We create it like if it had been explicitly set with SET before. + The 'new' mimics what sql_yacc.yy does when 'SET @a=10;'. sql_set_variables() is what is called from 'case SQLCOM_SET_OPTION' in dispatch_command()). Instead of building a one-element list to pass to sql_set_variables(), we could instead manually call check() and update(); @@ -2920,7 +3703,7 @@ int get_var_with_binlog(THD *thd, LEX_STRING &name, uint size; /* First we need to store value of var_entry, when the next situation - appers: + appears: > set @a:=1; > insert into t1 values (@a), (@a:=@a+1), (@a:=@a+1); We have to write to binlog value @a= 1; @@ -2982,7 +3765,13 @@ void Item_func_get_user_var::fix_length_and_dec() case STRING_RESULT: max_length= MAX_BLOB_WIDTH; break; + case DECIMAL_RESULT: + max_length= DECIMAL_MAX_LENGTH; + decimals= min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1); + break; case ROW_RESULT: // Keep compiler happy + default: + DBUG_ASSERT(0); break; } } @@ -3539,7 +4328,7 @@ const char * Item_func_sp::func_name() const { THD *thd= current_thd; - /* Calculate length to avoud reallocation of string for sure */ + /* Calculate length to avoid reallocation of string for sure */ uint len= ((m_name->m_db.length + m_name->m_name.length)*2 + //characters*quoting 2 + // ` and ` @@ -3590,7 +4379,7 @@ Item_func_sp::execute(Item **itp) #endif /* - We don't need to surpress senfing of ok packet here (by setting + We don't need to suppress sending of OK packet here (by setting thd->net.no_send_ok to true), because we are not allowing statements in functions now. */ @@ -3663,9 +4452,13 @@ Item_func_sp::fix_length_and_dec() decimals= 0; max_length= 21; break; + case DECIMAL_RESULT: + // TODO: where to find real precision and scale? + decimals= min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1); + max_length= DECIMAL_MAX_LENGTH; case ROW_RESULT: default: - // This case should never be choosen + // This case should never be chosen DBUG_ASSERT(0); break; } diff --git a/sql/item_func.h b/sql/item_func.h index a3618cca23e..20f70fce575 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -133,7 +133,10 @@ public: void print(String *str); void print_op(String *str); void print_args(String *str, uint from); - void fix_num_length_and_dec(); + virtual void fix_num_length_and_dec(); + void count_only_length(); + void count_real_length(); + void count_decimal_length(); inline bool get_arg0_date(TIME *ltime, uint fuzzy_date) { return (null_value=args[0]->get_date(ltime, fuzzy_date)); @@ -148,7 +151,9 @@ public: Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg); Item *get_tmp_table_item(THD *thd); - + + my_decimal *val_decimal(my_decimal *); + bool agg_arg_collations(DTCollation &c, Item **items, uint nitems, uint flags= 0); bool agg_arg_collations_for_comparison(DTCollation &c, @@ -172,49 +177,70 @@ public: longlong val_int() { DBUG_ASSERT(fixed == 1); return (longlong) val_real(); } enum Item_result result_type () const { return REAL_RESULT; } - void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); } + void fix_length_and_dec() + { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); } }; -class Item_num_func :public Item_func +class Item_func_numhybrid: public Item_func { - protected: +protected: Item_result hybrid_type; public: - Item_num_func(Item *a) :Item_func(a),hybrid_type(REAL_RESULT) {} - Item_num_func(Item *a,Item *b) :Item_func(a,b),hybrid_type(REAL_RESULT) {} - String *val_str(String*str); - longlong val_int() - { DBUG_ASSERT(fixed == 1); return (longlong) val_real(); } + Item_func_numhybrid(Item *a) :Item_func(a),hybrid_type(REAL_RESULT) + {} + Item_func_numhybrid(Item *a,Item *b) + :Item_func(a,b),hybrid_type(REAL_RESULT) + {} + enum Item_result result_type () const { return hybrid_type; } - void fix_length_and_dec() { fix_num_length_and_dec(); } + void fix_length_and_dec(); + void fix_num_length_and_dec(); + virtual void find_num_type()= 0; /* To be called from fix_length_and_dec */ + + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal *); + String *val_str(String*str); + + virtual longlong int_op()= 0; + virtual double real_op()= 0; + virtual my_decimal *decimal_op(my_decimal *)= 0; bool is_null() { (void) val_real(); return null_value; } }; +/* function where type of result detected by first argument */ +class Item_func_num1: public Item_func_numhybrid +{ +public: + Item_func_num1(Item *a) :Item_func_numhybrid(a) {} + Item_func_num1(Item *a, Item *b) :Item_func_numhybrid(a, b) {} -class Item_num_op :public Item_func + void fix_num_length_and_dec(); + void find_num_type(); +}; + + +/* Base class for operations like '+', '-', '*' */ +class Item_num_op :public Item_func_numhybrid { - protected: - Item_result hybrid_type; public: - Item_num_op(Item *a,Item *b) :Item_func(a,b),hybrid_type(REAL_RESULT) {} - String *val_str(String*str); + Item_num_op(Item *a,Item *b) :Item_func_numhybrid(a, b) {} + virtual void result_precision()= 0; void print(String *str) { print_op(str); } - enum Item_result result_type () const { return hybrid_type; } - void fix_length_and_dec() { fix_num_length_and_dec(); find_num_type(); } - void find_num_type(void); - bool is_null() { (void) val_real(); return null_value; } + void find_num_type(); }; class Item_int_func :public Item_func { public: - Item_int_func() :Item_func() { max_length=21; } - Item_int_func(Item *a) :Item_func(a) { max_length=21; } - Item_int_func(Item *a,Item *b) :Item_func(a,b) { max_length=21; } - Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) { max_length=21; } - Item_int_func(List<Item> &list) :Item_func(list) { max_length=21; } + Item_int_func() :Item_func() { max_length= 21; } + Item_int_func(Item *a) :Item_func(a) { max_length= 21; } + Item_int_func(Item *a,Item *b) :Item_func(a,b) { max_length= 21; } + Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) + { max_length= 21; } + Item_int_func(List<Item> &list) :Item_func(list) { max_length= 21; } Item_int_func(THD *thd, Item_int_func *item) :Item_func(thd, item) {} double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); } String *val_str(String*str); @@ -257,22 +283,51 @@ public: }; -class Item_func_plus :public Item_num_op +class Item_decimal_typecast :public Item_func { + my_decimal decimal_value; public: - Item_func_plus(Item *a,Item *b) :Item_num_op(a,b) {} - const char *func_name() const { return "+"; } + Item_decimal_typecast(Item *a, int len, int dec) :Item_func(a) + { + max_length= len + 2; + decimals= dec; + } + String *val_str(String *str); double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal*); + enum Item_result result_type () const { return DECIMAL_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_DECIMAL; } + void fix_length_and_dec() {}; +}; + + +class Item_func_additive_op :public Item_num_op +{ +public: + Item_func_additive_op(Item *a,Item *b) :Item_num_op(a,b) {} + void result_precision(); +}; + + +class Item_func_plus :public Item_func_additive_op +{ +public: + Item_func_plus(Item *a,Item *b) :Item_func_additive_op(a,b) {} + const char *func_name() const { return "+"; } + longlong int_op(); + double real_op(); + my_decimal *decimal_op(my_decimal *); }; -class Item_func_minus :public Item_num_op +class Item_func_minus :public Item_func_additive_op { public: - Item_func_minus(Item *a,Item *b) :Item_num_op(a,b) {} + Item_func_minus(Item *a,Item *b) :Item_func_additive_op(a,b) {} const char *func_name() const { return "-"; } - double val_real(); - longlong val_int(); + longlong int_op(); + double real_op(); + my_decimal *decimal_op(my_decimal *); void fix_length_and_dec(); }; @@ -282,8 +337,10 @@ class Item_func_mul :public Item_num_op public: Item_func_mul(Item *a,Item *b) :Item_num_op(a,b) {} const char *func_name() const { return "*"; } - double val_real(); - longlong val_int(); + longlong int_op(); + double real_op(); + my_decimal *decimal_op(my_decimal *); + void result_precision(); }; @@ -291,22 +348,27 @@ class Item_func_div :public Item_num_op { public: Item_func_div(Item *a,Item *b) :Item_num_op(a,b) {} - double val_real(); - longlong val_int(); + longlong int_op() { DBUG_ASSERT(0); } + double real_op(); + my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "/"; } void fix_length_and_dec(); + void result_precision(); }; -class Item_func_int_div :public Item_num_op +class Item_func_int_div :public Item_func { public: - Item_func_int_div(Item *a,Item *b) :Item_num_op(a,b) - { hybrid_type=INT_RESULT; } + Item_func_int_div(Item *a,Item *b) :Item_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; } }; @@ -314,37 +376,47 @@ class Item_func_mod :public Item_num_op { public: Item_func_mod(Item *a,Item *b) :Item_num_op(a,b) {} - double val_real(); - longlong val_int(); + longlong int_op(); + double real_op(); + my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "%"; } + void result_precision(); +}; + + +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_num_func +class Item_func_neg :public Item_func_signproc { public: - Item_func_neg(Item *a) :Item_num_func(a) {} - double val_real(); - longlong val_int(); + Item_func_neg(Item *a) :Item_func_signproc(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(); }; -class Item_func_abs :public Item_num_func +class Item_func_abs :public Item_func_num1 { public: - Item_func_abs(Item *a) :Item_num_func(a) {} + Item_func_abs(Item *a) :Item_func_num1(a) {} + double real_op(); + longlong int_op(); + my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "abs"; } - double val_real(); - longlong val_int(); - enum Item_result result_type () const - { return args[0]->result_type() == INT_RESULT ? INT_RESULT : REAL_RESULT; } void fix_length_and_dec(); }; -// A class to handle logaritmic and trigometric functions +// A class to handle logarithmic and trigonometric functions class Item_dec_func :public Item_real_func { @@ -491,34 +563,49 @@ public: }; -class Item_func_ceiling :public Item_func_integer +class Item_func_int_val :public Item_func_num1 +{ +public: + Item_func_int_val(Item *a) :Item_func_num1(a) {} + void fix_num_length_and_dec(); + void find_num_type(); +}; + + +class Item_func_ceiling :public Item_func_int_val { - Item_func_ceiling(); /* Never called */ public: - Item_func_ceiling(Item *a) :Item_func_integer(a) {} + Item_func_ceiling(Item *a) :Item_func_int_val(a) {} const char *func_name() const { return "ceiling"; } - longlong val_int(); + longlong int_op(); + double real_op(); + my_decimal *decimal_op(my_decimal *); }; -class Item_func_floor :public Item_func_integer + +class Item_func_floor :public Item_func_int_val { public: - Item_func_floor(Item *a) :Item_func_integer(a) {} + Item_func_floor(Item *a) :Item_func_int_val(a) {} const char *func_name() const { return "floor"; } - longlong val_int(); + longlong int_op(); + double real_op(); + my_decimal *decimal_op(my_decimal *); }; /* This handles round and truncate */ -class Item_func_round :public Item_real_func +class Item_func_round :public Item_func_num1 { bool truncate; public: - Item_func_round(Item *a,Item *b,bool trunc_arg) - :Item_real_func(a,b),truncate(trunc_arg) {} + Item_func_round(Item *a, Item *b, bool trunc_arg) + :Item_func_num1(a,b), truncate(trunc_arg) {} const char *func_name() const { return truncate ? "truncate" : "round"; } - double val_real(); - void fix_length_and_dec(); + double real_op(); + longlong int_op(); + my_decimal *decimal_op(my_decimal *); + void fix_num_length_and_dec(); }; @@ -554,7 +641,8 @@ class Item_func_units :public Item_real_func :Item_real_func(a),name(name_arg),mul(mul_arg),add(add_arg) {} double val_real(); const char *func_name() const { return name; } - void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); } + void fix_length_and_dec() + { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); } }; @@ -569,6 +657,7 @@ public: double val_real(); longlong val_int(); String *val_str(String *); + my_decimal *val_decimal(my_decimal *); void fix_length_and_dec(); enum Item_result result_type () const { return cmp_type; } table_map not_null_tables() const { return 0; } @@ -755,7 +844,11 @@ public: Item_func_last_insert_id(Item *a) :Item_int_func(a) {} longlong val_int(); const char *func_name() const { return "last_insert_id"; } - void fix_length_and_dec() { if (arg_count) max_length= args[0]->max_length; } + void fix_length_and_dec() + { + if (arg_count) + max_length= args[0]->max_length; + } }; class Item_func_benchmark :public Item_int_func @@ -809,6 +902,14 @@ class Item_func_udf_float :public Item_udf_func DBUG_ASSERT(fixed == 1); return (longlong) Item_func_udf_float::val_real(); } + my_decimal *val_decimal(my_decimal *dec_buf) + { + double res=val_real(); + if (null_value) + return NULL; + double2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf); + return dec_buf; + } double val_real(); String *val_str(String *str); void fix_length_and_dec() { fix_num_length_and_dec(); } @@ -825,7 +926,22 @@ public: double val_real() { return (double) Item_func_udf_int::val_int(); } String *val_str(String *str); enum Item_result result_type () const { return INT_RESULT; } - void fix_length_and_dec() { decimals=0; max_length=21; } + void fix_length_and_dec() { decimals= 0; max_length= 21; } +}; + + +class Item_func_udf_decimal :public Item_udf_func +{ +public: + Item_func_udf_decimal(udf_func *udf_arg) :Item_udf_func(udf_arg) {} + Item_func_udf_decimal(udf_func *udf_arg, List<Item> &list) + :Item_udf_func(udf_arg,list) {} + longlong val_int(); + double val_real(); + my_decimal *val_decimal(my_decimal *); + String *val_str(String *str); + enum Item_result result_type () const { return DECIMAL_RESULT; } + void fix_length_and_dec(); }; @@ -852,6 +968,14 @@ 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_buf) + { + String *res=val_str(&str_value); + if (!res) + return NULL; + string2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf); + return dec_buf; + } enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec(); }; @@ -876,6 +1000,15 @@ public: }; +class Item_func_udf_decimal :public Item_int_func +{ +public: + Item_func_udf_decimal(udf_func *udf_arg) :Item_int_func() {} + Item_func_udf_decimal(udf_func *udf_arg, List<Item> &list) :Item_int_func(list) {} + my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; } +}; + + class Item_func_udf_str :public Item_func { public: @@ -934,7 +1067,7 @@ class Item_master_pos_wait :public Item_int_func }; -/* Handling of user definiable variables */ +/* Handling of user definable variables */ class user_var_entry; @@ -945,11 +1078,13 @@ class Item_func_set_user_var :public Item_func user_var_entry *entry; char buffer[MAX_FIELD_WIDTH]; String value; + my_decimal decimal_buff; union { longlong vint; double vreal; String *vstr; + my_decimal *vdec; } save_result; String save_buff; @@ -961,6 +1096,7 @@ public: double val_real(); longlong val_int(); String *val_str(String *str); + my_decimal *val_decimal(my_decimal *); bool update_hash(void *ptr, uint length, enum Item_result type, CHARSET_INFO *cs, Derivation dv); bool check(); @@ -986,6 +1122,7 @@ public: LEX_STRING get_name() { return name; } double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal*); String *val_str(String* str); void fix_length_and_dec(); void print(String *str); @@ -1095,7 +1232,8 @@ public: enum Cast_target { ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT, - ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME, ITEM_CAST_CHAR + ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME, ITEM_CAST_CHAR, + ITEM_CAST_DECIMAL }; @@ -1161,6 +1299,22 @@ public: return d; } + my_decimal *val_decimal(my_decimal *dec_buf) + { + Item *it; + my_decimal *result; + + if (execute(&it)) + { + null_value= 1; + return NULL; + } + result= it->val_decimal(dec_buf); + null_value= it->null_value; + return result; + } + + String *val_str(String *str) { Item *it; diff --git a/sql/item_row.cc b/sql/item_row.cc index a5a430785d6..08c682afa85 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -100,10 +100,9 @@ void Item_row::split_sum_func(THD *thd, Item **ref_pointer_array, (item->used_tables() && item->type() != REF_ITEM)) { uint el= fields.elements; - ref_pointer_array[el]=*arg; + ref_pointer_array[el]= *arg; Item *new_item= new Item_ref(ref_pointer_array + el, 0, (*arg)->name); fields.push_front(*arg); - ref_pointer_array[el]= *arg; thd->change_item_tree(arg, new_item); } } diff --git a/sql/item_row.h b/sql/item_row.h index 64bd5cbbb44..e6b23eebb49 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -56,6 +56,11 @@ public: illegal_method_call((const char*)"val_str"); return 0; }; + my_decimal *val_decimal(my_decimal *) + { + illegal_method_call((const char*)"val_decimal"); + return 0; + }; bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields); table_map used_tables() const { return used_tables_cache; }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index e3f1053dc73..55185a5f75b 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -49,6 +49,8 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, 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; @@ -1784,10 +1786,9 @@ void Item_func_make_set::split_sum_func(THD *thd, Item **ref_pointer_array, (item->used_tables() && item->type() != REF_ITEM)) { uint el= fields.elements; - ref_pointer_array[el]=item; + ref_pointer_array[el]= item; Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name); fields.push_front(item); - ref_pointer_array[el]= item; thd->change_item_tree(&item, new_item); } Item_str_func::split_sum_func(thd, ref_pointer_array, fields); @@ -1803,7 +1804,7 @@ void Item_func_make_set::fix_length_and_dec() for (uint i=0 ; i < arg_count ; i++) max_length+=args[i]->max_length; - + used_tables_cache|= item->used_tables(); not_null_tables_cache&= item->not_null_tables(); const_item_cache&= item->const_item(); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 97c42c3abf6..dc50c9a4ccd 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -397,8 +397,7 @@ public: bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { DBUG_ASSERT(fixed == 0); - return (!item->fixed && - item->fix_fields(thd, tlist, &item) || + return ((!item->fixed && item->fix_fields(thd, tlist, &item)) || item->check_cols(1) || Item_func::fix_fields(thd, tlist, ref)); } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index b5cb01494fa..8d392232f02 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -143,7 +143,7 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) res= engine->prepare(); - // all transformetion is done (used by prepared statements) + // all transformation is done (used by prepared statements) changed= 1; if (!res) @@ -246,7 +246,7 @@ void Item_subselect::update_used_tables() { if (!engine->uncacheable()) { - // did all used tables become ststic? + // did all used tables become static? if (!(used_tables_cache & ~engine->upper_select_const_tables())) const_item_cache= 1; } @@ -292,7 +292,7 @@ Item_maxmin_subselect::Item_maxmin_subselect(THD *thd_param, const_item_cache= parent->get_const_item_cache(); /* - this subquery alwais creates during preparation, so we can assign + this subquery always creates during preparation, so we can assign thd here */ thd= thd_param; @@ -356,7 +356,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join) !(select_lex->item_list.head()->type() == FIELD_ITEM || select_lex->item_list.head()->type() == REF_ITEM) && /* - switch off this optimisation for prepare statement, + switch off this optimization for prepare statement, because we do not rollback this changes TODO: make rollback for it, or special name resolving mode in 5.0. */ @@ -374,7 +374,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join) } substitution= select_lex->item_list.head(); /* - as far as we moved content to upper leven, field which depend of + as far as we moved content to upper level, field which depend of 'upper' select is not really dependent => we remove this dependence */ substitution->walk(&Item::remove_dependence_processor, @@ -494,7 +494,7 @@ longlong Item_singlerow_subselect::val_int() } } -String *Item_singlerow_subselect::val_str (String *str) +String *Item_singlerow_subselect::val_str(String *str) { if (!exec() && !value->null_value) { @@ -509,10 +509,41 @@ String *Item_singlerow_subselect::val_str (String *str) } +my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value) +{ + if (!exec() && !value->null_value) + { + null_value= 0; + return value->val_decimal(decimal_value); + } + else + { + reset(); + return 0; + } +} + + +bool Item_singlerow_subselect::val_bool() +{ + if (!exec() && !value->null_value) + { + null_value= 0; + return value->val_bool(); + } + else + { + reset(); + return 0; + } +} + + Item_exists_subselect::Item_exists_subselect(st_select_lex *select_lex): Item_subselect() { DBUG_ENTER("Item_exists_subselect::Item_exists_subselect"); + bool val_bool(); init(select_lex, new select_exists_subselect(this)); max_columns= UINT_MAX; null_value= 0; //can't be NULL @@ -622,6 +653,32 @@ String *Item_exists_subselect::val_str(String *str) return str; } + +my_decimal *Item_exists_subselect::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed == 1); + if (exec()) + { + reset(); + return 0; + } + int2my_decimal(E_DEC_FATAL_ERROR, value, 0, decimal_value); + return decimal_value; +} + + +bool Item_exists_subselect::val_bool() +{ + DBUG_ASSERT(fixed == 1); + if (exec()) + { + reset(); + return 0; + } + return value; +} + + double Item_in_subselect::val_real() { DBUG_ASSERT(fixed == 1); @@ -752,7 +809,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, /* Item_sum_(max|min) can't substitute other item => we can use 0 as - reference + reference, also Item_sum_(max|min) can't be fixed after creation, so + we do not check item->fixed */ if (item->fix_fields(thd, join->tables_list, 0)) goto err; @@ -774,7 +832,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, // left expression belong to outer select SELECT_LEX *current= thd->lex->current_select, *up; thd->lex->current_select= up= current->return_after_parsing(); - if (!left_expr->fixed && + if (!left_expr->fixed && left_expr->fix_fields(thd, up->get_table_list(), &left_expr)) { thd->lex->current_select= current; @@ -803,7 +861,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, thd->lex->current_select= current; /* - As far as Item_ref_in_optimizer do not substitude itself on fix_fields + As far as Item_ref_in_optimizer do not substitute itself on fix_fields we can use same item for all selects. */ expr= new Item_direct_ref((Item**)optimizer->get_cache(), @@ -840,6 +898,10 @@ Item_in_subselect::single_value_transformer(JOIN *join, */ select_lex->having= join->having= and_items(join->having, item); select_lex->having_fix_field= 1; + /* + we do not check join->having->fixed, because Item_and (from and_items) + or comparison function (from func->create) can't be fixed after creation + */ tmp= join->having->fix_fields(thd, join->tables_list, 0); select_lex->having_fix_field= 0; if (tmp) @@ -871,6 +933,11 @@ Item_in_subselect::single_value_transformer(JOIN *join, new Item_cond_and(having, join->having) : having); select_lex->having_fix_field= 1; + /* + we do not check join->having->fixed, because Item_and (from + and_items) or comparison function (from func->create) can't be + fixed after creation + */ tmp= join->having->fix_fields(thd, join->tables_list, 0); select_lex->having_fix_field= 0; if (tmp) @@ -887,6 +954,10 @@ Item_in_subselect::single_value_transformer(JOIN *join, argument (reference) to fix_fields() */ select_lex->where= join->conds= and_items(join->conds, item); + /* + we do not check join->conds->fixed, because Item_and can't be fixed + after creation + */ if (join->conds->fix_fields(thd, join->tables_list, 0)) goto err; } @@ -908,6 +979,10 @@ Item_in_subselect::single_value_transformer(JOIN *join, item= new Item_cond_or(new Item_func_isnull(left_expr), item); select_lex->having= join->having= item; select_lex->having_fix_field= 1; + /* + we do not check join->having->fixed, because comparison function + (from func->create) can't be fixed after creation + */ tmp= join->having->fix_fields(thd, join->tables_list, 0); select_lex->having_fix_field= 0; if (tmp) @@ -982,7 +1057,7 @@ Item_in_subselect::row_value_transformer(JOIN *join) goto err; } - // we will refer to apper level cache array => we have to save it in PS + // we will refer to upper level cache array => we have to save it in PS optimizer->keep_top_level_cache(); thd->lex->current_select= current; @@ -1000,9 +1075,9 @@ Item_in_subselect::row_value_transformer(JOIN *join) check_cols(left_expr->el(i)->cols())) goto err; Item *func= new Item_ref_null_helper(this, - select_lex->ref_pointer_array+i, - (char *) "<no matter>", - (char *) "<list ref>"); + select_lex->ref_pointer_array+i, + (char *) "<no matter>", + (char *) "<list ref>"); func= eq_creator.create(new Item_direct_ref((*optimizer->get_cache())-> addr(i), @@ -1023,6 +1098,10 @@ Item_in_subselect::row_value_transformer(JOIN *join) */ select_lex->having= join->having= and_items(join->having, item); select_lex->having_fix_field= 1; + /* + join->having can't be fixed after creation, so we do not check + join->having->fixed + */ if (join->having->fix_fields(thd, join->tables_list, 0)) { select_lex->having_fix_field= 0; @@ -1038,6 +1117,10 @@ Item_in_subselect::row_value_transformer(JOIN *join) argument (reference) to fix_fields() */ select_lex->where= join->conds= and_items(join->conds, item); + /* + join->conds can't be fixed after creation, so we do not check + join->conds->fixed + */ if (join->conds->fix_fields(thd, join->tables_list, 0)) goto err; } @@ -1533,7 +1616,7 @@ void subselect_indexsubquery_engine::print(String *str) str->append(" on ", 4); str->append(key_info->name); if (check_null) - str->append(" chicking NULL", 14); + str->append(" checking NULL", 14); if (cond) { str->append(" where ", 7); @@ -1545,7 +1628,7 @@ void subselect_indexsubquery_engine::print(String *str) /* change select_result object of engine - SINOPSYS + SYNOPSIS subselect_single_select_engine::change_result() si new subselect Item res new select_result object @@ -1567,7 +1650,7 @@ bool subselect_single_select_engine::change_result(Item_subselect *si, /* change select_result object of engine - SINOPSYS + SYNOPSIS subselect_single_select_engine::change_result() si new subselect Item res new select_result object @@ -1590,7 +1673,7 @@ bool subselect_union_engine::change_result(Item_subselect *si, /* change select_result emulation, never should be called - SINOPSYS + SYNOPSIS subselect_single_select_engine::change_result() si new subselect Item res new select_result object @@ -1611,7 +1694,7 @@ bool subselect_uniquesubquery_engine::change_result(Item_subselect *si, /* Report about presence of tables in subquery - SINOPSYS + SYNOPSIS subselect_single_select_engine::no_tables() RETURN @@ -1627,7 +1710,7 @@ bool subselect_single_select_engine::no_tables() /* Report about presence of tables in subquery - SINOPSYS + SYNOPSIS subselect_union_engine::no_tables() RETURN @@ -1648,7 +1731,7 @@ bool subselect_union_engine::no_tables() /* Report about presence of tables in subquery - SINOPSYS + SYNOPSIS subselect_uniquesubquery_engine::no_tables() RETURN diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 53fe21a9bb6..4661fae81da 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -142,6 +142,8 @@ public: double val_real(); longlong val_int (); String *val_str (String *); + my_decimal *val_decimal(my_decimal *); + bool val_bool(); enum Item_result result_type() const; void fix_length_and_dec(); @@ -155,7 +157,7 @@ public: friend class select_singlerow_subselect; }; -/* used in static ALL/ANY optimisation */ +/* used in static ALL/ANY optimization */ class select_max_min_finder_subselect; class Item_maxmin_subselect :public Item_singlerow_subselect { @@ -193,6 +195,8 @@ public: longlong val_int(); double val_real(); String *val_str(String*); + my_decimal *val_decimal(my_decimal *); + bool val_bool(); void fix_length_and_dec(); void print(String *str); @@ -294,7 +298,7 @@ public: virtual int prepare()= 0; virtual void fix_length_and_dec(Item_cache** row)= 0; virtual int exec()= 0; - virtual uint cols()= 0; /* return number of columnss in select */ + virtual uint cols()= 0; /* return number of columns in select */ virtual uint8 uncacheable()= 0; /* query is uncacheable */ enum Item_result type() { return res_type; } virtual void exclude()= 0; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 29837c3afbd..2ecc1eb083c 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -124,6 +124,16 @@ Item *Item_sum::get_tmp_table_item(THD *thd) return sum_item; } + +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) @@ -139,6 +149,32 @@ bool Item_sum::walk (Item_processor processor, byte *argument) } +Field *Item_sum::create_tmp_field(bool group, TABLE *table, + uint convert_blob_length) +{ + switch (result_type()) { + case REAL_RESULT: + return new Field_double(max_length,maybe_null,name,table,decimals); + case INT_RESULT: + return new Field_longlong(max_length,maybe_null,name,table,unsigned_flag); + case STRING_RESULT: + if (max_length > 255 && convert_blob_length) + return new Field_varstring(convert_blob_length, maybe_null, + name, table, + collation.collation); + return make_string_field(table); + case DECIMAL_RESULT: + return new Field_new_decimal(max_length - (decimals?1:0), + maybe_null, name, table, decimals); + case ROW_RESULT: + default: + // This case should never be choosen + DBUG_ASSERT(0); + return 0; + } +} + + String * Item_sum_num::val_str(String *str) { @@ -151,6 +187,17 @@ Item_sum_num::val_str(String *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); +} + + String * Item_sum_int::val_str(String *str) { @@ -184,8 +231,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1)) return TRUE; - if (decimals < args[i]->decimals) - decimals=args[i]->decimals; + set_if_bigger(decimals, args[i]->decimals); maybe_null |= args[i]->maybe_null; } result_field=0; @@ -198,6 +244,29 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) } +Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item) + :Item_sum(thd, item), value(item->value), hybrid_type(item->hybrid_type), + 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) + { + case INT_RESULT: + sum_int= item->sum_int; + break; + case DECIMAL_RESULT: + my_decimal2decimal(&item->sum_dec, &sum_dec); + break; + case REAL_RESULT: + sum= item->sum; + break; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } + collation.set(item->collation); +} + bool Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { @@ -217,20 +286,29 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) item->fix_fields(thd, tables, args) || (item= args[0])->check_cols(1)) return TRUE; + decimals=item->decimals; - hybrid_type= item->result_type(); - if (hybrid_type == INT_RESULT) - { - max_length=20; - } - else if (hybrid_type == REAL_RESULT) - { - max_length=float_length(decimals); - }else + switch (hybrid_type= item->result_type()) { - max_length=item->max_length; - } - decimals=item->decimals; + case INT_RESULT: + max_length= 20; + sum_int= 0; + break; + case DECIMAL_RESULT: + max_length= item->max_length; + my_decimal_set_zero(&sum_dec); + break; + case REAL_RESULT: + max_length= float_length(decimals); + sum= 0.0; + break; + case STRING_RESULT: + max_length= item->max_length; + break; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + }; /* MIN/MAX can return NULL for empty set indepedent of the used column */ maybe_null= 1; unsigned_flag=item->unsigned_flag; @@ -252,6 +330,19 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ** reset and add of sum_func ***********************************************************************/ +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) +{ + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal2decimal(item->dec_buffs, dec_buffs); + my_decimal2decimal(item->dec_buffs + 1, dec_buffs + 1); + } + else + sum= item->sum; +} + Item *Item_sum_sum::copy_or_same(THD* thd) { return new (thd->mem_root) Item_sum_sum(thd, this); @@ -260,30 +351,128 @@ Item *Item_sum_sum::copy_or_same(THD* thd) void Item_sum_sum::clear() { - null_value=1; sum=0.0; + DBUG_ENTER("Item_sum_sum::clear"); + null_value=1; + if (hybrid_type == DECIMAL_RESULT) + { + curr_dec_buff= 0; + my_decimal_set_zero(dec_buffs); + } + else + sum= 0.0; + DBUG_VOID_RETURN; +} + + +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()) + { + case REAL_RESULT: + case STRING_RESULT: + hybrid_type= REAL_RESULT; + sum= 0.0; + break; + case INT_RESULT: + case DECIMAL_RESULT: + /* SUM result can't be longer than length(arg) + length(MAX_ROWS) */ + max_length= min(args[0]->max_length + DECIMAL_LONGLONG_DIGITS, + DECIMAL_MAX_LENGTH); + curr_dec_buff= 0; + hybrid_type= DECIMAL_RESULT; + my_decimal_set_zero(dec_buffs); + break; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } + DBUG_PRINT("info", ("Type: %s (%d, %d)", + (hybrid_type == REAL_RESULT ? "REAL_RESULT" : + hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : + hybrid_type == INT_RESULT ? "INT_RESULT" : + "--ILLEGAL!!!--"), + max_length, + (int)decimals)); + DBUG_VOID_RETURN; } bool Item_sum_sum::add() { - sum+= args[0]->val_real(); - if (!args[0]->null_value) - null_value= 0; - return 0; + DBUG_ENTER("Item_sum_sum::add"); + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal value, *val= args[0]->val_decimal(&value); + if (!args[0]->null_value) + { + my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1), + val, dec_buffs + curr_dec_buff); + curr_dec_buff^= 1; + null_value= 0; + } + } + else + { + sum+= args[0]->val_real(); + if (!args[0]->null_value) + null_value= 0; + } + DBUG_RETURN(0); +} + + +longlong Item_sum_sum::val_int() +{ + DBUG_ASSERT(fixed == 1); + if (hybrid_type == DECIMAL_RESULT) + { + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, unsigned_flag, + &result); + return result; + } + return Item_sum_num::val_int(); } double Item_sum_sum::val_real() { DBUG_ASSERT(fixed == 1); + if (hybrid_type == DECIMAL_RESULT) + my_decimal2double(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, &sum); return sum; } +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); +} + + +my_decimal *Item_sum_sum::val_decimal(my_decimal *val) +{ + DBUG_ASSERT(hybrid_type == DECIMAL_RESULT); + return(dec_buffs + curr_dec_buff); +} + /* Item_sum_sum_distinct */ Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item) - :Item_sum_num(item), sum(0.0), tree(0) + :Item_sum_sum(item), tree(0) { /* quick_group is an optimizer hint, which means that GROUP BY can be @@ -297,12 +486,24 @@ Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item) Item_sum_sum_distinct::Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *original) - :Item_sum_num(thd, original), sum(0.0), tree(0) + :Item_sum_sum(thd, original), tree(0), dec_bin_buff(original->dec_bin_buff) { quick_group= 0; } +void Item_sum_sum_distinct::fix_length_and_dec() +{ + Item_sum_sum::fix_length_and_dec(); + if (hybrid_type == DECIMAL_RESULT) + { + dec_bin_buff= (byte *) + sql_alloc(my_decimal_get_binary_size(args[0]->max_length, + args[0]->decimals)); + } +} + + Item * Item_sum_sum_distinct::copy_or_same(THD *thd) { @@ -320,10 +521,11 @@ C_MODE_END bool Item_sum_sum_distinct::setup(THD *thd) { + DBUG_ENTER("Item_sum_sum_distinct::setup"); SELECT_LEX *select_lex= thd->lex->current_select; /* what does it mean??? */ if (select_lex->linkage == GLOBAL_OPTIONS_TYPE) - return 1; + DBUG_RETURN(1); DBUG_ASSERT(tree == 0); /* setup can not be called twice */ @@ -337,17 +539,25 @@ 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 */ - static uint key_length= sizeof(double); - tree= new Unique(simple_raw_key_cmp, &key_length, key_length, + 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, thd->variables.max_heap_table_size); - return tree == 0; + DBUG_PRINT("info", ("tree 0x%lx, key length %d", (ulong)tree, + *key_length_ptr)); + DBUG_RETURN(tree == 0); } void Item_sum_sum_distinct::clear() { + DBUG_ENTER("Item_sum_sum_distinct::clear"); DBUG_ASSERT(tree); /* we always have a tree */ null_value= 1; tree->reset(); + DBUG_VOID_RETURN; } void Item_sum_sum_distinct::cleanup() @@ -360,25 +570,71 @@ void Item_sum_sum_distinct::cleanup() bool Item_sum_sum_distinct::add() { - /* args[0]->val_real() may reset args[0]->null_value */ - double val= args[0]->val_real(); - if (!args[0]->null_value) + DBUG_ENTER("Item_sum_sum_distinct::add"); + if (hybrid_type == DECIMAL_RESULT) { - DBUG_ASSERT(tree); - null_value= 0; - if (val) - return tree->unique_add(&val); + my_decimal value, *val= args[0]->val_decimal(&value); + if (!args[0]->null_value) + { + DBUG_ASSERT(tree); + null_value= 0; + my_decimal2binary(E_DEC_FATAL_ERROR, val, dec_bin_buff, + args[0]->max_length, args[0]->decimals); + DBUG_RETURN(tree->unique_add(dec_bin_buff)); + } } - return 0; + else + { + /* args[0]->val() may reset args[0]->null_value */ + double val= args[0]->val_real(); + if (!args[0]->null_value) + { + DBUG_ASSERT(tree); + null_value= 0; + DBUG_PRINT("info", ("real: %lg, tree 0x%lx", val, (ulong)tree)); + if (val) + DBUG_RETURN(tree->unique_add(&val)); + } + else + DBUG_PRINT("info", ("real: NULL")); + } + DBUG_RETURN(0); +} + + +void Item_sum_sum_distinct::add_real(double val) +{ + DBUG_ENTER("Item_sum_sum_distinct::add_real"); + sum+= val; + DBUG_PRINT("info", ("sum %lg, val %lg", sum, val)); + DBUG_VOID_RETURN; +} + + +void Item_sum_sum_distinct::add_decimal(byte *val) +{ + binary2my_decimal(E_DEC_FATAL_ERROR, val, &tmp_dec, + args[0]->max_length, args[0]->decimals); + my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1), + &tmp_dec, dec_buffs + curr_dec_buff); + curr_dec_buff^= 1; } C_MODE_START -static int sum_sum_distinct(void *element, element_count num_of_dups, - void *item_sum_sum_distinct) +static int sum_sum_distinct_real(void *element, element_count num_of_dups, + void *item_sum_sum_distinct) +{ + ((Item_sum_sum_distinct *) + (item_sum_sum_distinct))->add_real(* (double *) element); + return 0; +} + +static int sum_sum_distinct_decimal(void *element, element_count num_of_dups, + void *item_sum_sum_distinct) { ((Item_sum_sum_distinct *) - (item_sum_sum_distinct))->add(* (double *) element); + (item_sum_sum_distinct))->add_decimal((byte *)element); return 0; } @@ -386,16 +642,86 @@ C_MODE_END double Item_sum_sum_distinct::val_real() { + DBUG_ENTER("Item_sum_sum_distinct::val"); /* We don't have a tree only if 'setup()' hasn't been called; this is the case of sql_select.cc:return_zero_rows. */ - sum= 0.0; - if (tree) - tree->walk(sum_sum_distinct, (void *) this); - return sum; + 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_decimal2double(E_DEC_FATAL_ERROR, val, &sum); + } + else + { + sum= 0.0; + DBUG_PRINT("info", ("tree 0x%lx", (ulong)tree)); + if (tree) + tree->walk(sum_sum_distinct_real, (void *) this); + } + DBUG_RETURN(sum); } + +my_decimal *Item_sum_sum_distinct::val_decimal(my_decimal *fake) +{ + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal_set_zero(dec_buffs); + curr_dec_buff= 0; + if (tree) + tree->walk(sum_sum_distinct_decimal, (void *)this); + } + else + { + double real= val_real(); + double2my_decimal(E_DEC_FATAL_ERROR, real, dec_buffs + curr_dec_buff); + } + return(dec_buffs + curr_dec_buff); +} + + +longlong Item_sum_sum_distinct::val_int() +{ + longlong i; + 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); + } + else + i= (longlong) val_real(); + return i; +} + + +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; +} + + /* end of Item_sum_sum_distinct */ Item *Item_sum_count::copy_or_same(THD* thd) @@ -442,6 +768,20 @@ void Item_sum_count::cleanup() /* Avgerage */ +void Item_sum_avg::fix_length_and_dec() +{ + Item_sum_sum::fix_length_and_dec(); + maybe_null=null_value=1; + decimals= min(args[0]->decimals + 4, NOT_FIXED_DEC); + if (hybrid_type == DECIMAL_RESULT) + { + f_scale= args[0]->decimals; + max_length= DECIMAL_MAX_LENGTH + (f_scale ? 1 : 0); + f_precision= DECIMAL_MAX_LENGTH; + dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale); + } +} + Item *Item_sum_avg::copy_or_same(THD* thd) { @@ -449,21 +789,43 @@ 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) + 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); + } +} + + void Item_sum_avg::clear() { - sum=0.0; count=0; + Item_sum_sum::clear(); + count=0; } bool Item_sum_avg::add() { - double nr= args[0]->val_real(); + if (Item_sum_sum::add()) + return TRUE; if (!args[0]->null_value) - { - sum+=nr; count++; - } - return 0; + return FALSE; } double Item_sum_avg::val_real() @@ -474,11 +836,46 @@ double Item_sum_avg::val_real() null_value=1; return 0.0; } - null_value=0; - return sum/ulonglong2double(count); + return Item_sum_sum::val_real() / ulonglong2double(count); } +my_decimal *Item_sum_avg::val_decimal(my_decimal *val) +{ + 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); + int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt); + my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, 4); + return 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; +} + + + /* Standard deviation */ @@ -500,26 +897,140 @@ Item *Item_sum_std::copy_or_same(THD* thd) Variance */ + +Item_sum_variance::Item_sum_variance(THD *thd, Item_sum_variance *item): + Item_sum_num(thd, item), hybrid_type(item->hybrid_type), + cur_dec(item->cur_dec), count(item->count) +{ + if (hybrid_type == DECIMAL_RESULT) + { + memcpy(dec_sum, item->dec_sum, sizeof(item->dec_sum)); + memcpy(dec_sqr, item->dec_sqr, sizeof(item->dec_sqr)); + for (int i=0; i<2; i++) + { + dec_sum[i].fix_buffer_pointer(); + dec_sqr[i].fix_buffer_pointer(); + } + } + else + { + sum= item->sum; + sum_sqr= item->sum_sqr; + } +} + + +void Item_sum_variance::fix_length_and_dec() +{ + DBUG_ENTER("Item_sum_sum::fix_length_and_dec"); + maybe_null=null_value=1; + decimals= args[0]->decimals + 4; + switch (args[0]->result_type()) + { + case REAL_RESULT: + case STRING_RESULT: + hybrid_type= REAL_RESULT; + sum= 0.0; + break; + case INT_RESULT: + case DECIMAL_RESULT: + /* 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); + f_scale0= args[0]->decimals; + f_precision0= DECIMAL_MAX_LENGTH / 2; + f_scale1= min(f_scale0 * 2, NOT_FIXED_DEC - 1); + f_precision1= DECIMAL_MAX_LENGTH; + dec_bin_size0= my_decimal_get_binary_size(f_precision0, f_scale0); + dec_bin_size1= my_decimal_get_binary_size(f_precision1, f_scale1); + break; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + } + DBUG_PRINT("info", ("Type: %s (%d, %d)", + (hybrid_type == REAL_RESULT ? "REAL_RESULT" : + hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" : + hybrid_type == INT_RESULT ? "INT_RESULT" : + "--ILLEGAL!!!--"), + max_length, + (int)decimals)); + DBUG_VOID_RETURN; +} + + Item *Item_sum_variance::copy_or_same(THD* thd) { return new (thd->mem_root) Item_sum_variance(thd, this); } +Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table, + uint convert_blob_len) +{ + if (hybrid_type == DECIMAL_RESULT) + { + if (group) + return new Field_string(dec_bin_size0+dec_bin_size1+sizeof(longlong), + 0, name,table,&my_charset_bin); + else + return new Field_new_decimal(DECIMAL_MAX_LENGTH, + maybe_null, name, table, f_scale1 + 4); + } + else + { + if (group) + return new Field_string(sizeof(double)*2+sizeof(longlong), + 0, name,table,&my_charset_bin); + else + return new Field_double(max_length, maybe_null,name,table,decimals); + } +} + + void Item_sum_variance::clear() { - sum=sum_sqr=0.0; + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal_set_zero(dec_sum); + my_decimal_set_zero(dec_sqr); + cur_dec= 0; + } + else + sum=sum_sqr=0.0; count=0; } bool Item_sum_variance::add() { - double nr= args[0]->val_real(); - if (!args[0]->null_value) + if (hybrid_type == DECIMAL_RESULT) { - sum+=nr; - sum_sqr+=nr*nr; - count++; + my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf); + my_decimal sqr_buf; + if (!args[0]->null_value) + { + count++; + int next_dec= cur_dec ^ 1; + my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, dec, dec); + my_decimal_add(E_DEC_FATAL_ERROR, dec_sqr+next_dec, + dec_sqr+cur_dec, &sqr_buf); + my_decimal_add(E_DEC_FATAL_ERROR, dec_sum+next_dec, + dec_sum+cur_dec, dec); + cur_dec= next_dec; + } + } + else + { + double nr= args[0]->val_real(); + if (!args[0]->null_value) + { + sum+=nr; + sum_sqr+=nr*nr; + count++; + } } return 0; } @@ -533,16 +1044,77 @@ double Item_sum_variance::val_real() 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; return tmp2 <= 0.0 ? 0.0 : tmp2; } + +my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_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; + } + 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); + my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &sum_sqr_buf, &count_buf, 2); + my_decimal_sub(E_DEC_FATAL_ERROR, &sum_sqr_buf, dec_sqr+cur_dec, dec_buf); + my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &sum_sqr_buf, &count_buf, 2); + return dec_buf; +} + void Item_sum_variance::reset_field() { - double nr= args[0]->val_real(); char *res=result_field->ptr; + if (hybrid_type == DECIMAL_RESULT) + { + 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_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); + } + 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); + } + return; + } + double nr= args[0]->val_real(); if (args[0]->null_value) bzero(res,sizeof(double)*2+sizeof(longlong)); @@ -558,10 +1130,33 @@ void Item_sum_variance::reset_field() void Item_sum_variance::update_field() { - double nr,old_nr,old_sqr; longlong field_count; char *res=result_field->ptr; + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal value, *arg_val= args[0]->val_decimal(&value); + if (!args[0]->null_value) + { + binary2my_decimal(E_DEC_FATAL_ERROR, res, + dec_sum+1, f_precision0, f_scale0); + binary2my_decimal(E_DEC_FATAL_ERROR, res+dec_bin_size0, + dec_sqr+1, f_precision1, f_scale1); + field_count= sint8korr(res + (dec_bin_size0 + dec_bin_size1)); + my_decimal_add(E_DEC_FATAL_ERROR, dec_sum, arg_val, dec_sum+1); + my_decimal_mul(E_DEC_FATAL_ERROR, dec_sum+1, arg_val, arg_val); + my_decimal_add(E_DEC_FATAL_ERROR, dec_sqr, dec_sqr+1, dec_sum+1); + field_count++; + my_decimal2binary(E_DEC_FATAL_ERROR, dec_sum, + res, f_precision0, f_scale0); + my_decimal2binary(E_DEC_FATAL_ERROR, dec_sqr, + res+dec_bin_size0, f_precision1, f_scale1); + res+= dec_bin_size0 + dec_bin_size1; + int8store(res, field_count); + } + return; + } + double nr,old_nr,old_sqr; float8get(old_nr, res); float8get(old_sqr, res+sizeof(double)); field_count=sint8korr(res+sizeof(double)*2); @@ -582,9 +1177,20 @@ void Item_sum_variance::update_field() void Item_sum_hybrid::clear() { - sum= 0.0; - sum_int= 0; - value.length(0); + switch (hybrid_type) + { + case INT_RESULT: + sum_int= 0; + break; + case DECIMAL_RESULT: + my_decimal_set_zero(&sum_dec); + break; + case REAL_RESULT: + sum= 0.0; + break; + default: + value.length(0); + } null_value= 1; } @@ -606,6 +1212,9 @@ double Item_sum_hybrid::val_real() if (unsigned_flag) return ulonglong2double(sum_int); return (double) sum_int; + case DECIMAL_RESULT: + my_decimal2double(E_DEC_FATAL_ERROR, &sum_dec, &sum); + return sum; case REAL_RESULT: return sum; case ROW_RESULT: @@ -622,9 +1231,47 @@ longlong Item_sum_hybrid::val_int() DBUG_ASSERT(fixed == 1); if (null_value) return 0; - if (hybrid_type == INT_RESULT) + switch (hybrid_type) + { + case INT_RESULT: + return sum_int; + case DECIMAL_RESULT: + { + longlong result; + my_decimal2int(E_DEC_FATAL_ERROR, &sum_dec, unsigned_flag, &result); return sum_int; - return (longlong) Item_sum_hybrid::val_real(); + } + default: + return (longlong) Item_sum_hybrid::val_real(); + } +} + + +my_decimal *Item_sum_hybrid::val_decimal(my_decimal *val) +{ + DBUG_ASSERT(fixed == 1); + if (null_value) + return 0; + switch (hybrid_type) { + case STRING_RESULT: + string2my_decimal(E_DEC_FATAL_ERROR, &value, val); + break; + case REAL_RESULT: + double2my_decimal(E_DEC_FATAL_ERROR, sum, val); + break; + case DECIMAL_RESULT: + val= &sum_dec; + break; + case INT_RESULT: + int2my_decimal(E_DEC_FATAL_ERROR, sum_int, unsigned_flag, val); + break; + case ROW_RESULT: + default: + // This case should never be choosen + DBUG_ASSERT(0); + break; + } + return val; // Keep compiler happy } @@ -640,6 +1287,9 @@ Item_sum_hybrid::val_str(String *str) case REAL_RESULT: str->set(sum,decimals, &my_charset_bin); break; + case DECIMAL_RESULT: + my_decimal2string(E_DEC_FATAL_ERROR, &sum_dec, 0, 0, 0, str); + return str; case INT_RESULT: if (unsigned_flag) str->set((ulonglong) sum_int, &my_charset_bin); @@ -713,6 +1363,17 @@ bool Item_sum_min::add() } } break; + case DECIMAL_RESULT: + { + my_decimal value, *val= args[0]->val_decimal(&value); + if (!args[0]->null_value && + (null_value || (my_decimal_cmp(&sum_dec, val) > 0))) + { + my_decimal2decimal(val, &sum_dec); + null_value= 0; + } + } + break; case REAL_RESULT: { double nr= args[0]->val_real(); @@ -766,6 +1427,17 @@ bool Item_sum_max::add() } } break; + case DECIMAL_RESULT: + { + my_decimal value, *val= args[0]->val_decimal(&value); + if (!args[0]->null_value && + (null_value || (my_decimal_cmp(val, &sum_dec) > 0))) + { + my_decimal2decimal(val, &sum_dec); + null_value= 0; + } + } + break; case REAL_RESULT: { double nr= args[0]->val_real(); @@ -867,7 +1539,9 @@ void Item_sum_num::reset_field() void Item_sum_hybrid::reset_field() { - if (hybrid_type == STRING_RESULT) + switch(hybrid_type) + { + case STRING_RESULT: { char buff[MAX_FIELD_WIDTH]; String tmp(buff,sizeof(buff),result_field->charset()),*res; @@ -883,8 +1557,9 @@ void Item_sum_hybrid::reset_field() result_field->set_notnull(); result_field->store(res->ptr(),res->length(),tmp.charset()); } + break; } - else if (hybrid_type == INT_RESULT) + case INT_RESULT: { longlong nr=args[0]->val_int(); @@ -899,8 +1574,9 @@ void Item_sum_hybrid::reset_field() result_field->set_notnull(); } result_field->store(nr); + break; } - else // REAL_RESULT + case REAL_RESULT: { double nr= args[0]->val_real(); @@ -915,14 +1591,46 @@ void Item_sum_hybrid::reset_field() result_field->set_notnull(); } result_field->store(nr); + break; + } + case DECIMAL_RESULT: + { + my_decimal value, *arg_dec= args[0]->val_decimal(&value); + + if (maybe_null) + { + if (args[0]->null_value) + result_field->set_null(); + else + result_field->set_notnull(); + } + if (!args[0]->null_value) + result_field->store_decimal(arg_dec); + break; + } + case ROW_RESULT: + default: + DBUG_ASSERT(0); } } void Item_sum_sum::reset_field() { - double nr= args[0]->val_real(); // Nulls also return 0 - float8store(result_field->ptr,nr); + 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); + } + else + { + DBUG_ASSERT(hybrid_type == REAL_RESULT); + double nr= args[0]->val_real(); // Nulls also return 0 + float8store(result_field->ptr, nr); + } if (args[0]->null_value) result_field->set_null(); else @@ -949,17 +1657,40 @@ void Item_sum_count::reset_field() void Item_sum_avg::reset_field() { - double nr= args[0]->val_real(); char *res=result_field->ptr; - - if (args[0]->null_value) - bzero(res,sizeof(double)+sizeof(longlong)); + if (hybrid_type == DECIMAL_RESULT) + { + 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); + } + else + { + my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec, + res, f_precision, f_scale); + res+= dec_bin_size; + longlong tmp=1; + int8store(res,tmp); + } + } else { - float8store(res,nr); - res+=sizeof(double); - longlong tmp=1; - int8store(res,tmp); + double nr= args[0]->val_real(); + + if (args[0]->null_value) + bzero(res,sizeof(double)+sizeof(longlong)); + else + { + float8store(res,nr); + res+=sizeof(double); + longlong tmp=1; + int8store(res,tmp); + } } } @@ -983,17 +1714,39 @@ void Item_sum_bit::update_field() void Item_sum_sum::update_field() { - double old_nr,nr; - char *res=result_field->ptr; - - float8get(old_nr,res); - nr= args[0]->val_real(); - if (!args[0]->null_value) + if (hybrid_type == DECIMAL_RESULT) { - old_nr+=nr; - result_field->set_notnull(); + my_decimal value, *arg_val= args[0]->val_decimal(&value); + if (!args[0]->null_value) + { + if (!result_field->is_null()) + { + my_decimal field_value, + *field_val= result_field->val_decimal(&field_value); + my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, field_val); + result_field->store_decimal(dec_buffs); + } + else + { + result_field->store_decimal(arg_val); + result_field->set_notnull(); + } + } + } + else + { + double old_nr,nr; + char *res=result_field->ptr; + + float8get(old_nr,res); + nr= args[0]->val_real(); + if (!args[0]->null_value) + { + old_nr+=nr; + result_field->set_notnull(); + } + float8store(res,old_nr); } - float8store(res,old_nr); } @@ -1017,32 +1770,59 @@ void Item_sum_count::update_field() void Item_sum_avg::update_field() { - double nr,old_nr; longlong field_count; char *res=result_field->ptr; + if (hybrid_type == DECIMAL_RESULT) + { + my_decimal value, *arg_val= args[0]->val_decimal(&value); + if (!args[0]->null_value) + { + binary2my_decimal(E_DEC_FATAL_ERROR, res, + 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; + int8store(res, field_count); + } + } + else + { + double nr, old_nr; - float8get(old_nr,res); - field_count=sint8korr(res+sizeof(double)); + float8get(old_nr, res); + field_count= sint8korr(res + sizeof(double)); - nr= args[0]->val_real(); - if (!args[0]->null_value) - { - old_nr+=nr; - field_count++; + nr= args[0]->val_real(); + if (!args[0]->null_value) + { + old_nr+= nr; + field_count++; + } + float8store(res,old_nr); + res+= sizeof(double); + int8store(res, field_count); } - float8store(res,old_nr); - res+=sizeof(double); - int8store(res,field_count); } void Item_sum_hybrid::update_field() { - if (hybrid_type == STRING_RESULT) + switch (hybrid_type) + { + case STRING_RESULT: min_max_update_str_field(); - else if (hybrid_type == INT_RESULT) + break; + case INT_RESULT: min_max_update_int_field(); - else + break; + case DECIMAL_RESULT: + min_max_update_decimal_field(); + break; + default: min_max_update_real_field(); + } } @@ -1112,41 +1892,119 @@ Item_sum_hybrid::min_max_update_int_field() } -Item_avg_field::Item_avg_field(Item_sum_avg *item) +void +Item_sum_hybrid::min_max_update_decimal_field() +{ + /* TODO: optimize: do not get result_field in case of args[0] is NULL */ + my_decimal old_val, nr_val; + const my_decimal *old_nr= result_field->val_decimal(&old_val); + const my_decimal *nr= args[0]->val_decimal(&nr_val); + if (!args[0]->null_value) + { + if (result_field->is_null(0)) + old_nr=nr; + else + { + bool res= my_decimal_cmp(old_nr, nr) > 0; + /* (cmp_sign > 0 && res) || (!(cmp_sign > 0) && !res) */ + if ((cmp_sign > 0) ^ (!res)) + old_nr=nr; + } + result_field->set_notnull(); + } + else if (result_field->is_null(0)) + result_field->set_null(); + result_field->store_decimal(old_nr); +} + + +Item_avg_field::Item_avg_field(Item_result res_type, Item_sum_avg *item) { name=item->name; decimals=item->decimals; max_length=item->max_length; field=item->result_field; maybe_null=1; + hybrid_type= res_type; + if (hybrid_type == DECIMAL_RESULT) + { + f_scale= item->f_scale; + f_precision= item->f_precision; + dec_bin_size= item->dec_bin_size; + } } double Item_avg_field::val_real() { // fix_fields() never calls for this Item - double nr; - longlong count; - float8get(nr,field->ptr); - char *res=(field->ptr+sizeof(double)); - count=sint8korr(res); - - if (!count) + if (hybrid_type == DECIMAL_RESULT) { - null_value=1; - return 0.0; + 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; } - null_value=0; - return nr/(double) count; + else + { + double nr; + longlong count; + float8get(nr,field->ptr); + char *res=(field->ptr+sizeof(double)); + count=sint8korr(res); + + if (!count) + { + null_value=1; + return 0.0; + } + null_value=0; + return nr/(double) count; + } +} + +longlong Item_avg_field::val_int() +{ + return (longlong)val_real(); +} + + +my_decimal *Item_avg_field::val_decimal(my_decimal * val) +{ + // fix_fields() never calls for this Item + longlong count= sint8korr(field->ptr + dec_bin_size); + if ((null_value= !count)) + return NULL; + + 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; } + String *Item_avg_field::val_str(String *str) { // fix_fields() never calls for this Item - double nr= Item_avg_field::val_real(); - if (null_value) - return 0; - str->set(nr,decimals, &my_charset_bin); + 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; } @@ -1169,11 +2027,29 @@ Item_variance_field::Item_variance_field(Item_sum_variance *item) max_length=item->max_length; field=item->result_field; maybe_null=1; + if ((hybrid_type= item->hybrid_type) == DECIMAL_RESULT) + { + f_scale0= item->f_scale0; + f_precision0= item->f_precision0; + dec_bin_size0= item->dec_bin_size0; + f_scale1= item->f_scale1; + f_precision1= item->f_precision1; + dec_bin_size1= item->dec_bin_size1; + } } 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; + } double sum,sum_sqr; longlong count; float8get(sum,field->ptr); @@ -1201,6 +2077,28 @@ String *Item_variance_field::val_str(String *str) return str; } + +my_decimal *Item_variance_field::val_decimal(my_decimal *dec_buf) +{ + // fix_fields() never calls for this Item + longlong count= sint8korr(field->ptr+dec_bin_size0+dec_bin_size1); + if ((null_value= !count)) + return 0; + + my_decimal dec_count, dec_sum, dec_sqr, tmp; + int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count); + binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr, + &dec_sum, f_precision0, f_scale0); + binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr+dec_bin_size0, + &dec_sqr, f_precision1, f_scale1); + my_decimal_mul(E_DEC_FATAL_ERROR, &tmp, &dec_sum, &dec_sum); + my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &tmp, &dec_count, 2); + my_decimal_sub(E_DEC_FATAL_ERROR, &dec_sum, &dec_sqr, dec_buf); + my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &dec_sum, &dec_count, 2); + return dec_buf; +} + + /**************************************************************************** ** COUNT(DISTINCT ...) ****************************************************************************/ @@ -1597,6 +2495,58 @@ Item *Item_sum_udf_int::copy_or_same(THD* thd) } +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; +} + + +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; +} + + +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; +} + + +my_decimal *Item_sum_udf_decimal::val_decimal(my_decimal *dec_buf) +{ + DBUG_ASSERT(fixed == 1); + DBUG_ENTER("Item_func_udf_decimal::val_decimal"); + DBUG_PRINT("info",("result_type: %d arg_count: %d", + args[0]->result_type(), arg_count)); + + DBUG_RETURN(udf.val_decimal(&null_value, dec_buf)); +} + + +Item *Item_sum_udf_decimal::copy_or_same(THD* thd) +{ + return new (thd->mem_root) Item_sum_udf_decimal(thd, this); +} + + longlong Item_sum_udf_int::val_int() { DBUG_ASSERT(fixed == 1); @@ -2037,7 +2987,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) for (i=0 ; i < arg_count ; i++) { - if ((!args[i]->fixed && + if ((!args[i]->fixed && args[i]->fix_fields(thd, tables, args + i)) || args[i]->check_cols(1)) return TRUE; diff --git a/sql/item_sum.h b/sql/item_sum.h index 7866a9ae913..d759f5607c3 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -78,6 +78,7 @@ 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);} @@ -92,6 +93,9 @@ 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); bool walk (Item_processor processor, byte *argument); }; @@ -112,6 +116,7 @@ public: return (longlong) val_real(); /* Real as default */ } String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); void reset_field(); }; @@ -132,17 +137,24 @@ public: class Item_sum_sum :public Item_sum_num { +protected: + Item_result hybrid_type; double sum; - void fix_length_and_dec() { maybe_null=null_value=1; } + my_decimal dec_buffs[2]; + uint curr_dec_buff; + void fix_length_and_dec(); - public: - Item_sum_sum(Item *item_par) :Item_sum_num(item_par),sum(0.0) {} - Item_sum_sum(THD *thd, Item_sum_sum *item) - :Item_sum_num(thd, item), sum(item->sum) {} +public: + Item_sum_sum(Item *item_par) :Item_sum_num(item_par) {} + Item_sum_sum(THD *thd, Item_sum_sum *item); enum Sumfunctype sum_func () const {return SUM_FUNC;} void clear(); bool add(); double val_real(); + longlong val_int(); + String *val_str(String*str); + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type () const { return hybrid_type; } void reset_field(); void update_field(); void no_rows_in_result() {} @@ -159,29 +171,35 @@ class Item_sum_sum :public Item_sum_num class Unique; -class Item_sum_sum_distinct :public Item_sum_num +class Item_sum_sum_distinct :public Item_sum_sum { - double sum; Unique *tree; + byte *dec_bin_buff; + my_decimal tmp_dec; private: Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item); public: Item_sum_sum_distinct(Item *item_par); ~Item_sum_sum_distinct() {} - + bool setup(THD *thd); void clear(); void cleanup(); bool add(); double val_real(); + my_decimal *val_decimal(my_decimal *); + longlong val_int(); + String *val_str(String *str); - inline void add(double val) { sum+= val; } + void add_real(double val); + void add_decimal(byte *val); enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; } void reset_field() {} // not used void update_field() {} // not used const char *func_name() const { return "sum_distinct"; } Item *copy_or_same(THD* thd); virtual void no_rows_in_result() {} + void fix_length_and_dec(); }; @@ -304,44 +322,51 @@ class Item_avg_field :public Item_result_field { public: Field *field; - Item_avg_field(Item_sum_avg *item); + Item_result hybrid_type; + uint f_precision, f_scale; + uint dec_bin_size; + Item_avg_field(Item_result res_type, Item_sum_avg *item); enum Type type() const { return FIELD_AVG_ITEM; } double val_real(); - longlong val_int() - { /* can't be fix_fields()ed */ return (longlong) val_real(); } + longlong val_int(); + my_decimal *val_decimal(my_decimal *); bool is_null() { (void) val_int(); return null_value; } String *val_str(String*); - enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + enum_field_types field_type() const + { + return hybrid_type == DECIMAL_RESULT ? + MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE; + } void fix_length_and_dec() {} + enum Item_result result_type () const { return hybrid_type; } }; -class Item_sum_avg :public Item_sum_num +class Item_sum_avg :public Item_sum_sum { - void fix_length_and_dec() - { - decimals=min(decimals+4, NOT_FIXED_DEC); - maybe_null=1; - } - - double sum; +public: ulonglong count; + uint f_precision, f_scale; + uint dec_bin_size; - public: - Item_sum_avg(Item *item_par) :Item_sum_num(item_par), sum(0.0), count(0) {} + Item_sum_avg(Item *item_par) :Item_sum_sum(item_par), count(0) {} Item_sum_avg(THD *thd, Item_sum_avg *item) - :Item_sum_num(thd, item), sum(item->sum), count(item->count) {} + :Item_sum_sum(thd, item), count(item->count) {} + void fix_length_and_dec(); enum Sumfunctype sum_func () const {return AVG_FUNC;} void clear(); bool add(); double val_real(); + my_decimal *val_decimal(my_decimal *); + String *val_str(String *str); void reset_field(); void update_field(); Item *result_item(Field *field) - { return new Item_avg_field(this); } + { return new Item_avg_field(hybrid_type, this); } void no_rows_in_result() {} const char *func_name() const { return "avg"; } Item *copy_or_same(THD* thd); + Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); }; class Item_sum_variance; @@ -350,15 +375,25 @@ class Item_variance_field :public Item_result_field { public: Field *field; + Item_result hybrid_type; + uint f_precision0, f_scale0; + uint f_precision1, f_scale1; + uint dec_bin_size0, dec_bin_size1; Item_variance_field(Item_sum_variance *item); enum Type type() const {return FIELD_VARIANCE_ITEM; } double val_real(); longlong val_int() { /* can't be fix_fields()ed */ return (longlong) val_real(); } String *val_str(String*); + my_decimal *val_decimal(my_decimal *); bool is_null() { (void) val_int(); return null_value; } - enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + enum_field_types field_type() const + { + return hybrid_type == DECIMAL_RESULT ? + MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE; + } void fix_length_and_dec() {} + enum Item_result result_type () const { return hybrid_type; } }; @@ -376,23 +411,27 @@ public: class Item_sum_variance : public Item_sum_num { + void fix_length_and_dec(); + +public: + Item_result hybrid_type; double sum, sum_sqr; + my_decimal dec_sum[2], dec_sqr[2]; + int cur_dec; ulonglong count; - void fix_length_and_dec() - { - decimals=min(decimals+4, NOT_FIXED_DEC); - maybe_null=1; - } + uint f_precision0, f_scale0; + uint f_precision1, f_scale1; + uint dec_bin_size0, dec_bin_size1; - public: - Item_sum_variance(Item *item_par) :Item_sum_num(item_par),count(0) {} - Item_sum_variance(THD *thd, Item_sum_variance *item): - Item_sum_num(thd, item), sum(item->sum), sum_sqr(item->sum_sqr), - count(item->count) {} + Item_sum_variance(Item *item_par) :Item_sum_num(item_par), hybrid_type(REAL_RESULT), + cur_dec(0),count(0) + {} + Item_sum_variance(THD *thd, Item_sum_variance *item); enum Sumfunctype sum_func () const { return VARIANCE_FUNC; } void clear(); bool add(); double val_real(); + my_decimal *val_decimal(my_decimal *); void reset_field(); void update_field(); Item *result_item(Field *field) @@ -400,6 +439,8 @@ class Item_sum_variance : public Item_sum_num void no_rows_in_result() {} const char *func_name() const { return "variance"; } Item *copy_or_same(THD* thd); + Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); + enum Item_result result_type () const { return hybrid_type; } }; class Item_sum_std; @@ -410,6 +451,7 @@ public: Item_std_field(Item_sum_std *item); enum Type type() const { return FIELD_STD_ITEM; } double val_real(); + enum Item_result result_type () const { return REAL_RESULT; } }; /* @@ -429,16 +471,18 @@ class Item_sum_std :public Item_sum_variance { return new Item_std_field(this); } const char *func_name() const { return "std"; } Item *copy_or_same(THD* thd); + enum Item_result result_type () const { return REAL_RESULT; } }; // This class is a string or number function depending on num_func class Item_sum_hybrid :public Item_sum { - protected: +protected: String value,tmp_value; double sum; longlong sum_int; + my_decimal sum_dec; Item_result hybrid_type; enum_field_types hybrid_field_type; int cmp_sign; @@ -449,15 +493,10 @@ class Item_sum_hybrid :public Item_sum Item_sum_hybrid(Item *item_par,int sign) :Item_sum(item_par), sum(0.0), sum_int(0), hybrid_type(INT_RESULT), hybrid_field_type(FIELD_TYPE_LONGLONG), - cmp_sign(sign), used_table_cache(~(table_map) 0), was_values(TRUE) - { collation.set(&my_charset_bin); } - Item_sum_hybrid(THD *thd, Item_sum_hybrid *item): - Item_sum(thd, item), value(item->value), - sum(item->sum), sum_int(item->sum_int), hybrid_type(item->hybrid_type), - hybrid_field_type(item->hybrid_field_type),cmp_sign(item->cmp_sign), - used_table_cache(item->used_table_cache), + cmp_sign(sign), used_table_cache(~(table_map) 0), was_values(TRUE) - { collation.set(item->collation); } + { collation.set(&my_charset_bin); } + Item_sum_hybrid(THD *thd, Item_sum_hybrid *item); bool fix_fields(THD *, TABLE_LIST *, Item **); table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } @@ -465,6 +504,7 @@ class Item_sum_hybrid :public Item_sum void clear(); double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal *); void reset_field(); String *val_str(String *); void make_const() { used_table_cache=0; } @@ -475,6 +515,7 @@ class Item_sum_hybrid :public Item_sum void min_max_update_str_field(); void min_max_update_real_field(); void min_max_update_int_field(); + void min_max_update_decimal_field(); void cleanup(); bool any_value() { return was_values; } void no_rows_in_result(); @@ -523,7 +564,7 @@ public: void reset_field(); void update_field(); void fix_length_and_dec() - { decimals=0; max_length=21; unsigned_flag=1; maybe_null=null_value=0; } + { decimals= 0; max_length=21; unsigned_flag= 1; maybe_null= null_value= 0; } }; @@ -661,6 +702,23 @@ public: Item *copy_or_same(THD* thd); }; +class Item_sum_udf_decimal :public Item_udf_sum +{ +public: + Item_sum_udf_decimal(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list) + :Item_udf_sum(udf_arg,list) {} + Item_sum_udf_decimal(THD *thd, Item_sum_udf_decimal *item) + :Item_udf_sum(thd, item) {} + String *val_str(String *); + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type () const { return DECIMAL_RESULT; } + void fix_length_and_dec() { fix_num_length_and_dec(); } + Item *copy_or_same(THD* thd); +}; + #else /* Dummy functions to get sql_yacc.cc compiled */ class Item_sum_udf_float :public Item_sum_num @@ -694,6 +752,22 @@ public: }; +class Item_sum_udf_decimal :public Item_sum_num +{ + public: + Item_sum_udf_decimal(udf_func *udf_arg) :Item_sum_num() {} + Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {} + Item_sum_udf_decimal(THD *thd, Item_sum_udf_float *item) + :Item_sum_num(thd, item) {} + enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } + double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } + my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; } + void clear() {} + bool add() { return 0; } + void update_field() {} +}; + + class Item_sum_udf_str :public Item_sum_num { public: diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 917018463e5..ab511ae2883 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -315,7 +315,9 @@ public: }; -/* This can't be a Item_str_func, because the val() functions are special */ +/* + This can't be a Item_str_func, because the val_real() functions are special +*/ class Item_date :public Item_func { diff --git a/sql/item_uniq.cc b/sql/item_uniq.cc index 88e0cbbc0e6..c1a19d71d04 100644 --- a/sql/item_uniq.cc +++ b/sql/item_uniq.cc @@ -20,3 +20,9 @@ #endif #include "mysql_priv.h" + +Field *Item_sum_unique_users::create_tmp_field(bool group, TABLE *table, + uint convert_blob_length) +{ + return new Field_long(9,maybe_null,name,table,1); +} diff --git a/sql/item_uniq.h b/sql/item_uniq.h index e74c09ca3c4..602474f7581 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -57,4 +57,5 @@ public: return new Item_sum_unique_users(thd, this); } void print(String *str) { str->append("0.0", 3); } + Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); }; diff --git a/sql/log_event.cc b/sql/log_event.cc index d09b2b3dc03..d2a0e8642f9 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3099,6 +3099,16 @@ void User_var_log_event::pack_info(Protocol* protocol) buf= my_malloc(val_offset + 22, MYF(MY_WME)); event_len= longlong10_to_str(uint8korr(val), buf + val_offset,-10)-buf; break; + case DECIMAL_RESULT: + { + buf= my_malloc(val_offset + DECIMAL_MAX_STR_LENGTH, MYF(MY_WME)); + String str(buf+val_offset, DECIMAL_MAX_STR_LENGTH, &my_charset_bin); + my_decimal dec; + binary2my_decimal(E_DEC_FATAL_ERROR, val+2, &dec, val[0], val[1]); + my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, 0, &str); + event_len= str.length() + val_offset; + break; + } case STRING_RESULT: /* 15 is for 'COLLATE' and other chars */ buf= my_malloc(event_len+val_len*2+1+2*MY_CS_NAME_SIZE+15, MYF(MY_WME)); @@ -3167,7 +3177,7 @@ bool User_var_log_event::write(IO_CACHE* file) char buf[UV_NAME_LEN_SIZE]; char buf1[UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE + UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE]; - char buf2[8], *pos= buf2; + char buf2[max(8, DECIMAL_MAX_FIELD_SIZE + 2)], *pos= buf2; uint buf1_length; ulong event_length; @@ -3182,8 +3192,6 @@ bool User_var_log_event::write(IO_CACHE* file) { buf1[1]= type; int4store(buf1 + 2, charset_number); - int4store(buf1 + 2 + UV_CHARSET_NUMBER_SIZE, val_len); - buf1_length= 10; switch (type) { case REAL_RESULT: @@ -3192,6 +3200,16 @@ bool User_var_log_event::write(IO_CACHE* file) case INT_RESULT: int8store(buf2, *(longlong*) val); break; + case DECIMAL_RESULT: + { + my_decimal *dec= (my_decimal *)val; + dec->fix_buffer_pointer(); + buf2[0]= (char)(dec->intg + dec->frac); + buf2[1]= (char)dec->frac; + decimal2bin((decimal*)val, buf2+2, buf2[0], buf2[1]); + val_len= decimal_bin_size(buf2[0], buf2[1]) + 2; + break; + } case STRING_RESULT: pos= val; break; @@ -3200,6 +3218,8 @@ bool User_var_log_event::write(IO_CACHE* file) DBUG_ASSERT(1); return 0; } + int4store(buf1 + 2 + UV_CHARSET_NUMBER_SIZE, val_len); + buf1_length= 10; } /* Length of the whole event */ @@ -3247,6 +3267,23 @@ void User_var_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* las longlong10_to_str(uint8korr(val), int_buf, -10); fprintf(file, ":=%s;\n", int_buf); break; + case DECIMAL_RESULT: + { + char str_buf[200]; + int str_len= sizeof(str_buf) - 1; + int precision= (int)val[0]; + int scale= (int)val[1]; + decimal_digit dec_buf[10]; + decimal dec; + dec.len= 10; + dec.buf= dec_buf; + + 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); + break; + } case STRING_RESULT: { /* @@ -3323,7 +3360,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli) switch (type) { case REAL_RESULT: float8get(real_val, val); - it= new Item_real(real_val); + it= new Item_float(real_val); val= (char*) &real_val; // Pointer to value in native format val_len= 8; break; @@ -3333,6 +3370,14 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli) val= (char*) &int_val; // Pointer to value in native format val_len= 8; break; + case DECIMAL_RESULT: + { + Item_decimal *dec= new Item_decimal(val+2, val[0], val[1]); + it= dec; + val= (char *)dec->val_decimal(NULL); + val_len= sizeof(my_decimal); + break; + } case STRING_RESULT: it= new Item_string(val, val_len, charset); break; diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc new file mode 100644 index 00000000000..eafcd2eaaf3 --- /dev/null +++ b/sql/my_decimal.cc @@ -0,0 +1,212 @@ +/* Copyright (C) 2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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 +/* + report result of decimal operation + + SYNOPSIS + decimal_operation_results() + result decimal library return code (E_DEC_* see include/decimal.h) + + return + result +*/ +int decimal_operation_results(int result) +{ + switch (result) + { + case E_DEC_OK: + break; +//TODO: fix error messages + case E_DEC_TRUNCATED: + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + WARN_DATA_TRUNCATED, ER(WARN_DATA_TRUNCATED), + "", (long)-1); + break; + case E_DEC_OVERFLOW: + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_WARN_DATA_OUT_OF_RANGE, + ER(ER_WARN_DATA_OUT_OF_RANGE), + "", (long)-1); + break; + case E_DEC_DIV_ZERO: + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_DIVISION_BY_ZERO, ER(ER_DIVISION_BY_ZERO)); + break; + case E_DEC_BAD_NUM: + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, + ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD), + "decimal", "", "", (long)-1); + break; + case E_DEC_OOM: + my_error(ER_OUT_OF_RESOURCES, MYF(0)); + break; + default: + DBUG_ASSERT(0); + } + return result; +} + + +/* + Converting decimal to string + + SYNOPSIS + my_decimal2string() + + return + E_DEC_OK + E_DEC_TRUNCATED + E_DEC_OVERFLOW + E_DEC_OOM +*/ + +int my_decimal2string(uint mask, const my_decimal *d, + int fixed_prec, int fixed_dec, + char filler, String *str) +{ + int length= (fixed_prec ? (fixed_prec + 1) : my_decimal_string_length(d)); + int result; + if (str->alloc(length)) + return check_result(mask, E_DEC_OOM); + char *sptr= (char *)str->ptr(); + int res= decimal2string((decimal *)d, sptr, + &length, fixed_prec, fixed_dec, + filler); + result= check_result(mask, res); + str->length(length); + return result; +} + + +/* + Convert from decimal to binary representation + + SYNOPSIS + my_decimal2binary() + mask error processing mask + d number for conversion + bin pointer to buffer where to write result + prec overall number of decimal digits + scale number of decimal digits after decimal point + + NOTE + Before conversion we round number if it need but produce truncation + error in this case + + RETURN + E_DEC_OK + E_DEC_TRUNCATED + E_DEC_OVERFLOW +*/ + +int my_decimal2binary(uint mask, const my_decimal *d, byte *bin, int prec, + int scale) +{ + int err1= E_DEC_OK, err2; + my_decimal rounded; + my_decimal2decimal(d, &rounded); + decimal_optimize_fraction(&rounded); + if (scale < rounded.frac) + { + err1= E_DEC_TRUNCATED; + /* decimal_round can return only E_DEC_TRUNCATED */ + decimal_round(&rounded, &rounded, scale, HALF_UP); + } + err2= decimal2bin(&rounded, bin, prec, scale); + if (!err2) + err2= err1; + return check_result(mask, err2); +} + + +/* + Convert string for decimal when string can be in some multibyte charset + + SYNOPSIS + str2my_decimal() + mask error processing mask + from string to process + length length of given string + charset charset of given string + decimal_value buffer for result storing + + RESULT + E_DEC_OK + E_DEC_TRUNCATED + E_DEC_OVERFLOW + 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; + int err; + char buff[STRING_BUFFER_USUAL_SIZE]; + String tmp(buff, sizeof(buff), &my_charset_bin); + if (charset->mbminlen > 1) + { + uint dummy_errors; + tmp.copy(from, length, charset, &my_charset_latin1, &dummy_errors); + from= tmp.ptr(); + length= tmp.length(); + charset= &my_charset_bin; + } + my_decimal_set_zero(decimal_value); + err= string2decimal((char *)from, (decimal *)decimal_value, &end); + if (*end && !err) + err= E_DEC_TRUNCATED; + check_result(mask, err); + return err; +} + + +#ifndef DBUG_OFF +/* routines for debugging print */ + +/* print decimal */ +void +print_decimal(const my_decimal *dec) +{ + fprintf(DBUG_FILE, + "\nDecimal: sign: %d intg: %d frac: %d \n\ +%09d,%09d,%09d,%09d,%09d,%09d,%09d,%09d\n", + dec->sign(), dec->intg, dec->frac, + dec->buf[0], dec->buf[1], dec->buf[2], dec->buf[3], + dec->buf[4], dec->buf[5], dec->buf[6], dec->buf[7]); +} + + +/* print decimal with its binary representation */ +void +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++) + { + fprintf(DBUG_FILE, "%02X ", (uint)((uchar *)ptr)[i]); + } + fprintf(DBUG_FILE, "\n"); +} +#endif + + +#endif /*MYSQL_CLIENT*/ diff --git a/sql/my_decimal.h b/sql/my_decimal.h new file mode 100644 index 00000000000..63d3fb7e2e5 --- /dev/null +++ b/sql/my_decimal.h @@ -0,0 +1,332 @@ +/* Copyright (C) 2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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 */ + +/* + It is interface module to fixed precision decimals library. + + Most functions use 'uint mask' as parameter, if during operation error + which fit in this mask is detected then it will be processed automatically + here. (errors are E_DEC_* constants, see include/decimal.h) + + Most function are just inline wrappers around library calls +*/ + +#ifndef my_decimal_h +#define my_decimal_h + +C_MODE_START +#include <decimal.h> +C_MODE_END + +#define DECIMAL_LONGLONG_DIGITS 22 +#define DECIMAL_LONG_DIGITS 10 +#define DECIMAL_LONG3_DIGITS 8 + +/* number of digits on which we increase scale of devision result */ +#define DECIMAL_DIV_SCALE_INCREASE 5 + +/* maximum length of buffer in our big digits (uint32) */ +#define DECIMAL_BUFF_LENGTH 8 +/* + maximum guaranteed length of number in decimal digits (number of our + digits * number of decimal digits in one our big digit - number of decimal + digits in one our big digit decreased on 1 (because we always put decimal + point on the border of our big digits)) +*/ +#define DECIMAL_MAX_LENGTH ((8 * 9) - 8) +/* + maximum length of string representation (number of maximum decimal + digits + 1 position for sign + 1 position for decimal point) +*/ +#define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_LENGTH + 2) +/* + maximum size of packet length +*/ +#define DECIMAL_MAX_FIELD_SIZE DECIMAL_MAX_LENGTH + + +inline uint my_decimal_size(uint precision, uint scale) +{ + /* + Always allocate more space to allow library to put decimal point + where it want + */ + return decimal_size(precision, scale) + 1; +} + + +/* 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 */ +class my_decimal :public decimal +{ + decimal_digit buffer[DECIMAL_BUFF_LENGTH]; + +public: + + void init() + { + len= DECIMAL_BUFF_LENGTH; + buf= buffer; +#if !defined(HAVE_purify) && !defined(DBUG_OFF) + for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++) + buffer[i]= i; +#endif + } + my_decimal() + { + init(); + } + void fix_buffer_pointer() { buf= buffer; } + + bool sign() const { return decimal::sign; } + void sign(bool s) { decimal::sign= s; } +}; + + +#ifndef DBUG_OFF +void print_decimal(const my_decimal *dec); +void print_decimal_buff(const my_decimal *dec, const byte* ptr, int length); +#endif + +#ifndef MYSQL_CLIENT +int decimal_operation_results(int result); +#else +inline int decimal_operation_results(int result) +{ + return result; +} +#endif /*MYSQL_CLIENT*/ + +inline int check_result(uint mask, int result) +{ + if (result & mask) + decimal_operation_results(result); + return result; +} + + +inline +int my_decimal_string_length(const my_decimal *d) +{ + return decimal_string_size(d); +} + + +inline +int my_decimal_max_length(const my_decimal *d) +{ + /* -1 because we do not count \0 */ + return decimal_string_size(d) - 1; +} + + +inline +int my_decimal_get_binary_size(uint precision, uint scale) +{ + return decimal_bin_size((int)precision, (int)scale); +} + + +inline +void my_decimal2decimal(const my_decimal *from, my_decimal *to) +{ + *to= *from; + to->fix_buffer_pointer(); +} + + +int my_decimal2binary(uint mask, const my_decimal *d, byte *bin, int prec, + int scale); + + +inline +int binary2my_decimal(uint mask, const byte *bin, my_decimal *d, int prec, + int scale) +{ + return check_result(mask, bin2decimal((char *)bin, (decimal *)d, prec, + scale)); +} + + +inline +int my_decimal_set_zero(my_decimal *d) +{ + decimal_make_zero(((decimal *)d)); + return 0; +} + + +inline +bool my_decimal_is_zero(const my_decimal *decimal_value) +{ + return decimal_is_zero((decimal *)decimal_value); +} + + +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, + (truncate ? TRUNCATE : HALF_UP))); +} + + +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)); +} + + +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)); +} + + +#ifndef MYSQL_CLIENT +int my_decimal2string(uint mask, const my_decimal *d, int fixed_prec, + int fixed_dec, char filler, String *str); +#endif + +inline +int my_decimal2int(uint mask, const my_decimal *d, my_bool unsigned_flag, + longlong *l) +{ + my_decimal rounded; + /* decimal_round can return only E_DEC_TRUNCATED */ + decimal_round((decimal*)d, &rounded, 0, HALF_UP); + return check_result(mask, (unsigned_flag ? + decimal2ulonglong(&rounded, (ulonglong *)l) : + decimal2longlong(&rounded, l))); +} + + +inline +int my_decimal2double(uint mask, const my_decimal *d, double *result) +{ + return check_result(mask, decimal2double((decimal *)d, result)); +} + + +inline +int str2my_decimal(uint mask, const char *str, my_decimal *d, + char **end= 0) +{ + /* 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)); +} + + +int str2my_decimal(uint mask, const char *from, uint length, + CHARSET_INFO *charset, my_decimal *decimal_value); + + +#ifdef MYSQL_SERVER +inline +int string2my_decimal(uint mask, const String *str, my_decimal *d) +{ + return str2my_decimal(mask, str->ptr(), str->length(), str->charset(), d); +} +#endif + + +inline +int double2my_decimal(uint mask, double val, my_decimal *d) +{ + return check_result(mask, double2decimal(val, (decimal *)d)); +} + + +inline +int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d) +{ + return check_result(mask, (unsigned_flag ? + ulonglong2decimal((ulonglong)i, d) : + longlong2decimal(i, d))); +} + + +inline +int my_decimal_neg(st_decimal *arg) +{ + decimal_neg(arg); + return 0; +} + + +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)); +} + + +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)); +} + + +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)); +} + + +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, + div_scale_inc)); +} + + +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)); +} + + +/* Returns -1 if a<b, 1 if a>b and 0 if a==b */ +inline +int my_decimal_cmp(const my_decimal *a, const my_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); +} + +#endif /*my_decimal_h*/ + diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2cabcb6d49c..fdcf061ab7a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -343,6 +343,8 @@ void debug_sync_point(const char* lock_name, uint lock_timeout); #define WEEK_YEAR 2 #define WEEK_FIRST_WEEKDAY 4 +#define STRING_BUFFER_USUAL_SIZE 80 + enum enum_parsing_place { NO_MATTER, @@ -413,6 +415,7 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key, #include "sql_string.h" #include "sql_list.h" #include "sql_map.h" +#include "my_decimal.h" #include "handler.h" #include "parse_file.h" #include "table.h" @@ -421,6 +424,7 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key, #include "sql_udf.h" class user_var_entry; #include "item.h" +extern my_decimal decimal_zero; typedef Comp_creator* (*chooser_compare_func_creator)(bool invert); /* sql_parse.cc */ void free_items(Item *item); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9400bedb585..668ef033414 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -261,11 +261,12 @@ bool opt_large_files= sizeof(my_off_t) > 4; bool opt_help= 0; bool opt_verbose= 0; -arg_cmp_func Arg_comparator::comparator_matrix[4][2] = +arg_cmp_func Arg_comparator::comparator_matrix[5][2] = {{&Arg_comparator::compare_string, &Arg_comparator::compare_e_string}, {&Arg_comparator::compare_real, &Arg_comparator::compare_e_real}, {&Arg_comparator::compare_int_signed, &Arg_comparator::compare_e_int}, - {&Arg_comparator::compare_row, &Arg_comparator::compare_e_row}}; + {&Arg_comparator::compare_row, &Arg_comparator::compare_e_row}, + {&Arg_comparator::compare_decimal, &Arg_comparator::compare_e_decimal}}; /* Global variables */ @@ -372,6 +373,7 @@ const char *sql_mode_str="OFF"; const char *in_left_expr_name= "<left expr>"; /* name of additional condition */ const char *in_additional_cond= "<IN COND>"; +my_decimal decimal_zero; /* classes for comparation parsing/processing */ Eq_creator eq_creator; Ne_creator ne_creator; @@ -2384,6 +2386,7 @@ static int init_common_variables(const char *conf_file_name, int argc, char **argv, const char **groups) { umask(((~my_umask) & 0666)); + my_decimal_set_zero(&decimal_zero); // set decimal_zero constant; tzset(); // Set tzname max_system_variables.pseudo_thread_id= (ulong)~0; diff --git a/sql/procedure.cc b/sql/procedure.cc index 420a4f6262b..a31b93da358 100644 --- a/sql/procedure.cc +++ b/sql/procedure.cc @@ -41,6 +41,34 @@ static struct st_procedure_def { { "analyse",proc_analyse_init } // Analyse a result }; + +my_decimal *Item_proc_string::val_decimal(my_decimal *decimal_value) +{ + if (null_value) + return 0; + string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value); + return (decimal_value); +} + + +my_decimal *Item_proc_int::val_decimal(my_decimal *decimal_value) +{ + if (null_value) + return 0; + int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_value); + return (decimal_value); +} + + +my_decimal *Item_proc_real::val_decimal(my_decimal *decimal_value) +{ + if (null_value) + return 0; + double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_value); + return (decimal_value); +} + + /***************************************************************************** ** Setup handling of procedure ** Return 0 if everything is ok diff --git a/sql/procedure.h b/sql/procedure.h index 33c1288c88e..4e5bf8a2f4b 100644 --- a/sql/procedure.h +++ b/sql/procedure.h @@ -71,6 +71,7 @@ public: s->set(value,decimals,default_charset()); return s; } + my_decimal *val_decimal(my_decimal *); unsigned int size_of() { return sizeof(*this);} }; @@ -89,6 +90,7 @@ public: double val_real() { return (double) value; } longlong val_int() { return value; } String *val_str(String *s) { s->set(value, default_charset()); return s; } + my_decimal *val_decimal(my_decimal *); unsigned int size_of() { return sizeof(*this);} }; @@ -122,6 +124,7 @@ public: { return null_value ? (String*) 0 : (String*) &str_value; } + my_decimal *val_decimal(my_decimal *); unsigned int size_of() { return sizeof(*this);} }; diff --git a/sql/protocol.cc b/sql/protocol.cc index d537f9cf829..7c56bb3fc7a 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -735,6 +735,7 @@ bool Protocol_simple::store(const char *from, uint length, DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DECIMAL || field_types[field_pos] == MYSQL_TYPE_BIT || + field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL || (field_types[field_pos] >= MYSQL_TYPE_ENUM && field_types[field_pos] <= MYSQL_TYPE_GEOMETRY)); field_pos++; @@ -751,6 +752,7 @@ bool Protocol_simple::store(const char *from, uint length, DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DECIMAL || field_types[field_pos] == MYSQL_TYPE_BIT || + field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL || (field_types[field_pos] >= MYSQL_TYPE_ENUM && field_types[field_pos] <= MYSQL_TYPE_GEOMETRY)); field_pos++; @@ -813,6 +815,26 @@ bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag) } +bool Protocol_simple::store_decimal(const my_decimal *d) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + 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); + return net_store_data(str.ptr(), str.length()); +} + + bool Protocol_simple::store(float from, uint32 decimals, String *buffer) { #ifndef DEBUG_OFF @@ -1027,6 +1049,24 @@ bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag) return 0; } +bool Protocol_prep::store_decimal(const my_decimal *d) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + 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); + return store(str.ptr(), str.length(), str.charset()); +} bool Protocol_prep::store(float from, uint32 decimals, String *buffer) { diff --git a/sql/protocol.h b/sql/protocol.h index fddd3ceba94..ad2593d3ab7 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -82,6 +82,7 @@ public: virtual bool store_short(longlong from)=0; virtual bool store_long(longlong from)=0; virtual bool store_longlong(longlong from, bool unsigned_flag)=0; + virtual bool store_decimal(const my_decimal *)=0; virtual bool store(const char *from, uint length, CHARSET_INFO *cs)=0; virtual bool store(const char *from, uint length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs)=0; @@ -107,6 +108,7 @@ public: virtual bool store_short(longlong from); virtual bool store_long(longlong from); virtual bool store_longlong(longlong from, bool unsigned_flag); + virtual bool store_decimal(const my_decimal *); virtual bool store(const char *from, uint length, CHARSET_INFO *cs); virtual bool store(const char *from, uint length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs); @@ -137,6 +139,7 @@ public: virtual bool store_short(longlong from); virtual bool store_long(longlong from); virtual bool store_longlong(longlong from, bool unsigned_flag); + virtual bool store_decimal(const my_decimal *); virtual bool store(const char *from,uint length, CHARSET_INFO *cs); virtual bool store(const char *from, uint length, CHARSET_INFO *fromcs, CHARSET_INFO *tocs); diff --git a/sql/set_var.cc b/sql/set_var.cc index 04bb2c5e78f..6fb44ae3ea3 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1539,7 +1539,7 @@ byte *sys_var_thd_bool::value_ptr(THD *thd, enum_var_type type, bool sys_var::check_enum(THD *thd, set_var *var, TYPELIB *enum_names) { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; const char *value; String str(buff, sizeof(buff), system_charset_info), *res; @@ -1576,7 +1576,7 @@ err: bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) { bool not_used; - char buff[80], *error= 0; + char buff[STRING_BUFFER_USUAL_SIZE], *error= 0; uint error_len= 0; String str(buff, sizeof(buff), system_charset_info), *res; @@ -1787,7 +1787,7 @@ bool sys_var_thd_date_time_format::update(THD *thd, set_var *var) bool sys_var_thd_date_time_format::check(THD *thd, set_var *var) { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String str(buff,sizeof(buff), system_charset_info), *res; DATE_TIME_FORMAT *format; @@ -1891,7 +1891,7 @@ bool sys_var_collation::check(THD *thd, set_var *var) if (var->value->result_type() == STRING_RESULT) { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String str(buff,sizeof(buff), system_charset_info), *res; if (!(res=var->value->val_str(&str))) { @@ -1925,7 +1925,7 @@ bool sys_var_character_set::check(THD *thd, set_var *var) if (var->value->result_type() == STRING_RESULT) { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; String str(buff,sizeof(buff), system_charset_info), *res; if (!(res=var->value->val_str(&str))) { @@ -2982,7 +2982,7 @@ int set_var::check(THD *thd) return 0; } - if ((!value->fixed && + if ((!value->fixed && value->fix_fields(thd, 0, &value)) || value->check_cols(1)) return -1; if (var->check_update_type(value->result_type())) @@ -3121,7 +3121,7 @@ int set_var_password::update(THD *thd) bool sys_var_thd_storage_engine::check(THD *thd, set_var *var) { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; const char *value; String str(buff, sizeof(buff), &my_charset_latin1), *res; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index d52474998a8..5ccbd9c518a 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -36,6 +36,8 @@ sp_map_result_type(enum enum_field_types type) case MYSQL_TYPE_INT24: return INT_RESULT; case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + return DECIMAL_RESULT; case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: return REAL_RESULT; @@ -127,7 +129,7 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type) else { DBUG_PRINT("info", ("INT_RESULT: %d", i)); - it= new Item_int(it->val_int()); + it= new Item_int(i); } break; } @@ -147,13 +149,80 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type) uint8 decimals= it->decimals; uint32 max_length= it->max_length; DBUG_PRINT("info", ("REAL_RESULT: %g", d)); - it= new Item_real(it->val_real()); + it= new Item_float(d); it->decimals= decimals; it->max_length= max_length; } break; } - default: + 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 + if (it->null_value) + { + DBUG_PRINT("info", ("DECIMAL_RESULT: 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 + break; + } + case STRING_RESULT: { char buffer[MAX_FIELD_WIDTH]; String tmp(buffer, sizeof(buffer), it->collation.collation); @@ -172,6 +241,9 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type) } break; } + case ROW_RESULT: + default: + DBUG_ASSERT(0); } } @@ -732,6 +804,10 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) static_cast<Item_func_get_user_var*>(fi); suv= new Item_func_set_user_var(guv->get_name(), item); + /* + we do not check suv->fixed, bacause it can't be fixed after + creation + */ suv->fix_fields(thd, NULL, &item); suv->fix_length_and_dec(); suv->check(); diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 609882b84c6..0c6c8c5aa70 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -249,14 +249,20 @@ sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars) it= new Item_int(s); break; case REAL_RESULT: - it= new Item_real(s, strlen(s)); + it= new Item_float(s, strlen(s)); break; - default: + case DECIMAL_RESULT: + it= new Item_decimal(s, strlen(s), thd->db_charset); + break; + case STRING_RESULT: { uint len= strlen(s); 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); } diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index b6bd49b1553..c2eea524cac 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -59,6 +59,11 @@ int compare_ulonglong2(void* cmp_arg __attribute__((unused)), return compare_ulonglong(s,t); } +int compare_decimal2(int* len, const char *s, const char *t) +{ + return memcmp(s, t, *len); +} + Procedure * proc_analyse_init(THD *thd, ORDER *param, select_result *result, @@ -140,6 +145,8 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, } 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); } @@ -261,7 +268,7 @@ bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num) } else // ulonglong is as big as bigint in MySQL { - if ((check_ulonglong(num, info->integers) == REAL_NUM)) + if ((check_ulonglong(num, info->integers) == DECIMAL_NUM)) return 0; ev_info->ullval = (ulonglong) max(ev_info->ullval, info->ullval); ev_info->max_dval = (double) max(ev_info->max_dval, info->dval); @@ -449,6 +456,80 @@ void field_real::add() } // field_real::add +void field_decimal::add() +{ + my_decimal dec_buf, *dec= item->val_decimal(&dec_buf); + uint length, zero_count, decs; + TREE_ELEMENT *element; + + if (item->null_value) + { + nulls++; + return; + } + + length= my_decimal_string_length(dec); + + if (room_in_tree) + { + char buf[DECIMAL_MAX_FIELD_SIZE]; + my_decimal2binary(E_DEC_FATAL_ERROR, dec, buf, + item->max_length, item->decimals); + if (!(element = tree_insert(&tree, (void*)buf, 0, tree.custom_arg))) + { + room_in_tree = 0; // Remove tree, out of RAM ? + delete_tree(&tree); + } + /* + if element->count == 1, this element can be found only once from tree + if element->count == 2, or more, this element is already in tree + */ + else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements) + { + room_in_tree = 0; // Remove tree, too many elements + delete_tree(&tree); + } + } + + if (!found) + { + found = 1; + min_arg = max_arg = sum[0] = *dec; + min_arg.fix_buffer_pointer(); + max_arg.fix_buffer_pointer(); + sum[0].fix_buffer_pointer(); + my_decimal_mul(E_DEC_FATAL_ERROR, sum_sqr, dec, dec); + cur_sum= 0; + min_length = max_length = length; + } + else + { + int next_cur_sum= cur_sum ^ 1; + my_decimal sqr_buf; + + my_decimal_add(E_DEC_FATAL_ERROR, sum+next_cur_sum, sum+cur_sum, dec); + my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, dec, dec); + my_decimal_add(E_DEC_FATAL_ERROR, + sum_sqr+next_cur_sum, sum_sqr+cur_sum, &sqr_buf); + cur_sum= next_cur_sum; + if (length < min_length) + min_length = length; + if (length > max_length) + max_length = length; + if (my_decimal_cmp(dec, &min_arg) < 0) + { + min_arg= *dec; + min_arg.fix_buffer_pointer(); + } + if (my_decimal_cmp(dec, &max_arg) > 0) + { + max_arg= *dec; + max_arg.fix_buffer_pointer(); + } + } +} + + void field_longlong::add() { char buff[MAX_FIELD_WIDTH]; @@ -886,6 +967,70 @@ void field_ulonglong::get_opt_type(String *answer, } //field_ulonglong::get_opt_type +void field_decimal::get_opt_type(String *answer, + ha_rows total_rows __attribute__((unused))) +{ + my_decimal zero; + char buff[MAX_FIELD_WIDTH]; + + 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); + if (is_unsigned) + strcat(buff, " UNSIGNED"); + answer->append(buff, (uint) strlen(buff)); +} + + +String *field_decimal::get_min_arg(String *str) +{ + my_decimal2string(E_DEC_FATAL_ERROR, &min_arg, 0, 0, '0', str); + return str; +} + + +String *field_decimal::get_max_arg(String *str) +{ + my_decimal2string(E_DEC_FATAL_ERROR, &max_arg, 0, 0, '0', str); + return str; +} + + +String *field_decimal::avg(String *s, ha_rows rows) +{ + if (!(rows - nulls)) + { + s->set((double) 0.0, 1,my_thd_charset); + return s; + } + my_decimal num, avg_val; + int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num); + my_decimal_div(E_DEC_FATAL_ERROR, &avg_val, sum+cur_sum, &num, 0); + my_decimal2string(E_DEC_FATAL_ERROR, &avg_val, 0, 0, '0', s); + return s; +} + + +String *field_decimal::std(String *s, ha_rows rows) +{ + if (!(rows - nulls)) + { + s->set((double) 0.0, 1,my_thd_charset); + return s; + } + my_decimal num, std_val, sum2, sum2d; + int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num); + my_decimal_mul(E_DEC_FATAL_ERROR, &sum2, sum+cur_sum, sum+cur_sum); + my_decimal_div(E_DEC_FATAL_ERROR, &std_val, &sum2, &num, 0); + my_decimal_sub(E_DEC_FATAL_ERROR, &sum2, sum_sqr+cur_sum, &std_val); + my_decimal_div(E_DEC_FATAL_ERROR, &std_val, &sum2, &num, 0); + my_decimal2string(E_DEC_FATAL_ERROR, &std_val, 0, 0, '0', s); + return s; +} + + int collect_string(String *element, element_count count __attribute__((unused)), TREE_INFO *info) @@ -920,6 +1065,28 @@ int collect_real(double *element, element_count count __attribute__((unused)), } // collect_real +int collect_decimal(char *element, element_count count, + TREE_INFO *info) +{ + char buff[DECIMAL_MAX_STR_LENGTH]; + String s(buff, sizeof(buff),&my_charset_bin); + + if (info->found) + info->str->append(','); + else + info->found = 1; + my_decimal dec; + binary2my_decimal(E_DEC_FATAL_ERROR, element, &dec, + info->item->max_length, info->item->decimals); + + info->str->append('\''); + my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, '0', &s); + info->str->append(s); + info->str->append('\''); + return 0; +} + + int collect_longlong(longlong *element, element_count count __attribute__((unused)), TREE_INFO *info) @@ -1021,12 +1188,12 @@ uint check_ulonglong(const char *str, uint length) bigger = LONG_NUM; } else if (length > ulonglong_len) - return REAL_NUM; + return DECIMAL_NUM; else { cmp = ulonglong_str; smaller = LONG_NUM; - bigger = REAL_NUM; + bigger = DECIMAL_NUM; } while (*cmp && *cmp++ == *str++) ; return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger; diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h index 3d1cffecaef..a0f0df9b43b 100644 --- a/sql/sql_analyse.h +++ b/sql/sql_analyse.h @@ -61,6 +61,7 @@ int compare_longlong2(void* cmp_arg __attribute__((unused)), int compare_ulonglong(const ulonglong *s, const ulonglong *t); int compare_ulonglong2(void* cmp_arg __attribute__((unused)), const ulonglong *s, const ulonglong *t); +int compare_decimal2(int* len, const char *s, const char *t); Procedure *proc_analyse_init(THD *thd, ORDER *param, select_result *result, List<Item> &field_list); void free_string(String*); @@ -143,6 +144,36 @@ public: }; +int collect_decimal(char *element, element_count count, + TREE_INFO *info); + +class field_decimal :public field_info +{ + my_decimal min_arg, max_arg; + my_decimal sum[2], sum_sqr[2]; + int cur_sum; + int bin_size; +public: + field_decimal(Item* a, analyse* b) :field_info(a,b) + { + bin_size= my_decimal_get_binary_size(a->max_length, a->decimals); + init_tree(&tree, 0, 0, bin_size, (qsort_cmp2)compare_decimal2, + 0, 0, (void *)&bin_size); + }; + + void add(); + void get_opt_type(String*, ha_rows); + String *get_min_arg(String *); + String *get_max_arg(String *); + String *avg(String *s, ha_rows rows); + friend int collect_decimal(char *element, element_count count, + TREE_INFO *info); + tree_walk_action collect_enum() + { return (tree_walk_action) collect_decimal; } + String *std(String *s, ha_rows rows); +}; + + int collect_real(double *element, element_count count, TREE_INFO *info); class field_real: public field_info diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 0a57c0f6bc9..85e0d27160b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2169,6 +2169,8 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, thd->change_item_tree(ref, item_ref); else if (item_ref) *ref= item_ref; + if (!(*ref)->fixed) + (*ref)->fix_fields(thd, 0, ref); } DBUG_RETURN((Field*) view_ref_found); } @@ -3389,7 +3391,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) if (cond_and->list.elements) { COND *on_expr= cond_and; - on_expr->fix_fields(thd, 0, &on_expr); + if (!on_expr->fixed) + on_expr->fix_fields(thd, 0, &on_expr); if (!embedded->outer_join) // Not left join { *conds= and_conds(*conds, cond_and); @@ -3398,7 +3401,8 @@ 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)->fix_fields(thd, tables, conds)) + if (!(*conds)->fixed && + (*conds)->fix_fields(thd, tables, conds)) goto err_no_arena; } } @@ -3410,8 +3414,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->fix_fields(thd, tables, - &embedded->on_expr)) + if (!embedded->on_expr->fixed && + 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 89442d157c6..32c9e2a50f7 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1340,6 +1340,9 @@ bool select_max_min_finder_subselect::send_data(List<Item> &items) case STRING_RESULT: op= &select_max_min_finder_subselect::cmp_str; break; + case DECIMAL_RESULT: + op= &select_max_min_finder_subselect::cmp_decimal; + break; case ROW_RESULT: // This case should never be choosen DBUG_ASSERT(0); @@ -1381,6 +1384,26 @@ bool select_max_min_finder_subselect::cmp_int() 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); +} + bool select_max_min_finder_subselect::cmp_str() { String *val1, *val2, buf1, buf2; @@ -1447,6 +1470,8 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u) /* Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) + Item_func_set_user_var can't be fixed after creation, so we do not + check xx->fixed */ xx->fix_fields(thd, (TABLE_LIST*) thd->lex->select_lex.table_list.first, 0); diff --git a/sql/sql_class.h b/sql/sql_class.h index 29185dfbf7b..32a4093dee9 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1519,6 +1519,7 @@ public: bool send_data(List<Item> &items); bool cmp_real(); bool cmp_int(); + bool cmp_decimal(); bool cmp_str(); }; @@ -1592,9 +1593,10 @@ class user_var_entry ulong length, update_query_id, used_query_id; Item_result type; - double val(my_bool *null_value); + double val_real(my_bool *null_value); longlong val_int(my_bool *null_value); String *val_str(my_bool *null_value, String *str, uint decimals); + my_decimal *val_decimal(my_bool *null_value, my_decimal *result); DTCollation collation; }; @@ -1623,9 +1625,11 @@ public: ~Unique(); inline bool unique_add(void *ptr) { + DBUG_ENTER("unique_add"); + DBUG_PRINT("info", ("tree %u - %u", tree.elements_in_tree, max_elements)); if (tree.elements_in_tree > max_elements && flush()) - return 1; - return !tree_insert(&tree, ptr, 0, tree.custom_arg); + DBUG_RETURN(1); + DBUG_RETURN(!tree_insert(&tree, ptr, 0, tree.custom_arg)); } bool get(TABLE *table); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index c9c21d82568..dd2ac3c013b 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -409,8 +409,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, } tables->table=table; - if (cond && ((!cond->fixed && - cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1))) + if (cond && ((!cond->fixed && + cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1))) goto err0; table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it @@ -495,7 +495,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, for (key_len=0 ; (item=it_ke++) ; key_part++) { // 'item' can be changed by fix_fields() call - if ((!item->fixed && + if ((!item->fixed && item->fix_fields(thd, tables, it_ke.ref())) || (item= *it_ke.ref())->check_cols(1)) goto err; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index b8c77a822c4..78ce3c95d6b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -40,10 +40,6 @@ sys_var_long_ptr trg_new_row_fake_var(0, 0); #define yySkip() lex->ptr++ #define yyLength() ((uint) (lex->ptr - lex->tok_start)-1) -#if MYSQL_VERSION_ID < 32300 -#define FLOAT_NUM REAL_NUM -#endif - pthread_key(LEX*,THR_LEX); /* Longest standard keyword name */ @@ -437,12 +433,12 @@ inline static uint int_token(const char *str,uint length) else if (length < signed_longlong_len) return LONG_NUM; else if (length > signed_longlong_len) - return REAL_NUM; + return DECIMAL_NUM; else { cmp=signed_longlong_str+1; smaller=LONG_NUM; // If <= signed_longlong_str - bigger=REAL_NUM; + bigger=DECIMAL_NUM; } } else @@ -458,10 +454,10 @@ inline static uint int_token(const char *str,uint length) else if (length > longlong_len) { if (length > unsigned_longlong_len) - return REAL_NUM; + return DECIMAL_NUM; cmp=unsigned_longlong_str; smaller=ULONGLONG_NUM; - bigger=REAL_NUM; + bigger=DECIMAL_NUM; } else { @@ -799,7 +795,7 @@ int yylex(void *arg, void *yythd) return(FLOAT_NUM); } yylval->lex_str=get_token(lex,yyLength()); - return(REAL_NUM); + return(DECIMAL_NUM); case MY_LEX_HEX_NUMBER: // Found x'hexstring' yyGet(); // Skip ' diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5981a8b2d4d..e712cda8073 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2527,7 +2527,8 @@ mysql_execute_command(THD *thd) goto error; /* PURGE MASTER LOGS BEFORE 'data' */ it= (Item *)lex->value_list.head(); - if (it->check_cols(1) || it->fix_fields(lex->thd, 0, &it)) + if ((!it->fixed &&it->fix_fields(lex->thd, 0, &it)) || + it->check_cols(1)) { my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE"); goto error; @@ -3746,7 +3747,7 @@ unsent_create_error: { Item *it= (Item *)lex->value_list.head(); - if (it->fix_fields(lex->thd, 0, &it) || it->check_cols(1)) + if ((!it->fixed && it->fix_fields(lex->thd, 0, &it)) || it->check_cols(1)) { my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY), MYF(0)); @@ -5070,21 +5071,19 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, break; case FIELD_TYPE_NULL: break; - case FIELD_TYPE_DECIMAL: + case FIELD_TYPE_NEWDECIMAL: if (!length) { - if ((new_field->length= new_field->decimals)) - new_field->length++; - else + if (!(new_field->length= new_field->decimals)) new_field->length= 10; // Default length for DECIMAL } - if (new_field->length < MAX_FIELD_WIDTH) // Skip wrong argument - { - new_field->length+=sign_len; - if (new_field->decimals) - new_field->length++; - } - break; + new_field->pack_length= + my_decimal_get_binary_size(new_field->length, new_field->decimals); + if (new_field->length <= DECIMAL_MAX_LENGTH && + new_field->length >= new_field->decimals) + break; + my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name); + DBUG_RETURN(1); case MYSQL_TYPE_VARCHAR: /* Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table @@ -5270,6 +5269,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, new_field->pack_length= (new_field->length + 7) / 8; break; } + case FIELD_TYPE_DECIMAL: + DBUG_ASSERT(0); /* Was obsolete */ } if (!(new_field->flags & BLOB_FLAG) && diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index a71b8148f8e..6488820d2f9 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -332,6 +332,13 @@ static void set_param_double(Item_param *param, uchar **pos, ulong len) *pos+= 8; } +static void set_param_decimal(Item_param *param, uchar **pos, ulong len) +{ + ulong length= get_param_length(pos, len); + param->set_decimal((char*)*pos, length); + *pos+= len; +} + #ifndef EMBEDDED_LIBRARY /* @@ -508,6 +515,12 @@ static void setup_one_conversion_function(THD *thd, Item_param *param, param->item_type= Item::REAL_ITEM; param->item_result_type= REAL_RESULT; break; + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + param->set_param_func= set_param_decimal; + param->item_type= Item::DECIMAL_ITEM; + param->item_result_type= DECIMAL_RESULT; + break; case MYSQL_TYPE_TIME: param->set_param_func= set_param_time; param->item_type= Item::STRING_ITEM; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 68438f7a785..6af257893d4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -542,6 +542,10 @@ JOIN::optimize() } else if ((conds=new Item_cond_and(conds,having))) { + /* + Item_cond_and can't be fixed after creation, so we do not check + conds->fixed + */ conds->fix_fields(thd, tables_list, &conds); conds->change_ref_to_fields(thd, tables_list); conds->top_level_item(); @@ -7213,7 +7217,8 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top) if (conds) { conds= and_conds(conds, table->on_expr); - conds->fix_fields(join->thd, 0, &conds); + if (!conds->fixed) + conds->fix_fields(join->thd, 0, &conds); } else conds= table->on_expr; @@ -7432,6 +7437,11 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) 21)))) { cond=new_cond; + /* + Item_func_eq can't be fixed after creation so we do not check + cond->fixed, also it do not need tables so we use 0 as second + argument. + */ cond->fix_fields(thd, 0, &cond); } thd->insert_id(0); // Clear for next request @@ -7446,6 +7456,11 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) if ((new_cond= new Item_func_eq(args[0],new Item_int("0", 0, 2)))) { cond=new_cond; + /* + Item_func_eq can't be fixed after creation so we do not check + cond->fixed, also it do not need tables so we use 0 as second + argument. + */ cond->fix_fields(thd, 0, &cond); } } @@ -7641,8 +7656,13 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, else new_field= item->make_string_field(table); break; - case ROW_RESULT: - default: + case DECIMAL_RESULT: + new_field= new Field_new_decimal(item->max_length - (item->decimals?1:0), + maybe_null, + item->name, table, item->decimals); + break; + case ROW_RESULT: + default: // This case should never be choosen DBUG_ASSERT(0); new_field= 0; // to satisfy compiler (uninitialized variable) @@ -7693,47 +7713,10 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, { Item_sum *item_sum=(Item_sum*) item; bool maybe_null=item_sum->maybe_null; - switch (item_sum->sum_func()) { - case Item_sum::AVG_FUNC: /* Place for sum & count */ - if (group) - return new Field_string(sizeof(double)+sizeof(longlong), - 0, item->name,table,&my_charset_bin); - else - return new Field_double(item_sum->max_length,maybe_null, - item->name, table, item_sum->decimals); - case Item_sum::VARIANCE_FUNC: /* Place for sum & count */ - case Item_sum::STD_FUNC: - if (group) - return new Field_string(sizeof(double)*2+sizeof(longlong), - 0, item->name,table,&my_charset_bin); - else - return new Field_double(item_sum->max_length, maybe_null, - item->name,table,item_sum->decimals); - case Item_sum::UNIQUE_USERS_FUNC: - return new Field_long(9,maybe_null,item->name,table,1); - default: - switch (item_sum->result_type()) { - case REAL_RESULT: - return new Field_double(item_sum->max_length,maybe_null, - item->name,table,item_sum->decimals); - case INT_RESULT: - return new Field_longlong(item_sum->max_length,maybe_null, - item->name,table,item->unsigned_flag); - case STRING_RESULT: - if (item_sum->max_length > 255 && convert_blob_length) - return new Field_varstring(convert_blob_length, maybe_null, - item->name, table, - item->collation.collation); - return item_sum->make_string_field(table); - case ROW_RESULT: - default: - // This case should never be choosen - DBUG_ASSERT(0); - thd->fatal_error(); - return 0; - } - } - /* We never come here */ + Field *result= item_sum->create_tmp_field(group, table, convert_blob_length); + if (!result) + thd->fatal_error(); + return result; } case Item::FIELD_ITEM: case Item::DEFAULT_VALUE_ITEM: @@ -7751,6 +7734,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::PROC_ITEM: case Item::INT_ITEM: case Item::REAL_ITEM: + case Item::DECIMAL_ITEM: case Item::STRING_ITEM: case Item::REF_ITEM: case Item::NULL_ITEM: diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5abfe44f51b..62c214923f8 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2250,15 +2250,21 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, table->field[6]->store((const char*) pos, strlen((const char*) pos), cs); if (field->has_charset()) - table->field[8]->store((longlong) field->field_length/ + table->field[8]->store((longlong) field->representation_length()/ field->charset()->mbmaxlen); else - table->field[8]->store((longlong) field->field_length); - table->field[9]->store((longlong) field->field_length); + table->field[8]->store((longlong) field->representation_length()); + table->field[9]->store((longlong) field->representation_length()); { uint dec =field->decimals(); switch (field->type()) { + case FIELD_TYPE_NEWDECIMAL: + table->field[10]->store((longlong) field->field_length); + table->field[10]->set_notnull(); + table->field[11]->store((longlong) field->decimals()); + table->field[11]->set_notnull(); + break; case FIELD_TYPE_DECIMAL: { uint int_part=field->field_length - (dec ? dec + 1 : 0); @@ -2266,8 +2272,8 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, table->field[10]->set_notnull(); table->field[11]->store((longlong) field->decimals()); table->field[11]->set_notnull(); + break; } - break; case FIELD_TYPE_TINY: case FIELD_TYPE_SHORT: case FIELD_TYPE_LONG: @@ -2283,8 +2289,8 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables, table->field[11]->store((longlong) dec); table->field[11]->set_notnull(); } + break; } - break; default: break; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 38f1e6e7250..d7cefb3dceb 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -777,6 +777,14 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, } sql_field->pack_flag= FIELDFLAG_NUMBER; break; + case FIELD_TYPE_NEWDECIMAL: + sql_field->pack_flag=(FIELDFLAG_NUMBER | + (sql_field->flags & UNSIGNED_FLAG ? 0 : + FIELDFLAG_DECIMAL) | + (sql_field->flags & ZEROFILL_FLAG ? + FIELDFLAG_ZEROFILL : 0) | + (sql_field->decimals << FIELDFLAG_DEC_SHIFT)); + break; case FIELD_TYPE_TIMESTAMP: /* We should replace old TIMESTAMP fields with their newer analogs */ if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD) diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 5968d13efde..b9e837b0d64 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -176,7 +176,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables) trg_field; trg_field= trg_field->next_trg_field) { trg_field->setup_field(thd, table, lex->trg_chistics.event); - if (trg_field->fix_fields(thd, (TABLE_LIST *)0, (Item **)0)) + if (!trg_field->fixed && + trg_field->fix_fields(thd, (TABLE_LIST *)0, (Item **)0)) return 1; } diff --git a/sql/sql_udf.h b/sql/sql_udf.h index d1f99a6d232..51ea6d4d627 100644 --- a/sql/sql_udf.h +++ b/sql/sql_udf.h @@ -103,6 +103,7 @@ class udf_handler :public Sql_alloc *null_value=0; return tmp; } + my_decimal *val_decimal(my_bool *null_value, my_decimal *dec_buf); void clear() { is_null= 0; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 82cc1394eaf..f9df1be2abd 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -501,7 +501,7 @@ int mysql_update(THD *thd, free_underlaid_joins(thd, select_lex); if (error < 0) { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated, (ulong) thd->cuted_fields); thd->row_count_func= @@ -1383,7 +1383,7 @@ err: bool multi_update::send_eof() { - char buff[80]; + char buff[STRING_BUFFER_USUAL_SIZE]; thd->proc_info="updating reference tables"; /* Does updates for the last n - 1 tables, returns 0 if ok */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 1402a85229b..012a64b36c2 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -239,6 +239,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token CURRENT_USER %token DATABASES %token DATA_SYM +%token DECIMAL_NUM %token DECLARE_SYM %token DEFAULT %token DELAYED_SYM @@ -382,7 +383,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token RAID_CHUNKSIZE %token READ_SYM %token READS_SYM -%token REAL_NUM %token REDUNDANT_SYM %token REFERENCES %token REGEXP @@ -667,7 +667,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %right BINARY COLLATE_SYM %type <lex_str> - IDENT IDENT_QUOTED TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM + IDENT IDENT_QUOTED TEXT_STRING DECIMAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident ident_or_text UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal NCHAR_STRING opt_component key_cache_name @@ -2658,6 +2658,7 @@ udf_func_type: udf_type: STRING_SYM {$$ = (int) STRING_RESULT; } | REAL {$$ = (int) REAL_RESULT; } + | DECIMAL_SYM {$$ = (int) DECIMAL_RESULT; } | INT_SYM {$$ = (int) INT_RESULT; }; field_list: @@ -2838,11 +2839,11 @@ type: | MEDIUMTEXT opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; } | LONGTEXT opt_binary { $$=FIELD_TYPE_LONG_BLOB; } | DECIMAL_SYM float_options field_options - { $$=FIELD_TYPE_DECIMAL;} + { $$=FIELD_TYPE_NEWDECIMAL;} | NUMERIC_SYM float_options field_options - { $$=FIELD_TYPE_DECIMAL;} + { $$=FIELD_TYPE_NEWDECIMAL;} | FIXED_SYM float_options field_options - { $$=FIELD_TYPE_DECIMAL;} + { $$=FIELD_TYPE_NEWDECIMAL;} | ENUM {Lex->interval_list.empty();} '(' string_list ')' opt_binary { $$=FIELD_TYPE_ENUM; } | SET { Lex->interval_list.empty();} '(' string_list ')' opt_binary @@ -2904,8 +2905,8 @@ real_type: float_options: - /* empty */ {} - | '(' NUM ')' { Lex->length=$2.str; } + /* empty */ { Lex->dec=Lex->length= (char*)0; } + | '(' NUM ')' { Lex->length=$2.str; Lex->dec= (char*)0; } | precision {}; precision: @@ -4187,13 +4188,15 @@ simple_expr: | ASCII_SYM '(' expr ')' { $$= new Item_func_ascii($3); } | BINARY simple_expr %prec NEG { - $$= create_func_cast($2, ITEM_CAST_CHAR, -1, &my_charset_bin); + $$= create_func_cast($2, ITEM_CAST_CHAR, -1, 0, &my_charset_bin); } | CAST_SYM '(' expr AS cast_type ')' { + LEX *lex= Lex; $$= create_func_cast($3, $5, - Lex->length ? atoi(Lex->length) : -1, - Lex->charset); + lex->length ? atoi(lex->length) : -1, + lex->dec ? atoi(lex->dec) : 0, + lex->charset); } | CASE_SYM opt_expr WHEN_SYM when_list opt_else END { $$= new Item_func_case(* $4, $2, $5 ); } @@ -4201,6 +4204,7 @@ simple_expr: { $$= create_func_cast($3, $5, Lex->length ? atoi(Lex->length) : -1, + Lex->dec ? atoi(Lex->dec) : 0, Lex->charset); } | CONVERT_SYM '(' expr USING charset_name ')' @@ -4565,6 +4569,22 @@ simple_expr: $$ = new Item_sum_udf_int(udf); } break; + case DECIMAL_RESULT: + if (udf->type == UDFTYPE_FUNCTION) + { + if ($3 != NULL) + $$ = new Item_func_udf_decimal(udf, *$3); + else + $$ = new Item_func_udf_decimal(udf); + } + else + { + if ($3 != NULL) + $$ = new Item_sum_udf_decimal(udf, *$3); + else + $$ = new Item_sum_udf_decimal(udf); + } + break; default: YYABORT; } @@ -4814,16 +4834,17 @@ in_sum_expr: }; cast_type: - BINARY opt_len { $$=ITEM_CAST_CHAR; Lex->charset= &my_charset_bin; } - | CHAR_SYM opt_len opt_binary { $$=ITEM_CAST_CHAR; } + BINARY opt_len { $$=ITEM_CAST_CHAR; Lex->charset= &my_charset_bin; Lex->dec= 0; } + | CHAR_SYM opt_len opt_binary { $$=ITEM_CAST_CHAR; Lex->dec= 0; } | NCHAR_SYM opt_len { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; } - | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->length= (char*)0; } - | SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->length= (char*)0; } - | UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->length= (char*)0; } - | UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->length= (char*)0; } - | DATE_SYM { $$=ITEM_CAST_DATE; Lex->charset= NULL; Lex->length= (char*)0; } - | TIME_SYM { $$=ITEM_CAST_TIME; Lex->charset= NULL; Lex->length= (char*)0; } - | DATETIME { $$=ITEM_CAST_DATETIME; Lex->charset= NULL; Lex->length= (char*)0; } + | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } + | SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } + | UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } + | UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } + | DATE_SYM { $$=ITEM_CAST_DATE; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } + | TIME_SYM { $$=ITEM_CAST_TIME; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } + | DATETIME { $$=ITEM_CAST_DATETIME; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; } + | DECIMAL_SYM float_options { $$=ITEM_CAST_DECIMAL; Lex->charset= NULL; } ; expr_list: @@ -5326,7 +5347,7 @@ ULONG_NUM: NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } | LONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } | ULONGLONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } - | REAL_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } + | DECIMAL_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } | FLOAT_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); } ; @@ -5334,7 +5355,7 @@ ulonglong_num: NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); } | ULONGLONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); } | LONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); } - | REAL_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); } + | DECIMAL_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); } | FLOAT_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); } ; @@ -6575,9 +6596,9 @@ NUM_literal: NUM { int error; $$ = new Item_int($1.str, (longlong) my_strtoll10($1.str, NULL, &error), $1.length); } | LONG_NUM { int error; $$ = new Item_int($1.str, (longlong) my_strtoll10($1.str, NULL, &error), $1.length); } | ULONGLONG_NUM { $$ = new Item_uint($1.str, $1.length); } - | REAL_NUM + | DECIMAL_NUM { - $$= new Item_real($1.str, $1.length); + $$= new Item_decimal($1.str, $1.length, YYTHD->charset()); if (YYTHD->net.report_error) { YYABORT; diff --git a/strings/decimal.c b/strings/decimal.c index 42e65c26ad1..937ceb2f59b 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -113,11 +113,16 @@ typedef longlong dec2; #define DIG_PER_DEC1 9 #define DIG_MASK 100000000 #define DIG_BASE 1000000000 +#define DIG_MAX 999999999 #define DIG_BASE2 LL(1000000000000000000) #define ROUND_UP(X) (((X)+DIG_PER_DEC1-1)/DIG_PER_DEC1) static const dec1 powers10[DIG_PER_DEC1+1]={ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; static const int dig2bytes[DIG_PER_DEC1+1]={0, 1, 1, 2, 2, 3, 3, 4, 4, 4}; +static const dec1 frac_max[DIG_PER_DEC1-1]={ + 900000000, 990000000, 999000000, + 999900000, 999990000, 999999000, + 999999900, 999999990 }; #define sanity(d) DBUG_ASSERT((d)->len >0 && ((d)->buf[0] | \ (d)->buf[(d)->len-1] | 1)) @@ -190,43 +195,144 @@ static const int dig2bytes[DIG_PER_DEC1+1]={0, 1, 1, 2, 2, 3, 3, 4, 4, 4}; } while(0) /* - Convert decimal to its printable string representation + Get maximum value for given precision and scale SYNOPSIS - decimal2string() - from - value to convert - to - points to buffer where string representation should be stored - *to_len - in: size of to buffer - out: length of the actually written string - - RETURN VALUE - E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW + max_decimal() + precision/scale - see decimal_bin_size() below + to - decimal where where the result will be stored + to->buf and to->len must be set. */ -int decimal2string(decimal *from, char *to, int *to_len) +void max_decimal(int precision, int frac, decimal *to) { - int len, intg=from->intg, frac=from->frac, i; - int error=E_DEC_OK; - char *s=to; - dec1 *buf, *buf0=from->buf, tmp; + int intpart; + dec1 *buf= to->buf; + DBUG_ASSERT(precision && precision >= frac); - DBUG_ASSERT(*to_len >= 2+from->sign); + to->sign= 0; + if ((intpart= to->intg= (precision - frac))) + { + int firstdigits= intpart % DIG_PER_DEC1; + if (firstdigits) + *buf++= powers10[firstdigits] - 1; /* get 9 99 999 ... */ + for(intpart/= DIG_PER_DEC1; intpart; intpart--) + *buf++= DIG_MAX; + } - /* removing leading zeroes */ - i=((intg-1) % DIG_PER_DEC1)+1; + if ((to->frac= frac)) + { + int lastdigits= frac % DIG_PER_DEC1; + for(frac/= DIG_PER_DEC1; frac; frac--) + *buf++= DIG_MAX; + if (lastdigits) + *buf= frac_max[lastdigits - 1]; + } +} + + +static dec1 *remove_leading_zeroes(decimal *from, int *intg_result) +{ + int intg= from->intg, i; + dec1 *buf0= from->buf; + i= ((intg - 1) % DIG_PER_DEC1) + 1; while (intg > 0 && *buf0 == 0) { - intg-=i; - i=DIG_PER_DEC1; + intg-= i; + i= DIG_PER_DEC1; buf0++; } if (intg > 0) { - for (i=(intg-1) % DIG_PER_DEC1; *buf0 < powers10[i--]; intg--) ; + for (i= (intg - 1) % DIG_PER_DEC1; *buf0 < powers10[i--]; intg--) ; DBUG_ASSERT(intg > 0); } else intg=0; + *intg_result= intg; + return buf0; +} + + +/* + Remove ending 0 digits from fraction part + + SYNOPSIS + decimal_optimize_fraction() + from number for processing +*/ + +void decimal_optimize_fraction(decimal *from) +{ + int frac= from->frac, i; + dec1 *buf0= from->buf + ROUND_UP(from->intg) + ROUND_UP(frac) - 1; + + if (frac == 0) + return; + + i= ((frac - 1) % DIG_PER_DEC1 + 1); + while (frac > 0 && *buf0 == 0) + { + frac-= i; + i= DIG_PER_DEC1; + buf0--; + } + if (frac > 0) + { + for (i= DIG_PER_DEC1 - ((frac - 1) % DIG_PER_DEC1); + *buf0 % powers10[i++] == 0; + frac--); + } + from->frac= frac; +} + + +/* + Convert decimal to its printable string representation + + SYNOPSIS + decimal2string() + from - value to convert + to - points to buffer where string representation + should be stored + *to_len - in: size of to buffer + out: length of the actually written string + fixed_precision - 0 if representation can be variable length and + fixed_decimals will not be checked in this case. + Put number as with fixed point position with this + number of digits (sign counted and decimal point is + counted) + fixed_decimals - number digits after point. + filler - character to fill gaps in case of fixed_precision > 0 + + RETURN VALUE + E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW +*/ + +int decimal2string(decimal *from, char *to, int *to_len, + int fixed_precision, int fixed_decimals, + char filler) +{ + int len, intg, frac=from->frac, i, intg_len, frac_len, fill; + /* number digits before decimal point */ + int fixed_intg= (fixed_precision ? + (fixed_precision - + (from->sign ? 1 : 0) - + (fixed_decimals ? 1 : 0) - + fixed_decimals) : + 0); + int error=E_DEC_OK; + char *s=to; + dec1 *buf, *buf0=from->buf, tmp; + + DBUG_ASSERT(*to_len >= 2+from->sign); + DBUG_ASSERT(fixed_precision == 0 || + (fixed_precision < *to_len && + fixed_precision > ((from->sign ? 1 : 0) + + (fixed_decimals ? 1 : 0)))); + + /* removing leading zeroes */ + buf0= remove_leading_zeroes(from, &intg); if (unlikely(intg+frac==0)) { intg=1; @@ -234,8 +340,23 @@ int decimal2string(decimal *from, char *to, int *to_len) buf0=&tmp; } - len= from->sign + intg + test(frac) + frac; - if (unlikely(len > --*to_len)) /* reserve one byte for \0 */ + intg_len= fixed_precision ? fixed_intg : (intg ? intg : 1); + frac_len= fixed_precision ? fixed_decimals : frac; + len= from->sign + intg_len + test(frac) + frac_len; + if (fixed_precision) + { + if (frac > fixed_decimals) + { + error= E_DEC_TRUNCATED; + frac= fixed_decimals; + } + if (intg > fixed_intg) + { + error= E_DEC_OVERFLOW; + intg= fixed_intg; + } + } + else if (unlikely(len > --*to_len)) /* reserve one byte for \0 */ { int i=len-*to_len; error= (frac && i <= frac + 1) ? E_DEC_TRUNCATED : E_DEC_OVERFLOW; @@ -247,7 +368,7 @@ int decimal2string(decimal *from, char *to, int *to_len) } else frac-=i; - len= from->sign + intg + test(frac) + frac; + len= from->sign + intg_len + test(frac) + frac_len; } *to_len=len; s[len]=0; @@ -257,7 +378,8 @@ int decimal2string(decimal *from, char *to, int *to_len) if (frac) { - char *s1=s+intg; + char *s1= s + intg_len; + fill= frac_len - frac; buf=buf0+ROUND_UP(intg); *s1++='.'; for (; frac>0; frac-=DIG_PER_DEC1) @@ -271,22 +393,351 @@ int decimal2string(decimal *from, char *to, int *to_len) x*=10; } } + for(; fill; fill--) + *s1++=filler; } - s+=intg; - for (buf=buf0+ROUND_UP(intg); intg>0; intg-=DIG_PER_DEC1) + fill= intg_len - intg; + if (intg == 0) + fill--; /* symbol 0 before digital point */ + for(; fill; fill--) + *s++=filler; + if (intg) { - dec1 x=*--buf; - for (i=min(intg, DIG_PER_DEC1); i; i--) + s+=intg; + for (buf=buf0+ROUND_UP(intg); intg>0; intg-=DIG_PER_DEC1) { - dec1 y=x/10; - *--s='0'+(uchar)(x-y*10); - x=y; + dec1 x=*--buf; + for (i=min(intg, DIG_PER_DEC1); i; i--) + { + dec1 y=x/10; + *--s='0'+(uchar)(x-y*10); + x=y; + } } } + else + *s= '0'; return error; } + +/* + Return bounds of decimal digits in the number + + SYNOPSIS + digits_bounds() + from - decimal number for processing + start_result - index (from 0 ) of first decimal digits will + be written by this address + end_result - index of position just after last decimal digit + be written by this address +*/ + +static void digits_bounds(decimal *from, int *start_result, int *end_result) +{ + int start, stop, i; + dec1 *buf_beg= from->buf; + dec1 *end= from->buf + ROUND_UP(from->intg) + ROUND_UP(from->frac); + dec1 *buf_end= end - 1; + + /* find non-zero digit from number begining */ + while (buf_beg < end && *buf_beg == 0) + buf_beg++; + + if (buf_beg >= end) + { + /* it is zero */ + *start_result= *end_result= 0; + return; + } + + /* find non-zero decimal digit from number begining */ + if (buf_beg == from->buf && from->intg) + { + start= DIG_PER_DEC1 - (i= ((from->intg-1) % DIG_PER_DEC1 + 1)); + i--; + } + else + { + i= DIG_PER_DEC1 - 1; + start= (buf_beg - from->buf) * DIG_PER_DEC1; + } + if (buf_beg < end) + for (; *buf_beg < powers10[i--]; start++) ; + *start_result= start; /* index of first decimal digit (from 0) */ + + /* find non-zero digit at the end */ + while (buf_end > buf_beg && *buf_end == 0) + buf_end--; + /* find non-zero decimal digit from the end */ + if (buf_end == end - 1 && from->frac) + { + stop= ((buf_end - from->buf) * DIG_PER_DEC1 + + (i= ((from->frac - 1) % DIG_PER_DEC1 + 1))); + i= DIG_PER_DEC1 - i + 1; + } + else + { + stop= (buf_end - from->buf + 1) * DIG_PER_DEC1; + i= 1; + } + for (; *buf_end % powers10[i++] == 0; stop--); + *end_result= stop; /* index of position after last decimal digit (from 0) */ +} + + +/* + Left shift for alignment of data in buffer + + SYNOPSIS + do_mini_left_shift() + dec pointer to decimal number which have to be shifted + shift number of decimal digits on which it should be shifted + beg/end bounds of decimal digits (see digits_bounds()) + + NOTE + Result fitting in the buffer should be garanted. + 'shift' have to be from 1 to DIG_PER_DEC1-1 (inclusive) +*/ + +void do_mini_left_shift(decimal *dec, int shift, int beg, int last) +{ + dec1 *from= dec->buf + ROUND_UP(beg + 1) - 1; + dec1 *end= dec->buf + ROUND_UP(last) - 1; + int c_shift= DIG_PER_DEC1 - shift; + DBUG_ASSERT(from >= dec->buf); + DBUG_ASSERT(end < dec->buf + dec->len); + if (beg % DIG_PER_DEC1 < shift) + *(from - 1)= (*from) / powers10[c_shift]; + for(; from < end; from++) + *from= ((*from % powers10[c_shift]) * powers10[shift] + + (*(from + 1)) / powers10[c_shift]); + *from= (*from % powers10[c_shift]) * powers10[shift]; +} + + +/* + Right shift for alignment of data in buffer + + SYNOPSIS + do_mini_left_shift() + dec pointer to decimal number which have to be shifted + shift number of decimal digits on which it should be shifted + beg/end bounds of decimal digits (see digits_bounds()) + + NOTE + Result fitting in the buffer should be garanted. + 'shift' have to be from 1 to DIG_PER_DEC1-1 (inclusive) +*/ + +void do_mini_right_shift(decimal *dec, int shift, int beg, int last) +{ + dec1 *from= dec->buf + ROUND_UP(last) - 1; + dec1 *end= dec->buf + ROUND_UP(beg + 1) - 1; + int c_shift= DIG_PER_DEC1 - shift; + DBUG_ASSERT(from < dec->buf + dec->len); + DBUG_ASSERT(end >= dec->buf); + if (DIG_PER_DEC1 - ((last - 1) % DIG_PER_DEC1 + 1) < shift) + *(from + 1)= (*from % powers10[shift]) * powers10[c_shift]; + for(; from > end; from--) + *from= (*from / powers10[shift] + + (*(from - 1) % powers10[shift]) * powers10[c_shift]); + *from= *from / powers10[shift]; +} + + +/* + Shift of decimal digits in given number (with rounding if it need) + + SYNOPSIS + decimal_shift() + dec number to be shifted + shift number of decimal positions + shift > 0 means shift to left shift + shift < 0 meand right shift + NOTE + In fact it is multipling on 10^shift. + RETURN + E_DEC_OK OK + E_DEC_OVERFLOW operation lead to overflow, number is untoched + E_DEC_TRUNCATED number was rounded to fit into buffer +*/ + +int decimal_shift(decimal *dec, int shift) +{ + /* index of first non zero digit (all indexes from 0) */ + int beg; + /* index of position after last decimal digit */ + int end; + /* index of digit position just after point */ + int point= ROUND_UP(dec->intg) * DIG_PER_DEC1; + /* new point position */ + int new_point= point + shift; + /* number of digits in result */ + int digits_int, digits_frac; + /* length of result and new fraction in big digits*/ + int new_len, new_frac_len; + /* return code */ + int err= E_DEC_OK; + int new_front; + + if (shift == 0) + return E_DEC_OK; + + digits_bounds(dec, &beg, &end); + + if (beg == end) + { + decimal_make_zero(dec); + return E_DEC_OK; + } + + digits_int= new_point - beg; + set_if_bigger(digits_int, 0); + digits_frac= end - new_point; + set_if_bigger(digits_frac, 0); + + if ((new_len= ROUND_UP(digits_int) + (new_frac_len= ROUND_UP(digits_frac))) > + dec->len) + { + int lack= new_len - dec->len; + int diff; + + if (new_frac_len < lack) + return E_DEC_OVERFLOW; /* lack more then we have in fraction */ + + /* cat off fraction part to allow new number to fit in our buffer */ + err= E_DEC_TRUNCATED; + new_frac_len-= lack; + diff= digits_frac - (new_frac_len * DIG_PER_DEC1); + /* Make rounding method as parameter? */ + decimal_round(dec, dec, end - point - diff, HALF_UP); + end-= diff; + digits_frac= new_frac_len * DIG_PER_DEC1; + + if (end <= beg) + { + /* + we lost all digits (they will be shifted out of buffer), so we can + just return 0 + */ + decimal_make_zero(dec); + return E_DEC_TRUNCATED; + } + } + + if (shift % DIG_PER_DEC1) + { + int l_mini_shift, r_mini_shift, mini_shift; + int do_left; + /* + Calculate left/right shift to align decimal digits inside our bug + digits correctly + */ + if (shift > 0) + { + l_mini_shift= shift % DIG_PER_DEC1; + r_mini_shift= DIG_PER_DEC1 - l_mini_shift; + /* + It is left shift so prefer left shift, but if we have not place from + left, we have to have it from right, because we checked length of + result + */ + do_left= l_mini_shift <= beg; + DBUG_ASSERT(do_left || (dec->len * DIG_PER_DEC1 - end) >= r_mini_shift); + } + else + { + r_mini_shift= (-shift) % DIG_PER_DEC1; + l_mini_shift= DIG_PER_DEC1 - r_mini_shift; + /* see comment above */ + do_left= !((dec->len * DIG_PER_DEC1 - end) >= r_mini_shift); + DBUG_ASSERT(!do_left || l_mini_shift <= beg); + } + if (do_left) + { + do_mini_left_shift(dec, l_mini_shift, beg, end); + mini_shift=- l_mini_shift; + } + else + { + do_mini_right_shift(dec, r_mini_shift, beg, end); + mini_shift= r_mini_shift; + } + new_point+= mini_shift; + /* + If number is shifted and correctly aligned in buffer we can + finish + */ + if (!(shift+= mini_shift) && (new_point - digits_int) < DIG_PER_DEC1) + { + dec->intg= digits_int; + dec->frac= digits_frac; + return err; /* already shifted as it should be */ + } + beg+= mini_shift; + end+= mini_shift; + } + + /* if new 'decimal front' is in first digit, we do not need move digits */ + if ((new_front= (new_point - digits_int)) >= DIG_PER_DEC1 || + new_front < 0) + { + /* need to move digits */ + int d_shift; + if (new_front > 0) + { + /* move left */ + d_shift= new_front / DIG_PER_DEC1; + dec1 *to= dec->buf + (ROUND_UP(beg + 1) - 1 - d_shift); + dec1 *barier= dec->buf + (ROUND_UP(end) - 1 - d_shift); + DBUG_ASSERT(to >= dec->buf); + DBUG_ASSERT(barier + d_shift < dec->buf + dec->len); + for(; to <= barier; to++) + *to= *(to + d_shift); + for(barier+= d_shift; to <= barier; to++) + *to= 0; + d_shift= -d_shift; + } + else + { + /* move right */ + d_shift= (1 - new_front) / DIG_PER_DEC1; + dec1 *to= dec->buf + ROUND_UP(end) - 1 + d_shift; + dec1 *barier= dec->buf + ROUND_UP(beg + 1) - 1 + d_shift; + DBUG_ASSERT(to < dec->buf + dec->len); + DBUG_ASSERT(barier - d_shift >= dec->buf); + for(; to >= barier; to--) + *to= *(to - d_shift); + for(barier-= d_shift; to >= barier; to--) + *to= 0; + } + d_shift*= DIG_PER_DEC1; + beg+= d_shift; + end+= d_shift; + new_point+= d_shift; + } + + /* + If there are gaps then fill ren with 0. + + Only one of following 'for' loops will work becouse beg <= end + */ + beg= ROUND_UP(beg + 1) - 1; + end= ROUND_UP(end) - 1; + DBUG_ASSERT(new_point >= 0); + new_point= ROUND_UP(new_point) - 1; + for(; new_point > end; new_point--) + dec->buf[new_point]= 0; + for(; new_point < beg; new_point++) + dec->buf[new_point]= 0; + dec->intg= digits_int; + dec->frac= digits_frac; + return err; +} + + /* Convert string to decimal @@ -309,7 +760,7 @@ int decimal2string(decimal *from, char *to, int *to_len) static int str2dec(char *from, decimal *to, char **end, my_bool fixed) { - char *s=from, *s1; + char *s=from, *s1, *endp; int i, intg, frac, error, intg1, frac1; dec1 x,*buf; LINT_INIT(error); @@ -328,15 +779,19 @@ static int str2dec(char *from, decimal *to, char **end, my_bool fixed) intg=s-s1; if (*s=='.') { - char *s2=s+1; - while (my_isdigit(&my_charset_latin1, *s2)) - s2++; - frac=s2-s-1; + endp= s+1; + while (my_isdigit(&my_charset_latin1, *endp)) + endp++; + frac= endp - s - 1; } else - frac=0; + { + frac= 0; + endp= s; + } + if (end) - *end=s1+intg+frac+test(frac); + *end= endp; if (frac+intg == 0) return E_DEC_BAD_NUM; @@ -405,10 +860,26 @@ 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; + + if(error != E_DEC_OVERFLOW) + error= decimal_shift(to, exp); + } return error; } + int string2decimal(char *from, decimal *to, char **end) { return str2dec(from, to, end, 0); @@ -590,7 +1061,7 @@ int decimal2bin(decimal *from, char *to, int precision, int frac) { dec1 mask=from->sign ? -1 : 0, *buf1=from->buf, *stop1; int error=E_DEC_OK, intg=precision-frac, - isize1, intg1, intg1x, from_intg=from->intg, + isize1, intg1, intg1x, from_intg, intg0=intg/DIG_PER_DEC1, frac0=frac/DIG_PER_DEC1, intg0x=intg-intg0*DIG_PER_DEC1, @@ -600,22 +1071,9 @@ int decimal2bin(decimal *from, char *to, int precision, int frac) isize0=intg0*sizeof(dec1)+dig2bytes[intg0x], fsize0=frac0*sizeof(dec1)+dig2bytes[frac0x], fsize1=frac1*sizeof(dec1)+dig2bytes[frac1x]; + char *orig_to= to; - /* removing leading zeroes */ - intg1=((from_intg-1) % DIG_PER_DEC1)+1; - while (from_intg > 0 && *buf1 == 0) - { - from_intg-=intg1; - intg1=DIG_PER_DEC1; - buf1++; - } - if (from_intg > 0) - { - for (intg1=(from_intg-1) % DIG_PER_DEC1; *buf1 < powers10[intg1--]; from_intg--) ; - DBUG_ASSERT(from_intg > 0); - } - else - from_intg=0; + buf1= remove_leading_zeroes(from, &from_intg); if (unlikely(from_intg+fsize1==0)) { @@ -703,6 +1161,7 @@ int decimal2bin(decimal *from, char *to, int precision, int frac) while (fsize0-- > fsize1) *to++=(uchar)mask; } + orig_to[0]^= 0x80; return error; } @@ -729,10 +1188,16 @@ int bin2decimal(char *from, decimal *to, int precision, int scale) intg0=intg/DIG_PER_DEC1, frac0=scale/DIG_PER_DEC1, intg0x=intg-intg0*DIG_PER_DEC1, frac0x=scale-frac0*DIG_PER_DEC1, intg1=intg0+(intg0x>0), frac1=frac0+(frac0x>0); - dec1 *buf=to->buf, mask=(*from <0) ? -1 : 0; + dec1 *buf=to->buf, mask=(*from <0) ? 0 : -1; char *stop; + char *d_copy; + int bin_size= decimal_bin_size(precision, scale); sanity(to); + d_copy= (char *)my_alloca(bin_size); + memcpy(d_copy, from, bin_size); + d_copy[0]^= 0x80; + from= d_copy; FIX_INTG_FRAC_ERROR(to->len, intg1, frac1, error); if (unlikely(error)) @@ -804,6 +1269,7 @@ int bin2decimal(char *from, decimal *to, int precision, int scale) *buf=(x ^ mask) * powers10[DIG_PER_DEC1 - frac0x]; buf++; } + my_afree(d_copy); return error; } @@ -861,7 +1327,9 @@ int decimal_round(decimal *from, decimal *to, int scale, decimal_round_mode mode { int frac0=scale>0 ? ROUND_UP(scale) : scale/DIG_PER_DEC1, frac1=ROUND_UP(from->frac), round_digit, - intg0=ROUND_UP(from->intg), error=E_DEC_OK, len=to->len; + intg0=ROUND_UP(from->intg), error=E_DEC_OK, len=to->len, + intg1=ROUND_UP(from->intg + + (((intg0 + frac0)>0) && (from->buf[0] == DIG_MAX))); dec1 *buf0=from->buf, *buf1=to->buf, x, y, carry=0; sanity(to); @@ -888,12 +1356,17 @@ int decimal_round(decimal *from, decimal *to, int scale, decimal_round_mode mode return E_DEC_OK; } - if (to != from) + if (to != from || intg1>intg0) { - dec1 *end=buf0+intg0+min(frac1, frac0); - while (buf0 < end) - *buf1++ = *buf0++; - buf0=from->buf; + dec1 *p0= buf0+intg0+max(frac1, frac0); + dec1 *p1= buf1+intg1+max(frac1, frac0); + + to->buf[0]= 0; + while (buf0 < p0) + *(--p1) = *(--p0); + + intg0= intg1; + buf0=to->buf; buf1=to->buf; to->sign=from->sign; to->intg=min(intg0, len)*DIG_PER_DEC1; @@ -1446,9 +1919,9 @@ static int do_div_mod(decimal *from1, decimal *from2, while (dintg++ < 0) *buf0++=0; - len1=(i=ROUND_UP(prec1))+ROUND_UP(2*frac2+scale_incr+1); + len1=(i=ROUND_UP(prec1))+ROUND_UP(2*frac2+scale_incr+1) + 1; set_if_bigger(len1, 3); - if (!(tmp1=my_alloca(len1*sizeof(dec1)))) + if (!(tmp1=(dec1 *)my_alloca(len1*sizeof(dec1)))) return E_DEC_OOM; memcpy(tmp1, buf1, i*sizeof(dec1)); bzero(tmp1+i, (len1-i)*sizeof(dec1)); @@ -1668,7 +2141,7 @@ int decimal_mod(decimal *from1, decimal *from2, decimal *to) #ifdef MAIN -int full=0; +int full= 0; decimal a, b, c; char buf1[100], buf2[100], buf3[100]; @@ -1681,14 +2154,26 @@ void dump_decimal(decimal *d) printf("%09d} */ ", d->buf[i]); } -void print_decimal(decimal *d, char *orig) + +void check_result_code(int actual, int want) +{ + if (actual != want) + { + printf("\n^^^^^^^^^^^^^ mast return %d\n", want); + exit(1); + } +} + + +void print_decimal(decimal *d, char *orig, int actual, int want) { char s[100]; int slen=sizeof(s); if (full) dump_decimal(d); - decimal2string(d, s, &slen); + decimal2string(d, s, &slen, 0, 0, 0); printf("'%s'", s); + check_result_code(actual, want); if (orig && strcmp(orig, s)) { printf("\n^^^^^^^^^^^^^ must've been '%s'\n", orig); @@ -1705,43 +2190,45 @@ void test_d2s() printf("==== decimal2string ====\n"); a.buf[0]=12345; a.intg=5; a.frac=0; a.sign=0; slen=sizeof(s); - res=decimal2string(&a, s, &slen); + res=decimal2string(&a, s, &slen, 0, 0, 0); dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); a.buf[1]=987000000; a.frac=3; slen=sizeof(s); - res=decimal2string(&a, s, &slen); + res=decimal2string(&a, s, &slen, 0, 0, 0); dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); a.sign=1; slen=sizeof(s); - res=decimal2string(&a, s, &slen); + res=decimal2string(&a, s, &slen, 0, 0, 0); dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); slen=8; - res=decimal2string(&a, s, &slen); + res=decimal2string(&a, s, &slen, 0, 0, 0); dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); slen=5; - res=decimal2string(&a, s, &slen); + res=decimal2string(&a, s, &slen, 0, 0, 0); dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); a.buf[0]=987000000; a.frac=3; a.intg=0; slen=sizeof(s); - res=decimal2string(&a, s, &slen); + res=decimal2string(&a, s, &slen, 0, 0, 0); dump_decimal(&a); printf(" --> res=%d str='%s' len=%d\n", res, s, slen); } -void test_s2d(char *s, char *orig) +void test_s2d(char *s, char *orig, int ex) { char s1[100]; + int res; sprintf(s1, "'%s'", s); - printf("len=%2d %-30s => res=%d ", a.len, s1, string2decimal(s, &a, 0)); - print_decimal(&a, orig); + printf("len=%2d %-30s => res=%d ", a.len, s1, + (res= string2decimal(s, &a, 0))); + print_decimal(&a, orig, res, ex); printf("\n"); } -void test_d2f(char *s) +void test_d2f(char *s, int ex) { char s1[100]; double x; @@ -1752,12 +2239,12 @@ void test_d2f(char *s) 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) +void test_d2b2d(char *str, int p, int s, char *orig, int ex) { char s1[100], buf[100]; - double x; int res, i, size=decimal_bin_size(p, s); sprintf(s1, "'%s'", str); @@ -1772,20 +2259,20 @@ void test_d2b2d(char *str, int p, int s, char *orig) } res=bin2decimal(buf, &a, p, s); printf(" => res=%d ", res); - print_decimal(&a, orig); + print_decimal(&a, orig, res, ex); printf("\n"); } -void test_f2d(double from) +void test_f2d(double from, int ex) { int res; res=double2decimal(from, &a); printf("%-40.*f => res=%d ", DBL_DIG-2, from, res); - print_decimal(&a, 0); + print_decimal(&a, 0, res, ex); printf("\n"); } -void test_ull2d(ulonglong from, char *orig) +void test_ull2d(ulonglong from, char *orig, int ex) { char s[100]; int res; @@ -1793,11 +2280,11 @@ void test_ull2d(ulonglong from, char *orig) res=ulonglong2decimal(from, &a); longlong10_to_str(from,s,10); printf("%-40s => res=%d ", s, res); - print_decimal(&a, orig); + print_decimal(&a, orig, res, ex); printf("\n"); } -void test_ll2d(longlong from, char *orig) +void test_ll2d(longlong from, char *orig, int ex) { char s[100]; int res; @@ -1805,11 +2292,11 @@ void test_ll2d(longlong from, char *orig) res=longlong2decimal(from, &a); longlong10_to_str(from,s,-10); printf("%-40s => res=%d ", s, res); - print_decimal(&a, orig); + print_decimal(&a, orig, res, ex); printf("\n"); } -void test_d2ull(char *s, char *orig) +void test_d2ull(char *s, char *orig, int ex) { char s1[100]; ulonglong x; @@ -1820,6 +2307,7 @@ void test_d2ull(char *s, char *orig) if (full) dump_decimal(&a); longlong10_to_str(x,s1,10); printf("%-40s => res=%d %s\n", s, res, s1); + check_result_code(res, ex); if (orig && strcmp(orig, s1)) { printf("\n^^^^^^^^^^^^^ must've been '%s'\n", orig); @@ -1827,7 +2315,7 @@ void test_d2ull(char *s, char *orig) } } -void test_d2ll(char *s, char *orig) +void test_d2ll(char *s, char *orig, int ex) { char s1[100]; longlong x; @@ -1838,6 +2326,7 @@ void test_d2ll(char *s, char *orig) if (full) dump_decimal(&a); longlong10_to_str(x,s1,-10); printf("%-40s => res=%d %s\n", s, res, s1); + check_result_code(res, ex); if (orig && strcmp(orig, s1)) { printf("\n^^^^^^^^^^^^^ must've been '%s'\n", orig); @@ -1845,7 +2334,7 @@ void test_d2ll(char *s, char *orig) } } -void test_da(char *s1, char *s2, char *orig) +void test_da(char *s1, char *s2, char *orig, int ex) { char s[100]; int res; @@ -1854,11 +2343,11 @@ void test_da(char *s1, char *s2, char *orig) string2decimal(s2, &b, 0); res=decimal_add(&a, &b, &c); printf("%-40s => res=%d ", s, res); - print_decimal(&c, orig); + print_decimal(&c, orig, res, ex); printf("\n"); } -void test_ds(char *s1, char *s2, char *orig) +void test_ds(char *s1, char *s2, char *orig, int ex) { char s[100]; int res; @@ -1867,7 +2356,7 @@ void test_ds(char *s1, char *s2, char *orig) string2decimal(s2, &b, 0); res=decimal_sub(&a, &b, &c); printf("%-40s => res=%d ", s, res); - print_decimal(&c, orig); + print_decimal(&c, orig, res, ex); printf("\n"); } @@ -1887,7 +2376,7 @@ void test_dc(char *s1, char *s2, int orig) } } -void test_dm(char *s1, char *s2, char *orig) +void test_dm(char *s1, char *s2, char *orig, int ex) { char s[100]; int res; @@ -1896,11 +2385,11 @@ void test_dm(char *s1, char *s2, char *orig) string2decimal(s2, &b, 0); res=decimal_mul(&a, &b, &c); printf("%-40s => res=%d ", s, res); - print_decimal(&c, orig); + print_decimal(&c, orig, res, ex); printf("\n"); } -void test_dv(char *s1, char *s2, char *orig) +void test_dv(char *s1, char *s2, char *orig, int ex) { char s[100]; int res; @@ -1909,14 +2398,15 @@ void test_dv(char *s1, char *s2, char *orig) string2decimal(s2, &b, 0); res=decimal_div(&a, &b, &c, 5); printf("%-40s => res=%d ", s, res); + check_result_code(res, ex); if (res == E_DEC_DIV_ZERO) printf("E_DEC_DIV_ZERO"); else - print_decimal(&c, orig); + print_decimal(&c, orig, res, ex); printf("\n"); } -void test_md(char *s1, char *s2, char *orig) +void test_md(char *s1, char *s2, char *orig, int ex) { char s[100]; int res; @@ -1925,16 +2415,17 @@ void test_md(char *s1, char *s2, char *orig) string2decimal(s2, &b, 0); res=decimal_mod(&a, &b, &c); printf("%-40s => res=%d ", s, res); + check_result_code(res, ex); if (res == E_DEC_DIV_ZERO) printf("E_DEC_DIV_ZERO"); else - print_decimal(&c, orig); + print_decimal(&c, orig, res, ex); printf("\n"); } char *round_mode[]={"TRUNCATE", "HALF_EVEN", "HALF_UP", "CEILING", "FLOOR"}; -void test_ro(char *s1, int n, decimal_round_mode mode, char *orig) +void test_ro(char *s1, int n, decimal_round_mode mode, char *orig, int ex) { char s[100]; int res; @@ -1942,11 +2433,69 @@ void test_ro(char *s1, int n, decimal_round_mode mode, char *orig) string2decimal(s1, &a, 0); res=decimal_round(&a, &b, n, mode); printf("%-40s => res=%d ", s, res); - print_decimal(&b, orig); + print_decimal(&b, orig, res, ex); + printf("\n"); +} + + +void test_mx(int precision, int frac, char *orig) +{ + char s[100]; + sprintf(s, "%d, %d", precision, frac); + max_decimal(precision, frac, &a); + printf("%-40s => ", s); + print_decimal(&a, orig, 0, 0); + printf("\n"); +} + + +void test_pr(char *s1, int prec, int dec, char filler, char *orig, int ex) +{ + char s[100]; + char s2[100]; + int slen= sizeof(s2); + int res; + + sprintf(s, "'%s', %d, %d, '%c'", s1, prec, dec, filler); + string2decimal(s1, &a, 0); + res= decimal2string(&a, s2, &slen, prec, dec, filler); + printf("%-40s => res=%d '%s'", s, res, s2); + check_result_code(res, ex); + if (orig && strcmp(orig, s2)) + { + printf("\n^^^^^^^^^^^^^ must've been '%s'\n", orig); + exit(1); + } + printf("\n"); +} + + +void test_sh(char *s1, int shift, char *orig, int ex) +{ + char s[100]; + int res; + sprintf(s, "'%s' %s %d", s1, ((shift < 0) ? ">>" : "<<"), abs(shift)); + string2decimal(s1, &a, 0); + res= decimal_shift(&a, shift); + printf("%-40s => res=%d ", s, res); + print_decimal(&a, orig, res, ex); printf("\n"); } -main() + +void test_fr(char *s1, char *orig) +{ + char s[100]; + sprintf(s, "'%s'", s1); + printf("%-40s => ", s); + string2decimal(s1, &a, 0); + decimal_optimize_fraction(&a); + print_decimal(&a, orig, 0, 0); + printf("\n"); +} + + +int main() { a.buf=(void*)buf1; a.len=sizeof(buf1)/sizeof(dec1); @@ -1959,142 +2508,145 @@ main() test_d2s(); printf("==== string2decimal ====\n"); - test_s2d("12345", "12345"); - test_s2d("12345.", "12345"); - test_s2d("123.45", "123.45"); - test_s2d("-123.45", "-123.45"); - test_s2d(".00012345000098765", ".00012345000098765"); - test_s2d(".12345000098765", ".12345000098765"); - test_s2d("-.000000012345000098765", "-.000000012345000098765"); - test_s2d("1234500009876.5", "1234500009876.5"); + test_s2d("12345", "12345", 0); + test_s2d("12345.", "12345", 0); + test_s2d("123.45", "123.45", 0); + test_s2d("-123.45", "-123.45", 0); + test_s2d(".00012345000098765", "0.00012345000098765", 0); + test_s2d(".12345000098765", "0.12345000098765", 0); + test_s2d("-.000000012345000098765", "-0.000000012345000098765", 0); + test_s2d("1234500009876.5", "1234500009876.5", 0); a.len=1; - test_s2d("123450000098765", "98765"); - test_s2d("123450.000098765", "123450"); + test_s2d("123450000098765", "98765", 2); + test_s2d("123450.000098765", "123450", 1); a.len=sizeof(buf1)/sizeof(dec1); + test_s2d("123E5", "12300000", 0); + test_s2d("123E-2", "1.23", 0); printf("==== decimal2double ====\n"); - test_d2f("12345"); - test_d2f("123.45"); - test_d2f("-123.45"); - test_d2f(".00012345000098765"); - test_d2f("1234500009876.5"); + test_d2f("12345", 0); + test_d2f("123.45", 0); + test_d2f("-123.45", 0); + test_d2f("0.00012345000098765", 0); + test_d2f("1234500009876.5", 0); printf("==== double2decimal ====\n"); - test_f2d(12345); - test_f2d(1.0/3); - test_f2d(-123.45); - test_f2d(0.00012345000098765); - test_f2d(1234500009876.5); + test_f2d(12345, 0); + test_f2d(1.0/3, 0); + test_f2d(-123.45, 0); + test_f2d(0.00012345000098765, 0); + test_f2d(1234500009876.5, 0); printf("==== ulonglong2decimal ====\n"); - test_ull2d(ULL(12345), "12345"); - test_ull2d(ULL(0), "0"); - test_ull2d(ULL(18446744073709551615), "18446744073709551615"); + test_ull2d(ULL(12345), "12345", 0); + test_ull2d(ULL(0), "0", 0); + test_ull2d(ULL(18446744073709551615), "18446744073709551615", 0); printf("==== decimal2ulonglong ====\n"); - test_d2ull("12345", "12345"); - test_d2ull("0", "0"); - test_d2ull("18446744073709551615", "18446744073709551615"); - test_d2ull("18446744073709551616", "18446744073"); - test_d2ull("-1", "0"); - test_d2ull("1.23", "1"); - test_d2ull("9999999999999999999999999.000", "9999999999999999"); + test_d2ull("12345", "12345", 0); + test_d2ull("0", "0", 0); + test_d2ull("18446744073709551615", "18446744073709551615", 0); + test_d2ull("18446744073709551616", "18446744073", 2); + test_d2ull("-1", "0", 2); + test_d2ull("1.23", "1", 1); + test_d2ull("9999999999999999999999999.000", "9999999999999999", 2); printf("==== longlong2decimal ====\n"); - test_ll2d(LL(-12345), "-12345"); - test_ll2d(LL(-1), "-1"); - test_ll2d(LL(-9223372036854775807), "-9223372036854775807"); - test_ll2d(ULL(9223372036854775808), "-9223372036854775808"); + test_ll2d(LL(-12345), "-12345", 0); + test_ll2d(LL(-1), "-1", 0); + test_ll2d(LL(-9223372036854775807), "-9223372036854775807", 0); + test_ll2d(ULL(9223372036854775808), "-9223372036854775808", 0); printf("==== decimal2longlong ====\n"); - test_d2ll("18446744073709551615", "18446744073"); - test_d2ll("-1", "-1"); - test_d2ll("-1.23", "-1"); - test_d2ll("-9223372036854775807", "-9223372036854775807"); - test_d2ll("-9223372036854775808", "-9223372036854775808"); - test_d2ll("9223372036854775808", "9223372036854775807"); + test_d2ll("18446744073709551615", "18446744073", 2); + test_d2ll("-1", "-1", 0); + test_d2ll("-1.23", "-1", 1); + test_d2ll("-9223372036854775807", "-9223372036854775807", 0); + test_d2ll("-9223372036854775808", "-9223372036854775808", 0); + test_d2ll("9223372036854775808", "9223372036854775807", 2); printf("==== do_add ====\n"); - test_da(".00012345000098765" ,"123.45", "123.45012345000098765"); - test_da(".1" ,".45", ".55"); - test_da("1234500009876.5" ,".00012345000098765", "1234500009876.50012345000098765"); - test_da("9999909999999.5" ,".555", "9999910000000.055"); - test_da("99999999" ,"1", "100000000"); - test_da("989999999" ,"1", "990000000"); - test_da("999999999" ,"1", "1000000000"); - test_da("12345" ,"123.45", "12468.45"); - test_da("-12345" ,"-123.45", "-12468.45"); - test_ds("-12345" ,"123.45", "-12468.45"); - test_ds("12345" ,"-123.45", "12468.45"); + test_da(".00012345000098765" ,"123.45", "123.45012345000098765", 0); + test_da(".1" ,".45", "0.55", 0); + test_da("1234500009876.5" ,".00012345000098765", "1234500009876.50012345000098765", 0); + test_da("9999909999999.5" ,".555", "9999910000000.055", 0); + test_da("99999999" ,"1", "100000000", 0); + test_da("989999999" ,"1", "990000000", 0); + test_da("999999999" ,"1", "1000000000", 0); + test_da("12345" ,"123.45", "12468.45", 0); + test_da("-12345" ,"-123.45", "-12468.45", 0); + test_ds("-12345" ,"123.45", "-12468.45", 0); + test_ds("12345" ,"-123.45", "12468.45", 0); printf("==== do_sub ====\n"); - test_ds(".00012345000098765", "123.45","-123.44987654999901235"); - test_ds("1234500009876.5", ".00012345000098765","1234500009876.49987654999901235"); - test_ds("9999900000000.5", ".555","9999899999999.945"); - test_ds("1111.5551", "1111.555",".0001"); - test_ds(".555", ".555","0"); - test_ds("10000000", "1","9999999"); - test_ds("1000001000", ".1","1000000999.9"); - test_ds("1000000000", ".1","999999999.9"); - test_ds("12345", "123.45","12221.55"); - test_ds("-12345", "-123.45","-12221.55"); - test_da("-12345", "123.45","-12221.55"); - test_da("12345", "-123.45","12221.55"); - test_ds("123.45", "12345","-12221.55"); - test_ds("-123.45", "-12345","12221.55"); - test_da("123.45", "-12345","-12221.55"); - test_da("-123.45", "12345","12221.55"); - test_da("5", "-6.0","-1.0"); + test_ds(".00012345000098765", "123.45","-123.44987654999901235", 0); + test_ds("1234500009876.5", ".00012345000098765","1234500009876.49987654999901235", 0); + test_ds("9999900000000.5", ".555","9999899999999.945", 0); + test_ds("1111.5551", "1111.555","0.0001", 0); + test_ds(".555", ".555","0", 0); + test_ds("10000000", "1","9999999", 0); + test_ds("1000001000", ".1","1000000999.9", 0); + test_ds("1000000000", ".1","999999999.9", 0); + test_ds("12345", "123.45","12221.55", 0); + test_ds("-12345", "-123.45","-12221.55", 0); + test_da("-12345", "123.45","-12221.55", 0); + test_da("12345", "-123.45","12221.55", 0); + test_ds("123.45", "12345","-12221.55", 0); + test_ds("-123.45", "-12345","12221.55", 0); + test_da("123.45", "-12345","-12221.55", 0); + test_da("-123.45", "12345","12221.55", 0); + test_da("5", "-6.0","-1.0", 0); printf("==== decimal_mul ====\n"); - test_dm("12", "10","120"); - test_dm("-123.456", "98765.4321","-12193185.1853376"); - test_dm("-123456000000", "98765432100000","-12193185185337600000000000"); - test_dm("123456", "987654321","121931851853376"); - test_dm("123456", "9876543210","1219318518533760"); - test_dm("123", "0.01","1.23"); - test_dm("123", "0","0"); + test_dm("12", "10","120", 0); + test_dm("-123.456", "98765.4321","-12193185.1853376", 0); + test_dm("-123456000000", "98765432100000","-12193185185337600000000000", 0); + test_dm("123456", "987654321","121931851853376", 0); + test_dm("123456", "9876543210","1219318518533760", 0); + test_dm("123", "0.01","1.23", 0); + test_dm("123", "0","0", 0); printf("==== decimal_div ====\n"); - test_dv("120", "10","12.000000000"); - test_dv("123", "0.01","12300.000000000"); - test_dv("120", "100000000000.00000",".000000001200000000"); - test_dv("123", "0",""); - test_dv("-12193185.1853376", "98765.4321","-123.456000000000000000"); - test_dv("121931851853376", "987654321","123456.000000000"); - test_dv("0", "987","0"); - test_dv("1", "3",".333333333"); - test_dv("1.000000000000", "3",".333333333333333333"); - test_dv("1", "1","1.000000000"); - test_dv("0.0123456789012345678912345", "9999999999",".000000000001234567890246913578148141"); + test_dv("120", "10","12.000000000", 0); + test_dv("123", "0.01","12300.000000000", 0); + test_dv("120", "100000000000.00000","0.000000001200000000", 0); + test_dv("123", "0","", 4); + test_dv("-12193185.1853376", "98765.4321","-123.456000000000000000", 0); + test_dv("121931851853376", "987654321","123456.000000000", 0); + test_dv("0", "987","0", 0); + test_dv("1", "3","0.333333333", 0); + test_dv("1.000000000000", "3","0.333333333333333333", 0); + test_dv("1", "1","1.000000000", 0); + test_dv("0.0123456789012345678912345", "9999999999","0.000000000001234567890246913578148141", 0); printf("==== decimal_mod ====\n"); - test_md("234","10","4"); - test_md("234.567","10.555","2.357"); - test_md("-234.567","10.555","-2.357"); - test_md("234.567","-10.555","2.357"); + test_md("234","10","4", 0); + test_md("234.567","10.555","2.357", 0); + test_md("-234.567","10.555","-2.357", 0); + test_md("234.567","-10.555","2.357", 0); if (full) { c.buf[1]=0x3ABECA; - test_md("99999999999999999999999999999999999999","3","0"); + test_md("99999999999999999999999999999999999999","3","0", 0); printf("%X\n", c.buf[1]); } printf("==== decimal2bin/bin2decimal ====\n"); - test_d2b2d("-10.55", 4, 2,"-10.55"); - test_d2b2d("0.0123456789012345678912345", 30, 25,".0123456789012345678912345"); - test_d2b2d("12345", 5, 0,"12345"); - test_d2b2d("12345", 10, 3,"12345.000"); - test_d2b2d("123.45", 10, 3,"123.450"); - test_d2b2d("-123.45", 20, 10,"-123.4500000000"); - test_d2b2d(".00012345000098765", 15, 14,".00012345000098"); - test_d2b2d(".00012345000098765", 22, 20,".00012345000098765000"); - test_d2b2d(".12345000098765", 30, 20,".12345000098765000000"); - test_d2b2d("-.000000012345000098765", 30, 20,"-.00000001234500009876"); - test_d2b2d("1234500009876.5", 30, 5,"1234500009876.50000"); - test_d2b2d("111111111.11", 10, 2,"11111111.11"); - full=1; - test_d2b2d("123.4", 10, 2, "123.40"); + test_d2b2d("-10.55", 4, 2,"-10.55", 0); + test_d2b2d("0.0123456789012345678912345", 30, 25,"0.0123456789012345678912345", 0); + test_d2b2d("12345", 5, 0,"12345", 0); + test_d2b2d("12345", 10, 3,"12345.000", 0); + test_d2b2d("123.45", 10, 3,"123.450", 0); + test_d2b2d("-123.45", 20, 10,"-123.4500000000", 0); + test_d2b2d(".00012345000098765", 15, 14,"0.00012345000098", 0); + test_d2b2d(".00012345000098765", 22, 20,"0.00012345000098765000", 0); + test_d2b2d(".12345000098765", 30, 20,"0.12345000098765000000", 0); + test_d2b2d("-.000000012345000098765", 30, 20,"-0.00000001234500009876", 0); + test_d2b2d("1234500009876.5", 30, 5,"1234500009876.50000", 0); + test_d2b2d("111111111.11", 10, 2,"11111111.11", 0); + test_d2b2d("000000000.01", 7, 3,"0.010", 0); + test_d2b2d("123.4", 10, 2, "123.40", 0); + printf("==== decimal_cmp ====\n"); test_dc("12","13",-1); @@ -2107,45 +2659,174 @@ main() test_dc("4","4",0); printf("==== decimal_round ====\n"); - test_ro("5678.123451",-4,TRUNCATE,"0"); - test_ro("5678.123451",-3,TRUNCATE,"5000"); - test_ro("5678.123451",-2,TRUNCATE,"5600"); - test_ro("5678.123451",-1,TRUNCATE,"5670"); - test_ro("5678.123451",0,TRUNCATE,"5678"); - test_ro("5678.123451",1,TRUNCATE,"5678.1"); - test_ro("5678.123451",2,TRUNCATE,"5678.12"); - test_ro("5678.123451",3,TRUNCATE,"5678.123"); - test_ro("5678.123451",4,TRUNCATE,"5678.1234"); - test_ro("5678.123451",5,TRUNCATE,"5678.12345"); - test_ro("5678.123451",6,TRUNCATE,"5678.123451"); - test_ro("-5678.123451",-4,TRUNCATE,"0"); + test_ro("5678.123451",-4,TRUNCATE,"0", 0); + test_ro("5678.123451",-3,TRUNCATE,"5000", 0); + test_ro("5678.123451",-2,TRUNCATE,"5600", 0); + test_ro("5678.123451",-1,TRUNCATE,"5670", 0); + test_ro("5678.123451",0,TRUNCATE,"5678", 0); + test_ro("5678.123451",1,TRUNCATE,"5678.1", 0); + test_ro("5678.123451",2,TRUNCATE,"5678.12", 0); + test_ro("5678.123451",3,TRUNCATE,"5678.123", 0); + test_ro("5678.123451",4,TRUNCATE,"5678.1234", 0); + test_ro("5678.123451",5,TRUNCATE,"5678.12345", 0); + test_ro("5678.123451",6,TRUNCATE,"5678.123451", 0); + test_ro("-5678.123451",-4,TRUNCATE,"0", 0); memset(buf2, 33, sizeof(buf2)); - test_ro("99999999999999999999999999999999999999",-31,TRUNCATE,"99999990000000000000000000000000000000"); - test_ro("15.1",0,HALF_UP,"15"); - test_ro("15.5",0,HALF_UP,"16"); - test_ro("15.9",0,HALF_UP,"16"); - test_ro("-15.1",0,HALF_UP,"-15"); - test_ro("-15.5",0,HALF_UP,"-16"); - test_ro("-15.9",0,HALF_UP,"-16"); - test_ro("15.1",1,HALF_UP,"15.1"); - test_ro("-15.1",1,HALF_UP,"-15.1"); - test_ro("15.17",1,HALF_UP,"15.2"); - test_ro("15.4",-1,HALF_UP,"20"); - test_ro("-15.4",-1,HALF_UP,"-20"); - test_ro("5.4",-1,HALF_UP,"10"); - test_ro(".999", 0, HALF_UP, "1"); + test_ro("99999999999999999999999999999999999999",-31,TRUNCATE,"99999990000000000000000000000000000000", 0); + test_ro("15.1",0,HALF_UP,"15", 0); + test_ro("15.5",0,HALF_UP,"16", 0); + test_ro("15.9",0,HALF_UP,"16", 0); + test_ro("-15.1",0,HALF_UP,"-15", 0); + test_ro("-15.5",0,HALF_UP,"-16", 0); + test_ro("-15.9",0,HALF_UP,"-16", 0); + test_ro("15.1",1,HALF_UP,"15.1", 0); + test_ro("-15.1",1,HALF_UP,"-15.1", 0); + test_ro("15.17",1,HALF_UP,"15.2", 0); + test_ro("15.4",-1,HALF_UP,"20", 0); + test_ro("-15.4",-1,HALF_UP,"-20", 0); + test_ro("5.4",-1,HALF_UP,"10", 0); + test_ro(".999", 0, HALF_UP, "1", 0); memset(buf2, 33, sizeof(buf2)); - test_ro("999999999", -9, HALF_UP, "1000000000"); - test_ro("15.1",0,HALF_EVEN,"15"); - test_ro("15.5",0,HALF_EVEN,"16"); - test_ro("14.5",0,HALF_EVEN,"14"); - test_ro("15.9",0,HALF_EVEN,"16"); - test_ro("15.1",0,CEILING,"16"); - test_ro("-15.1",0,CEILING,"-15"); - test_ro("15.1",0,FLOOR,"15"); - test_ro("-15.1",0,FLOOR,"-16"); - test_ro("999999999999999999999.999", 0, CEILING,"1000000000000000000000"); - test_ro("-999999999999999999999.999", 0, FLOOR,"-1000000000000000000000"); + test_ro("999999999", -9, HALF_UP, "1000000000", 0); + test_ro("15.1",0,HALF_EVEN,"15", 0); + test_ro("15.5",0,HALF_EVEN,"16", 0); + test_ro("14.5",0,HALF_EVEN,"14", 0); + test_ro("15.9",0,HALF_EVEN,"16", 0); + test_ro("15.1",0,CEILING,"16", 0); + test_ro("-15.1",0,CEILING,"-15", 0); + test_ro("15.1",0,FLOOR,"15", 0); + test_ro("-15.1",0,FLOOR,"-16", 0); + test_ro("999999999999999999999.999", 0, CEILING,"1000000000000000000000", 0); + test_ro("-999999999999999999999.999", 0, FLOOR,"-1000000000000000000000", 0); + + printf("==== max_decimal ====\n"); + test_mx(1,1,"0.9"); + test_mx(1,0,"9"); + test_mx(2,1,"9.9"); + test_mx(4,2,"99.99"); + test_mx(6,3,"999.999"); + test_mx(8,4,"9999.9999"); + test_mx(10,5,"99999.99999"); + test_mx(12,6,"999999.999999"); + test_mx(14,7,"9999999.9999999"); + test_mx(16,8,"99999999.99999999"); + test_mx(18,9,"999999999.999999999"); + test_mx(20,10,"9999999999.9999999999"); + test_mx(20,20,"0.99999999999999999999"); + test_mx(20,0,"99999999999999999999"); + test_mx(40,20,"99999999999999999999.99999999999999999999"); + + printf("==== decimal2string ====\n"); + test_pr("123.123", 0, 0, 0, "123.123", 0); + test_pr("123.123", 7, 3, '0', "123.123", 0); + test_pr("123.123", 9, 3, '0', "00123.123", 0); + test_pr("123.123", 9, 4, '0', "0123.1230", 0); + test_pr("123.123", 9, 5, '0', "123.12300", 0); + test_pr("123.123", 9, 2, '0', "000123.12", 1); + test_pr("123.123", 9, 6, '0', "23.123000", 2); + + printf("==== decimal_shift ====\n"); + test_sh("123.123", 1, "1231.23", 0); + test_sh("123457189.123123456789000", 1, "1234571891.23123456789", 0); + test_sh("123457189.123123456789000", 4, "1234571891231.23456789", 0); + test_sh("123457189.123123456789000", 8, "12345718912312345.6789", 0); + test_sh("123457189.123123456789000", 9, "123457189123123456.789", 0); + test_sh("123457189.123123456789000", 10, "1234571891231234567.89", 0); + test_sh("123457189.123123456789000", 17, "12345718912312345678900000", 0); + test_sh("123457189.123123456789000", 18, "123457189123123456789000000", 0); + test_sh("123457189.123123456789000", 19, "1234571891231234567890000000", 0); + test_sh("123457189.123123456789000", 26, "12345718912312345678900000000000000", 0); + test_sh("123457189.123123456789000", 27, "123457189123123456789000000000000000", 0); + test_sh("123457189.123123456789000", 28, "1234571891231234567890000000000000000", 0); + test_sh("000000000000000000000000123457189.123123456789000", 26, "12345718912312345678900000000000000", 0); + test_sh("00000000123457189.123123456789000", 27, "123457189123123456789000000000000000", 0); + test_sh("00000000000000000123457189.123123456789000", 28, "1234571891231234567890000000000000000", 0); + test_sh("123", 1, "1230", 0); + test_sh("123", 10, "1230000000000", 0); + test_sh(".123", 1, "1.23", 0); + test_sh(".123", 10, "1230000000", 0); + test_sh(".123", 14, "12300000000000", 0); + test_sh("000.000", 1000, "0", 0); + test_sh("000.", 1000, "0", 0); + test_sh(".000", 1000, "0", 0); + test_sh("1", 1000, "1", 2); + test_sh("123.123", -1, "12.3123", 0); + test_sh("123987654321.123456789000", -1, "12398765432.1123456789", 0); + test_sh("123987654321.123456789000", -2, "1239876543.21123456789", 0); + test_sh("123987654321.123456789000", -3, "123987654.321123456789", 0); + test_sh("123987654321.123456789000", -8, "1239.87654321123456789", 0); + test_sh("123987654321.123456789000", -9, "123.987654321123456789", 0); + test_sh("123987654321.123456789000", -10, "12.3987654321123456789", 0); + test_sh("123987654321.123456789000", -11, "1.23987654321123456789", 0); + test_sh("123987654321.123456789000", -12, "0.123987654321123456789", 0); + test_sh("123987654321.123456789000", -13, "0.0123987654321123456789", 0); + test_sh("123987654321.123456789000", -14, "0.00123987654321123456789", 0); + test_sh("00000087654321.123456789000", -14, "0.00000087654321123456789", 0); + a.len= 2; + test_sh("123.123", -2, "1.23123", 0); + test_sh("123.123", -3, "0.123123", 0); + test_sh("123.123", -6, "0.000123123", 0); + test_sh("123.123", -7, "0.0000123123", 0); + test_sh("123.123", -15, "0.000000000000123123", 0); + test_sh("123.123", -16, "0.000000000000012312", 1); + test_sh("123.123", -17, "0.000000000000001231", 1); + test_sh("123.123", -18, "0.000000000000000123", 1); + test_sh("123.123", -19, "0.000000000000000012", 1); + test_sh("123.123", -20, "0.000000000000000001", 1); + test_sh("123.123", -21, "0", 1); + test_sh(".000000000123", -1, "0.0000000000123", 0); + test_sh(".000000000123", -6, "0.000000000000000123", 0); + test_sh(".000000000123", -7, "0.000000000000000012", 1); + test_sh(".000000000123", -8, "0.000000000000000001", 1); + test_sh(".000000000123", -9, "0", 1); + test_sh(".000000000123", 1, "0.00000000123", 0); + test_sh(".000000000123", 8, "0.0123", 0); + test_sh(".000000000123", 9, "0.123", 0); + test_sh(".000000000123", 10, "1.23", 0); + test_sh(".000000000123", 17, "12300000", 0); + test_sh(".000000000123", 18, "123000000", 0); + test_sh(".000000000123", 19, "1230000000", 0); + test_sh(".000000000123", 20, "12300000000", 0); + test_sh(".000000000123", 21, "123000000000", 0); + test_sh(".000000000123", 22, "1230000000000", 0); + test_sh(".000000000123", 23, "12300000000000", 0); + test_sh(".000000000123", 24, "123000000000000", 0); + test_sh(".000000000123", 25, "1230000000000000", 0); + test_sh(".000000000123", 26, "12300000000000000", 0); + test_sh(".000000000123", 27, "123000000000000000", 0); + test_sh(".000000000123", 28, "0.000000000123", 2); + test_sh("123456789.987654321", -1, "12345678.998765432", 1); + test_sh("123456789.987654321", -2, "1234567.899876543", 1); + test_sh("123456789.987654321", -8, "1.234567900", 1); + test_sh("123456789.987654321", -9, "0.123456789987654321", 0); + test_sh("123456789.987654321", -10, "0.012345678998765432", 1); + test_sh("123456789.987654321", -17, "0.000000001234567900", 1); + test_sh("123456789.987654321", -18, "0.000000000123456790", 1); + test_sh("123456789.987654321", -19, "0.000000000012345679", 1); + test_sh("123456789.987654321", -26, "0.000000000000000001", 1); + test_sh("123456789.987654321", -27, "0", 1); + test_sh("123456789.987654321", 1, "1234567900", 1); + test_sh("123456789.987654321", 2, "12345678999", 1); + test_sh("123456789.987654321", 4, "1234567899877", 1); + test_sh("123456789.987654321", 8, "12345678998765432", 1); + test_sh("123456789.987654321", 9, "123456789987654321", 0); + test_sh("123456789.987654321", 10, "123456789.987654321", 2); + test_sh("123456789.987654321", 0, "123456789.987654321", 0); + a.len= sizeof(buf1)/sizeof(dec1); + + printf("==== decimal_optimize_fraction ====\n"); + test_fr("1.123456789000000000", "1.123456789"); + test_fr("1.12345678000000000", "1.12345678"); + test_fr("1.1234567000000000", "1.1234567"); + test_fr("1.123456000000000", "1.123456"); + test_fr("1.12345000000000", "1.12345"); + test_fr("1.1234000000000", "1.1234"); + test_fr("1.123000000000", "1.123"); + test_fr("1.12000000000", "1.12"); + test_fr("1.1000000000", "1.1"); + test_fr("1.000000000", "1"); + test_fr("1.0", "1"); + test_fr("10000000000000000000.0", "10000000000000000000"); return 0; } diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 3cbc9918d6c..36cff4d23aa 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -7258,7 +7258,7 @@ static void test_decimal_bug() */ bzero((char*) bind, sizeof(bind)); - bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer_type= MYSQL_TYPE_NEWDECIMAL; bind[0].buffer= (void *)data; bind[0].buffer_length= 25; bind[0].is_null= &is_null; |