From a090a3c5713d759065acce70d34373b64156df6e Mon Sep 17 00:00:00 2001
From: Kristian Nielsen <knielsen@knielsen-hq.org>
Date: Sat, 30 Nov 2024 21:27:29 +0100
Subject: [PATCH] MDEV-33239: mysqlbinlog always stops at timestamp 0xffffffff

Do not use the magic value 0xffffffff as meaning "no --stop-datetime option
specified", as this is a valid timestamp value. Use an explicit boolean flag
instead.

Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org>
---
 client/mysqlbinlog.cc              | 10 ++++++----
 mysql-test/main/mysqlbinlog.result | 19 +++++++++++++++++++
 mysql-test/main/mysqlbinlog.test   | 25 +++++++++++++++++++++++++
 3 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index dc9d015e6c2..4769fdaf111 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -164,7 +164,8 @@ static Domain_gtid_event_filter *domain_id_gtid_filter= NULL;
 static Server_gtid_event_filter *server_id_gtid_filter= NULL;
 
 static char *start_datetime_str, *stop_datetime_str;
-static my_time_t start_datetime= 0, stop_datetime= MY_TIME_T_MAX;
+static my_time_t start_datetime= 0, stop_datetime= 0;
+static bool stop_datetime_given= false;
 static ulonglong rec_count= 0;
 static MYSQL* mysql = NULL;
 static const char* dirname_for_local_load= 0;
@@ -1032,7 +1033,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
       if (ev_type != ROTATE_EVENT && is_server_id_excluded(ev->server_id))
         goto end;
     }
-    if ((ev->when >= stop_datetime)
+    if ((stop_datetime_given && ev->when >= stop_datetime)
         || (pos >= stop_position_mot))
     {
       /* end the program */
@@ -2125,6 +2126,7 @@ get_one_option(const struct my_option *opt, const char *argument,
     break;
   case OPT_STOP_DATETIME:
     stop_datetime= convert_str_to_timestamp(stop_datetime_str);
+    stop_datetime_given= true;
     break;
   case OPT_BASE64_OUTPUT_MODE:
     int val;
@@ -3198,7 +3200,7 @@ static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
         Emit a warning in the event that we finished processing input
         before reaching the boundary indicated by --stop-datetime.
       */
-      if (stop_datetime != MY_TIME_T_MAX &&
+      if (stop_datetime_given &&
           stop_datetime > last_ev_when)
       {
           retval = OK_STOP;
@@ -3305,7 +3307,7 @@ int main(int argc, char** argv)
     if (stop_position != (ulonglong)(~(my_off_t)0))
       warning("The --stop-position option is ignored in raw mode");
 
-    if (stop_datetime != MY_TIME_T_MAX)
+    if (stop_datetime_given)
       warning("The --stop-datetime option is ignored in raw mode");
     result_file= 0;
     if (result_file_name)
diff --git a/mysql-test/main/mysqlbinlog.result b/mysql-test/main/mysqlbinlog.result
index c7b354105c2..8181a76244c 100644
--- a/mysql-test/main/mysqlbinlog.result
+++ b/mysql-test/main/mysqlbinlog.result
@@ -1300,4 +1300,23 @@ ERROR: Bad syntax in rewrite-db. Expected syntax is FROM->TO.
 ERROR: Bad syntax in rewrite-db. Expected syntax is FROM->TO.
 ERROR: Bad syntax in rewrite-db. Expected syntax is FROM->TO.
 ERROR: Bad syntax in rewrite-db. Expected syntax is FROM->TO.
+#
+# MDEV-33239: mysqlbinlog always stops at timestamp 0xffffffff
+#
+RESET MASTER;
+CREATE TABLE t (a INT);
+INSERT INTO t VALUES (1);
+SET @@timestamp= 0 + 0xffffffff;
+INSERT INTO t VALUES (2);
+SELECT * FROM t ORDER BY a;
+a
+1
+2
+FLUSH BINARY LOGS;
+DROP TABLE t;
+SELECT * FROM t ORDER BY a;
+a
+1
+2
+DROP TABLE t;
 ALTER DATABASE test CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci;
diff --git a/mysql-test/main/mysqlbinlog.test b/mysql-test/main/mysqlbinlog.test
index 3beea178b78..8c904d3fd26 100644
--- a/mysql-test/main/mysqlbinlog.test
+++ b/mysql-test/main/mysqlbinlog.test
@@ -641,4 +641,29 @@ FLUSH LOGS;
 --exec $MYSQL_BINLOG --rewrite-db=" test -> foo " --short-form $MYSQLD_DATADIR/master-bin.000001 > /dev/null 2> $MYSQLTEST_VARDIR/tmp/mysqlbinlog.warn
 
 
+--echo #
+--echo # MDEV-33239: mysqlbinlog always stops at timestamp 0xffffffff
+--echo #
+
+RESET MASTER;
+
+CREATE TABLE t (a INT);
+INSERT INTO t VALUES (1);
+# The 0xffffffff timestamp is truncated on 32-bit, gives warning.
+--disable_warnings
+SET @@timestamp= 0 + 0xffffffff;
+--enable_warnings
+INSERT INTO t VALUES (2);
+SELECT * FROM t ORDER BY a;
+
+FLUSH BINARY LOGS;
+DROP TABLE t;
+
+# The bug was that mysqlbinlog would stop before the event with timestamp
+# 0xffffffff, so the second insert would be missing from the table.
+--exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 | $MYSQL test
+SELECT * FROM t ORDER BY a;
+DROP TABLE t;
+
+
 --source include/test_db_charset_restore.inc