diff --git a/mysql-test/main/type_date.result b/mysql-test/main/type_date.result index 6d955ef698c..950672161fd 100644 --- a/mysql-test/main/type_date.result +++ b/mysql-test/main/type_date.result @@ -988,5 +988,15 @@ Note 1265 Data truncated for column 'a' at row 1 DROP TABLE t1; SET sql_mode=DEFAULT; # +# MDEV-17216 Assertion `!dt->fraction_remainder(decimals())' failed in Field_temporal_with_date::store_TIME_with_warning +# +SET sql_mode=''; +CREATE TABLE t1 (i1 date ); +CREATE TABLE t2 (i2 int unsigned ); +INSERT INTO t2 VALUES (0); +INSERT INTO t1 SELECT * FROM t2; +DROP TABLE t1,t2; +SET sql_mode=DEFAULT; +# # End of 10.4 tests # diff --git a/mysql-test/main/type_date.test b/mysql-test/main/type_date.test index f1fd8b302e4..75bbfb3b916 100644 --- a/mysql-test/main/type_date.test +++ b/mysql-test/main/type_date.test @@ -665,6 +665,18 @@ DROP TABLE t1; SET sql_mode=DEFAULT; +--echo # +--echo # MDEV-17216 Assertion `!dt->fraction_remainder(decimals())' failed in Field_temporal_with_date::store_TIME_with_warning +--echo # +SET sql_mode=''; +CREATE TABLE t1 (i1 date ); +CREATE TABLE t2 (i2 int unsigned ); +INSERT INTO t2 VALUES (0); +INSERT INTO t1 SELECT * FROM t2; +DROP TABLE t1,t2; +SET sql_mode=DEFAULT; + + --echo # --echo # End of 10.4 tests --echo # diff --git a/mysql-test/main/type_datetime.result b/mysql-test/main/type_datetime.result index 7f5147c48d9..f75b8d84f48 100644 --- a/mysql-test/main/type_datetime.result +++ b/mysql-test/main/type_datetime.result @@ -1400,5 +1400,16 @@ Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where octet_length(coalesce(TIME'00:00:00.0',`test`.`t1`.`a`)) <=> octet_length(coalesce((TIMESTAMP'2001-01-01 00:00:00.00'),`test`.`t1`.`a`)) DROP TABLE t1; # +# MDEV-17216 Assertion `!dt->fraction_remainder(decimals())' failed in Field_temporal_with_date::store_TIME_with_warning +# +CREATE TABLE t1 (b BIT(20)); +CREATE TABLE t2 (t DATETIME); +INSERT IGNORE INTO t1 VALUES (b'000001001100000'); +INSERT INTO t2 SELECT * FROM t1; +DROP TABLE t1, t2; +CREATE TABLE t1 (a DATETIME); +INSERT INTO t1 SELECT CAST(20010101 AS UNSIGNED); +DROP TABLE t1; +# # End of 10.4 tests # diff --git a/mysql-test/main/type_datetime.test b/mysql-test/main/type_datetime.test index 3c8287f8793..cc3d2a3b1f7 100644 --- a/mysql-test/main/type_datetime.test +++ b/mysql-test/main/type_datetime.test @@ -898,6 +898,21 @@ EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT * FROM t1 WHERE LENGTH(COALESCE(TIME' DROP TABLE t1; +--echo # +--echo # MDEV-17216 Assertion `!dt->fraction_remainder(decimals())' failed in Field_temporal_with_date::store_TIME_with_warning +--echo # + +CREATE TABLE t1 (b BIT(20)); +CREATE TABLE t2 (t DATETIME); +INSERT IGNORE INTO t1 VALUES (b'000001001100000'); +INSERT INTO t2 SELECT * FROM t1; +DROP TABLE t1, t2; + +CREATE TABLE t1 (a DATETIME); +INSERT INTO t1 SELECT CAST(20010101 AS UNSIGNED); +DROP TABLE t1; + + --echo # --echo # End of 10.4 tests --echo # diff --git a/mysql-test/main/type_timestamp.result b/mysql-test/main/type_timestamp.result index 6fcc802b91a..071b2181e73 100644 --- a/mysql-test/main/type_timestamp.result +++ b/mysql-test/main/type_timestamp.result @@ -1018,3 +1018,20 @@ DROP TABLE t1; # # End of 10.3 tests # +# +# Start of 10.4 tests +# +# +# MDEV-17216 Assertion `!dt->fraction_remainder(decimals())' failed in Field_temporal_with_date::store_TIME_with_warning +# +CREATE TABLE t1 (b BIT(20)); +CREATE TABLE t2 (t TIMESTAMP); +INSERT IGNORE INTO t1 VALUES (b'000001001100000'); +INSERT INTO t2 SELECT * FROM t1; +DROP TABLE t1, t2; +CREATE TABLE t1 (a TIMESTAMP); +INSERT INTO t1 SELECT CAST(20010101 AS UNSIGNED); +DROP TABLE t1; +# +# End of 10.4 tests +# diff --git a/mysql-test/main/type_timestamp.test b/mysql-test/main/type_timestamp.test index 6d81a86331a..eeb6e2f8213 100644 --- a/mysql-test/main/type_timestamp.test +++ b/mysql-test/main/type_timestamp.test @@ -606,3 +606,25 @@ DROP TABLE t1; --echo # --echo # End of 10.3 tests --echo # + +--echo # +--echo # Start of 10.4 tests +--echo # + +--echo # +--echo # MDEV-17216 Assertion `!dt->fraction_remainder(decimals())' failed in Field_temporal_with_date::store_TIME_with_warning +--echo # + +CREATE TABLE t1 (b BIT(20)); +CREATE TABLE t2 (t TIMESTAMP); +INSERT IGNORE INTO t1 VALUES (b'000001001100000'); +INSERT INTO t2 SELECT * FROM t1; +DROP TABLE t1, t2; + +CREATE TABLE t1 (a TIMESTAMP); +INSERT INTO t1 SELECT CAST(20010101 AS UNSIGNED); +DROP TABLE t1; + +--echo # +--echo # End of 10.4 tests +--echo # diff --git a/sql/field.cc b/sql/field.cc index ba2b5b3eab9..d7214687e2d 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2067,9 +2067,8 @@ my_decimal* Field_int::val_decimal(my_decimal *decimal_value) bool Field_int::get_date(MYSQL_TIME *ltime,date_mode_t fuzzydate) { ASSERT_COLUMN_MARKED_FOR_READ; - longlong nr= val_int(); - bool neg= !(flags & UNSIGNED_FLAG) && nr < 0; - return int_to_datetime_with_warn(get_thd(), neg, neg ? -nr : nr, ltime, + Longlong_hybrid nr(val_int(), (flags & UNSIGNED_FLAG)); + return int_to_datetime_with_warn(get_thd(), nr, ltime, fuzzydate, field_name.str); } @@ -5112,7 +5111,7 @@ int Field_timestamp::store(double nr) int error; ErrConvDouble str(nr); THD *thd= get_thd(); - Datetime dt(&error, nr, sql_mode_for_timestamp(thd), decimals()); + Datetime dt(&error, Sec6(nr), sql_mode_for_timestamp(thd), decimals()); return store_TIME_with_warning(thd, &dt, &str, error); } @@ -5120,9 +5119,9 @@ int Field_timestamp::store(double nr) int Field_timestamp::store(longlong nr, bool unsigned_val) { int error; - ErrConvInteger str(nr, unsigned_val); + ErrConvInteger str(Longlong_hybrid(nr, unsigned_val)); THD *thd= get_thd(); - Datetime dt(&error, nr, unsigned_val, sql_mode_for_timestamp(thd)); + Datetime dt(&error, Sec6(nr, unsigned_val), sql_mode_for_timestamp(thd)); return store_TIME_with_warning(thd, &dt, &str, error); } @@ -5422,7 +5421,7 @@ int Field_timestamp::store_decimal(const my_decimal *d) int error; THD *thd= get_thd(); ErrConvDecimal str(d); - Datetime dt(&error, d, sql_mode_for_timestamp(thd), decimals()); + Datetime dt(&error, Sec6(d), sql_mode_for_timestamp(thd), decimals()); return store_TIME_with_warning(thd, &dt, &str, error); } @@ -5572,7 +5571,7 @@ int Field_datetime::store(double nr) { int error; ErrConvDouble str(nr); - Datetime dt(&error, nr, sql_mode_for_dates(get_thd()), decimals()); + Datetime dt(&error, Sec6(nr), sql_mode_for_dates(get_thd()), decimals()); return store_TIME_with_warning(&dt, &str, error); } @@ -5580,8 +5579,8 @@ int Field_datetime::store(double nr) int Field_datetime::store(longlong nr, bool unsigned_val) { int error; - ErrConvInteger str(nr, unsigned_val); - Datetime dt(&error, nr, unsigned_val, sql_mode_for_dates(get_thd())); + ErrConvInteger str(Longlong_hybrid(nr, unsigned_val)); + Datetime dt(&error, Sec6(nr, unsigned_val), sql_mode_for_dates(get_thd())); return store_TIME_with_warning(&dt, &str, error); } @@ -5599,7 +5598,7 @@ int Field_datetime::store_decimal(const my_decimal *d) { int error; ErrConvDecimal str(d); - Datetime tm(&error, d, sql_mode_for_dates(get_thd()), decimals()); + Datetime tm(&error, Sec6(d), sql_mode_for_dates(get_thd()), decimals()); return store_TIME_with_warning(&tm, &str, error); } @@ -5734,17 +5733,17 @@ int Field_time::store(double nr) { ErrConvDouble str(nr); int was_cut; - Time tm(get_thd(), &was_cut, nr, decimals()); + Time tm(get_thd(), &was_cut, Sec6(nr), decimals()); return store_TIME_with_warning(&tm, &str, was_cut); } int Field_time::store(longlong nr, bool unsigned_val) { - ErrConvInteger str(nr, unsigned_val); + ErrConvInteger str(Longlong_hybrid(nr, unsigned_val)); int was_cut; // Need fractional digit truncation if nr overflows to '838:59:59.999999' - Time tm(get_thd(), &was_cut, nr, unsigned_val, decimals()); + Time tm(get_thd(), &was_cut, Sec6(nr, unsigned_val), decimals()); return store_TIME_with_warning(&tm, &str, was_cut); } @@ -5902,7 +5901,7 @@ int Field_time::store_decimal(const my_decimal *d) { ErrConvDecimal str(d); int was_cut; - Time tm(get_thd(), &was_cut, d, decimals()); + Time tm(get_thd(), &was_cut, Sec6(d), decimals()); return store_TIME_with_warning(&tm, &str, was_cut); } @@ -6222,7 +6221,8 @@ bool Field_year::get_date(MYSQL_TIME *ltime,date_mode_t fuzzydate) int tmp= (int) ptr[0]; if (tmp || field_length != 4) tmp+= 1900; - return int_to_datetime_with_warn(get_thd(), false, tmp * 10000, + return int_to_datetime_with_warn(get_thd(), + Longlong_hybrid(tmp * 10000, true), ltime, fuzzydate, field_name.str); } @@ -6266,15 +6266,15 @@ int Field_date_common::store(double nr) { int error; ErrConvDouble str(nr); - Datetime dt(&error, nr, sql_mode_for_dates(get_thd())); + Datetime dt(&error, Sec6(nr), sql_mode_for_dates(get_thd())); return store_TIME_with_warning(&dt, &str, error); } int Field_date_common::store(longlong nr, bool unsigned_val) { int error; - ErrConvInteger str(nr, unsigned_val); - Datetime dt(&error, nr, unsigned_val, sql_mode_for_dates(get_thd())); + ErrConvInteger str(Longlong_hybrid(nr, unsigned_val)); + Datetime dt(&error, Sec6(nr, unsigned_val), sql_mode_for_dates(get_thd())); return store_TIME_with_warning(&dt, &str, error); } @@ -6291,7 +6291,7 @@ int Field_date_common::store_decimal(const my_decimal *d) { int error; ErrConvDecimal str(d); - Datetime tm(&error, d, sql_mode_for_dates(get_thd())); + Datetime tm(&error, Sec6(d), sql_mode_for_dates(get_thd())); return store_TIME_with_warning(&tm, &str, error); } diff --git a/sql/item.cc b/sql/item.cc index 38c95039b27..04a676d5b1d 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1276,9 +1276,8 @@ Item *Item_param::safe_charset_converter(THD *thd, CHARSET_INFO *tocs) bool Item::get_date_from_int(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - longlong value= val_int(); - bool neg= !unsigned_flag && value < 0; - if (null_value || int_to_datetime_with_warn(thd, neg, neg ? -value : value, + Longlong_hybrid value(val_int(), unsigned_flag); + if (null_value || int_to_datetime_with_warn(thd, value, ltime, fuzzydate, field_name_or_null())) return null_value|= make_zero_date(ltime, fuzzydate); @@ -9701,8 +9700,6 @@ bool Item_cache_time::cache_value() bool Item_cache_temporal::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - ErrConvInteger str(value); - if (!has_value()) { bzero((char*) ltime,sizeof(*ltime)); diff --git a/sql/item_func.cc b/sql/item_func.cc index ccac348e4bc..ea6a39ab150 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -838,9 +838,8 @@ bool Item_func_hybrid_field_type::get_date_from_int_op(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) { - longlong value= int_op(); - bool neg= !unsigned_flag && value < 0; - if (null_value || int_to_datetime_with_warn(thd, neg, neg ? -value : value, + Longlong_hybrid value(int_op(), unsigned_flag); + if (null_value || int_to_datetime_with_warn(thd, value, ltime, fuzzydate, NULL)) return make_zero_mysql_time(ltime, fuzzydate); return (null_value= 0); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index bb10976c434..d0727293c5f 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -5134,9 +5134,7 @@ bool Item_dyncol_get::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydat if (signed_value || val.x.ulong_value <= LONGLONG_MAX) { longlong llval = (longlong)val.x.ulong_value; - bool neg = llval < 0; - if (int_to_datetime_with_warn(thd, neg, (ulonglong)(neg ? -llval : - llval), + if (int_to_datetime_with_warn(thd, Longlong_hybrid(llval, !signed_value), ltime, fuzzydate, 0 /* TODO */)) goto null; return 0; diff --git a/sql/sql_error.h b/sql/sql_error.h index 822503f89d3..b783d527cb3 100644 --- a/sql/sql_error.h +++ b/sql/sql_error.h @@ -846,8 +846,8 @@ public: class ErrConvInteger : public ErrConv, public Longlong_hybrid { public: - ErrConvInteger(longlong num_arg, bool unsigned_flag= false) : - ErrConv(), Longlong_hybrid(num_arg, unsigned_flag) {} + ErrConvInteger(const Longlong_hybrid &nr) + : ErrConv(), Longlong_hybrid(nr) { } const char *ptr() const { return m_unsigned ? ullstr(m_value, err_buffer) : diff --git a/sql/sql_time.cc b/sql/sql_time.cc index c3019668497..2bbe7257eb0 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -467,17 +467,17 @@ bool decimal_to_datetime_with_warn(THD *thd, const my_decimal *value, } -bool int_to_datetime_with_warn(THD *thd, bool neg, ulonglong value, +bool int_to_datetime_with_warn(THD *thd, const Longlong_hybrid &nr, MYSQL_TIME *ltime, date_mode_t fuzzydate, const char *field_name) { - const ErrConvInteger str(neg ? - (longlong) value : (longlong) value, !neg); + const ErrConvInteger str(nr); /* Note: conversion from an integer to TIME can overflow to '838:59:59.999999', so the conversion result can have fractional digits. */ Temporal_hybrid *t= new (ltime) - Temporal_hybrid(thd, Sec6(neg, value, 0), + Temporal_hybrid(thd, Sec6(nr), fuzzydate, &str, field_name); return !t->is_valid_temporal(); } diff --git a/sql/sql_time.h b/sql/sql_time.h index f113962b596..7db7bd4944a 100644 --- a/sql/sql_time.h +++ b/sql/sql_time.h @@ -50,7 +50,7 @@ bool decimal_to_datetime_with_warn(THD *thd, const my_decimal *value, MYSQL_TIME *ltime, date_mode_t fuzzydate, const char *name); -bool int_to_datetime_with_warn(THD *thd, bool neg, ulonglong value, +bool int_to_datetime_with_warn(THD *thd, const Longlong_hybrid &nr, MYSQL_TIME *ltime, date_mode_t fuzzydate, const char *name); diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 1dfaa3a73b0..c6e22776d27 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -253,14 +253,14 @@ VSec6::VSec6(THD *thd, Item *item, const char *type_str, ulonglong limit) { if (item->decimals == 0) { // optimize for an important special case - longlong nr= item->val_int(); - make_from_int(nr, item->unsigned_flag); + Longlong_hybrid nr(item->val_int(), item->unsigned_flag); + make_from_int(nr); m_is_null= item->null_value; if (!m_is_null && m_sec > limit) { m_sec= limit; m_truncated= true; - ErrConvInteger err(nr, item->unsigned_flag); + ErrConvInteger err(nr); thd->push_warning_truncated_wrong_value(type_str, err.ptr()); } } diff --git a/sql/sql_type.h b/sql/sql_type.h index 1a6c77008e8..767e715a94e 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -225,10 +225,10 @@ protected: bool m_truncated; // Indicates if the constructor truncated the value void make_from_decimal(const my_decimal *d); void make_from_double(double d); - void make_from_int(longlong nr, bool unsigned_val) + void make_from_int(const Longlong_hybrid &nr) { - m_neg= nr < 0 && !unsigned_val; - m_sec= m_neg ? (ulonglong) -nr : (ulonglong) nr; + m_neg= nr.neg(); + m_sec= nr.abs(); m_usec= 0; m_truncated= false; } @@ -238,20 +238,21 @@ protected: } Sec6() { } public: - Sec6(bool neg, ulonglong nr, ulong frac) - :m_sec(nr), m_usec(frac), m_neg(neg), m_truncated(false) - { } - Sec6(double nr) + explicit Sec6(double nr) { make_from_double(nr); } - Sec6(const my_decimal *d) + explicit Sec6(const my_decimal *d) { make_from_decimal(d); } - Sec6(longlong nr, bool unsigned_val) + explicit Sec6(const Longlong_hybrid &nr) { - make_from_int(nr, unsigned_val); + make_from_int(nr); + } + explicit Sec6(longlong nr, bool unsigned_val) + { + make_from_int(Longlong_hybrid(nr, unsigned_val)); } bool neg() const { return m_neg; } bool truncated() const { return m_truncated; } @@ -396,9 +397,10 @@ protected: bool to_mysql_time_with_warn(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate, const char *field_name) const { - longlong value= m_year * 10000; // Make it YYYYMMDD - const ErrConvInteger str(value, true); - Sec6 sec(false, value, 0); + // Make it YYYYMMDD + Longlong_hybrid value(static_cast(m_year) * 10000, true); + const ErrConvInteger str(value); + Sec6 sec(value); return sec.convert_to_mysql_time(thd, to, fuzzydate, &str, field_name); } uint year_precision(const Item *item) const; @@ -846,14 +848,8 @@ public: time_type= MYSQL_TIMESTAMP_NONE; xxx_to_time_result_to_valid_value(thd, warn, opt); } - Time(THD *thd, int *warn, double nr) - :Time(thd, warn, Sec6(nr), Options()) - { } - Time(THD *thd, int *warn, longlong nr, bool unsigned_val) - :Time(thd, warn, Sec6(nr, unsigned_val), Options()) - { } - Time(THD *thd, int *warn, const my_decimal *d) - :Time(thd, warn, Sec6(d), Options()) + Time(THD *thd, int *warn, const Sec6 &nr) + :Time(thd, warn, nr, Options()) { } Time(THD *thd, Item *item, const Options opt, uint dec) @@ -873,25 +869,11 @@ public: { trunc(dec); } - Time(THD *thd, int *warn, double nr, uint dec) + Time(THD *thd, int *warn, const Sec6 &nr, uint dec) :Time(thd, warn, nr) { trunc(dec); } - Time(THD *thd, int *warn, longlong nr, bool unsigned_val, uint dec) - :Time(thd, warn, nr, unsigned_val) - { - /* - Decimal digit truncation is needed here in case if nr was out - of the supported TIME range, so "this" was set to '838:59:59.999999'. - */ - trunc(dec); - } - Time(THD *thd, int *warn, const my_decimal *d, uint dec) - :Time(thd, warn, d) - { - trunc(dec); - } static date_mode_t flags_for_get_date() { return TIME_TIME_ONLY | TIME_INVALID_DATES; } @@ -1242,56 +1224,33 @@ public: date_to_datetime_if_needed(); DBUG_ASSERT(is_valid_value_slow()); } - Datetime(int *warn, double nr, date_mode_t flags) - :Temporal_with_date(warn, Sec6(nr), flags) - { - date_to_datetime_if_needed(); - DBUG_ASSERT(is_valid_value_slow()); - } - Datetime(int *warn, const my_decimal *d, date_mode_t flags) - :Temporal_with_date(warn, Sec6(d), flags) - { - date_to_datetime_if_needed(); - DBUG_ASSERT(is_valid_value_slow()); - } - /* - Create a Datime object from a longlong number. - Note, unlike in Time(), we don't need an "unsigned_val" here, - as it's not important if overflow happened because - of a negative number, or because of a huge positive number. - */ - Datetime(int *warn, longlong sec, ulong usec, date_mode_t flags) - :Temporal_with_date(warn, Sec6(false, (ulonglong) sec, usec), flags) + Datetime(int *warn, const Sec6 &nr, date_mode_t flags) + :Temporal_with_date(warn, nr, flags) { date_to_datetime_if_needed(); DBUG_ASSERT(is_valid_value_slow()); } Datetime(THD *thd, Item *item, date_mode_t flags, uint dec) - :Temporal_with_date(Datetime(thd, item, flags)) + :Datetime(thd, item, flags) { trunc(dec); } Datetime(MYSQL_TIME_STATUS *status, const char *str, size_t len, CHARSET_INFO *cs, date_mode_t fuzzydate, uint dec) - :Temporal_with_date(Datetime(status, str, len, cs, fuzzydate)) + :Datetime(status, str, len, cs, fuzzydate) { trunc(dec); } - Datetime(int *warn, double nr, date_mode_t fuzzydate, uint dec) - :Temporal_with_date(Datetime(warn, nr, fuzzydate)) - { - trunc(dec); - } - Datetime(int *warn, const my_decimal *d, date_mode_t fuzzydate, uint dec) - :Temporal_with_date(Datetime(warn, d, fuzzydate)) + Datetime(int *warn, const Sec6 &nr, date_mode_t fuzzydate, uint dec) + :Datetime(warn, nr, fuzzydate) { trunc(dec); } Datetime(THD *thd, int *warn, const MYSQL_TIME *from, date_mode_t fuzzydate, uint dec) - :Temporal_with_date(Datetime(thd, warn, from, fuzzydate)) + :Datetime(thd, warn, from, fuzzydate) { trunc(dec); }