summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2018-09-20 16:02:58 +0400
committerAlexander Barkov <bar@mariadb.com>2018-09-20 16:02:58 +0400
commit0c6455aa4658790439a58956f05df200a5e380b8 (patch)
treeb792c811420d76f7b6edc079f1a7e9923aebe9b0 /sql
parente43bc02e7b2752f0deb88cd1edc24d827e01dca9 (diff)
downloadmariadb-git-0c6455aa4658790439a58956f05df200a5e380b8.tar.gz
MDEV-17249 MAKETIME(-1e50,0,0) returns a wrong result
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc3
-rw-r--r--sql/item.cc8
-rw-r--r--sql/item_func.cc5
-rw-r--r--sql/item_func.h10
-rw-r--r--sql/item_sum.cc6
-rw-r--r--sql/item_sum.h19
-rw-r--r--sql/item_timefunc.cc22
-rw-r--r--sql/sql_error.h7
-rw-r--r--sql/sql_type_int.h40
9 files changed, 88 insertions, 32 deletions
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