From dddbd5ff427894941fee3d7528ca2058e026b82e Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 29 Sep 2026 12:23:56 +0300 Subject: [PATCH] MDEV-41344 Timestamp conversion does not work for TRADITIONAL mode Field_temporal::get_copy_func() returns do_field_datetime whenever the session's sql_mode has NO_ZERO_DATE or NO_ZERO_IN_DATE (e.g. under sql_mode=TRADITIONAL), or when the two fields are not eq_def(), regardless of whether the field is a system-versioned row_end. get_copy_func() checked for that value and returned early, before ever reaching the VERS_ROW_END check that installs do_field_versioned_timestamp. So an ALTER TABLE .. FORCE meant to convert an old-format row_end silently copied the value unchanged instead: the conversion check correctly demanded a copy, but the copy step never applied it, with no error or warning. The fix checks the row_end conversion need first, independently of what Field_temporal::get_copy_func() picked. row_end is server-maintained and never zero, so NO_ZERO_DATE does not apply to it. Tested by "traditional" combination in old_timestamp.test, the test restores real pre-11.5 row_end fixtures and runs mariadb-upgrade --force. --- .../suite/versioning/t/old_timestamp.combinations | 4 ++++ sql/field_conv.cc | 10 ++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 mysql-test/suite/versioning/t/old_timestamp.combinations diff --git a/mysql-test/suite/versioning/t/old_timestamp.combinations b/mysql-test/suite/versioning/t/old_timestamp.combinations new file mode 100644 index 00000000000..7a13300df3c --- /dev/null +++ b/mysql-test/suite/versioning/t/old_timestamp.combinations @@ -0,0 +1,4 @@ +[normal] + +[traditional] +sql-mode=TRADITIONAL diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 8b22127e7d3..d76d35abf20 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -782,12 +782,14 @@ Field::Copy_func *Field_timestamp::get_copy_func(const Field *from) const Field::Copy_func *copy= Field_temporal::get_copy_func(from); if (from->type() == MYSQL_TYPE_TIMESTAMP) { + if ((flags & VERS_ROW_END) && (from->flags & VERS_ROW_END) && + from->table->file->check_versioned_compatibility()) + { + DBUG_ASSERT(eq_def(from)); + return do_field_versioned_timestamp; + } if (copy == do_field_datetime) return do_field_timestamp; - if (copy == do_field_eq && - from->table->file->check_versioned_compatibility() && - (flags & VERS_ROW_END) && (from->flags & VERS_ROW_END)) - return do_field_versioned_timestamp; } return copy; }