Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions mysql-test/suite/versioning/r/trx_id.result
Original file line number Diff line number Diff line change
Expand Up @@ -611,3 +611,21 @@ ERROR HY000: Lock wait timeout exceeded; try restarting transaction
disconnect con1;
connection default;
drop table t1;
#
# MDEV-40147 MSAN: use-of-uninitialized-value in my_time_compare
#
CREATE TABLE t (
a INT,
row_start BIGINT UNSIGNED GENERATED ALWAYS AS ROW START,
row_end BIGINT UNSIGNED GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME (row_start, row_end)
) WITH SYSTEM VERSIONING ENGINE=InnoDB;
INSERT INTO t () VALUES ();
ANALYZE TABLE t PERSISTENT FOR ALL;
Table Op Msg_type Msg_text
test.t analyze status Engine-independent statistics collected
test.t analyze status OK
SELECT * FROM t WHERE row_end > CURRENT_TIME();
ERROR HY000: TRX_ID ... not found in `mysql.transaction_registry`
DROP TABLE t;
# End of 10.11 tests
23 changes: 23 additions & 0 deletions mysql-test/suite/versioning/t/trx_id.test
Original file line number Diff line number Diff line change
Expand Up @@ -643,3 +643,26 @@ alter table xx;
--disconnect con1
--connection default
drop table t1;

--echo #
--echo # MDEV-40147 MSAN: use-of-uninitialized-value in my_time_compare
--echo #

CREATE TABLE t (
a INT,
row_start BIGINT UNSIGNED GENERATED ALWAYS AS ROW START,
row_end BIGINT UNSIGNED GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME (row_start, row_end)
) WITH SYSTEM VERSIONING ENGINE=InnoDB;

INSERT INTO t () VALUES ();

ANALYZE TABLE t PERSISTENT FOR ALL;

--replace_regex /TRX_ID \d+/TRX_ID .../
--error ER_VERS_NO_TRX_ID
SELECT * FROM t WHERE row_end > CURRENT_TIME();

DROP TABLE t;

--echo # End of 10.11 tests
9 changes: 6 additions & 3 deletions sql/sql_time.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ int append_interval(String *str, interval_type int_type,
*/
bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
int lsign, MYSQL_TIME *l_time3, date_mode_t fuzzydate);
int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b);
int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b)
__attribute__((nonnull));
void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);

void calc_time_from_sec(MYSQL_TIME *to, ulong seconds, ulong microseconds);
Expand Down Expand Up @@ -183,8 +184,10 @@ check_date_with_warn(THD *thd, const MYSQL_TIME *ltime,

bool adjust_time_range_with_warn(THD *thd, MYSQL_TIME *ltime, uint dec);

longlong pack_time(const MYSQL_TIME *my_time);
longlong pack_time(const MYSQL_TIME *my_time)
__attribute__((nonnull));
void unpack_time(longlong packed, MYSQL_TIME *my_time,
enum_mysql_timestamp_type ts_type);
enum_mysql_timestamp_type ts_type)
__attribute__((nonnull));

#endif /* SQL_TIME_INCLUDED */
16 changes: 9 additions & 7 deletions sql/sql_type.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8951,7 +8951,7 @@ Type_handler_temporal_result::Item_const_eq(const Item_const *a,
{
const MYSQL_TIME *ta= a->const_ptr_mysql_time();
const MYSQL_TIME *tb= b->const_ptr_mysql_time();
return !my_time_compare(ta, tb) &&
return ta && tb && !my_time_compare(ta, tb) &&
(!binary_cmp ||
a->get_type_all_attributes_from_const()->decimals ==
b->get_type_all_attributes_from_const()->decimals);
Expand Down Expand Up @@ -9107,10 +9107,10 @@ int Type_handler_temporal_with_date::stored_field_cmp_to_item(THD *thd,
Item *item) const
{
MYSQL_TIME field_time, item_time, item_time2, *item_time_cmp= &item_time;
field->get_date(&field_time, Datetime::Options(TIME_INVALID_DATES, thd));
item->get_date(thd, &item_time, Datetime::Options(TIME_INVALID_DATES, thd));
if (item_time.time_type == MYSQL_TIMESTAMP_TIME &&
time_to_datetime(thd, &item_time, item_time_cmp= &item_time2))
if (field->get_date(&field_time, Datetime::Options(TIME_INVALID_DATES, thd))
|| item->get_date(thd, &item_time, Datetime::Options(TIME_INVALID_DATES, thd))
|| (item_time.time_type == MYSQL_TIMESTAMP_TIME &&
time_to_datetime(thd, &item_time, item_time_cmp= &item_time2)))
return 1;
Comment on lines +9110 to 9114

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In Type_handler_temporal_with_date::stored_field_cmp_to_item, if field->get_date fails, returning 1 (which indicates field > item) is inconsistent and incorrect when item is valid. To be consistent with Type_handler_time_common::stored_field_cmp_to_item (lines 9124-9127), we should return -1 when field->get_date fails, and 1 when item->get_date (or its conversion) fails. This ensures symmetric and correct comparison behavior when one of the operands is invalid.

  if (field->get_date(&field_time, Datetime::Options(TIME_INVALID_DATES, thd)))
    return -1;
  if (item->get_date(thd, &item_time, Datetime::Options(TIME_INVALID_DATES, thd)) ||
      (item_time.time_type == MYSQL_TIMESTAMP_TIME &&
       time_to_datetime(thd, &item_time, item_time_cmp= &item_time2)))
    return 1;

return my_time_compare(&field_time, item_time_cmp);
}
Expand All @@ -9121,8 +9121,10 @@ int Type_handler_time_common::stored_field_cmp_to_item(THD *thd,
Item *item) const
{
MYSQL_TIME field_time, item_time;
field->get_date(&field_time, Time::Options(thd));
item->get_date(thd, &item_time, Time::Options(thd));
if (field->get_date(&field_time, Time::Options(thd)))
return -1; /* !=0 is important, and avoid my_time_compare */
if (item->get_date(thd, &item_time, Time::Options(thd)))
return 1; /* !=0 is important, and avoid my_time_compare */
return my_time_compare(&field_time, &item_time);
}

Expand Down