diff options
-rw-r--r-- | mysql-test/r/func_time.result | 45 | ||||
-rw-r--r-- | mysql-test/r/type_float.result | 36 | ||||
-rw-r--r-- | mysql-test/t/func_time.test | 21 | ||||
-rw-r--r-- | mysql-test/t/type_float.test | 29 | ||||
-rw-r--r-- | sql/field.cc | 3 | ||||
-rw-r--r-- | sql/item.cc | 8 | ||||
-rw-r--r-- | sql/item_func.cc | 5 | ||||
-rw-r--r-- | sql/item_func.h | 10 | ||||
-rw-r--r-- | sql/item_sum.cc | 6 | ||||
-rw-r--r-- | sql/item_sum.h | 19 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 22 | ||||
-rw-r--r-- | sql/sql_error.h | 7 | ||||
-rw-r--r-- | sql/sql_type_int.h | 40 |
13 files changed, 219 insertions, 32 deletions
diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 3f0d99e1315..1db897d4ec0 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -2661,5 +2661,50 @@ SELECT PERIOD_DIFF(2018, AES_ENCRYPT('Rae Bareli', 'Rae Bareli')); PERIOD_DIFF(2018, AES_ENCRYPT('Rae Bareli', 'Rae Bareli')) 24257 # +# MDEV-17249 MAKETIME(-1e50,0,0) returns a wrong result +# +SELECT +MAKETIME(1e10,0,0), +MAKETIME(-1e10,0,0), +MAKETIME(1e50,0,0), +MAKETIME(-1e50,0,0), +MAKETIME(COALESCE(1e50),0,0), +MAKETIME(COALESCE(-1e50),0,0); +MAKETIME(1e10,0,0) 838:59:59 +MAKETIME(-1e10,0,0) -838:59:59 +MAKETIME(1e50,0,0) 838:59:59 +MAKETIME(-1e50,0,0) -838:59:59 +MAKETIME(COALESCE(1e50),0,0) 838:59:59 +MAKETIME(COALESCE(-1e50),0,0) -838:59:59 +Warnings: +Level Warning +Code 1292 +Message Truncated incorrect time value: '10000000000:00:00' +Level Warning +Code 1292 +Message Truncated incorrect time value: '-10000000000:00:00' +Level Warning +Code 1292 +Message Truncated incorrect time value: '9223372036854775807:00:00' +Level Warning +Code 1292 +Message Truncated incorrect time value: '-9223372036854775808:00:00' +Level Warning +Code 1292 +Message Truncated incorrect time value: '9223372036854775807:00:00' +Level Warning +Code 1292 +Message Truncated incorrect time value: '-9223372036854775808:00:00' +CREATE TABLE t1 (a FLOAT); +INSERT INTO t1 VALUES (1e30),(-1e30); +SELECT MAKETIME(a,0,0) FROM t1; +MAKETIME(a,0,0) +838:59:59 +-838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '9223372036854775807:00:00' +Warning 1292 Truncated incorrect time value: '-9223372036854775808:00:00' +DROP TABLE t1; +# # End of 5.5 tests # diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index f41c2e7688b..f8574167de3 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -447,3 +447,39 @@ End of 5.0 tests select format(truncate('1.7976931348623157E+308',-12),1,'fr_BE') as foo; foo 0 +# +# MDEV-17249 MAKETIME(-1e50,0,0) returns a wrong result +# +SELECT LEFT('a',EXP(50)); +LEFT('a',EXP(50)) +a +SELECT LEFT('a', COALESCE(1e30)); +LEFT('a', COALESCE(1e30)) +a +CREATE TABLE t1 (a FLOAT); +INSERT INTO t1 VALUES (1e30); +SELECT LEFT('a',a), LEFT('a',1e30) FROM t1; +LEFT('a',a) LEFT('a',1e30) +a a +DROP TABLE t1; +PREPARE stmt FROM 'SELECT LEFT(111,?)'; +SET @a=1e30; +EXECUTE stmt USING @a; +LEFT(111,?) +111 +DEALLOCATE PREPARE stmt; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3); +SELECT LEFT('a',(SELECT 1e30 FROM t1 LIMIT 1)); +LEFT('a',(SELECT 1e30 FROM t1 LIMIT 1)) +a +DROP TABLE t1; +CREATE TABLE t1 (a DOUBLE); +INSERT INTO t1 VALUES (1e30),(0); +SELECT LEFT('a', SUM(a)) FROM t1; +LEFT('a', SUM(a)) +a +SELECT LEFT('a', AVG(a)) FROM t1; +LEFT('a', AVG(a)) +a +DROP TABLE t1; diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 361eff170fb..10b2b2958c2 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -1634,6 +1634,27 @@ SELECT SEC_TO_TIME(MAKEDATE(0,RAND(~0))); # SELECT PERIOD_DIFF(2018, AES_ENCRYPT('Rae Bareli', 'Rae Bareli')); + +--echo # +--echo # MDEV-17249 MAKETIME(-1e50,0,0) returns a wrong result +--echo # + +--vertical_results +SELECT + MAKETIME(1e10,0,0), + MAKETIME(-1e10,0,0), + MAKETIME(1e50,0,0), + MAKETIME(-1e50,0,0), + MAKETIME(COALESCE(1e50),0,0), + MAKETIME(COALESCE(-1e50),0,0); +--horizontal_results + +CREATE TABLE t1 (a FLOAT); +INSERT INTO t1 VALUES (1e30),(-1e30); +SELECT MAKETIME(a,0,0) FROM t1; +DROP TABLE t1; + + --echo # --echo # End of 5.5 tests --echo # diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test index b33c51566a0..fa45b1041d8 100644 --- a/mysql-test/t/type_float.test +++ b/mysql-test/t/type_float.test @@ -331,3 +331,32 @@ eval select concat((truncate((-1.7976931348623157E+307),(0x1e))), --echo # select format(truncate('1.7976931348623157E+308',-12),1,'fr_BE') as foo; + + +--echo # +--echo # MDEV-17249 MAKETIME(-1e50,0,0) returns a wrong result +--echo # + +SELECT LEFT('a',EXP(50)); +SELECT LEFT('a', COALESCE(1e30)); + +CREATE TABLE t1 (a FLOAT); +INSERT INTO t1 VALUES (1e30); +SELECT LEFT('a',a), LEFT('a',1e30) FROM t1; +DROP TABLE t1; + +PREPARE stmt FROM 'SELECT LEFT(111,?)'; +SET @a=1e30; +EXECUTE stmt USING @a; +DEALLOCATE PREPARE stmt; + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2),(3); +SELECT LEFT('a',(SELECT 1e30 FROM t1 LIMIT 1)); +DROP TABLE t1; + +CREATE TABLE t1 (a DOUBLE); +INSERT INTO t1 VALUES (1e30),(0); +SELECT LEFT('a', SUM(a)) FROM t1; +SELECT LEFT('a', AVG(a)) FROM t1; +DROP TABLE t1; diff --git a/sql/field.cc b/sql/field.cc index 5b111ab5e03..28b3d743ed8 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -3948,7 +3948,8 @@ longlong Field_float::val_int(void) { float j; float4get(j,ptr); - return (longlong) rint(j); + bool error; + return double_to_longlong(j, false, &error); } diff --git a/sql/item.cc b/sql/item.cc index 745cbf31f0c..e1afc339cc2 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3692,7 +3692,10 @@ longlong Item_param::val_int() { switch (state) { case REAL_VALUE: - return (longlong) rint(value.real); + { + bool error; + return double_to_longlong(value.real, unsigned_flag, &error); + } case INT_VALUE: return value.integer; case DECIMAL_VALUE: @@ -9231,7 +9234,8 @@ longlong Item_cache_real::val_int() DBUG_ASSERT(fixed == 1); if (!has_value()) return 0; - return (longlong) rint(value); + bool error; + return double_to_longlong(value, unsigned_flag, &error); } diff --git a/sql/item_func.cc b/sql/item_func.cc index 8b3c72dd328..73fc099252b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -999,7 +999,10 @@ longlong Item_func_hybrid_result_type::val_int() case INT_RESULT: return int_op(); case REAL_RESULT: - return (longlong) rint(real_op()); + { + bool error; + return double_to_longlong(real_op(), unsigned_flag, &error); + } case STRING_RESULT: { if (is_temporal_type(field_type())) diff --git a/sql/item_func.h b/sql/item_func.h index 3a609fc0fe0..64b3b5cfb75 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -411,7 +411,11 @@ public: String *val_str(String*str); my_decimal *val_decimal(my_decimal *decimal_value); longlong val_int() - { DBUG_ASSERT(fixed == 1); return (longlong) rint(val_real()); } + { + DBUG_ASSERT(fixed == 1); + bool error; + return double_to_longlong(val_real(), unsigned_flag, &error); + } enum Item_result result_type () const { return REAL_RESULT; } void fix_length_and_dec() { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); } @@ -1465,7 +1469,9 @@ class Item_func_udf_float :public Item_udf_func longlong val_int() { DBUG_ASSERT(fixed == 1); - return (longlong) rint(Item_func_udf_float::val_real()); + bool error; + return double_to_longlong(Item_func_udf_float::val_real(), + unsigned_flag, &error); } my_decimal *val_decimal(my_decimal *dec_buf) { diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 16334cd7b30..22fbe2bacfe 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1434,7 +1434,8 @@ longlong Item_sum_sum::val_int() &result); return result; } - return (longlong) rint(val_real()); + bool error; + return double_to_longlong(val_real(), unsigned_flag, &error); } @@ -2648,7 +2649,8 @@ double Item_avg_field::val_real() longlong Item_avg_field::val_int() { - return (longlong) rint(val_real()); + bool error; + return double_to_longlong(val_real(), unsigned_flag, &error); } diff --git a/sql/item_sum.h b/sql/item_sum.h index dcc3e494f82..b0bca5e7ad2 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -699,7 +699,9 @@ public: longlong val_int() { DBUG_ASSERT(fixed == 1); - return (longlong) rint(val_real()); /* Real as default */ + // Real as default + bool error; + return double_to_longlong(val_real(), unsigned_flag, &error); } String *val_str(String*str); my_decimal *val_decimal(my_decimal *); @@ -867,7 +869,11 @@ public: bool add(); double val_real(); // In SPs we might force the "wrong" type with select into a declare variable - longlong val_int() { return (longlong) rint(val_real()); } + longlong val_int() + { + bool error; + return double_to_longlong(val_real(), unsigned_flag, &error); + } my_decimal *val_decimal(my_decimal *); String *val_str(String *str); void reset_field(); @@ -904,7 +910,10 @@ public: enum Type type() const {return FIELD_VARIANCE_ITEM; } double val_real(); longlong val_int() - { /* can't be fix_fields()ed */ return (longlong) rint(val_real()); } + { /* can't be fix_fields()ed */ + bool error; + return double_to_longlong(val_real(), unsigned_flag, &error); + } String *val_str(String *str) { return val_string_from_real(str); } my_decimal *val_decimal(my_decimal *dec_buf) @@ -1215,7 +1224,9 @@ class Item_sum_udf_float :public Item_udf_sum longlong val_int() { DBUG_ASSERT(fixed == 1); - return (longlong) rint(Item_sum_udf_float::val_real()); + bool error; + return double_to_longlong(Item_sum_udf_float::val_real(), + unsigned_flag, &error); } double val_real(); String *val_str(String*str); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index eeb373a75ee..cc03cc004bd 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -40,6 +40,7 @@ #include "set_var.h" #include "sql_locale.h" // MY_LOCALE my_locale_en_US #include "strfunc.h" // check_word +#include "sql_type_int.h" // Longlong_hybrid #include "sql_time.h" // make_truncated_value_warning, // get_date_from_daynr, // calc_weekday, calc_week, @@ -2741,8 +2742,7 @@ bool Item_func_timediff::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) { DBUG_ASSERT(fixed == 1); - bool overflow= 0; - longlong hour= args[0]->val_int(); + Longlong_hybrid hour(args[0]->val_int(), args[0]->unsigned_flag); longlong minute= args[1]->val_int(); ulonglong second; ulong microsecond; @@ -2754,21 +2754,11 @@ bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) bzero(ltime, sizeof(*ltime)); ltime->time_type= MYSQL_TIMESTAMP_TIME; + ltime->neg= hour.neg(); - /* Check for integer overflows */ - if (hour < 0) + if (hour.abs() <= TIME_MAX_HOUR) { - if (args[0]->unsigned_flag) - overflow= 1; - else - ltime->neg= 1; - } - if (-hour > TIME_MAX_HOUR || hour > TIME_MAX_HOUR) - overflow= 1; - - if (!overflow) - { - ltime->hour= (uint) ((hour < 0 ? -hour : hour)); + ltime->hour= (uint) hour.abs(); ltime->minute= (uint) minute; ltime->second= (uint) second; ltime->second_part= microsecond; @@ -2779,7 +2769,7 @@ bool Item_func_maketime::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date) ltime->minute= TIME_MAX_MINUTE; ltime->second= TIME_MAX_SECOND; char buf[28]; - char *ptr= longlong10_to_str(hour, buf, args[0]->unsigned_flag ? 10 : -10); + char *ptr= longlong10_to_str(hour.value(), buf, hour.is_unsigned() ? 10 : -10); int len = (int)(ptr - buf) + sprintf(ptr, ":%02u:%02u", (uint)minute, (uint)second); make_truncated_value_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, buf, len, MYSQL_TIMESTAMP_TIME, diff --git a/sql/sql_error.h b/sql/sql_error.h index 5f912ad8102..903ad65521d 100644 --- a/sql/sql_error.h +++ b/sql/sql_error.h @@ -18,6 +18,7 @@ #include "sql_list.h" /* Sql_alloc, MEM_ROOT */ #include "m_string.h" /* LEX_STRING */ +#include "sql_type_int.h" // Longlong_hybrid #include "sql_string.h" /* String */ #include "mysql_com.h" /* MYSQL_ERRMSG_SIZE */ @@ -542,13 +543,11 @@ public: { return err_conv(err_buffer, sizeof(err_buffer), str, len, cs); } }; -class ErrConvInteger : public ErrConv +class ErrConvInteger : public ErrConv, public Longlong_hybrid { - longlong m_value; - bool m_unsigned; public: ErrConvInteger(longlong num_arg, bool unsigned_flag= false) : - ErrConv(), m_value(num_arg), m_unsigned(unsigned_flag) {} + ErrConv(), Longlong_hybrid(num_arg, unsigned_flag) {} const char *ptr() const { return m_unsigned ? ullstr(m_value, err_buffer) : diff --git a/sql/sql_type_int.h b/sql/sql_type_int.h new file mode 100644 index 00000000000..055790ba431 --- /dev/null +++ b/sql/sql_type_int.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. + Copyright (c) 2011, 2016, MariaDB + + 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; version 2 of the License. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef SQL_TYPE_INT_INCLUDED +#define SQL_TYPE_INT_INCLUDED + + +// A longlong/ulonglong hybrid. Good to store results of val_int(). +class Longlong_hybrid +{ +protected: + longlong m_value; + bool m_unsigned; +public: + Longlong_hybrid(longlong nr, bool unsigned_flag) + :m_value(nr), m_unsigned(unsigned_flag) + { } + longlong value() const { return m_value; } + bool is_unsigned() const { return m_unsigned; } + bool neg() const { return m_value < 0 && !m_unsigned; } + ulonglong abs() const + { + return neg() ? (ulonglong) -m_value : (ulonglong) m_value; + } +}; + +#endif // SQL_TYPE_INT_INCLUDED |