diff options
-rw-r--r-- | mysql-test/r/func_time.result | 132 | ||||
-rw-r--r-- | mysql-test/r/type_decimal.result | 4 | ||||
-rw-r--r-- | mysql-test/r/type_newdecimal.result | 6 | ||||
-rw-r--r-- | mysql-test/suite/rpl/r/kill_hard-6290.result | 4 | ||||
-rw-r--r-- | mysql-test/suite/rpl/t/kill_hard-6290.test | 11 | ||||
-rw-r--r-- | mysql-test/t/func_time.test | 84 | ||||
-rw-r--r-- | sql/field.h | 23 | ||||
-rw-r--r-- | sql/item.h | 38 | ||||
-rw-r--r-- | sql/item_func.cc | 91 | ||||
-rw-r--r-- | sql/item_func.h | 17 | ||||
-rw-r--r-- | sql/item_timefunc.h | 10 | ||||
-rw-r--r-- | sql/sql_parse.cc | 2 | ||||
-rw-r--r-- | storage/tokudb/mysql-test/tokudb/r/type_decimal.result | 4 | ||||
-rw-r--r-- | storage/tokudb/mysql-test/tokudb/r/type_newdecimal.result | 6 |
14 files changed, 346 insertions, 86 deletions
diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 995b5f702e2..8c156efbac1 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -1941,9 +1941,139 @@ SELECT 1 FROM DUAL WHERE MINUTE(TIMEDIFF(NULL, '12:12:12')); SELECT 1 FROM DUAL WHERE SECOND(TIMEDIFF(NULL, '12:12:12')); 1 # -# MDEV-4635 Crash in UNIX_TIMESTAMP(STR_TO_DATE('2020','%Y')) +# MDEV-4511 Assertion `scale <= precision' fails on GROUP BY TIMEDIFF with incorrect types # +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT a FROM t1 GROUP BY TIMEDIFF('2004-06-12',a) * 1; +a +2005-05-04 +Warnings: +Warning 1292 Truncated incorrect time value: '2004-06-12' +Warning 1292 Truncated incorrect time value: '2004-06-12' +DROP TABLE t1; +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT a FROM t1 GROUP BY ADDTIME(a,'10')*1; +a +2000-02-23 +2005-05-04 +DROP TABLE t1; +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT * FROM t1 GROUP BY SEC_TO_TIME(concat(a,'10'))*1; +a +2000-02-23 +2005-05-04 +DROP TABLE t1; +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT * FROM t1 GROUP BY ADDTIME(timestamp('2001-01-01 00:00:00'),CAST(a AS SIGNED)&0xF)*1; +a +2005-05-04 +2000-02-23 +DROP TABLE t1; +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT * FROM t1 GROUP BY STR_TO_DATE(a,concat('%Y-%m-%d.%f',if(rand(),'','')))*1; +a +2000-02-23 +2005-05-04 +DROP TABLE t1; +CREATE TABLE t1 AS SELECT +STR_TO_DATE('2001-01-01', '%Y-%m-%d') AS date_only, +STR_TO_DATE('10:10:10', '%H:%i:%s') AS time_only, +STR_TO_DATE('10:10:10.123', '%H:%i:%s.%f') AS time_microsecond, +STR_TO_DATE('2001-01-01 10:10:10', '%Y-%m-%d %H:%i:%s') AS date_time, +STR_TO_DATE('2001-01-01 10:10:10.123', '%Y-%m-%d %H:%i:%s.%f') AS date_time_microsecond; +SHOW COLUMNS FROM t1; +Field Type Null Key Default Extra +date_only date YES NULL +time_only time YES NULL +time_microsecond time(6) YES NULL +date_time datetime YES NULL +date_time_microsecond datetime(6) YES NULL +DROP TABLE t1; +CREATE TABLE t1 AS SELECT +SEC_TO_TIME(1)+0.1, +SEC_TO_TIME(1.1)+0.1, +SEC_TO_TIME(1.12)+0.1, +SEC_TO_TIME(1.123456)+0.1, +SEC_TO_TIME(1.1234567)+0.1; +SHOW COLUMNS FROM t1; +Field Type Null Key Default Extra +SEC_TO_TIME(1)+0.1 decimal(12,1) YES NULL +SEC_TO_TIME(1.1)+0.1 decimal(13,1) YES NULL +SEC_TO_TIME(1.12)+0.1 decimal(14,2) YES NULL +SEC_TO_TIME(1.123456)+0.1 decimal(18,6) YES NULL +SEC_TO_TIME(1.1234567)+0.1 decimal(18,6) YES NULL +DROP TABLE t1; +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT * FROM t1 GROUP BY FROM_UNIXTIME(concat(a,'10'))*1; +a +2000-02-23 +2005-05-04 +SELECT * FROM t1 GROUP BY (-FROM_UNIXTIME(concat(a,'10')))*1; +a +2005-05-04 +2000-02-23 +SELECT * FROM t1 GROUP BY (-FROM_UNIXTIME(concat(a,'10'))); +a +2005-05-04 +2000-02-23 +SELECT * FROM t1 GROUP BY ABS(FROM_UNIXTIME(concat(a,'10'))); +a +2000-02-23 +2005-05-04 +SELECT * FROM t1 GROUP BY @a:=(FROM_UNIXTIME(concat(a,'10'))*1); +a +2000-02-23 +2005-05-04 +DROP TABLE t1; SET TIME_ZONE='+02:00'; +# +# MDEV-6302 Wrong result set when using GROUP BY FROM_UNIXTIME(...)+0 +# +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT a, FROM_UNIXTIME(CONCAT(a,'10')) AS f1, FROM_UNIXTIME(CONCAT(a,'10'))+0 AS f2 FROM t1; +a f1 f2 +2005-05-04 1970-01-01 02:33:25 19700101023325.000000 +2000-02-23 1970-01-01 02:33:20 19700101023320.000000 +SELECT * FROM t1 GROUP BY FROM_UNIXTIME(CONCAT(a,'10'))+0; +a +2000-02-23 +2005-05-04 +DROP TABLE t1; +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT * FROM t1 GROUP BY FROM_UNIXTIME(concat(a,'10'))/1; +a +2000-02-23 +2005-05-04 +DROP TABLE t1; +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES ('2005-05-04'); +SELECT CONCAT(FROM_UNIXTIME(CONCAT(a,'10')) MOD FROM_UNIXTIME(CONCAT(a,'10'))) AS f2 FROM t1; +f2 +0.000000 +SELECT CHAR_LENGTH(CONCAT(FROM_UNIXTIME(CONCAT(a,'10')) MOD FROM_UNIXTIME(CONCAT(a,'10')))) AS f2 FROM t1; +f2 +8 +CREATE TABLE t2 AS SELECT CONCAT(FROM_UNIXTIME(CONCAT(a,'10')) MOD FROM_UNIXTIME(CONCAT(a,'10'))) AS f2 FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `f2` varchar(26) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM t2; +f2 +0.000000 +DROP TABLE t1,t2; +# +# MDEV-4635 Crash in UNIX_TIMESTAMP(STR_TO_DATE('2020','%Y')) +# SELECT UNIX_TIMESTAMP(STR_TO_DATE('2020','%Y')); UNIX_TIMESTAMP(STR_TO_DATE('2020','%Y')) NULL diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index fa36e9b5567..f8649f030bb 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -810,10 +810,10 @@ c1 drop table t1; SELECT 1 % .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS '%'; % -0.012345687012345687012345687012345687012345687012345687012345687012345687000000000 +0.012345687012345687012345687012 SELECT MOD(1, .123456789123456789123456789123456789123456789123456789123456789123456789123456789) AS 'MOD()'; MOD() -0.012345687012345687012345687012345687012345687012345687012345687012345687000000000 +0.012345687012345687012345687012 create table t1 (f1 decimal(6,6),f2 decimal(6,6) zerofill); insert into t1 values (-0.123456,0.123456); select group_concat(f1),group_concat(f2) from t1; diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index 6b6b5a2392c..7e030591fcd 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -703,7 +703,7 @@ select .7777777777777777777777777777777777777 * 777777777777777777.777777777777777777700000000000 select .7777777777777777777777777777777777777 - 0.1; .7777777777777777777777777777777777777 - 0.1 -0.6777777777777777777777777777777777777 +0.677777777777777777777777777778 select .343434343434343434 + .343434343434343434; .343434343434343434 + .343434343434343434 0.686868686868686868 @@ -1840,7 +1840,7 @@ Warnings: Note 1265 Data truncated for column 'c1' at row 4 DESC t2; Field Type Null Key Default Extra -c1 decimal(32,30) YES NULL +c1 decimal(33,30) YES NULL DROP TABLE t1,t2; CREATE TABLE t1 (a DECIMAL(30,30)); INSERT INTO t1 VALUES (0.1),(0.2),(0.3); @@ -1851,7 +1851,7 @@ Note 1265 Data truncated for column 'c1' at row 2 Note 1265 Data truncated for column 'c1' at row 3 DESC t2; Field Type Null Key Default Extra -c1 decimal(34,0) YES NULL +c1 decimal(33,30) YES NULL DROP TABLE t1,t2; CREATE TABLE t1 (a DECIMAL(30,30)); INSERT INTO t1 VALUES (0.1),(0.2),(0.3); diff --git a/mysql-test/suite/rpl/r/kill_hard-6290.result b/mysql-test/suite/rpl/r/kill_hard-6290.result new file mode 100644 index 00000000000..27b62416368 --- /dev/null +++ b/mysql-test/suite/rpl/r/kill_hard-6290.result @@ -0,0 +1,4 @@ +include/master-slave.inc +[connection master] +kill user test2@nohost; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/kill_hard-6290.test b/mysql-test/suite/rpl/t/kill_hard-6290.test new file mode 100644 index 00000000000..7624235666a --- /dev/null +++ b/mysql-test/suite/rpl/t/kill_hard-6290.test @@ -0,0 +1,11 @@ +# +# MDEV-6290 Crash in KILL HARD QUERY USER x@y when slave threads are running +# + +# this test doesn't depend on the binlog format, no need to run it three times +--source include/have_binlog_format_mixed.inc + +--source include/master-slave.inc +--connection server_2 +kill user test2@nohost; +--source include/rpl_end.inc diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 56c96bb5748..5bb19fe3587 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -1187,12 +1187,92 @@ SELECT 1 FROM DUAL WHERE SECOND(TIMEDIFF(NULL, '12:12:12')); --echo # ---echo # MDEV-4635 Crash in UNIX_TIMESTAMP(STR_TO_DATE('2020','%Y')) +--echo # MDEV-4511 Assertion `scale <= precision' fails on GROUP BY TIMEDIFF with incorrect types --echo # +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT a FROM t1 GROUP BY TIMEDIFF('2004-06-12',a) * 1; +DROP TABLE t1; + +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT a FROM t1 GROUP BY ADDTIME(a,'10')*1; +DROP TABLE t1; + +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT * FROM t1 GROUP BY SEC_TO_TIME(concat(a,'10'))*1; +DROP TABLE t1; + +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT * FROM t1 GROUP BY ADDTIME(timestamp('2001-01-01 00:00:00'),CAST(a AS SIGNED)&0xF)*1; +DROP TABLE t1; + +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT * FROM t1 GROUP BY STR_TO_DATE(a,concat('%Y-%m-%d.%f',if(rand(),'','')))*1; +DROP TABLE t1; + +CREATE TABLE t1 AS SELECT + STR_TO_DATE('2001-01-01', '%Y-%m-%d') AS date_only, + STR_TO_DATE('10:10:10', '%H:%i:%s') AS time_only, + STR_TO_DATE('10:10:10.123', '%H:%i:%s.%f') AS time_microsecond, + STR_TO_DATE('2001-01-01 10:10:10', '%Y-%m-%d %H:%i:%s') AS date_time, + STR_TO_DATE('2001-01-01 10:10:10.123', '%Y-%m-%d %H:%i:%s.%f') AS date_time_microsecond; +SHOW COLUMNS FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 AS SELECT + SEC_TO_TIME(1)+0.1, + SEC_TO_TIME(1.1)+0.1, + SEC_TO_TIME(1.12)+0.1, + SEC_TO_TIME(1.123456)+0.1, + SEC_TO_TIME(1.1234567)+0.1; +SHOW COLUMNS FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT * FROM t1 GROUP BY FROM_UNIXTIME(concat(a,'10'))*1; +SELECT * FROM t1 GROUP BY (-FROM_UNIXTIME(concat(a,'10')))*1; +SELECT * FROM t1 GROUP BY (-FROM_UNIXTIME(concat(a,'10'))); +SELECT * FROM t1 GROUP BY ABS(FROM_UNIXTIME(concat(a,'10'))); +SELECT * FROM t1 GROUP BY @a:=(FROM_UNIXTIME(concat(a,'10'))*1); + +DROP TABLE t1; + SET TIME_ZONE='+02:00'; + +--echo # +--echo # MDEV-6302 Wrong result set when using GROUP BY FROM_UNIXTIME(...)+0 +--echo # +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT a, FROM_UNIXTIME(CONCAT(a,'10')) AS f1, FROM_UNIXTIME(CONCAT(a,'10'))+0 AS f2 FROM t1; +SELECT * FROM t1 GROUP BY FROM_UNIXTIME(CONCAT(a,'10'))+0; +DROP TABLE t1; + +CREATE TABLE t1 (a DATE) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('2005-05-04'),('2000-02-23'); +SELECT * FROM t1 GROUP BY FROM_UNIXTIME(concat(a,'10'))/1; +DROP TABLE t1; + +CREATE TABLE t1 (a DATE); +INSERT INTO t1 VALUES ('2005-05-04'); +SELECT CONCAT(FROM_UNIXTIME(CONCAT(a,'10')) MOD FROM_UNIXTIME(CONCAT(a,'10'))) AS f2 FROM t1; +SELECT CHAR_LENGTH(CONCAT(FROM_UNIXTIME(CONCAT(a,'10')) MOD FROM_UNIXTIME(CONCAT(a,'10')))) AS f2 FROM t1; +CREATE TABLE t2 AS SELECT CONCAT(FROM_UNIXTIME(CONCAT(a,'10')) MOD FROM_UNIXTIME(CONCAT(a,'10'))) AS f2 FROM t1; +SHOW CREATE TABLE t2; +SELECT * FROM t2; +DROP TABLE t1,t2; + +--echo # +--echo # MDEV-4635 Crash in UNIX_TIMESTAMP(STR_TO_DATE('2020','%Y')) +--echo # SELECT UNIX_TIMESTAMP(STR_TO_DATE('2020','%Y')); -SET TIME_ZONE=DEFAULT; +SET TIME_ZONE=DEFAULT; --echo # --echo # MDEV-4863 COALESCE(time_or_datetime) returns wrong results in numeric context diff --git a/sql/field.h b/sql/field.h index 10b854001cd..c2a26f2c47d 100644 --- a/sql/field.h +++ b/sql/field.h @@ -113,6 +113,29 @@ inline bool is_temporal_type(enum_field_types type) return mysql_type_to_time_type(type) != MYSQL_TIMESTAMP_ERROR; } + +/** + Tests if field type is temporal and has time part, + i.e. represents TIME, DATETIME or TIMESTAMP types in SQL. + + @param type Field type, as returned by field->type(). + @retval true If field type is temporal type with time part. + @retval false If field type is not temporal type with time part. +*/ +inline bool is_temporal_type_with_time(enum_field_types type) +{ + switch (type) + { + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + return true; + default: + return false; + } +} + + /* Virtual_column_info is the class to contain additional characteristics that is specific for a virtual/computed diff --git a/sql/item.h b/sql/item.h index 3b3dfe5d327..f7ee860390f 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1014,9 +1014,47 @@ public: virtual cond_result eq_cmp_result() const { return COND_OK; } inline uint float_length(uint decimals_par) const { return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;} + /* Returns total number of decimal digits */ virtual uint decimal_precision() const; + /* Returns the number of integer part digits only */ inline int decimal_int_part() const { return my_decimal_int_part(decimal_precision(), decimals); } + /* + Returns the number of fractional digits only. + NOT_FIXED_DEC is replaced to the maximum possible number + of fractional digits, taking into account the data type. + */ + uint decimal_scale() const + { + return decimals < NOT_FIXED_DEC ? decimals : + is_temporal_type_with_time(field_type()) ? + TIME_SECOND_PART_DIGITS : + min(max_length, DECIMAL_MAX_SCALE); + } + /* + Returns how many digits a divisor adds into a division result. + This is important when the integer part of the divisor can be 0. + In this example: + SELECT 1 / 0.000001; -> 1000000.0000 + the divisor adds 5 digits into the result precision. + + Currently this method only replaces NOT_FIXED_DEC to + TIME_SECOND_PART_DIGITS for temporal data types. + This method can be made virtual, to create more efficient (smaller) + data types for division results. + For example, in + SELECT 1/1.000001; + the divisor could provide no additional precision into the result, + so could any other items that are know to return a result + with non-zero integer part. + */ + uint divisor_precision_increment() const + { + return decimals < NOT_FIXED_DEC ? decimals : + is_temporal_type_with_time(field_type()) ? + TIME_SECOND_PART_DIGITS : + decimals; + } /** TIME or DATETIME precision of the item: 0..6 */ diff --git a/sql/item_func.cc b/sql/item_func.cc index c00dde874fc..52693b1961a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -595,7 +595,7 @@ my_decimal *Item_real_func::val_decimal(my_decimal *decimal_value) } -void Item_func::fix_num_length_and_dec() +void Item_udf_func::fix_num_length_and_dec() { uint fl_length= 0; decimals=0; @@ -613,11 +613,6 @@ void Item_func::fix_num_length_and_dec() } -void Item_func_numhybrid::fix_num_length_and_dec() -{} - - - /** Count max_length and decimals for temporal functions. @@ -805,9 +800,9 @@ bool Item_func_connection_id::fix_fields(THD *thd, Item **ref) function of two arguments. */ -void Item_num_op::find_num_type(void) +void Item_num_op::fix_length_and_dec(void) { - DBUG_ENTER("Item_num_op::find_num_type"); + DBUG_ENTER("Item_num_op::fix_length_and_dec"); DBUG_PRINT("info", ("name %s", func_name())); DBUG_ASSERT(arg_count == 2); Item_result r0= args[0]->cast_to_int_type(); @@ -851,22 +846,26 @@ void Item_num_op::find_num_type(void) type depends only on the first argument) */ -void Item_func_num1::find_num_type() +void Item_func_num1::fix_length_and_dec() { - DBUG_ENTER("Item_func_num1::find_num_type"); + DBUG_ENTER("Item_func_num1::fix_length_and_dec"); DBUG_PRINT("info", ("name %s", func_name())); switch (cached_result_type= args[0]->cast_to_int_type()) { case INT_RESULT: + max_length= args[0]->max_length; unsigned_flag= args[0]->unsigned_flag; break; case STRING_RESULT: case REAL_RESULT: cached_result_type= REAL_RESULT; + decimals= args[0]->decimals; // Preserve NOT_FIXED_DEC max_length= float_length(decimals); break; case TIME_RESULT: cached_result_type= DECIMAL_RESULT; case DECIMAL_RESULT: + decimals= args[0]->decimal_scale(); // Do not preserve NOT_FIXED_DEC + max_length= args[0]->max_length; break; case ROW_RESULT: case IMPOSSIBLE_RESULT: @@ -881,20 +880,6 @@ void Item_func_num1::find_num_type() } -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_hybrid_result_type::val_str(String *str) { DBUG_ASSERT(fixed == 1); @@ -1541,11 +1526,14 @@ my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value) */ void Item_func_additive_op::result_precision() { - decimals= max(args[0]->decimals, args[1]->decimals); - int arg1_int= args[0]->decimal_precision() - args[0]->decimals; - int arg2_int= args[1]->decimal_precision() - args[1]->decimals; + decimals= max(args[0]->decimal_scale(), args[1]->decimal_scale()); + int arg1_int= args[0]->decimal_precision() - args[0]->decimal_scale(); + int arg2_int= args[1]->decimal_precision() - args[1]->decimal_scale(); int precision= max(arg1_int, arg2_int) + 1 + decimals; + DBUG_ASSERT(arg1_int >= 0); + DBUG_ASSERT(arg2_int >= 0); + /* Integer operations keep unsigned_flag if one of arguments is unsigned */ if (result_type() == INT_RESULT) unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag; @@ -1782,7 +1770,8 @@ void Item_func_mul::result_precision() unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag; else unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag; - decimals= min(args[0]->decimals + args[1]->decimals, DECIMAL_MAX_SCALE); + decimals= min(args[0]->decimal_scale() + args[1]->decimal_scale(), + DECIMAL_MAX_SCALE); uint est_prec = args[0]->decimal_precision() + args[1]->decimal_precision(); uint precision= min(est_prec, DECIMAL_MAX_PRECISION); max_length= my_decimal_precision_to_length_no_truncation(precision, decimals, @@ -1836,8 +1825,20 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value) void Item_func_div::result_precision() { + /* + We need to add args[1]->divisor_precision_increment(), + to properly handle the cases like this: + SELECT 5.05 / 0.014; -> 360.714286 + i.e. when the divisor has a zero integer part + and non-zero digits appear only after the decimal point. + Precision in this example is calculated as + args[0]->decimal_precision() + // 3 + args[1]->divisor_precision_increment() + // 3 + prec_increment // 4 + which gives 10 decimals digits. + */ uint precision=min(args[0]->decimal_precision() + - args[1]->decimals + prec_increment, + args[1]->divisor_precision_increment() + prec_increment, DECIMAL_MAX_PRECISION); /* Integer operations keep unsigned_flag if one of arguments is unsigned */ @@ -1845,7 +1846,7 @@ void Item_func_div::result_precision() unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag; else unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag; - decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE); + decimals= min(args[0]->decimal_scale() + prec_increment, DECIMAL_MAX_SCALE); max_length= my_decimal_precision_to_length_no_truncation(precision, decimals, unsigned_flag); } @@ -2051,7 +2052,7 @@ my_decimal *Item_func_mod::decimal_op(my_decimal *decimal_value) void Item_func_mod::result_precision() { - decimals= max(args[0]->decimals, args[1]->decimals); + decimals= max(args[0]->decimal_scale(), args[1]->decimal_scale()); max_length= max(args[0]->max_length, args[1]->max_length); } @@ -2107,18 +2108,12 @@ my_decimal *Item_func_neg::decimal_op(my_decimal *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; -} - - void Item_func_neg::fix_length_and_dec() { DBUG_ENTER("Item_func_neg::fix_length_and_dec"); Item_func_num1::fix_length_and_dec(); + /* 1 add because sign can appear */ + max_length= args[0]->max_length + 1; /* If this is in integer context keep the context as integer if possible @@ -2425,8 +2420,12 @@ void Item_func_integer::fix_length_and_dec() decimals=0; } -void Item_func_int_val::fix_num_length_and_dec() + +void Item_func_int_val::fix_length_and_dec() { + DBUG_ENTER("Item_func_int_val::fix_length_and_dec"); + DBUG_PRINT("info", ("name %s", func_name())); + ulonglong tmp_max_length= (ulonglong ) args[0]->max_length - (args[0]->decimals ? args[0]->decimals + 1 : 0) + 2; max_length= tmp_max_length > (ulonglong) 4294967295U ? @@ -2434,13 +2433,7 @@ void Item_func_int_val::fix_num_length_and_dec() 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 (cached_result_type= args[0]->cast_to_int_type()) { case STRING_RESULT: @@ -3894,12 +3887,6 @@ String *Item_func_udf_decimal::val_str(String *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() diff --git a/sql/item_func.h b/sql/item_func.h index 0d9901d90b2..49966964fbb 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -146,7 +146,6 @@ public: virtual void print(String *str, enum_query_type query_type); void print_op(String *str, enum_query_type query_type); void print_args(String *str, uint from, enum_query_type query_type); - virtual void fix_num_length_and_dec(); void count_only_length(Item **item, uint nitems); void count_real_length(); void count_decimal_length(); @@ -533,9 +532,6 @@ public: Item_func_numhybrid(List<Item> &list) :Item_func_hybrid_result_type(list) { } - 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 */ String *str_op(String *str) { DBUG_ASSERT(0); return 0; } bool date_op(MYSQL_TIME *ltime, uint fuzzydate) { DBUG_ASSERT(0); return true; } }; @@ -547,9 +543,7 @@ 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) {} - - void fix_num_length_and_dec(); - void find_num_type(); + void fix_length_and_dec(); }; @@ -565,7 +559,7 @@ class Item_num_op :public Item_func_numhybrid print_op(str, query_type); } - void find_num_type(); + void fix_length_and_dec(); }; @@ -785,7 +779,6 @@ public: const char *func_name() const { return "-"; } enum Functype functype() const { return NEG_FUNC; } void fix_length_and_dec(); - void fix_num_length_and_dec(); uint decimal_precision() const { return args[0]->decimal_precision(); } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} @@ -952,8 +945,7 @@ 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(); + void fix_length_and_dec(); }; @@ -1363,6 +1355,7 @@ public: fixed= 1; return res; } + void fix_num_length_and_dec(); void update_used_tables() { /* @@ -1476,7 +1469,7 @@ public: 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(); + void fix_length_and_dec() { fix_num_length_and_dec(); } }; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index c086579e34b..455540c4b0d 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -413,16 +413,15 @@ protected: public: Item_func_seconds_hybrid() :Item_func_numhybrid() {} Item_func_seconds_hybrid(Item *a) :Item_func_numhybrid(a) {} - void fix_num_length_and_dec() + void fix_length_and_dec() { if (arg_count) decimals= args[0]->temporal_precision(arg0_expected_type()); set_if_smaller(decimals, TIME_SECOND_PART_DIGITS); max_length=17 + (decimals ? decimals + 1 : 0); maybe_null= true; + cached_result_type= decimals ? DECIMAL_RESULT : INT_RESULT; } - void find_num_type() - { cached_result_type= decimals ? DECIMAL_RESULT : INT_RESULT; } double real_op() { DBUG_ASSERT(0); return 0; } String *str_op(String *str) { DBUG_ASSERT(0); return 0; } bool date_op(MYSQL_TIME *ltime, uint fuzzydate) { DBUG_ASSERT(0); return true; } @@ -470,11 +469,6 @@ protected: public: Item_func_time_to_sec(Item *item) :Item_func_seconds_hybrid(item) {} const char *func_name() const { return "time_to_sec"; } - void fix_num_length_and_dec() - { - maybe_null= true; - Item_func_seconds_hybrid::fix_num_length_and_dec(); - } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} bool check_valid_arguments_processor(uchar *int_arg) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d6aebf50a70..95a152bd848 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6736,7 +6736,7 @@ static uint kill_threads_for_user(THD *thd, LEX_USER *user, I_List_iterator<THD> it(threads); while ((tmp=it++)) { - if (tmp->command == COM_DAEMON) + if (!tmp->security_ctx->user) continue; /* Check that hostname (if given) and user name matches. diff --git a/storage/tokudb/mysql-test/tokudb/r/type_decimal.result b/storage/tokudb/mysql-test/tokudb/r/type_decimal.result index f54e1e5d5d5..5d271bc73fa 100644 --- a/storage/tokudb/mysql-test/tokudb/r/type_decimal.result +++ b/storage/tokudb/mysql-test/tokudb/r/type_decimal.result @@ -799,10 +799,10 @@ ROUND(qty,3) dps ROUND(qty,dps) DROP TABLE t1; SELECT 1 % .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS '%'; % -0.012345687012345687012345687012345687012345687012345687012345687012345687000000000 +0.012345687012345687012345687012 SELECT MOD(1, .123456789123456789123456789123456789123456789123456789123456789123456789123456789) AS 'MOD()'; MOD() -0.012345687012345687012345687012345687012345687012345687012345687012345687000000000 +0.012345687012345687012345687012 create table t1 (f1 decimal(6,6),f2 decimal(6,6) zerofill); insert into t1 values (-0.123456,0.123456); select group_concat(f1),group_concat(f2) from t1; diff --git a/storage/tokudb/mysql-test/tokudb/r/type_newdecimal.result b/storage/tokudb/mysql-test/tokudb/r/type_newdecimal.result index 5bc38edd67a..ab199d21bcc 100644 --- a/storage/tokudb/mysql-test/tokudb/r/type_newdecimal.result +++ b/storage/tokudb/mysql-test/tokudb/r/type_newdecimal.result @@ -704,7 +704,7 @@ select .7777777777777777777777777777777777777 * 777777777777777777.777777777777777777700000000000 select .7777777777777777777777777777777777777 - 0.1; .7777777777777777777777777777777777777 - 0.1 -0.6777777777777777777777777777777777777 +0.677777777777777777777777777778 select .343434343434343434 + .343434343434343434; .343434343434343434 + .343434343434343434 0.686868686868686868 @@ -1841,7 +1841,7 @@ Warnings: Note 1265 Data truncated for column 'c1' at row 4 DESC t2; Field Type Null Key Default Extra -c1 decimal(32,30) YES NULL +c1 decimal(33,30) YES NULL DROP TABLE t1,t2; CREATE TABLE t1 (a DECIMAL(30,30)); INSERT INTO t1 VALUES (0.1),(0.2),(0.3); @@ -1852,7 +1852,7 @@ Note 1265 Data truncated for column 'c1' at row 2 Note 1265 Data truncated for column 'c1' at row 3 DESC t2; Field Type Null Key Default Extra -c1 decimal(34,0) YES NULL +c1 decimal(33,30) YES NULL DROP TABLE t1,t2; CREATE TABLE t1 (a DECIMAL(30,30)); INSERT INTO t1 VALUES (0.1),(0.2),(0.3); |