From 8c0a260a5b81044ef94de8653794d9ac1d1f8cd0 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Sun, 27 Oct 2024 14:07:59 +0400 Subject: [PATCH] MDEV-35250 Assertion `dec <= 6' failed in my_timestamp_binary_length The TIMESTAMP related code did not handle AUTO_SEC_PART_DIGITS. FROM_UNIXTIME() sets its member 'decimals' to AUTO_SEC_PART_DIGITS. So some scripts involving FROM_UNIXTIME() crashed on assert in debug builds and returned unexpected results in release builds. --- mysql-test/main/type_timestamp.result | 61 +++++++++++++++++++++++++++ mysql-test/main/type_timestamp.test | 37 ++++++++++++++++ sql/filesort.cc | 9 ++-- sql/item.h | 6 ++- 4 files changed, 108 insertions(+), 5 deletions(-) diff --git a/mysql-test/main/type_timestamp.result b/mysql-test/main/type_timestamp.result index 7190cff26b2..cb94e2eef53 100644 --- a/mysql-test/main/type_timestamp.result +++ b/mysql-test/main/type_timestamp.result @@ -2336,3 +2336,64 @@ DROP TABLE t1; # # End of 11.3 tests # +# +# Start of 11.7 tests +# +# +# MDEV-35250 Assertion `dec <= 6' failed in my_timestamp_binary_length +# +SET time_zone='+00:00'; +SELECT FROM_UNIXTIME('1922-02-10'), BIT_AND(1); +FROM_UNIXTIME('1922-02-10') BIT_AND(1) +1970-01-01 00:32:02 1 +Warnings: +Warning 1292 Truncated incorrect DECIMAL value: '1922-02-10' +SELECT FROM_UNIXTIME('1922'), BIT_AND(1); +FROM_UNIXTIME('1922') BIT_AND(1) +1970-01-01 00:32:02 1 +SELECT FROM_UNIXTIME('1922.1'), BIT_AND(1); +FROM_UNIXTIME('1922.1') BIT_AND(1) +1970-01-01 00:32:02.100000 1 +SELECT FROM_UNIXTIME('1922.1'); +FROM_UNIXTIME('1922.1') +1970-01-01 00:32:02.100000 +SELECT * FROM (SELECT FROM_UNIXTIME('1'), BIT_AND(1)) t; +FROM_UNIXTIME('1') BIT_AND(1) +1970-01-01 00:00:01.000000 1 +SELECT * FROM (SELECT FROM_UNIXTIME('1.1'), BIT_AND(1)) t; +FROM_UNIXTIME('1.1') BIT_AND(1) +1970-01-01 00:00:01.100000 1 +CREATE TABLE t1 (a TEXT, b TEXT); +INSERT INTO t1 SELECT FROM_UNIXTIME('1'), BIT_AND(1); +INSERT INTO t1 SELECT FROM_UNIXTIME('1.1'), BIT_AND(1); +SELECT * FROM t1; +a b +1970-01-01 00:00:01 1 +1970-01-01 00:00:01.100000 1 +DROP TABLE t1; +SELECT 1 FROM (values(1),(2)) dt GROUP BY from_unixtime('a') WITH ROLLUP; +1 +1 +1 +Warnings: +Warning 1292 Truncated incorrect DECIMAL value: 'a' +Warning 1292 Truncated incorrect unixtime value: '0.0' +Warning 1292 Truncated incorrect DECIMAL value: 'a' +Warning 1292 Truncated incorrect unixtime value: '0.0' +Warning 1292 Truncated incorrect DECIMAL value: 'a' +Warning 1292 Truncated incorrect unixtime value: '0.0' +Warning 1292 Truncated incorrect DECIMAL value: 'a' +Warning 1292 Truncated incorrect unixtime value: '0.0' +Warning 1292 Truncated incorrect DECIMAL value: 'a' +Warning 1292 Truncated incorrect unixtime value: '0.0' +CREATE TABLE t1 (a TEXT); +INSERT INTO t1 VALUES (1),(2); +SELECT * FROM t1 ORDER BY from_unixtime(a); +a +1 +2 +DROP TABLE t1; +SET time_zone=DEFAULT; +# +# End of 11.7 tests +# diff --git a/mysql-test/main/type_timestamp.test b/mysql-test/main/type_timestamp.test index f3555d4ab84..6c7f1b9e6b1 100644 --- a/mysql-test/main/type_timestamp.test +++ b/mysql-test/main/type_timestamp.test @@ -1368,3 +1368,40 @@ DROP TABLE t1; --echo # --echo # End of 11.3 tests --echo # + +--echo # +--echo # Start of 11.7 tests +--echo # + +--echo # +--echo # MDEV-35250 Assertion `dec <= 6' failed in my_timestamp_binary_length +--echo # + +SET time_zone='+00:00'; +SELECT FROM_UNIXTIME('1922-02-10'), BIT_AND(1); +SELECT FROM_UNIXTIME('1922'), BIT_AND(1); +# Disable PS protocol to workaround CONC-739 +--disable_ps_protocol +SELECT FROM_UNIXTIME('1922.1'), BIT_AND(1); +SELECT FROM_UNIXTIME('1922.1'); +--enable_ps_protocol +SELECT * FROM (SELECT FROM_UNIXTIME('1'), BIT_AND(1)) t; +SELECT * FROM (SELECT FROM_UNIXTIME('1.1'), BIT_AND(1)) t; +CREATE TABLE t1 (a TEXT, b TEXT); +INSERT INTO t1 SELECT FROM_UNIXTIME('1'), BIT_AND(1); +INSERT INTO t1 SELECT FROM_UNIXTIME('1.1'), BIT_AND(1); +SELECT * FROM t1; +DROP TABLE t1; + +SELECT 1 FROM (values(1),(2)) dt GROUP BY from_unixtime('a') WITH ROLLUP; + +CREATE TABLE t1 (a TEXT); +INSERT INTO t1 VALUES (1),(2); +SELECT * FROM t1 ORDER BY from_unixtime(a); +DROP TABLE t1; + +SET time_zone=DEFAULT; + +--echo # +--echo # End of 11.7 tests +--echo # diff --git a/sql/filesort.cc b/sql/filesort.cc index 5e777399f80..e47a0a47290 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -1282,7 +1282,8 @@ Type_handler_timestamp_common::make_sort_key_part(uchar *to, Item *item, String *tmp_buffer) const { THD *thd= current_thd; - uint binlen= my_timestamp_binary_length(item->decimals); + decimal_digits_t dec= MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS); + uint binlen= my_timestamp_binary_length(dec); Timestamp_or_zero_datetime_native_null native(thd, item); if (native.is_null() || native.is_zero_datetime()) { @@ -2083,7 +2084,8 @@ Type_handler_timestamp_common::sort_length(THD *thd, const Type_std_attributes *item, SORT_FIELD_ATTR *sortorder) const { - sortorder->length= my_timestamp_binary_length(item->decimals); + decimal_digits_t dec= MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS); + sortorder->length= my_timestamp_binary_length(dec); sortorder->original_length= sortorder->length; } @@ -2619,7 +2621,8 @@ Type_handler_timestamp_common::make_packed_sort_key_part(uchar *to, Item *item, String *tmp) const { THD *thd= current_thd; - uint binlen= my_timestamp_binary_length(item->decimals); + decimal_digits_t dec= MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS); + uint binlen= my_timestamp_binary_length(dec); Timestamp_or_zero_datetime_native_null native(thd, item); if (native.is_null() || native.is_zero_datetime()) { diff --git a/sql/item.h b/sql/item.h index f0199b992f3..137b2be579a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -6789,7 +6789,8 @@ public: DBUG_ASSERT(sane()); if (null_value) return set_field_to_null(field); - Timestamp_or_zero_datetime_native native(m_value, decimals); + decimal_digits_t dec= MY_MIN(decimals, TIME_SECOND_PART_DIGITS); + Timestamp_or_zero_datetime_native native(m_value, dec); return native.save_in_field(field, decimals); } longlong val_int() override @@ -6826,7 +6827,8 @@ public: bool val_native(THD *thd, Native *to) override { DBUG_ASSERT(sane()); - return null_value || m_value.to_native(to, decimals); + decimal_digits_t dec= MY_MIN(decimals, TIME_SECOND_PART_DIGITS); + return null_value || m_value.to_native(to, dec); } Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); }